Further refine documentation

This commit is contained in:
Justine Tunney 2020-12-27 17:05:03 -08:00
parent 1bc3a25505
commit 548dcb9f08
27 changed files with 389 additions and 1478 deletions

View file

@ -1,10 +1,4 @@
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\"");
/* $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.
@ -36,13 +30,16 @@ asm(".include \"libc/disclaimer.inc\"");
* @(#)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/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
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\"");
STATIC_YOINK("_init_getopt");
#define BADCH (int)'?'
@ -50,48 +47,65 @@ STATIC_YOINK("_init_getopt");
/**
* If error message should be printed.
* @see getopt()
*/
int opterr;
/**
* Index into parent argv vector.
* @see getopt()
*/
int optind;
/**
* Character checked for validity.
* @see getopt()
*/
int optopt;
/**
* Reset getopt.
* @see getopt()
*/
int optreset;
/**
* Argument associated with option.
* @see getopt()
*/
char *optarg;
/**
* Option letter processing.
*/
char *getopt_place;
hidden char *getopt_place;
char kGetoptEmsg[1] hidden;
/**
* Parses argc/argv argument vector.
* Parses argc/argv argument vector, e.g.
*
* while ((opt = getopt(argc, argv, "hvx:")) != -1) {
* switch (opt) {
* case 'x':
* x = atoi(optarg);
* break;
* case 'v':
* ++verbose;
* break;
* case 'h':
* PrintUsage(EXIT_SUCCESS, stdout);
* default:
* PrintUsage(EX_USAGE, stderr);
* }
* }
*
* @see optind
* @see optarg
*/
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 || *getopt_place == 0) { /* update scanning pointer */
optreset = 0;
getopt_place = nargv[optind];
@ -117,7 +131,6 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
} else {
optopt = *getopt_place++;
}
/* See if option letter is one the caller wanted... */
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
if (*getopt_place == 0) ++optind;
@ -127,7 +140,6 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
}
return (BADCH);
}
/* Does this option need an argument? */
if (oli[1] != ':') {
/* don't need argument */
@ -152,5 +164,5 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
getopt_place = kGetoptEmsg;
++optind;
}
return (optopt); /* return option letter */
return optopt; /* return option letter */
}

View file

@ -1,444 +0,0 @@
.\" $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).

View file

@ -1,553 +0,0 @@
/**
* 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));
}

View file

@ -25,6 +25,5 @@
pop %rax
mov %eax,opterr(%rip)
mov %eax,optind(%rip)
lea kGetoptEmsg(%rip),%rax
mov %rax,getopt_place(%rip)
movl $kGetoptEmsg,getopt_place(%rip)
.init.end 201,_init_getopt