commit 3cd77ae67905c839ba2078e119f981d4f2284c7a from: Russ Cox date: Wed Jul 15 06:48:37 2009 UTC getflags: import from 4e, with usage fixes #6 http://bitbucket.org/rsc/plan9port/issue/6/ http://codereview.appspot.com/95043 commit - 9bea9069bf3bc282c6b7d129926d4a0f1b40c66b commit + 3cd77ae67905c839ba2078e119f981d4f2284c7a blob - /dev/null blob + bb0edf28d4f1d032702072a1c04f2e0d9b589f86 (mode 644) --- /dev/null +++ cmd/getflags.c @@ -0,0 +1,82 @@ +#include +#include + +void +usage(void) +{ + print("status=usage\n"); + exits(0); +} + +char* +findarg(char *flags, Rune r) +{ + char *p; + Rune rr; + + for(p=flags; p!=(char*)1; p=strchr(p, ',')+1){ + chartorune(&rr, p); + if(rr == r) + return p; + } + return nil; +} + +int +countargs(char *p) +{ + int n; + + n = 1; + while(*p == ' ') + p++; + for(; *p && *p != ','; p++) + if(*p == ' ' && *(p-1) != ' ') + n++; + return n; +} + +void +main(int argc, char *argv[]) +{ + char *flags, *p, buf[512]; + int i, n; + Fmt fmt; + + quotefmtinstall(); + argv0 = argv[0]; /* for sysfatal */ + + flags = getenv("flagfmt"); + if(flags == nil){ + fprint(2, "$flagfmt not set\n"); + print("exit 'missing flagfmt'"); + exits(0); + } + + fmtfdinit(&fmt, 1, buf, sizeof buf); + for(p=flags; p!=(char*)1; p=strchr(p, ',')+1) + fmtprint(&fmt, "flag%.1s=()\n", p); + ARGBEGIN{ + default: + if((p = findarg(flags, ARGC())) == nil) + usage(); + p += runelen(ARGC()); + if(*p == ',' || *p == 0){ + fmtprint(&fmt, "flag%C=1\n", ARGC()); + break; + } + n = countargs(p); + fmtprint(&fmt, "flag%C=(", ARGC()); + for(i=0; i +#include + +void +main(int argc, char **argv) +{ + Fmt fmt; + char buf[512]; + char *argv0, *args, *flags, *p, *p0; + int single; + Rune r; + + argv0 = getenv("0"); + if(argv0 == nil) { + if(argc > 1) + argv0 = argv[1]; + else + argv0 = "unknown-program-name"; + } + if((p = strrchr(argv0, '/')) != nil) + argv0 = p+1; + flags = getenv("flagfmt"); + args = getenv("args"); + + if(argv0 == nil){ + fprint(2, "aux/usage: $0 not set\n"); + exits("$0"); + } + if(flags == nil) + flags = ""; + if(args == nil) + args = ""; + + fmtfdinit(&fmt, 2, buf, sizeof buf); + fmtprint(&fmt, "usage: %s", argv0); + if(flags[0]){ + single = 0; + for(p=flags; *p; ){ + p += chartorune(&r, p); + if(*p == ',' || *p == 0){ + if(!single){ + fmtprint(&fmt, " [-"); + single = 1; + } + fmtprint(&fmt, "%C", r); + if(*p == ',') + p++; + continue; + } + while(*p == ' ') + p++; + if(single){ + fmtprint(&fmt, "]"); + single = 0; + } + p0 = p; + p = strchr(p0, ','); + if(p == nil) + p = ""; + else + *p++ = 0; + fmtprint(&fmt, " [-%C %s]", r, p0); + } + if(single) + fmtprint(&fmt, "]"); + } + if(args) + fmtprint(&fmt, " %s", args); + fmtprint(&fmt, "\n"); + fmtfdflush(&fmt); + exits("usage"); +} blob - /dev/null blob + 50274d4079a9fb4224a0f7dc5c690e28401930ed (mode 644) --- /dev/null +++ man8/getflags.8 @@ -0,0 +1,77 @@ +.TH GETFLAGS 8 +.SH NAME +getflags, usage \- command-line parsing for shell scripts +.SH SYNOPSIS +.B getflags $* +.PP +.B usage [ progname ] +.SH DESCRIPTION +.I Getflags +parses the options in its command-line arguments +according to the environment variable +.BR $flagfmt . +This variable should be a list of comma-separated options. +Each option can be a single letter, indicating that it does +not take arguments, or a letter followed by the space-separated +names of its arguments. +.I Getflags +prints an +.IR rc (1) +script on standard output which initializes the +environment variable +.BI $flag x +for every option mentioned in +.BR $flagfmt . +If the option is not present on the command-line, the script +sets that option's flag variable to an empty list. +Otherwise, the script sets that option's flag variable with +a list containing the option's arguments or, +if the option takes no arguments, +with the string +.BR 1 . +The script also sets the variable +.B $* +to the list of arguments following the options. +The final line in the script sets the +.B $status +variable, to the empty string on success +and to the string +.B usage +when there is an error parsing the command line. +.PP +.I Usage +prints a usage message to standard error. +It creates the message using +.BR $flagfmt , +as described above, +.BR $args , +which should contain the string to be printed explaining +non-option arguments, +and +.BR $0 , +the program name +(see +.IR rc (1)). +If run under +.IR sh (1), +which does not set +.BR $0 , +the program name must be given explicitly on the command line. +.SH EXAMPLE +Parse the arguments for +.IR leak (1): +.IP +.EX +flagfmt='b,s,f binary,r res,x width' +args='name | pid list' +if(! ifs=() eval `{getflags $*} || ~ $#* 0){ + usage + exit usage +} +.EE +.SH SOURCE +.B \*9/src/cmd/getflags.c +.br +.B \*9/src/cmd/usage.c +.SH SEE ALSO +.IR arg (3) blob - d0686679ab30456b2dada45c6f1d1032b0ee8bf2 blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 --- src/cmd/getflags/funcgetflags.c +++ src/cmd/getflags/funcgetflags.c @@ -1,267 +0,0 @@ -#include -#include -#include -#include "getflags.h" - -char **flag[NFLAG]; -char cmdline[NCMDLINE+1]; -char *cmdname; -char *flagset[]; -char *flagset[]={""}; -static char *flagarg=""; -static void reverse(char **, char **); -static int scanflag(int, char *); -static int reason; -#define RESET 1 -#define ARGCCOUNT 2 -#define FLAGSYN 3 -#define BADFLAG 4 -static int badflag; -char *getflagsargv[NGETFLAGSARGV+2]; /* original argv stored here for people who need it */ - -int -getflags(int argc, char *argv[], char *flags) -{ - char *s, *t; - int i, j, c, count; - flagarg=flags; - if(cmdname==0){ - cmdname=argv[0]; - for(i=0;i!=argc && i!=NGETFLAGSARGV;i++) getflagsargv[i]=argv[i]; - if(argc>NGETFLAGSARGV) getflagsargv[i++]="..."; - getflagsargv[i]=0; - } - s=cmdline; - for(i=0;i!=argc;i++){ - for(t=argv[i];*t;) - if(s!=&cmdline[NCMDLINE]) - *s++=*t++; - else - break; - if(i!=argc-1 && s!=&cmdline[NCMDLINE]) - *s++=' '; - } - *s='\0'; - i=1; - while(i!=argc && argv[i][0]=='-'){ - s=argv[i]+1; - if(*s=='\0'){ /* if argument is "-", stop scanning and delete it */ - for(j=i+1;j<=argc;j++) - argv[j-1]=argv[j]; - return argc-1; - } - while(*s){ - c=*s++; - count=scanflag(c, flags); - if(count==-1) return -1; - if(flag[c]){ reason=RESET; badflag=c; return -1; } - if(count==0){ - flag[c]=flagset; - if(*s=='\0'){ - for(j=i+1;j<=argc;j++) - argv[j-1]=argv[j]; - --argc; - } - } - else{ - if(*s=='\0'){ - for(j=i+1;j<=argc;j++) - argv[j-1]=argv[j]; - --argc; - s=argv[i]; - } - if(argc-i0); - f++; - } - if(c==fc) return count; - } - reason=BADFLAG; - badflag=c; - return -1; -} - -static void errn(char *, int), errs(char *), errc(int); - -void -usage(char *tail) -{ - char *s, *t, c; - int count, nflag=0; - switch(reason){ - case RESET: - errs("Flag -"); - errc(badflag); - errs(": set twice\n"); - break; - case ARGCCOUNT: - errs("Flag -"); - errc(badflag); - errs(": too few arguments\n"); - break; - case FLAGSYN: - errs("Bad argument to getflags!\n"); - break; - case BADFLAG: - errs("Illegal flag -"); - errc(badflag); - errc('\n'); - break; - } - errs("Usage: "); - errs(cmdname); - for(s=flagarg;*s;){ - c=*s; - if(*s++==' ') continue; - if(*s==':'){ - s++; - count=strtol(s, &s, 10); - } - else count=0; - if(count==0){ - if(nflag==0) errs(" [-"); - nflag++; - errc(c); - } - if(*s=='['){ - int depth=1; - s++; - for(;*s!='\0' && depth>0; s++) - if (*s==']') depth--; - else if (*s=='[') depth++; - } - } - if(nflag) errs("]"); - for(s=flagarg;*s;){ - c=*s; - if(*s++==' ') continue; - if(*s==':'){ - s++; - count=strtol(s, &s, 10); - } - else count=0; - if(count!=0){ - errs(" [-"); - errc(c); - if(*s=='['){ - int depth=1; - s++; - t=s; - for(;*s!='\0' && depth>0; s++) - if (*s==']') depth--; - else if (*s=='[') depth++; - errs(" "); - errn(t, s-t); - } - else - while(count--) errs(" arg"); - errs("]"); - } - else if(*s=='['){ - int depth=1; - s++; - for(;*s!='\0' && depth>0; s++) - if (*s==']') depth--; - else if (*s=='[') depth++; - } - } - if(tail){ - errs(" "); - errs(tail); - } - errs("\n"); - exits("usage"); -} - -static void -errn(char *s, int count) -{ - while(count){ errc(*s++); --count; } -} - -static void -errs(char *s) -{ - while(*s) errc(*s++); -} - -#define NBUF 80 -static char buf[NBUF], *bufp=buf; - -static void -errc(int c){ - *bufp++=c; - if(bufp==&buf[NBUF] || c=='\n'){ - write(2, buf, bufp-buf); - bufp=buf; - } -} - -#ifdef TEST -#include -main(int argc, char *argv[]) -{ - int c, i, n; - if(argc<3){ - fprint(2, "Usage: %s flags cmd ...\n", argv[0]); - exits("usage"); - } - n=getflags(argc-2, argv+2, argv[1]); - if(n<0) usage("..."); - putchar('\n'); - for(c=0;c!=128;c++) if(flag[c]){ - print("\t-.%c. ", c); - n=scanflag(c, argv[1]); - for(i=0;i!=n;i++) print(" <%s>", flag[c][i]); - putchar('\n'); - } -} -#endif blob - 781da33c685b810f1f85e95478b7807708c19ac5 blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 --- src/cmd/getflags/getflags.c +++ src/cmd/getflags/getflags.c @@ -1,199 +0,0 @@ -/*% cyntax % && cc -go # % - * getflags: process flags for command files - * Usage: ifs='' eval `{getflags [-s] flagfmt [arg ...]} # rc - * Usage: IFS= eval `getflags -b [-s] flagfmt [arg...]` # Bourne shell - * -b means give Bourne-shell compatible output - */ -#include -#include -#include "getflags.h" - -/* predefine functions */ -void bourneprint(int, char *[]); -void bournearg(char *); -void rcprint(int, char *[]); -void usmsg(char *); -int count(int, char *); -void rcarg(char *); - -void -main(int argc, char *argv[]) -{ - int bourne; - argc=getflags(argc, argv, "b"); - if(argc<2) usage("flagfmt [arg ...]"); - bourne=flag['b']!=0; - flag['b']=0; - if((argc=getflags(argc-1, argv+1, argv[1]))<0){ - usmsg(argv[1]); - exits(0); - } - if(bourne) bourneprint(argc, argv); - else rcprint(argc, argv); - exits(0); -} -void -bourneprint(int argc, char *argv[]) -{ - register int c, i, n; - for(c=0;c!=NFLAG;c++) if(flag[c]){ - print("FLAG%c=", c); /* bug -- c could be a bad char */ - n=count(c, argv[1]); - if(n==0) - print("1\n"); - else{ - print("'"); - bournearg(flag[c][0]); - for(i=1;i!=n;i++){ - print(" "); - bournearg(flag[c][i]); - } - print("'\n"); - } - } - print("set --"); - for(c=1;c!=argc;c++){ - print(" "); - bournearg(argv[c+1]); - } - print("\n"); -} -void -bournearg(char *s) -{ - for(;*s;s++) - if(*s=='\'') - print("'\\''"); - else - print("%c", *s); -} -void -rcprint(int argc, char *argv[]) -{ - int c, i, n; - for(c=0;c!=NFLAG;c++) if(flag[c]){ - print("FLAG%c=", c); /* bug -- c could be a bad char */ - n=count(c, argv[1]); - if(n==0) - print("''"); - else if(n==1) - rcarg(flag[c][0]); - else{ - print("("); - rcarg(flag[c][0]); - for(i=1;i!=n;i++){ - print(" "); - rcarg(flag[c][i]); - } - print(")"); - } - print("\n"); - } - print("*="); - if(argc==1) print("()"); - else if(argc==2) rcarg(argv[2]); - else{ - print("("); - rcarg(argv[2]); - for(c=2;c!=argc;c++){ - print(" "); - rcarg(argv[c+1]); - } - print(")"); - } - print("\n"); -} -void -usmsg(char *flagarg) -{ - char *s, *t, c; - int count, nflag=0; - print("echo Usage: $0'"); - for(s=flagarg;*s;){ - c=*s; - if(*s++==' ') continue; - if(*s==':') - count = strtol(s+1, &s, 10); - else count=0; - if(count==0){ - if(nflag==0) print(" [-"); - nflag++; - print("%c", c); - } - if(*s=='['){ - int depth=1; - s++; - for(;*s!='\0' && depth>0; s++) - if (*s==']') depth--; - else if (*s=='[') depth++; - } - } - if(nflag) print("]"); - for(s=flagarg;*s;){ - c=*s; - if(*s++==' ') continue; - if(*s==':') - count = strtol(s+1, &s, 10); - else count=0; - if(count!=0){ - print(" [-"); - print("%c", c); - if(*s=='['){ - int depth=1; - s++; - t=s; - for(;*s!='\0' && depth>0; s++) - if (*s==']') depth--; - else if (*s=='[') depth++; - print(" "); - write(1, t, s - t); - } - else - while(count--) print(" arg"); - print("]"); - } - else if(*s=='['){ - int depth=1; - s++; - for(;*s!='\0' && depth>0; s++) - if (*s==']') depth--; - else if (*s=='[') depth++; - } - } - print("' $usage;\n"); - print("exit 'usage'\n"); -} -int -count(int flag, char *flagarg) -{ - char *s, c; - int n; - for(s=flagarg;*s;){ - c=*s; - if(*s++==' ') continue; - if(*s==':') - n = strtol(s+1, &s, 10); - else n=0; - if(*s=='['){ - int depth=1; - s++; - for(;*s!='\0' && depth>0; s++) - if (*s==']') depth--; - else if (*s=='[') depth++; - } - if(c==flag) return n; - } - return -1; /* never happens */ -} -void -rcarg(char *s) -{ - if(*s=='\0' || strpbrk(s, "\n \t#;&|^$=`'{}()<>?")){ - print("\'"); - for(;*s;s++) - if(*s=='\'') print("''"); - else print("%c", *s); - print("\'"); - } - else print("%s", s); -} blob - ca7167b258ff96f2230daedb53d0146b81c6c737 blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 --- src/cmd/getflags/getflags.h +++ src/cmd/getflags/getflags.h @@ -1,10 +0,0 @@ -#define NFLAG 128 -#define NCMDLINE 512 -#define NGETFLAGSARGV 256 -extern char **flag[NFLAG]; -extern char cmdline[NCMDLINE+1]; -extern char *cmdname; -extern char *flagset[]; -extern char *getflagsargv[NGETFLAGSARGV+2]; -int getflags(int, char *[], char *); -void usage(char *); blob - fab59aa5e3293aa56e988e7f3e3e3b867a40f91b blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 --- src/cmd/getflags/mkfile +++ src/cmd/getflags/mkfile @@ -1,9 +0,0 @@ -<$PLAN9/src/mkhdr - -TARG=getflags -OFILES=\ - getflags.$O\ - funcgetflags.$O\ - -<$PLAN9/src/mkone -