aux/getflags: support named flags
When using aux/getflags, it produces unnecessarily obscure names for the flags. This allows the caller of aux/getflags to support arbitrary names.
This commit is contained in:
parent
8ae77554dd
commit
380adf8b48
3 changed files with 113 additions and 39 deletions
|
@ -7,62 +7,98 @@ getflags, usage \- command-line parsing for shell scripts
|
|||
.B aux/usage
|
||||
.SH DESCRIPTION
|
||||
.I Getflags
|
||||
parses the options in its command-line arguments
|
||||
parses the flags 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.
|
||||
This variable should be a comma-separated list of flag specifiers.
|
||||
Each flag is a single letter, optionally followed by a
|
||||
colon and a name. It may be followed by a space-separated
|
||||
list of argument names.
|
||||
|
||||
.PP
|
||||
.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
|
||||
script to be evaluated by the calling program.
|
||||
For every flag specified in
|
||||
.BR $flagfmt ,
|
||||
the generated script sets a corresponding environment variable.
|
||||
If the flag specifier contains
|
||||
.BR :name ,
|
||||
the corresponding variable is named
|
||||
.BR $name .
|
||||
Otherwise, it is named
|
||||
.BI $flag x.
|
||||
|
||||
.PP
|
||||
After evaluating the script, the environment variables will
|
||||
be set as follows:
|
||||
If a flag is not present in the argument list, the environment
|
||||
variable will default to the empty list.
|
||||
If the flag is present and takes no arguments, the environment
|
||||
variable will be initialized with the string
|
||||
.BR '1' .
|
||||
If the flag takes arguments, the flag's variable will be initialized
|
||||
with a list of those argument values.
|
||||
The script then sets the variable
|
||||
.B $*
|
||||
to the list of arguments following the options.
|
||||
The final line in the script sets the
|
||||
to the list of remaining non-flag arguments.
|
||||
.PP
|
||||
The
|
||||
.B $status
|
||||
variable, to the empty string on success
|
||||
and to the string
|
||||
.B usage
|
||||
is variable to the empty string on success, or
|
||||
.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
|
||||
The message is constructed using
|
||||
.BR $0 ,
|
||||
the program name
|
||||
(see
|
||||
.IR rc (1)).
|
||||
.BR $flagfmt ,
|
||||
and
|
||||
.BR $args .
|
||||
The program name is taken from
|
||||
.BR $0 ,
|
||||
as set by
|
||||
.IR rc (1)
|
||||
The list of flags is extracted from
|
||||
.BR $flagfmt .
|
||||
The description of positional argument list is taken from
|
||||
.BR $args .
|
||||
|
||||
.SH EXAMPLE
|
||||
.PP
|
||||
An example of the script generated:
|
||||
.IP
|
||||
.EX
|
||||
% flagfmt='e:example,x,a:arg with args'
|
||||
% aux/getflags -exa arg list positional stuff
|
||||
example=()
|
||||
flagx=()
|
||||
arg=()
|
||||
example=1
|
||||
flagx=1
|
||||
arg=(arg list)
|
||||
*=(positional stuff)
|
||||
status=''
|
||||
.EE
|
||||
.PP
|
||||
Parse the arguments for
|
||||
.IR leak (1):
|
||||
.IP
|
||||
.EX
|
||||
flagfmt='b,s,f binary,r res,x width'
|
||||
flagfmt='b:showbmp,s:acidfmt,f binary,r res,x width'
|
||||
args='name | pid list'
|
||||
if(! ifs=() eval `{aux/getflags $*} || ~ $#* 0){
|
||||
aux/usage
|
||||
exit usage
|
||||
}
|
||||
if(~ $#showbmp 0)
|
||||
echo '-b flag not set'
|
||||
echo $showbmp # named
|
||||
echo $acidfmt # also named
|
||||
echo $flagf # default name
|
||||
echo $flagr # default name
|
||||
.EE
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/aux/getflags.c
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
|
||||
void
|
||||
usage(void)
|
||||
|
@ -22,6 +23,21 @@ findarg(char *flags, Rune r)
|
|||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
argname(char *p)
|
||||
{
|
||||
Rune r;
|
||||
int n;
|
||||
|
||||
while(1){
|
||||
n = chartorune(&r, p);
|
||||
if(!isalpharune(r) && !isdigitrune(r))
|
||||
break;
|
||||
p += n;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
countargs(char *p)
|
||||
{
|
||||
|
@ -39,7 +55,7 @@ countargs(char *p)
|
|||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *flags, *p, buf[512];
|
||||
char *flags, *p, *s, *e, buf[512];
|
||||
int i, n;
|
||||
Fmt fmt;
|
||||
|
||||
|
@ -55,19 +71,38 @@ main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
fmtfdinit(&fmt, 1, buf, sizeof buf);
|
||||
for(p=flags; p!=(char*)1; p=strchr(p, ',')+1)
|
||||
fmtprint(&fmt, "flag%.1s=()\n", p);
|
||||
for(p=flags; p!=(char*)1 && *p != 0; p=strchr(p, ',')+1){
|
||||
s = e = nil;
|
||||
if(p[1] == ':'){
|
||||
s = p + 2;
|
||||
e = argname(s);
|
||||
}
|
||||
if(s != e)
|
||||
fmtprint(&fmt, "%.*s=()\n", (int)(e - s), s);
|
||||
else
|
||||
fmtprint(&fmt, "flag%.1s=()\n", p);
|
||||
}
|
||||
ARGBEGIN{
|
||||
default:
|
||||
if((p = findarg(flags, ARGC())) == nil)
|
||||
usage();
|
||||
p += runelen(ARGC());
|
||||
s = p + 1;
|
||||
e = p + 1;
|
||||
if(*p == ':' && (e = argname(s)) != s)
|
||||
p = e;
|
||||
if(*p == ',' || *p == 0){
|
||||
fmtprint(&fmt, "flag%C=1\n", ARGC());
|
||||
if(s != e)
|
||||
fmtprint(&fmt, "%.*s=1\n", (int)(e - s), s);
|
||||
else
|
||||
fmtprint(&fmt, "flag%C=1\n", ARGC());
|
||||
break;
|
||||
}
|
||||
n = countargs(p);
|
||||
fmtprint(&fmt, "flag%C=(", ARGC());
|
||||
if(s != e)
|
||||
fmtprint(&fmt, "%.*s=(", (int)(e - s), s);
|
||||
else
|
||||
fmtprint(&fmt, "flag%C=(", ARGC());
|
||||
for(i=0; i<n; i++)
|
||||
fmtprint(&fmt, "%s%q", i ? " " : "", EARGF(usage()));
|
||||
fmtprint(&fmt, ")\n");
|
||||
|
|
|
@ -31,6 +31,9 @@ main(void)
|
|||
single = 0;
|
||||
for(p=flags; *p; ){
|
||||
p += chartorune(&r, p);
|
||||
if(*p == ':')
|
||||
while(*p != '\0' && *p != ',' && *p != ' ')
|
||||
p++;
|
||||
if(*p == ',' || *p == 0){
|
||||
if(!single){
|
||||
fmtprint(&fmt, " [-");
|
||||
|
|
Loading…
Reference in a new issue