tgetflags: import from 4e, with usage - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 3cd77ae67905c839ba2078e119f981d4f2284c7a
 (DIR) parent 9bea9069bf3bc282c6b7d129926d4a0f1b40c66b
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Wed, 15 Jul 2009 02:48:37 -0400
       
       getflags: import from 4e, with usage
       
       fixes #6 http://bitbucket.org/rsc/plan9port/issue/6/
       
       http://codereview.appspot.com/95043
       
       Diffstat:
         A cmd/getflags.c                      |      82 +++++++++++++++++++++++++++++++
         A cmd/usage.c                         |      72 +++++++++++++++++++++++++++++++
         A man8/getflags.8                     |      77 +++++++++++++++++++++++++++++++
         M src/cmd/getflags/funcgetflags.c     |     267 -------------------------------
         M src/cmd/getflags/getflags.c         |     199 -------------------------------
         M src/cmd/getflags/getflags.h         |      10 ----------
         M src/cmd/getflags/mkfile             |       9 ---------
       
       7 files changed, 231 insertions(+), 485 deletions(-)
       ---
 (DIR) diff --git a/cmd/getflags.c b/cmd/getflags.c
       t@@ -0,0 +1,82 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +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<n; i++)
       +                        fmtprint(&fmt, "%s%q", i ? " " : "", EARGF(usage()));
       +                fmtprint(&fmt, ")\n");
       +        }ARGEND
       +        
       +        fmtprint(&fmt, "*=(");
       +        for(i=0; i<argc; i++)
       +                fmtprint(&fmt, "%s%q", i ? " " : "", argv[i]);
       +        fmtprint(&fmt, ")\n");
       +        fmtprint(&fmt, "status=''\n");
       +        fmtfdflush(&fmt);
       +        exits(0);
       +}
 (DIR) diff --git a/cmd/usage.c b/cmd/usage.c
       t@@ -0,0 +1,72 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +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");
       +}
 (DIR) diff --git a/man8/getflags.8 b/man8/getflags.8
       t@@ -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)
 (DIR) diff --git a/src/cmd/getflags/funcgetflags.c b/src/cmd/getflags/funcgetflags.c
       t@@ -1,267 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <ctype.h>
       -#include "getflags.h"
       -
       -char **flag[NFLAG];
       -char cmdline[NCMDLINE+1];
       -char *cmdname;
       -char *flagset[];
       -char *flagset[]={"<flag>"};
       -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-i<count){
       -                                        reason=ARGCCOUNT;
       -                                        badflag=c;
       -                                        return -1;
       -                                }
       -                                reverse(argv+i, argv+argc);
       -                                reverse(argv+i, argv+argc-count);
       -                                reverse(argv+argc-count+1, argv+argc);
       -                                argc-=count;
       -                                flag[c]=argv+argc+1;
       -                                flag[c][0]=s;
       -                                s="";
       -                        }
       -                }
       -        }
       -        return argc;
       -}
       -
       -void
       -static reverse(char **p, char **q)
       -{
       -        register char *t;
       -        for(;p<q;p++,--q){ t=*p; *p=*q; *q=t; }
       -}
       -
       -static int
       -scanflag(int c, char *f)
       -{
       -        int fc, count;
       -        if(0<=c && c<NFLAG) while(*f){
       -                if(*f==' '){
       -                        f++;
       -                        continue;
       -                }
       -                fc=*f++;
       -                if(*f==':'){
       -                        f++;
       -                        if(!isdigit((uchar)*f)){ reason=FLAGSYN; return -1; }
       -                        count=strtol(f, &f, 10);
       -                }
       -                else
       -                        count=0;
       -                if(*f=='['){
       -                        int depth=1;
       -                        do{
       -                                f++;
       -                                if(*f=='\0'){ reason=FLAGSYN; return -1; }
       -                                if(*f=='[') depth++;
       -                                if(*f==']') depth--;
       -                        }while(depth>0);
       -                        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 <stdio.h>
       -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
 (DIR) diff --git a/src/cmd/getflags/getflags.c b/src/cmd/getflags/getflags.c
       t@@ -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 <u.h>
       -#include <libc.h>
       -#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);
       -}
 (DIR) diff --git a/src/cmd/getflags/getflags.h b/src/cmd/getflags/getflags.h
       t@@ -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 *);
 (DIR) diff --git a/src/cmd/getflags/mkfile b/src/cmd/getflags/mkfile
       t@@ -1,9 +0,0 @@
       -<$PLAN9/src/mkhdr
       -
       -TARG=getflags
       -OFILES=\
       -        getflags.$O\
       -        funcgetflags.$O\
       -
       -<$PLAN9/src/mkone
       -