Initial import

This commit is contained in:
Justine Tunney 2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

418
third_party/getopt/README.txt vendored Normal file
View file

@ -0,0 +1,418 @@
GETOPT(3) Cosmopolitan Library Functions Manual GETOPT(3)
𝐍𝐀𝐌𝐄
𝗴𝗲𝘁𝗼𝗽𝘁 — get option character from command line argument list
𝐒𝐘𝐍𝐎𝐏𝐒𝐈𝐒
#𝗶𝗻𝗰𝗹𝘂𝗱𝗲 <𝘂𝗻𝗶𝘀𝘁𝗱.𝗵>
e̲x̲t̲e̲r̲n̲ c̲h̲a̲r̲ *̲o̲p̲t̲a̲r̲g̲;̲
e̲x̲t̲e̲r̲n̲ i̲n̲t̲ o̲p̲t̲e̲r̲r̲;̲
e̲x̲t̲e̲r̲n̲ i̲n̲t̲ o̲p̲t̲i̲n̲d̲;̲
e̲x̲t̲e̲r̲n̲ i̲n̲t̲ o̲p̲t̲o̲p̲t̲;̲
e̲x̲t̲e̲r̲n̲ i̲n̲t̲ o̲p̲t̲r̲e̲s̲e̲t̲;̲
i̲n̲t̲
𝗴𝗲𝘁𝗼𝗽𝘁(i̲n̲t̲ a̲r̲g̲c̲, c̲h̲a̲r̲ *̲ c̲o̲n̲s̲t̲ *̲a̲r̲g̲v̲, c̲o̲n̲s̲t̲ c̲h̲a̲r̲ *̲o̲p̲t̲s̲t̲r̲i̲n̲g̲);
𝐃𝐄𝐒𝐂𝐑𝐈𝐏𝐓𝐈𝐎𝐍
The 𝗴𝗲𝘁𝗼𝗽𝘁() function incrementally parses a command line argument
list a̲r̲g̲v̲ and returns the next k̲n̲o̲w̲n̲ option character. An option
character is k̲n̲o̲w̲n̲ if it has been specified in the string of
accepted option characters, o̲p̲t̲s̲t̲r̲i̲n̲g̲.
The option string o̲p̲t̲s̲t̲r̲i̲n̲g̲ may contain the following elements:
individual characters, characters followed by a colon, and charac
ters followed by two colons. A character followed by a single
colon indicates that an argument is to follow the option on the
command line. Two colons indicates that the argument is optional -
this is an extension not covered by POSIX. For example, an option
string "x" recognizes an option -𝘅, and an option string "x:" rec
ognizes an option and argument -𝘅 a̲r̲g̲u̲m̲e̲n̲t̲. It does not matter to
𝗴𝗲𝘁𝗼𝗽𝘁() if a following argument has leading whitespace; except in
the case where the argument is optional, denoted with two colons,
no leading whitespace is permitted.
On return from 𝗴𝗲𝘁𝗼𝗽𝘁(), o̲p̲t̲a̲r̲g̲ points to an option argument, if it
is anticipated, and the variable o̲p̲t̲i̲n̲d̲ contains the index to the
next a̲r̲g̲v̲ argument for a subsequent call to 𝗴𝗲𝘁𝗼𝗽𝘁().
The variables o̲p̲t̲e̲r̲r̲ and o̲p̲t̲i̲n̲d̲ are both initialized to 1. The
o̲p̲t̲i̲n̲d̲ variable may be set to another value larger than 0 before a
set of calls to 𝗴𝗲𝘁𝗼𝗽𝘁() in order to skip over more or less a̲r̲g̲v̲
entries. An o̲p̲t̲i̲n̲d̲ value of 0 is reserved for compatibility with
GNU 𝗴𝗲𝘁𝗼𝗽𝘁().
In order to use 𝗴𝗲𝘁𝗼𝗽𝘁() to evaluate multiple sets of arguments, or
to evaluate a single set of arguments multiple times, the variable
o̲p̲t̲r̲e̲s̲e̲t̲ must be set to 1 before the second and each additional set
of calls to 𝗴𝗲𝘁𝗼𝗽𝘁(), and the variable o̲p̲t̲i̲n̲d̲ must be reinitial
ized.
The 𝗴𝗲𝘁𝗼𝗽𝘁() function returns -1 when the argument list is
exhausted. The interpretation of options in the argument list may
be cancelled by the option -- (double dash) which causes 𝗴𝗲𝘁𝗼𝗽𝘁()
to signal the end of argument processing and return -1. When all
options have been processed (i.e., up to the first non-option argu
ment), 𝗴𝗲𝘁𝗼𝗽𝘁() returns -1.
𝐑𝐄𝐓𝐔𝐑𝐍 𝐕𝐀𝐋𝐔𝐄𝐒
The 𝗴𝗲𝘁𝗼𝗽𝘁() function returns the next known option character in
o̲p̲t̲s̲t̲r̲i̲n̲g̲. If 𝗴𝗲𝘁𝗼𝗽𝘁() encounters a character not found in
o̲p̲t̲s̲t̲r̲i̲n̲g̲ or if it detects a missing option argument, it returns
? (question mark). If o̲p̲t̲s̲t̲r̲i̲n̲g̲ has a leading : then a missing
option argument causes : to be returned instead of ?. In
either case, the variable o̲p̲t̲o̲p̲t̲ is set to the character that
caused the error. The 𝗴𝗲𝘁𝗼𝗽𝘁() function returns -1 when the argu
ment list is exhausted.
𝐄𝐗𝐀𝐌𝐏𝐋𝐄𝐒
The following code accepts the options -𝗯 and -𝗳 a̲r̲g̲u̲m̲e̲n̲t̲ and
adjusts a̲r̲g̲c̲ and a̲r̲g̲v̲ after option argument processing has com
pleted.
int bflag, ch, fd;
bflag = 0;
while ((ch = getopt(argc, argv, "bf:")) != -1) {
switch (ch) {
case 'b':
bflag = 1;
break;
case 'f':
if ((fd = open(optarg, O_RDONLY, 0)) == -1)
err(1, "%s", optarg);
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
𝐃𝐈𝐀𝐆𝐍𝐎𝐒𝐓𝐈𝐂𝐒
If the 𝗴𝗲𝘁𝗼𝗽𝘁() function encounters a character not found in the
string o̲p̲t̲s̲t̲r̲i̲n̲g̲ or detects a missing option argument, it writes an
error message to s̲t̲d̲e̲r̲r̲ and returns ?. Setting o̲p̲t̲e̲r̲r̲ to a zero
will disable these error messages. If o̲p̲t̲s̲t̲r̲i̲n̲g̲ has a leading :
then a missing option argument causes a : to be returned in addi
tion to suppressing any error messages.
Option arguments are allowed to begin with -; this is reasonable
but reduces the amount of error checking possible.
𝐒𝐄𝐄 𝐀𝐋𝐒𝐎
getopt(1), getopt_long(3), getsubopt(3)
𝐒𝐓𝐀𝐍𝐃𝐀𝐑𝐃𝐒
The 𝗴𝗲𝘁𝗼𝗽𝘁() function implements a superset of the functionality
specified by IEEE Std 1003.1 (“POSIX.1”).
The following extensions are supported:
· The o̲p̲t̲r̲e̲s̲e̲t̲ variable was added to make it possible to call the
𝗴𝗲𝘁𝗼𝗽𝘁() function multiple times.
· If the o̲p̲t̲i̲n̲d̲ variable is set to 0, 𝗴𝗲𝘁𝗼𝗽𝘁() will behave as if
the o̲p̲t̲r̲e̲s̲e̲t̲ variable has been set. This is for compatibility
with GNU 𝗴𝗲𝘁𝗼𝗽𝘁(). New code should use o̲p̲t̲r̲e̲s̲e̲t̲ instead.
· If the first character of o̲p̲t̲s̲t̲r̲i̲n̲g̲ is a plus sign (+), it
will be ignored. This is for compatibility with GNU 𝗴𝗲𝘁𝗼𝗽𝘁().
· If the first character of o̲p̲t̲s̲t̲r̲i̲n̲g̲ is a dash (-), non-
options will be returned as arguments to the option character
\1. This is for compatibility with GNU 𝗴𝗲𝘁𝗼𝗽𝘁().
· A single dash (-) may be specified as a character in
o̲p̲t̲s̲t̲r̲i̲n̲g̲, however it should n̲e̲v̲e̲r̲ have an argument associated
with it. This allows 𝗴𝗲𝘁𝗼𝗽𝘁() to be used with programs that
expect - as an option flag. This practice is wrong, and
should not be used in any current development. It is provided
for backward compatibility o̲n̲l̲y̲. Care should be taken not to
use - as the first character in o̲p̲t̲s̲t̲r̲i̲n̲g̲ to avoid a semantic
conflict with GNU 𝗴𝗲𝘁𝗼𝗽𝘁() semantics (see above). By default,
a single dash causes 𝗴𝗲𝘁𝗼𝗽𝘁() to return -1.
Historic BSD versions of 𝗴𝗲𝘁𝗼𝗽𝘁() set o̲p̲t̲o̲p̲t̲ to the last option
character processed. However, this conflicts with IEEE Std 1003.1
(“POSIX.1”) which stipulates that o̲p̲t̲o̲p̲t̲ be set to the last charac
ter that caused an error.
𝐇𝐈𝐒𝐓𝐎𝐑𝐘
The 𝗴𝗲𝘁𝗼𝗽𝘁() function appeared in 4.3BSD.
𝐁𝐔𝐆𝐒
The 𝗴𝗲𝘁𝗼𝗽𝘁() function was once specified to return EOF instead of
-1. This was changed by IEEE Std 1003.2-1992 (“POSIX.2”) to decou
ple 𝗴𝗲𝘁𝗼𝗽𝘁() from <s̲t̲d̲i̲o̲.̲h̲>.
It is possible to handle digits as option letters. This allows
𝗴𝗲𝘁𝗼𝗽𝘁() to be used with programs that expect a number (“-3”) as an
option. This practice is wrong, and should not be used in any cur
rent development. It is provided for backward compatibility o̲n̲l̲y̲.
The following code fragment works in most cases and can handle
mixed number and letter arguments.
int aflag = 0, bflag = 0, ch, lastch = '\0';
int length = -1, newarg = 1, prevoptind = 1;
while ((ch = getopt(argc, argv, "0123456789ab")) != -1) {
switch (ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (newarg || !isdigit(lastch))
length = 0;
else if (length > INT_MAX / 10)
usage();
length = (length * 10) + (ch - '0');
break;
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
default:
usage();
}
lastch = ch;
newarg = optind != prevoptind;
prevoptind = optind;
}
COSMOPOLITAN January 4, 2016 BSD
────────────────────────────────────────────────────────────────────────────
GETOPT_LONG(3) Cosmopolitan Library Functions Manual GETOPT_LONG(3)
𝐍𝐀𝐌𝐄
𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴, 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴_𝗼𝗻𝗹𝘆 — get long options from command line
argument list
𝐒𝐘𝐍𝐎𝐏𝐒𝐈𝐒
#𝗶𝗻𝗰𝗹𝘂𝗱𝗲 <𝗴𝗲𝘁𝗼𝗽𝘁.𝗵>
e̲x̲t̲e̲r̲n̲ c̲h̲a̲r̲ *̲o̲p̲t̲a̲r̲g̲;̲
e̲x̲t̲e̲r̲n̲ i̲n̲t̲ o̲p̲t̲i̲n̲d̲;̲
e̲x̲t̲e̲r̲n̲ i̲n̲t̲ o̲p̲t̲o̲p̲t̲;̲
e̲x̲t̲e̲r̲n̲ i̲n̲t̲ o̲p̲t̲e̲r̲r̲;̲
e̲x̲t̲e̲r̲n̲ i̲n̲t̲ o̲p̲t̲r̲e̲s̲e̲t̲;̲
i̲n̲t̲
𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴(i̲n̲t̲ a̲r̲g̲c̲, c̲h̲a̲r̲ *̲ c̲o̲n̲s̲t̲ *̲a̲r̲g̲v̲, c̲o̲n̲s̲t̲ c̲h̲a̲r̲ *̲o̲p̲t̲s̲t̲r̲i̲n̲g̲,
c̲o̲n̲s̲t̲ s̲t̲r̲u̲c̲t̲ o̲p̲t̲i̲o̲n̲ *̲l̲o̲n̲g̲o̲p̲t̲s̲, i̲n̲t̲ *̲l̲o̲n̲g̲i̲n̲d̲e̲x̲);
i̲n̲t̲
𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴_𝗼𝗻𝗹𝘆(i̲n̲t̲ a̲r̲g̲c̲, c̲h̲a̲r̲ *̲ c̲o̲n̲s̲t̲ *̲a̲r̲g̲v̲,
c̲o̲n̲s̲t̲ c̲h̲a̲r̲ *̲o̲p̲t̲s̲t̲r̲i̲n̲g̲, c̲o̲n̲s̲t̲ s̲t̲r̲u̲c̲t̲ o̲p̲t̲i̲o̲n̲ *̲l̲o̲n̲g̲o̲p̲t̲s̲,
i̲n̲t̲ *̲l̲o̲n̲g̲i̲n̲d̲e̲x̲);
𝐃𝐄𝐒𝐂𝐑𝐈𝐏𝐓𝐈𝐎𝐍
The 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴() function is similar to getopt(3) but it accepts
options in two forms: words and characters. The 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴()
function provides a superset of the functionality of getopt(3).
𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴() can be used in two ways. In the first way, every
long option understood by the program has a corresponding short
option, and the option structure is only used to translate from
long options to short options. When used in this fashion,
𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴() behaves identically to getopt(3). This is a good way
to add long option processing to an existing program with the mini
mum of rewriting.
In the second mechanism, a long option sets a flag in the o̲p̲t̲i̲o̲n̲
structure passed, or will store a pointer to the command line argu
ment in the o̲p̲t̲i̲o̲n̲ structure passed to it for options that take
arguments. Additionally, the long option's argument may be speci
fied as a single argument with an equal sign, e.g.
$ myprogram --myoption=somevalue
When a long option is processed, the call to 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴() will
return 0. For this reason, long option processing without short
cuts is not backwards compatible with getopt(3).
It is possible to combine these methods, providing for long options
processing with short option equivalents for some options. Less
frequently used options would be processed as long options only.
Abbreviated long option names are accepted when 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴() pro
cesses long options if the abbreviation is unique. An exact match
is always preferred for a defined long option.
The 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴() call requires an array to be initialized describ
ing the long options. Each element of the array is a structure:
struct option {
char *name;
int has_arg;
int *flag;
int val;
};
The n̲a̲m̲e̲ field should contain the option name without the leading
double dash.
The h̲a̲s̲_a̲r̲g̲ field should be one of:
no_argument no argument to the option is expected.
required_argument an argument to the option is required.
optional_argument an argument to the option may be pre
sented.
If f̲l̲a̲g̲ is not NULL, then the integer pointed to by it will be set
to the value in the v̲a̲l̲ field. If the f̲l̲a̲g̲ field is NULL, then the
v̲a̲l̲ field will be returned. Setting f̲l̲a̲g̲ to NULL and setting v̲a̲l̲
to the corresponding short option will make this function act just
like getopt(3).
If the l̲o̲n̲g̲i̲n̲d̲e̲x̲ field is not NULL, then the integer pointed to by
it will be set to the index of the long option relative to
l̲o̲n̲g̲o̲p̲t̲s̲.
The last element of the l̲o̲n̲g̲o̲p̲t̲s̲ array has to be filled with
zeroes.
The 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴_𝗼𝗻𝗹𝘆() function behaves identically to
𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴() with the exception that long options may start with
- in addition to --. If an option starting with - does not
match a long option but does match a single-character option, the
single-character option is returned.
𝐑𝐄𝐓𝐔𝐑𝐍 𝐕𝐀𝐋𝐔𝐄𝐒
If the f̲l̲a̲g̲ field in struct option is NULL, 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴() and
𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴_𝗼𝗻𝗹𝘆() return the value specified in the v̲a̲l̲ field,
which is usually just the corresponding short option. If f̲l̲a̲g̲ is
not NULL, these functions return 0 and store v̲a̲l̲ in the location
pointed to by f̲l̲a̲g̲. These functions return : if there was a
missing option argument, ? if the user specified an unknown or
ambiguous option, and -1 when the argument list has been exhausted.
𝐈𝐌𝐏𝐋𝐄𝐌𝐄𝐍𝐓𝐀𝐓𝐈𝐎𝐍 𝐃𝐈𝐅𝐅𝐄𝐑𝐄𝐍𝐂𝐄𝐒
This section describes differences to the GNU implementation found
in glibc-2.1.3:
· handling of - within the option string (not the first charac
ter):
GNU treats a - on the command line as a non-argument.
OpenBSD a - within the option string matches a - (single
dash) on the command line. This functionality is pro
vided for backward compatibility with programs, such
as su(1), that use - as an option flag. This prac
tice is wrong, and should not be used in any current
development.
· handling of :: in the option string in the presence of
POSIXLY_CORRECT:
Both GNU and OpenBSD ignore POSIXLY_CORRECT here and take
:: to mean the preceding option takes an optional
argument.
· return value in case of missing argument if first character
(after + or -) in the option string is not ::
GNU returns ?
OpenBSD returns : (since OpenBSD's getopt(3) does).
· handling of --a in getopt(3):
GNU parses this as option -, option a.
OpenBSD parses this as --, and returns -1 (ignoring the a)
(because the original 𝗴𝗲𝘁𝗼𝗽𝘁() did.)
· setting of o̲p̲t̲o̲p̲t̲ for long options with f̲l̲a̲g̲ non-NULL:
GNU sets o̲p̲t̲o̲p̲t̲ to v̲a̲l̲.
OpenBSD sets o̲p̲t̲o̲p̲t̲ to 0 (since v̲a̲l̲ would never be returned).
· handling of -W with W; in the option string in getopt(3)
(not 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴()):
GNU causes a segmentation fault.
OpenBSD no special handling is done; W; is interpreted as
two separate options, neither of which take an argu
ment.
· setting of o̲p̲t̲a̲r̲g̲ for long options without an argument that are
invoked via -W (with W; in the option string):
GNU sets o̲p̲t̲a̲r̲g̲ to the option name (the argument of -W).
OpenBSD sets o̲p̲t̲a̲r̲g̲ to NULL (the argument of the long option).
· handling of -W with an argument that is not (a prefix to) a
known long option (with W; in the option string):
GNU returns -W with o̲p̲t̲a̲r̲g̲ set to the unknown option.
OpenBSD treats this as an error (unknown option) and returns
? with o̲p̲t̲o̲p̲t̲ set to 0 and o̲p̲t̲a̲r̲g̲ set to NULL (as
GNU's man page documents).
· The error messages are different.
· OpenBSD does not permute the argument vector at the same points
in the calling sequence as GNU does. The aspects normally used
by the caller (ordering after -1 is returned, value of o̲p̲t̲i̲n̲d̲
relative to current positions) are the same, though. (We do
fewer variable swaps.)
𝐄𝐍𝐕𝐈𝐑𝐎𝐍𝐌𝐄𝐍𝐓
POSIXLY_CORRECT If set, option processing stops when the first
non-option is found and a leading + in the
o̲p̲t̲s̲t̲r̲i̲n̲g̲ is ignored.
𝐄𝐗𝐀𝐌𝐏𝐋𝐄𝐒
int bflag, ch, fd;
int daggerset;
/* options descriptor */
static struct option longopts[] = {
{ "buffy", no_argument, NULL, 'b' },
{ "fluoride", required_argument, NULL, 'f' },
{ "daggerset", no_argument, &daggerset, 1 },
{ NULL, 0, NULL, 0 }
};
bflag = 0;
while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1)
switch (ch) {
case 'b':
bflag = 1;
break;
case 'f':
if ((fd = open(optarg, O_RDONLY, 0)) == -1)
err(1, "unable to open %s", optarg);
break;
case 0:
if (daggerset)
fprintf(stderr, "Buffy will use her dagger to "
"apply fluoride to dracula's teeth\n");
break;
default:
usage();
}
argc -= optind;
argv += optind;
𝐒𝐄𝐄 𝐀𝐋𝐒𝐎
getopt(3)
𝐇𝐈𝐒𝐓𝐎𝐑𝐘
The 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴() and 𝗴𝗲𝘁𝗼𝗽𝘁_𝗹𝗼𝗻𝗴_𝗼𝗻𝗹𝘆() functions first appeared
in GNU libiberty. This implementation first appeared in
OpenBSD 3.3.
𝐁𝐔𝐆𝐒
The a̲r̲g̲v̲ argument is not really const as its elements may be per
muted (unless POSIXLY_CORRECT is set).
COSMOPOLITAN January 4, 2016 BSD

363
third_party/getopt/getopt.3 vendored Normal file
View file

@ -0,0 +1,363 @@
.\" Copyright (c) 1988, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $OpenBSD: getopt.3,v 1.46 2016/01/04 19:43:13 tb Exp $
.\"
.Dd $Mdocdate: January 4 2016 $
.Dt GETOPT 3
.Os
.Sh NAME
.Nm getopt
.Nd get option character from command line argument list
.Sh SYNOPSIS
.In unistd.h
.Vt extern char *optarg;
.Vt extern int opterr;
.Vt extern int optind;
.Vt extern int optopt;
.Vt extern int optreset;
.Ft int
.Fn getopt "int argc" "char * const *argv" "const char *optstring"
.Sh DESCRIPTION
The
.Fn getopt
function incrementally parses a command line argument list
.Fa argv
and returns the next
.Em known
option character.
An option character is
.Em known
if it has been specified in the string of accepted option characters,
.Fa optstring .
.Pp
The option string
.Fa optstring
may contain the following elements: individual characters,
characters followed by a colon, and characters followed by two colons.
A character followed by a single colon indicates that an argument
is to follow the option on the command line.
Two colons indicates that the argument is optional \- this is an
extension not covered by POSIX.
For example, an option string
.Qq x
recognizes an option
.Fl x ,
and an option string
.Qq Li x:
recognizes an option and argument
.Fl x Ar argument .
It does not matter to
.Fn getopt
if a following argument has leading whitespace; except in the case where
the argument is optional, denoted with two colons, no leading whitespace
is permitted.
.Pp
On return from
.Fn getopt ,
.Va optarg
points to an option argument, if it is anticipated,
and the variable
.Va optind
contains the index to the next
.Fa argv
argument for a subsequent call
to
.Fn getopt .
.Pp
The variables
.Va opterr
and
.Va optind
are both initialized to 1.
The
.Va optind
variable may be set to another value larger than 0 before a set of calls to
.Fn getopt
in order to skip over more or less
.Fa argv
entries.
An
.Va optind
value of 0 is reserved for compatibility with GNU
.Fn getopt .
.Pp
In order to use
.Fn getopt
to evaluate multiple sets of arguments, or to evaluate a single set of
arguments multiple times,
the variable
.Va optreset
must be set to 1 before the second and each additional set of calls to
.Fn getopt ,
and the variable
.Va optind
must be reinitialized.
.Pp
The
.Fn getopt
function returns \-1 when the argument list is exhausted.
The interpretation of options in the argument list may be cancelled
by the option
.Ql --
(double dash) which causes
.Fn getopt
to signal the end of argument processing and return \-1.
When all options have been processed (i.e., up to the first non-option
argument),
.Fn getopt
returns \-1.
.Sh RETURN VALUES
The
.Fn getopt
function returns the next known option character in
.Fa optstring .
If
.Fn getopt
encounters a character not found in
.Fa optstring
or if it detects a missing option argument,
it returns
.Sq \&?
(question mark).
If
.Fa optstring
has a leading
.Sq \&:
then a missing option argument causes
.Sq \&:
to be returned instead of
.Sq \&? .
In either case, the variable
.Va optopt
is set to the character that caused the error.
The
.Fn getopt
function returns \-1 when the argument list is exhausted.
.Sh EXAMPLES
The following code accepts the options
.Fl b
and
.Fl f Ar argument
and adjusts
.Va argc
and
.Va argv
after option argument processing has completed.
.Bd -literal -offset indent
int bflag, ch, fd;
bflag = 0;
while ((ch = getopt(argc, argv, "bf:")) != -1) {
switch (ch) {
case 'b':
bflag = 1;
break;
case 'f':
if ((fd = open(optarg, O_RDONLY, 0)) == -1)
err(1, "%s", optarg);
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
.Ed
.Sh DIAGNOSTICS
If the
.Fn getopt
function encounters a character not found in the string
.Fa optstring
or detects
a missing option argument, it writes an error message to
.Em stderr
and returns
.Ql \&? .
Setting
.Va opterr
to a zero will disable these error messages.
If
.Fa optstring
has a leading
.Ql \&:
then a missing option argument causes a
.Ql \&:
to be returned in addition to suppressing any error messages.
.Pp
Option arguments are allowed to begin with
.Ql - ;
this is reasonable but reduces the amount of error checking possible.
.Sh SEE ALSO
.Xr getopt 1 ,
.Xr getopt_long 3 ,
.Xr getsubopt 3
.Sh STANDARDS
The
.Fn getopt
function implements a superset of the functionality specified by
.St -p1003.1 .
.Pp
The following extensions are supported:
.Bl -bullet
.It
The
.Va optreset
variable was added to make it possible to call the
.Fn getopt
function multiple times.
.It
If the
.Va optind
variable is set to 0,
.Fn getopt
will behave as if the
.Va optreset
variable has been set.
This is for compatibility with
.Tn GNU
.Fn getopt .
New code should use
.Va optreset
instead.
.It
If the first character of
.Fa optstring
is a plus sign
.Pq Ql + ,
it will be ignored.
This is for compatibility with
.Tn GNU
.Fn getopt .
.It
If the first character of
.Fa optstring
is a dash
.Pq Ql - ,
non-options will be returned as arguments to the option character
.Ql \e1 .
This is for compatibility with
.Tn GNU
.Fn getopt .
.It
A single dash
.Pq Ql -
may be specified as a character in
.Fa optstring ,
however it should
.Em never
have an argument associated with it.
This allows
.Fn getopt
to be used with programs that expect
.Ql -
as an option flag.
This practice is wrong, and should not be used in any current development.
It is provided for backward compatibility
.Em only .
Care should be taken not to use
.Ql -
as the first character in
.Fa optstring
to avoid a semantic conflict with
.Tn GNU
.Fn getopt
semantics (see above).
By default, a single dash causes
.Fn getopt
to return \-1.
.El
.Pp
Historic
.Bx
versions of
.Fn getopt
set
.Fa optopt
to the last option character processed.
However, this conflicts with
.St -p1003.1
which stipulates that
.Fa optopt
be set to the last character that caused an error.
.Sh HISTORY
The
.Fn getopt
function appeared in
.Bx 4.3 .
.Sh BUGS
The
.Fn getopt
function was once specified to return
.Dv EOF
instead of \-1.
This was changed by
.St -p1003.2-92
to decouple
.Fn getopt
from
.In stdio.h .
.Pp
It is possible to handle digits as option letters.
This allows
.Fn getopt
to be used with programs that expect a number
.Pq Dq Li \-3
as an option.
This practice is wrong, and should not be used in any current development.
It is provided for backward compatibility
.Em only .
The following code fragment works in most cases and can handle mixed
number and letter arguments.
.Bd -literal -offset indent
int aflag = 0, bflag = 0, ch, lastch = '\e0';
int length = -1, newarg = 1, prevoptind = 1;
while ((ch = getopt(argc, argv, "0123456789ab")) != -1) {
switch (ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (newarg || !isdigit(lastch))
length = 0;
else if (length > INT_MAX / 10)
usage();
length = (length * 10) + (ch - '0');
break;
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
default:
usage();
}
lastch = ch;
newarg = optind != prevoptind;
prevoptind = optind;
}
.Ed

145
third_party/getopt/getopt.c vendored Normal file
View file

@ -0,0 +1,145 @@
asm(".ident\t\"\\n\\n\
getopt (BSD-3)\\n\
Copyright 1987, 1993, 1994 The Regents of the University of California\"");
asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */
/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)getopt.c 8.3 (Berkeley) 4/27/95
* $FreeBSD: src/lib/libc/stdlib/getopt.c,v 1.8 2007/01/09 00:28:10 imp Exp $
* $DragonFly: src/lib/libc/stdlib/getopt.c,v 1.7 2005/11/20 12:37:48 swildner Exp $
*/
#include "libc/str/str.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
int opterr, /* if error message should be printed */
optind, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
static char *place; /* option letter processing */
#define BADCH (int)'?'
#define BADARG (int)':'
static char EMSG[] = { '\0' };
INITIALIZER(300, _init_getopt, {
opterr = 1;
optind = 1;
place = EMSG;
});
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(int nargc, char * const nargv[], const char *ostr)
{
char *oli; /* option letter list index */
/*
* Some programs like cvs expect optind = 0 to trigger
* a reset of getopt.
*/
if (optind == 0)
optind = 1;
if (optreset || *place == 0) { /* update scanning pointer */
optreset = 0;
place = nargv[optind];
if (optind >= nargc || *place++ != '-') {
/* Argument is absent or is not an option */
place = EMSG;
return (-1);
}
optopt = *place++;
if (optopt == '-' && *place == 0) {
/* "--" => end of options */
++optind;
place = EMSG;
return (-1);
}
if (optopt == 0) {
/* Solitary '-', treat as a '-' option
if the program (eg su) is looking for it. */
place = EMSG;
if (strchr(ostr, '-') == NULL)
return (-1);
optopt = '-';
}
} else
optopt = *place++;
/* See if option letter is one the caller wanted... */
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
if (*place == 0)
++optind;
if (opterr && *ostr != ':')
fprintf(stderr,
"%s: illegal option -- %c\n", program_invocation_name,
optopt);
return (BADCH);
}
/* Does this option need an argument? */
if (oli[1] != ':') {
/* don't need argument */
optarg = NULL;
if (*place == 0)
++optind;
} else {
/* Option-argument is either the rest of this argument or the
entire next argument. */
if (*place)
optarg = place;
else if (nargc > ++optind)
optarg = nargv[optind];
else {
/* option-argument absent */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
fprintf(stderr,
"%s: option requires an argument -- %c\n",
program_invocation_name, optopt);
return (BADCH);
}
place = EMSG;
++optind;
}
return (optopt); /* return option letter */
}

26
third_party/getopt/getopt.h vendored Normal file
View file

@ -0,0 +1,26 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_GETOPT_GETOPT_H_
#define COSMOPOLITAN_THIRD_PARTY_GETOPT_GETOPT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern char *optarg;
extern int optind, opterr, optopt, optreset;
int getopt(int nargc, char *const nargv[], const char *ostr);
#define no_argument 0
#define required_argument 1
#define optional_argument 2
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
int getopt_long(int nargc, char *const *nargv, const char *options,
const struct option *long_options, int *idx);
int getopt_long_only(int nargc, char *const *nargv, const char *options,
const struct option *long_options, int *idx);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_GETOPT_GETOPT_H_ */

56
third_party/getopt/getopt.mk vendored Normal file
View file

@ -0,0 +1,56 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += THIRD_PARTY_GETOPT
THIRD_PARTY_GETOPT_ARTIFACTS += THIRD_PARTY_GETOPT_A
THIRD_PARTY_GETOPT = $(THIRD_PARTY_GETOPT_A_DEPS) $(THIRD_PARTY_GETOPT_A)
THIRD_PARTY_GETOPT_A = o/$(MODE)/third_party/getopt/getopt.a
THIRD_PARTY_GETOPT_A_FILES := $(wildcard third_party/getopt/*)
THIRD_PARTY_GETOPT_A_HDRS = $(filter %.h,$(THIRD_PARTY_GETOPT_A_FILES))
THIRD_PARTY_GETOPT_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_GETOPT_A_FILES))
THIRD_PARTY_GETOPT_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_GETOPT_A_FILES))
THIRD_PARTY_GETOPT_A_SRCS = \
$(THIRD_PARTY_GETOPT_A_SRCS_S) \
$(THIRD_PARTY_GETOPT_A_SRCS_C)
THIRD_PARTY_GETOPT_A_OBJS = \
$(THIRD_PARTY_GETOPT_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_GETOPT_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(THIRD_PARTY_GETOPT_A_SRCS_C:%.c=o/$(MODE)/%.o)
THIRD_PARTY_GETOPT_A_CHECKS = \
$(THIRD_PARTY_GETOPT_A).pkg \
$(THIRD_PARTY_GETOPT_A_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_GETOPT_A_DIRECTDEPS = \
LIBC_CALLS \
LIBC_FMT \
LIBC_LOG \
LIBC_NEXGEN32E \
LIBC_STDIO \
LIBC_STUBS \
LIBC_STR
THIRD_PARTY_GETOPT_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_GETOPT_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_GETOPT_A): \
third_party/getopt/ \
$(THIRD_PARTY_GETOPT_A).pkg \
$(THIRD_PARTY_GETOPT_A_OBJS)
$(THIRD_PARTY_GETOPT_A).pkg: \
$(THIRD_PARTY_GETOPT_A_OBJS) \
$(foreach x,$(THIRD_PARTY_GETOPT_A_DIRECTDEPS),$($(x)_A).pkg)
THIRD_PARTY_GETOPT_LIBS = $(foreach x,$(THIRD_PARTY_GETOPT_ARTIFACTS),$($(x)))
THIRD_PARTY_GETOPT_SRCS = $(foreach x,$(THIRD_PARTY_GETOPT_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_GETOPT_HDRS = $(foreach x,$(THIRD_PARTY_GETOPT_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_GETOPT_CHECKS = $(foreach x,$(THIRD_PARTY_GETOPT_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_GETOPT_OBJS = $(foreach x,$(THIRD_PARTY_GETOPT_ARTIFACTS),$($(x)_OBJS))
$(THIRD_PARTY_GETOPT_OBJS): $(BUILD_FILES) third_party/getopt/getopt.mk
.PHONY: o/$(MODE)/third_party/getopt
o/$(MODE)/third_party/getopt: $(THIRD_PARTY_GETOPT_CHECKS)

444
third_party/getopt/getopt_long.3 vendored Normal file
View file

@ -0,0 +1,444 @@
.\" $OpenBSD: getopt_long.3,v 1.21 2016/01/04 19:43:13 tb Exp $
.\" $NetBSD: getopt_long.3,v 1.11 2002/10/02 10:54:19 wiz Exp $
.\"
.\" Copyright (c) 1988, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)getopt.3 8.5 (Berkeley) 4/27/95
.\"
.Dd $Mdocdate: January 4 2016 $
.Dt GETOPT_LONG 3
.Os
.Sh NAME
.Nm getopt_long ,
.Nm getopt_long_only
.Nd get long options from command line argument list
.Sh SYNOPSIS
.In getopt.h
.Vt extern char *optarg;
.Vt extern int optind;
.Vt extern int optopt;
.Vt extern int opterr;
.Vt extern int optreset;
.Ft int
.Fn getopt_long "int argc" "char * const *argv" "const char *optstring" "const struct option *longopts" "int *longindex"
.Ft int
.Fn getopt_long_only "int argc" "char * const *argv" "const char *optstring" "const struct option *longopts" "int *longindex"
.Sh DESCRIPTION
The
.Fn getopt_long
function is similar to
.Xr getopt 3
but it accepts options in two forms: words and characters.
The
.Fn getopt_long
function provides a superset of the functionality of
.Xr getopt 3 .
.Fn getopt_long
can be used in two ways.
In the first way, every long option understood by the program has a
corresponding short option, and the option structure is only used to
translate from long options to short options.
When used in this fashion,
.Fn getopt_long
behaves identically to
.Xr getopt 3 .
This is a good way to add long option processing to an existing program
with the minimum of rewriting.
.Pp
In the second mechanism, a long option sets a flag in the
.Fa option
structure passed, or will store a pointer to the command line argument
in the
.Fa option
structure passed to it for options that take arguments.
Additionally, the long option's argument may be specified as a single
argument with an equal sign, e.g.
.Bd -literal -offset indent
$ myprogram --myoption=somevalue
.Ed
.Pp
When a long option is processed, the call to
.Fn getopt_long
will return 0.
For this reason, long option processing without
shortcuts is not backwards compatible with
.Xr getopt 3 .
.Pp
It is possible to combine these methods, providing for long options
processing with short option equivalents for some options.
Less frequently used options would be processed as long options only.
.Pp
Abbreviated long option names are accepted when
.Fn getopt_long
processes long options if the abbreviation is unique.
An exact match is always preferred for a defined long option.
.Pp
The
.Fn getopt_long
call requires an array to be initialized describing the long
options.
Each element of the array is a structure:
.Bd -literal -offset indent
struct option {
char *name;
int has_arg;
int *flag;
int val;
};
.Ed
.Pp
The
.Fa name
field should contain the option name without the leading double dash.
.Pp
The
.Fa has_arg
field should be one of:
.Pp
.Bl -tag -width "optional_argument" -compact -offset indent
.It Dv no_argument
no argument to the option is expected.
.It Dv required_argument
an argument to the option is required.
.It Dv optional_argument
an argument to the option may be presented.
.El
.Pp
If
.Fa flag
is not
.Dv NULL ,
then the integer pointed to by it will be set to the value in the
.Fa val
field.
If the
.Fa flag
field is
.Dv NULL ,
then the
.Fa val
field will be returned.
Setting
.Fa flag
to
.Dv NULL
and setting
.Fa val
to the corresponding short option will make this function act just
like
.Xr getopt 3 .
.Pp
If the
.Fa longindex
field is not
.Dv NULL ,
then the integer pointed to by it will be set to the index of the long
option relative to
.Fa longopts .
.Pp
The last element of the
.Fa longopts
array has to be filled with zeroes.
.Pp
The
.Fn getopt_long_only
function behaves identically to
.Fn getopt_long
with the exception that long options may start with
.Sq -
in addition to
.Sq -- .
If an option starting with
.Sq -
does not match a long option but does match a single-character option,
the single-character option is returned.
.Sh RETURN VALUES
If the
.Fa flag
field in
.Li struct option
is
.Dv NULL ,
.Fn getopt_long
and
.Fn getopt_long_only
return the value specified in the
.Fa val
field, which is usually just the corresponding short option.
If
.Fa flag
is not
.Dv NULL ,
these functions return 0 and store
.Fa val
in the location pointed to by
.Fa flag .
These functions return
.Sq \&:
if there was a missing option argument,
.Sq \&?
if the user specified an unknown or ambiguous option, and
\-1 when the argument list has been exhausted.
.Sh IMPLEMENTATION DIFFERENCES
This section describes differences to the GNU implementation
found in glibc-2.1.3:
.Bl -bullet
.It
handling of
.Ql -
within the option string (not the first character):
.Bl -tag -width "OpenBSD"
.It GNU
treats a
.Ql -
on the command line as a non-argument.
.It OpenBSD
a
.Ql -
within the option string matches a
.Ql -
(single dash) on the command line.
This functionality is provided for backward compatibility with
programs, such as
.Xr su 1 ,
that use
.Ql -
as an option flag.
This practice is wrong, and should not be used in any current development.
.El
.It
handling of
.Ql ::
in the option string in the presence of
.Ev POSIXLY_CORRECT :
.Bl -tag -width "OpenBSD"
.It Both
GNU and
.Ox
ignore
.Ev POSIXLY_CORRECT
here and take
.Ql ::
to mean the preceding option takes an optional argument.
.El
.It
return value in case of missing argument if first character
(after
.Ql +
or
.Ql - )
in the option string is not
.Ql \&: :
.Bl -tag -width "OpenBSD"
.It GNU
returns
.Ql \&?
.It OpenBSD
returns
.Ql \&:
(since
.Ox Ns 's
.Xr getopt 3
does).
.El
.It
handling of
.Ql --a
in
.Xr getopt 3 :
.Bl -tag -width "OpenBSD"
.It GNU
parses this as option
.Ql - ,
option
.Ql a .
.It OpenBSD
parses this as
.Ql -- ,
and returns \-1 (ignoring the
.Ql a )
(because the original
.Fn getopt
did.)
.El
.It
setting of
.Va optopt
for long options with
.Va flag
.No non- Ns Dv NULL :
.Bl -tag -width "OpenBSD"
.It GNU
sets
.Va optopt
to
.Va val .
.It OpenBSD
sets
.Va optopt
to 0 (since
.Va val
would never be returned).
.El
.It
handling of
.Ql -W
with
.Ql W;
in the option string in
.Xr getopt 3
(not
.Fn getopt_long ) :
.Bl -tag -width "OpenBSD"
.It GNU
causes a segmentation fault.
.It OpenBSD
no special handling is done;
.Ql W;
is interpreted as two separate options, neither of which take an argument.
.El
.It
setting of
.Va optarg
for long options without an argument that are invoked via
.Ql -W
(with
.Ql W;
in the option string):
.Bl -tag -width "OpenBSD"
.It GNU
sets
.Va optarg
to the option name (the argument of
.Ql -W ) .
.It OpenBSD
sets
.Va optarg
to
.Dv NULL
(the argument of the long option).
.El
.It
handling of
.Ql -W
with an argument that is not (a prefix to) a known long option
(with
.Ql W;
in the option string):
.Bl -tag -width "OpenBSD"
.It GNU
returns
.Ql -W
with
.Va optarg
set to the unknown option.
.It OpenBSD
treats this as an error (unknown option) and returns
.Ql \&?
with
.Va optopt
set to 0 and
.Va optarg
set to
.Dv NULL
(as GNU's man page documents).
.El
.It
The error messages are different.
.It
.Ox
does not permute the argument vector at the same points in
the calling sequence as GNU does.
The aspects normally used by the caller
(ordering after \-1 is returned, value of
.Va optind
relative to current positions) are the same, though.
(We do fewer variable swaps.)
.El
.Sh ENVIRONMENT
.Bl -tag -width Ev
.It Ev POSIXLY_CORRECT
If set, option processing stops when the first non-option is found and
a leading
.Sq +
in the
.Ar optstring
is ignored.
.El
.Sh EXAMPLES
.Bd -literal
int bflag, ch, fd;
int daggerset;
/* options descriptor */
static struct option longopts[] = {
{ "buffy", no_argument, NULL, 'b' },
{ "fluoride", required_argument, NULL, 'f' },
{ "daggerset", no_argument, &daggerset, 1 },
{ NULL, 0, NULL, 0 }
};
bflag = 0;
while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1)
switch (ch) {
case 'b':
bflag = 1;
break;
case 'f':
if ((fd = open(optarg, O_RDONLY, 0)) == -1)
err(1, "unable to open %s", optarg);
break;
case 0:
if (daggerset)
fprintf(stderr, "Buffy will use her dagger to "
"apply fluoride to dracula's teeth\en");
break;
default:
usage();
}
argc -= optind;
argv += optind;
.Ed
.Sh SEE ALSO
.Xr getopt 3
.Sh HISTORY
The
.Fn getopt_long
and
.Fn getopt_long_only
functions first appeared in GNU libiberty.
This implementation first appeared in
.Ox 3.3 .
.Sh BUGS
The
.Ar argv
argument is not really
.Dv const
as its elements may be permuted (unless
.Ev POSIXLY_CORRECT
is set).

553
third_party/getopt/getopt_long.c vendored Normal file
View file

@ -0,0 +1,553 @@
/**
* This file has an inappropriate amount of legal text for its
* complexity and should be rewritten. Consider using getopt().
*/
asm(".ident\t\"\\n\\n\
getopt_long (Licensed BSD-4, MIT)\\n\
Copyright (c) 2000 The NetBSD Foundation, Inc.\\n\
Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>\\n\
The getopt_long code is derived from software contributed to The\\n\
NetBSD Foundation by Dieter Baron and Thomas Klausner. This code\\n\
has received sponsorship from the U.S. Military. Special thanks\\n\
to the OpenBSD, NetBSD, FreeBSD, and DragonFlyBSD teams.\"");
asm(".include \"libc/disclaimer.inc\"");
#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
/* clang-format off */
/* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $*/
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD: src/lib/libc/stdlib/getopt_long.c,v 1.15 2006/09/23 14:48:31 ache Exp $
* $DragonFly: src/lib/libc/stdlib/getopt_long.c,v 1.14 2005/11/20 12:37:48 swildner Exp $
*/
#include "third_party/getopt/getopt.h"
#include "libc/str/str.h"
#include "libc/runtime/runtime.h"
#include "libc/log/bsd.h"
STATIC_YOINK("stoa");
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG2 ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG ""
#define NO_PREFIX (-1)
#define D_PREFIX 0
#define DD_PREFIX 1
#define W_PREFIX 2
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static int dash_prefix = NO_PREFIX;
#define recargchar "option requires an argument -- %c"
#define illoptchar "illegal option -- %c" /* From P1003.2 */
#define gnuoptchar "invalid option -- %c"
#define recargstring "option `%s%s' requires an argument"
#define ambig "option `%s%.*s' is ambiguous"
#define noarg "option `%s%.*s' doesn't allow an argument"
#define illoptstring "unrecognized option `%s%s'"
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
(__DECONST(char **, nargv))[pos] = nargv[cstart];
/* LINTED const cast */
(__DECONST(char **, nargv))[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too, int flags)
{
char *current_argv, *has_equal;
char *current_dash;
size_t current_argv_len;
int i, match, exact_match, second_partial_match;
current_argv = place;
switch (dash_prefix) {
case D_PREFIX:
current_dash = "-";
break;
case DD_PREFIX:
current_dash = "--";
break;
case W_PREFIX:
current_dash = "-W ";
break;
default:
current_dash = "";
break;
}
match = -1;
exact_match = 0;
second_partial_match = 0;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
exact_match = 1;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* first partial match */
match = i;
else if ((flags & FLAG_LONGONLY) ||
long_options[i].has_arg !=
long_options[match].has_arg ||
long_options[i].flag != long_options[match].flag ||
long_options[i].val != long_options[match].val)
second_partial_match = 1;
}
if (!exact_match && second_partial_match) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
(warnx)(ambig,
current_dash,
(int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
(warnx)(noarg,
current_dash,
(int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADCH);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
(warnx)(recargstring,
current_dash,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG2);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
(warnx)(illoptstring,
current_dash,
current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
int posixly_correct; /* no static, can be changed on the fly */
if (options == NULL)
return (-1);
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
place[1] == '\0') {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
dash_prefix = D_PREFIX;
if (*place == '-') {
place++; /* --foo long option */
dash_prefix = DD_PREFIX;
} else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too, flags);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
(warnx)(posixly_correct ? illoptchar : gnuoptchar,
optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
(warnx)(recargchar, optchar);
optopt = optchar;
return (BADARG2);
} else /* white space */
place = nargv[optind];
dash_prefix = W_PREFIX;
optchar = parse_long_options(nargv, options, long_options,
idx, 0, flags);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
(warnx)(recargchar, optchar);
optopt = optchar;
return (BADARG2);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}