mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
267 lines
4.5 KiB
C
267 lines
4.5 KiB
C
#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
|