optparser.c

changeset 12
5fd153b29d40
parent 9
55e7f2ff6021
child 19
3e498ec7abcd
--- a/optparser.c	Sat May 20 17:43:36 2000 +0200
+++ b/optparser.c	Sun May 21 17:33:48 2000 +0200
@@ -19,6 +19,25 @@
 #define O_OPT_ARG(o)	(O_ARGS(o)==OPT_OPT_ARG)
 #define O_ID(o)			(o->optid)
 
+#define OPT_ID_HELP OPT_ID_RESERVED('h')
+#define OPT_ID_VERSION OPT_ID_RESERVED('V')
+#define OPT_ID_ABOUT OPT_ID_RESERVED('a'|OPT_ID_NOSHORT_FLAG)
+
+
+static OptParserOpt common_opts[]={
+	{OPT_ID_HELP, "help", 0, NULL, DUMMY_TR("Show this  help")},
+	{OPT_ID_VERSION, "version", 0, NULL, DUMMY_TR("Show program version")},
+	{OPT_ID_ABOUT, "about", 0, NULL, DUMMY_TR("Show about text")},
+	{0, NULL, 0, NULL, NULL}
+};
+
+
+static OptParserCommonInfo dummy_cinfo[]={
+	NULL, /* version */
+	"Usage: $p\n", /* usage_tmpl */
+	NULL /* about */
+};
+	
 
 static const OptParserOpt *o_opts=NULL;
 static char *const *o_current=NULL;
@@ -28,21 +47,30 @@
 static const char*o_tmp=NULL;
 static int o_error=0;
 static int o_mode=OPTP_CHAIN;
+static const OptParserCommonInfo *o_cinfo=NULL;
+
+
+/* */
+
+
+static void print_help(const OptParserOpt *opts, bool midlong,
+					   const OptParserCommonInfo *cinfo);
 
 
 /* */
 
 
 void optparser_init(int argc, char *const argv[], int mode,
-					const OptParserOpt *opts)
+					const OptParserOpt *opts, const OptParserCommonInfo *cinfo)
 {
 	o_mode=mode;
-	o_opts=opts;
+	o_opts=(opts==NULL ? common_opts : opts);
 	o_current=argv+1;
 	o_left=argc-1;
 	o_chain_ptr=NULL;
 	o_args_left=0;
 	o_tmp=NULL;
+	o_cinfo=(cinfo==NULL ? dummy_cinfo : cinfo);
 }
 
 
@@ -52,7 +80,7 @@
 static const OptParserOpt *find_chain_opt(char p, const OptParserOpt *o)
 {
 	for(;O_ID(o);o++){
-		if(O_ID(o)==p)
+		if((O_ID(o)&~OPT_ID_RESERVED_FLAG)==p)
 			return o;
 	}
 	return NULL;
@@ -80,7 +108,7 @@
 };
 
 
