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
|
.B aux/usage
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.I Getflags
|
.I Getflags
|
||||||
parses the options in its command-line arguments
|
parses the flags in its command-line arguments
|
||||||
according to the environment variable
|
according to the environment variable
|
||||||
.BR $flagfmt .
|
.BR $flagfmt .
|
||||||
This variable should be a list of comma-separated options.
|
This variable should be a comma-separated list of flag specifiers.
|
||||||
Each option can be a single letter, indicating that it does
|
Each flag is a single letter, optionally followed by a
|
||||||
not take arguments, or a letter followed by the space-separated
|
colon and a name. It may be followed by a space-separated
|
||||||
names of its arguments.
|
list of argument names.
|
||||||
|
|
||||||
|
.PP
|
||||||
.I Getflags
|
.I Getflags
|
||||||
prints an
|
prints an
|
||||||
.IR rc (1)
|
.IR rc (1)
|
||||||
script on standard output which initializes the
|
script to be evaluated by the calling program.
|
||||||
environment variable
|
For every flag specified in
|
||||||
.BI $flag x
|
.BR $flagfmt ,
|
||||||
for every option mentioned in
|
the generated script sets a corresponding environment variable.
|
||||||
.BR $flagfmt .
|
If the flag specifier contains
|
||||||
If the option is not present on the command-line, the script
|
.BR :name ,
|
||||||
sets that option's flag variable to an empty list.
|
the corresponding variable is named
|
||||||
Otherwise, the script sets that option's flag variable with
|
.BR $name .
|
||||||
a list containing the option's arguments or,
|
Otherwise, it is named
|
||||||
if the option takes no arguments,
|
.BI $flag x.
|
||||||
with the string
|
|
||||||
.BR 1 .
|
.PP
|
||||||
The script also sets the variable
|
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 $*
|
.B $*
|
||||||
to the list of arguments following the options.
|
to the list of remaining non-flag arguments.
|
||||||
The final line in the script sets the
|
.PP
|
||||||
|
The
|
||||||
.B $status
|
.B $status
|
||||||
variable, to the empty string on success
|
is variable to the empty string on success, or
|
||||||
and to the string
|
.B 'usage'
|
||||||
.B usage
|
|
||||||
when there is an error parsing the command line.
|
when there is an error parsing the command line.
|
||||||
.PP
|
.PP
|
||||||
.I Usage
|
.I Usage
|
||||||
prints a usage message to standard error.
|
prints a usage message to standard error.
|
||||||
It creates the message using
|
The message is constructed using
|
||||||
.BR $flagfmt ,
|
|
||||||
as described above,
|
|
||||||
.BR $args ,
|
|
||||||
which should contain the string to be printed explaining
|
|
||||||
non-option arguments,
|
|
||||||
and
|
|
||||||
.BR $0 ,
|
.BR $0 ,
|
||||||
the program name
|
.BR $flagfmt ,
|
||||||
(see
|
and
|
||||||
.IR rc (1)).
|
.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
|
.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
|
Parse the arguments for
|
||||||
.IR leak (1):
|
.IR leak (1):
|
||||||
.IP
|
.IP
|
||||||
.EX
|
.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'
|
args='name | pid list'
|
||||||
if(! ifs=() eval `{aux/getflags $*} || ~ $#* 0){
|
if(! ifs=() eval `{aux/getflags $*} || ~ $#* 0){
|
||||||
aux/usage
|
aux/usage
|
||||||
exit 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
|
.EE
|
||||||
.SH SOURCE
|
.SH SOURCE
|
||||||
.B /sys/src/cmd/aux/getflags.c
|
.B /sys/src/cmd/aux/getflags.c
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
usage(void)
|
usage(void)
|
||||||
|
@ -22,6 +23,21 @@ findarg(char *flags, Rune r)
|
||||||
return nil;
|
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
|
int
|
||||||
countargs(char *p)
|
countargs(char *p)
|
||||||
{
|
{
|
||||||
|
@ -39,7 +55,7 @@ countargs(char *p)
|
||||||
void
|
void
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *flags, *p, buf[512];
|
char *flags, *p, *s, *e, buf[512];
|
||||||
int i, n;
|
int i, n;
|
||||||
Fmt fmt;
|
Fmt fmt;
|
||||||
|
|
||||||
|
@ -55,19 +71,38 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
fmtfdinit(&fmt, 1, buf, sizeof buf);
|
fmtfdinit(&fmt, 1, buf, sizeof buf);
|
||||||
for(p=flags; p!=(char*)1; p=strchr(p, ',')+1)
|
for(p=flags; p!=(char*)1 && *p != 0; p=strchr(p, ',')+1){
|
||||||
fmtprint(&fmt, "flag%.1s=()\n", p);
|
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{
|
ARGBEGIN{
|
||||||
default:
|
default:
|
||||||
if((p = findarg(flags, ARGC())) == nil)
|
if((p = findarg(flags, ARGC())) == nil)
|
||||||
usage();
|
usage();
|
||||||
p += runelen(ARGC());
|
p += runelen(ARGC());
|
||||||
|
s = p + 1;
|
||||||
|
e = p + 1;
|
||||||
|
if(*p == ':' && (e = argname(s)) != s)
|
||||||
|
p = e;
|
||||||
if(*p == ',' || *p == 0){
|
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;
|
break;
|
||||||
}
|
}
|
||||||
n = countargs(p);
|
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++)
|
for(i=0; i<n; i++)
|
||||||
fmtprint(&fmt, "%s%q", i ? " " : "", EARGF(usage()));
|
fmtprint(&fmt, "%s%q", i ? " " : "", EARGF(usage()));
|
||||||
fmtprint(&fmt, ")\n");
|
fmtprint(&fmt, ")\n");
|
||||||
|
|
|
@ -31,6 +31,9 @@ main(void)
|
||||||
single = 0;
|
single = 0;
|
||||||
for(p=flags; *p; ){
|
for(p=flags; *p; ){
|
||||||
p += chartorune(&r, p);
|
p += chartorune(&r, p);
|
||||||
|
if(*p == ':')
|
||||||
|
while(*p != '\0' && *p != ',' && *p != ' ')
|
||||||
|
p++;
|
||||||
if(*p == ',' || *p == 0){
|
if(*p == ',' || *p == 0){
|
||||||
if(!single){
|
if(!single){
|
||||||
fmtprint(&fmt, " [-");
|
fmtprint(&fmt, " [-");
|
||||||
|
|
Loading…
Reference in a new issue