trunk: changeset 15

Sun, 21 May 2000 17:33:48 +0200

author
tuomov
date
Sun, 21 May 2000 17:33:48 +0200
changeset 12
5fd153b29d40
parent 11
3ea4e7930c5b
child 13
9eb09d246c9f

trunk: changeset 15
- Optparser generates --help from option descriptions in the
OptParserOpt structure

- Changed the options --license, --authors and --proginfo to single
--about

include/libtu/optparser.h file | annotate | diff | comparison | revisions
include/libtu/util.h file | annotate | diff | comparison | revisions
optparser.c file | annotate | diff | comparison | revisions
tester.c file | annotate | diff | comparison | revisions
tester3.c file | annotate | diff | comparison | revisions
util.c file | annotate | diff | comparison | revisions
--- a/include/libtu/optparser.h	Sat May 20 17:43:36 2000 +0200
+++ b/include/libtu/optparser.h	Sun May 21 17:33:48 2000 +0200
@@ -11,8 +11,11 @@
 #include "types.h"
 
 
-#define OPT_ID(X)			((X)|0x10000)
-#define OPT_ID_RESERVED(X)	((X)|0x20000)
+#define OPT_ID_NOSHORT_FLAG 0x10000
+#define OPT_ID_RESERVED_FLAG 0x20000
+
+#define OPT_ID(X)			((X)|OPT_ID_NOSHORT_FLAG)
+#define OPT_ID_RESERVED(X)	((X)|OPT_ID_RESERVED_FLAG)
 
 /* OPTP_CHAIN is the normal behavior, i.e. single-letter options can be
  *		"chained" together: 'lr -lR'. Use for normal command line programs.
@@ -27,6 +30,7 @@
 
 enum{
 	OPTP_CHAIN=0,
+	OPTP_DEFAULT=0,
 	OPTP_MIDLONG=1,
 	OPTP_IMMEDIATE=2,
 	OPTP_NO_DASH=3
@@ -38,13 +42,22 @@
 };
 
 
-typedef struct{
+typedef struct _OptParserOpt{
 	int optid;
 	const char *longopt;
 	int	flags;
+	const char *argname;
+	const char *descr;
 } OptParserOpt;
 
 
+typedef struct _OptParserCommonInfo{
+	const char *version;
+	const char *usage_tmpl;
+	const char *about;
+} OptParserCommonInfo;
+
+
 enum{
 	OPT_ID_END=0,
 	OPT_ID_ARGUMENT=1,
@@ -58,7 +71,9 @@
 
 
 extern void optparser_init(int argc, char *const argv[], int mode,
-						   const OptParserOpt *opts);
+						   const OptParserOpt *opts,
+						   const OptParserCommonInfo *cinfo);
+
 extern int  optparser_get_opt();
 extern const char* optparser_get_arg();
 extern void optparser_print_error();
--- a/include/libtu/util.h	Sat May 20 17:43:36 2000 +0200
+++ b/include/libtu/util.h	Sun May 21 17:33:48 2000 +0200
@@ -13,26 +13,13 @@
 #include <stdlib.h>
 
 #include "types.h"
-
+#include "optparser.h"
 
-typedef struct{
-	const char *name;
-	const char *version;
-	const char *authors;
-	const char *license;
-	const char *usage;
-} ProgInfo;
-
-
-extern void libtu_init_argv0(const char *argv0, const ProgInfo *info);
-extern void libtu_init(int *argc, char *argv[], const ProgInfo *info);
+extern void libtu_init(const char *argv0);
+extern void libtu_init_copt(int argc, char *const argv[],
+							const OptParserCommonInfo *cinfo);
+					   
 
 extern const char *prog_execname();
-extern const ProgInfo *prog_info();
-extern const char *prog_name();
-extern const char *prog_version();
-extern const char *prog_authors();
-extern const char *prog_license();
-extern const char *prog_usage();
 
 #endif /* LIBTU_UTIL_H */
--- 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++;
+	}
+}
+
--- a/tester.c	Sat May 20 17:43:36 2000 +0200
+++ b/tester.c	Sun May 21 17:33:48 2000 +0200
@@ -9,13 +9,15 @@
 
 #include <libtu/misc.h>
 #include <libtu/tokenizer.h>