-int optparser_get_opt()
+static int optparser_do_get_opt()
 {
 #define RET(X) return o_tmp=p, o_error=X
 	const char *p, *p2=NULL;
@@ -143,7 +171,7 @@
 	o=o_opts;
 
 again:
-	for(;O_ID(o);o++){
+	for(; O_ID(o); o++){
 		if(type==LONG){
 			/* Do long option (--foo=bar) */
 			if(o->longopt==NULL)
@@ -173,7 +201,7 @@
 			if(strcmp(p2, o->longopt)!=0)
 				continue;
 		}else{ /* type==SHORT */
-			if(*p2!=O_ID(o))
+			if(*p2!=(O_ID(o)&~OPT_ID_RESERVED_FLAG))
 				continue;
 			   
 			if(*(p2+1)!='\0'){
@@ -212,6 +240,11 @@
 		o_args_left=1;
 		return O_ID(o);
 	}
+	
+	if(o!=&(common_opts[3])){
+		o=common_opts;
+		goto again;
+	}
 
 	if(dash)
 		RET(E_OPT_INVALID_OPTION);
@@ -221,6 +254,33 @@
 }
 
 
+int optparser_get_opt()
+{
+	int oid=optparser_do_get_opt();
+	
+	if(oid<=0 || (oid&OPT_ID_RESERVED_FLAG)==0)
+		return oid;
+	
+	switch(oid){
+	case OPT_ID_ABOUT:
+		if(o_cinfo->about!=NULL)
+			printf("%s", o_cinfo->about);
+		break;
+		
+	case OPT_ID_VERSION:
+		if(o_cinfo->version!=NULL)
+			printf("%s\n", o_cinfo->version);
+		break;
+			
+	case OPT_ID_HELP:
+		print_help(o_opts, o_mode==OPTP_MIDLONG, o_cinfo);
+		break;
+	}
+	
+	exit(EXIT_SUCCESS);
+}
+
+
 /* */
 
 
@@ -302,3 +362,211 @@
 	o_tmp=NULL;
 	o_error=0;
 }
+
+
+/* */
+
+
+static uint opt_w(const OptParserOpt *opt, bool midlong)
+{
+	uint w=0;
+	
+	if((opt->optid&OPT_ID_NOSHORT_FLAG)==0){
+		w+=2; /* "-o" */
+		if(opt->longopt!=NULL)
+			w+=2; /* ", " */
+	}
+	
+	if(opt->longopt!=NULL)
+		w+=strlen(opt->longopt)+(midlong ? 1 : 2);
+	
+	if(O_ARGS(opt)){
+		if(opt->argname==NULL)
+			w+=4;
+		else
+			w+=1+strlen(opt->argname); /* "=ARG" or " ARG" */
+		
+		if(O_OPT_ARG(opt))
+			w+=2; /* [ARG] */
+	}
+	
+	return w;
+}
+
+
+#define TERM_W 80
+#define OFF1 2
+#define OFF2 2
+#define SPACER1 "  "
+#define SPACER2 "  "
+
+static void print_opt(const OptParserOpt *opt, bool midlong,
+					  uint maxw, uint tw)
+{
+	FILE *f=stdout;
+	const char *p, *p2, *p3;
+	uint w=0;
+	
+	fprintf(f, SPACER1);
+	
+	/* short opt */
+	
+	if((O_ID(opt)&OPT_ID_NOSHORT_FLAG)==0){
+		fprintf(f, "-%c", O_ID(opt)&~OPT_ID_RESERVED_FLAG);
+		w+=2;
+		
+		if(opt->longopt!=NULL){
+			fprintf(f, ", ");
+			w+=2;
+		}
+	}
+	
+	/* long opt */
+	
+	if(opt->longopt!=NULL){
+		if(midlong){
+			w++;
+			fprintf(f, "-%s", opt->longopt);
+		}else{
+			w+=2;
+			fprintf(f, "--%s", opt->longopt);
+		}
+		w+=strlen(opt->longopt);
+	}
+	
+	/* arg */
+	
+	if(O_ARGS(opt)){
+		w++;
+		if(opt->longopt!=NULL && !midlong)
+			putc('=', f);
+		else
+			putc(' ', f);
+		
+		if(O_OPT_ARG(opt)){
+			w+=2;
+			putc('[', f);
+		}
+		
+		if(opt->argname!=NULL){
+			fprintf(f, "%s", opt->argname);
+			w+=strlen(opt->argname);
+		}else{
+			w+=3;
+			fprintf(f, "ARG");
+		}
+
+		if(O_OPT_ARG(opt))
+			putc(']', f);
+	}
+	
+	while(w++<maxw)
+		putc(' ', f);
+	
+	/* descr */
+	
+	p=p2=opt->descr;
+	
+	if(p==NULL){
+		putc('\n', f);
+		return;
+	}
+	
+	fprintf(f, SPACER2);
+
+	maxw+=OFF1+OFF2;
+	tw-=maxw;
+	
+	while(strlen(p)>tw){
+		p3=p2=p+tw-2;
+		
+		while(*p2!=' ' && p2!=p)
+			p2--;
+		
+		while(*p3!=' ' && *p3!='\0')
+			p3++;
+		
+		if((uint)(p3-p2)>tw){
+			/* long word - just wrap */
+			p2=p+tw-2;
+		}
+			
+		writef(f, p, p2-p);
+		if(*p2==' ')
+			putc('\n', f);
+		else
+			fprintf(f, "\\\n");
+		
+		p=p2+1;
+		
+		w=maxw;
+		while(w--)
+			putc(' ', f);
+	}
+	
+	fprintf(f, "%s\n", p);
+}
+
+					  
+static void print_opts(const OptParserOpt *opts, bool midlong,
+					   const OptParserCommonInfo *cinfo)
+{
+	uint w, maxw=0;
+	const OptParserOpt *o;
+	
+	o=opts;
+again:
+	for(; O_ID(o); o++){
+		w=opt_w(o, midlong);
+		if(w>maxw)
+			maxw=w;
+	}
+	
+	if(o!=&(common_opts[3])){
+		o=common_opts;
+		goto again;
+	}
+
+	o=opts;
+again2:
+	for(; O_ID(o); o++)
+		print_opt(o, midlong, maxw, TERM_W);
+	
+	if(o!=&(common_opts[3])){
+		printf("\n");
+		o=common_opts;
+		goto again2;
+	}
+}
+
+
+static void print_help(const OptParserOpt *opts, bool midlong,
+					   const OptParserCommonInfo *cinfo)
+{
+	const char *tmp, *p=cinfo->usage_tmpl;
+	size_t len;
+	size_t start;
+	
+	while(1){
+		tmp=strchr(p, '$');
+
+		if(tmp==NULL){
+			writef(stdout, p, strlen(p));
+			return;
+		}
+		
+		if(tmp!=p)
+			writef(stdout, p, tmp-p);
+		
+		p=tmp+1;
+		
+		if(*p=='p'){
+			tmp=prog_execname();
+			writef(stdout, tmp, strlen(tmp));
+		}else if(*p=='o'){
+			print_opts(opts, midlong, cinfo);
+		}
+		p++;
+	}
+}
+

mercurial