-
+#include <libtu/util.h>
 
-int main(void)
+int main(int argc, char *argv[])
 {
 	Tokenizer*tokz;
 	Token tok=TOK_INIT;
 	
+	libtu_init(argv[0]);
+	
 	if(!(tokz=tokz_open_file(stdin)))
 		return EXIT_FAILURE;
 
--- a/tester3.c	Sat May 20 17:43:36 2000 +0200
+++ b/tester3.c	Sun May 21 17:33:48 2000 +0200
@@ -13,31 +13,19 @@
 
 
 static const char usage[]=
-	"$u [options]\n"
+	"Usage: $p [options]\n"
 	"\n"
 	"Where options are:\n"
-	"\n"
-	"  -o, -f, -v, -z, -x\n"
-	"$c                   \n"
-	"\n";
+	"$o\n";
 	
 
-static ProgInfo proginfo={
-	"Tester III",
-	"0.1",
-	"foo",
-	"bar",
-	usage
-};
-
-
 static OptParserOpt opts[]={
-	{'o',	"opt",		OPT_ARG},
-	{'f',	"file",		OPT_ARG},
-	{'v',	"view",		0},
-	{'z',	"zip",		0},
-	{'x',	"extract",	0},
-	{0, NULL, 0}
+	{'o',	"opt", OPT_ARG, "OPTION", "foo bar baz quk asdf jklö äölk dfgh quik aaaa bbbb cccc dddd eeee ffff"},
+	{'f',	"file", OPT_ARG, "FILE", "asdfsadlfölökjasdflökjasdflkjöasdflkjöas dlöfjkasdfölkjasdfölkjasdfasdflöjasdfkasödjlfkasdlföjasdölfjkölkasjdfasdfölkjasd asdöljfasöldf  asdölfköasdlf asfdlök asdföljkadsfölasdfölasdölkfjasdölfasödlflöskflasdföaölsdf"},
+	{'v',	"view",	0, NULL, NULL},
+	{'z',	"zip", 0, NULL, NULL},
+	{'x',	"extract", 0, NULL, NULL},
+	{0, NULL, 0, NULL, NULL}
 };
 	
 
@@ -45,9 +33,9 @@
 {
 	int opt;
 	
-	libtu_init(&argc, argv, &proginfo);
+	libtu_init(argv[0]);
 	
-	optparser_init(argc, argv, OPTP_NO_DASH, opts);
+	optparser_init(argc, argv, OPTP_NO_DASH, opts, NULL);
 	
 	while((opt=optparser_get_opt())){
 		switch(opt){
--- a/util.c	Sat May 20 17:43:36 2000 +0200
+++ b/util.c	Sun May 21 17:33:48 2000 +0200
@@ -18,16 +18,12 @@
 #include <libtu/misc.h>
 
 
-static const ProgInfo *proginfo=NULL;
 static const char *progname=NULL;
 
-static void common_opts(int *argc, char *argv[]);
 
-
-void libtu_init_argv0(const char *argv0, const ProgInfo *info)
+void libtu_init(const char *argv0)
 {
 	progname=argv0;
-	proginfo=info;
 	
 #ifdef CONFIG_LOCALE
 	textdomain(simple_basename(argv0));
@@ -35,11 +31,22 @@
 }
 
 
-void libtu_init(int *argc, char *argv[], const ProgInfo *info)
+void libtu_init_copt(int argc, char *const argv[],
+					 const OptParserCommonInfo *cinfo)
 {
-	libtu_init_argv0(argv[0], info);
+	int opt;
+	
+	libtu_init(argv[0]);
+	
+	optparser_init(argc, argv, OPTP_DEFAULT, NULL, cinfo);
 	
-	common_opts(argc, argv);
+    while((opt=optparser_get_opt())){	
+		switch(opt){
+		default:
+			optparser_print_error();
+			exit(EXIT_FAILURE);
+		}
+	}
 }
 
 
@@ -48,178 +55,3 @@
 	return progname;
 }
 
-
-const ProgInfo *prog_info()
-{
-	return proginfo;
-}
-
-
-const char *prog_name()
-{
-	return proginfo ? proginfo->name : NULL;
-}
-
-
-const char *prog_version()
-{
-	return proginfo ? proginfo->version : NULL;
-}
-
-
-const char *prog_authors()
-{
-	return proginfo ? proginfo->authors : NULL;
-}
-
-
-const char *prog_license()
-{
-	return proginfo ? proginfo->license : NULL;
-}
-
-
-const char *prog_usage()
-{
-	return proginfo ? proginfo->usage : NULL;
-}
-
-
-/* */
-
-
-static char *usages[][2]={
-	{"--help",		"Show this help\n"},
-	{"--version",	"Show program version\n"},
-	{"--authors",	"Show program authors\n"},
-	{"--license",	"Show program license\n"},
-	{"--proginfo",	"Show program info\n"},
-	{NULL,}
-};
-
-
-static void common_usage(size_t start, size_t len)
-{
-	size_t l;
-	int i;
-	
-	for(i=0; usages[i][0]!=NULL; i++){
-	
-		for(l=0; l<start; l++){
-			putc(' ', stdout);
-		};
-		
-		l=strlen(usages[i][0]);
-		writef(stdout, usages[i][0], l);
-		
-		do{
-			putc(' ', stdout);
-		}while(++l<len-start);
-		
-		writef(stdout, usages[i][1], strlen(usages[i][1]));
-	}
-}
-
-
-static void show_usage(const char *p)
-{
-	const char *tmp;
-	size_t len;
-	size_t start;
-	
-	do{
-		tmp=strchr(p, '\n');
-
-		if(tmp==NULL){
-			len=strlen(p);
-			if(len==0)
-				break;
-		}else{
-			len=tmp-p;
-		}
-		
-		start=strspn(p, " ");
-		
-		if(p[start]=='$' && p[start+1]=='u'){
-			tmp=prog_execname();
-			if(start!=0)
-				writef(stdout, p, start);
-			printf(TR("Usage: %s"), tmp);
-			writef(stdout, p+start+2, len-start-2);
-			putc('\n', stdout);
-		}else if(p[start]=='$' && p[start+1]=='c'){
-			common_usage(start, len);
-		}else{
-			writef(stdout, p, len);
-			putc('\n', stdout);
-		}
-		
-		p+=len+1;
-	}while(*(p-1)!='\0');
-	
-}
-
-
-static void common_opts(int *argcp, char *argv[])
-{
-	int argc=*argcp;
-	const char *p, *p2;
-
-	argc--;
-	argv++;
-	
-	for(; argc>0; argc--, argv++){
-		if(strcmp(*argv, "--help")==0){
-			p=prog_usage();
-			if(p==NULL){
-				printf(TR("Usage: %s [options]\n"
-						  "Where options are:\n\n"), prog_execname());
-				common_usage(5, 20);
-				printf("\n");
-			}else{
-				show_usage(p);
-			}
-		}else if(strcmp(*argv, "--version")==0){
-			p=prog_version();
-			if(p==NULL)
-				printf(TR("No version available\n"));
-			else
-				printf("%s\n", p);
-		}else if(strcmp(*argv, "--authors")==0){
-			p=prog_authors();
-			if(p==NULL)
-				printf(TR("No author(s) info available\n"));
-			else
-				printf("%s\n", p);
-		}else if(strcmp(*argv, "--license")==0){
-			p=prog_license();
-			if(p==NULL)
-				printf(TR("No license available\n"));
-			else
-				printf("%s", TR(p));
-		}else if(strcmp(*argv, "--proginfo")==0){
-			p2=prog_version();
-			p=prog_name();
-			
-			if(p==NULL){
-				p=prog_execname();
-			
-				if(p==NULL){
-					printf(TR("No name available\n"));
-					break;
-				}
-			}
-			
-			if(p2)
-				printf("%s v%s\n", p, p2);
-			else
-				printf("%s\n", p);
-		}else if(strcmp(*argv, "--")){
-			break;
-		}else{
-			continue;
-		}
-			
-		exit(EXIT_SUCCESS);
-	}
-}

mercurial