getopt_long_only(). At some point this should replace the BSD getopt(3) but we are not there yet. While I am here add protection from the multiple getopt() definitions due to conflicting standards.OPENBSD_3_3
@ -0,0 +1,85 @@ | |||
/* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */ | |||
/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ | |||
/*- | |||
* 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. | |||
*/ | |||
#ifndef _GETOPT_H_ | |||
#define _GETOPT_H_ | |||
#include <sys/cdefs.h> | |||
/* | |||
* GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions | |||
*/ | |||
#define no_argument 0 | |||
#define required_argument 1 | |||
#define optional_argument 2 | |||
struct option { | |||
/* name of long option */ | |||
const char *name; | |||
/* | |||
* one of no_argument, required_argument, and optional_argument: | |||
* whether option takes an argument | |||
*/ | |||
int has_arg; | |||
/* if not NULL, set *flag to val when option found */ | |||
int *flag; | |||
/* if flag not NULL, value to set *flag to; else return value */ | |||
int val; | |||
}; | |||
__BEGIN_DECLS | |||
int getopt_long(int, char * const *, const char *, | |||
const struct option *, int *); | |||
int getopt_long_only(int, char * const *, const char *, | |||
const struct option *, int *); | |||
#ifndef _GETOPT_DEFINED_ | |||
#define _GETOPT_DEFINED_ | |||
int getopt(int, char * const *, const char *); | |||
int getsubopt(char **, char * const *, char **); | |||
extern char *optarg; /* getopt(3) external variables */ | |||
extern int opterr; | |||
extern int optind; | |||
extern int optopt; | |||
extern int optreset; | |||
extern char *suboptarg; /* getsubopt(3) external variable */ | |||
#endif | |||
__END_DECLS | |||
#endif /* !_GETOPT_H_ */ |
@ -0,0 +1,326 @@ | |||
.\" $OpenBSD: getopt_long.3,v 1.1 2002/12/03 20:24:30 millert 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. All advertising materials mentioning features or use of this software | |||
.\" must display the following acknowledgement: | |||
.\" This product includes software developed by the University of | |||
.\" California, Berkeley and its contributors. | |||
.\" 4. 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 April 1, 2000 | |||
.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 | |||
.Fd #include <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" "struct option *long options" "int *index" | |||
.Ft int | |||
.Fn getopt_long_only "int argc" "char * const *argv" "const char *optstring" "struct option *long options" "int *index" | |||
.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 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 | |||
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 | |||
The | |||
.Fn getopt_long | |||
call requires a structure to be initialized describing the long | |||
options. | |||
The structure is: | |||
.Bd -literal | |||
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: | |||
.Bl -tag -width "optional_argument" | |||
.It Li no_argument | |||
no argument to the option is expect. | |||
.It Li required_argument | |||
an argument to the option is required. | |||
.It Li 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 | |||
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 EXAMPLES | |||
.Bd -literal -compact | |||
int bflag, ch, fd; | |||
int daggerset; | |||
/* options descriptor */ | |||
static struct option longopts[] = { | |||
{ "buffy", no_argument, 0, 'b' }, | |||
{ "fluoride", required_argument, 0, 'f' }, | |||
{ "daggerset", no_argument, &daggerset, 1 }, | |||
{ 0, 0, 0, 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; | |||
case '?': | |||
default: | |||
usage(); | |||
} | |||
argc -= optind; | |||
argv += optind; | |||
.Ed | |||
.Sh IMPLEMENTATION DIFFERENCES | |||
This section describes differences to the GNU implementation | |||
found in glibc-2.1.3: | |||
.Bl -tag -width "xxx" | |||
.It Li o | |||
handling of - as first char of option string in presence of | |||
environment variable POSIXLY_CORRECT: | |||
.Bl -tag -width "OpenBSD" | |||
.It Li GNU | |||
ignores POSIXLY_CORRECT and returns non-options as | |||
arguments to option '\e1'. | |||
.It Li OpenBSD | |||
honors POSIXLY_CORRECT and stops at the first non-option. | |||
.El | |||
.It Li o | |||
handling of :: in options string in presence of POSIXLY_CORRECT: | |||
.Bl -tag -width "OpenBSD" | |||
.It Li Both | |||
GNU and OpenBSD ignore POSIXLY_CORRECT here and take :: to | |||
mean the preceding option takes an optional argument. | |||
.El | |||
.It Li o | |||
return value in case of missing argument if first character | |||
(after + or -) in option string is not ':': | |||
.Bl -tag -width "OpenBSD" | |||
.It Li GNU | |||
returns '?' | |||
.It OpenBSD | |||
returns ':' (since OpenBSD's getopt does). | |||
.El | |||
.It Li o | |||
handling of --a in getopt: | |||
.Bl -tag -width "OpenBSD" | |||
.It Li GNU | |||
parses this as option '-', option 'a'. | |||
.It Li OpenBSD | |||
parses this as '--', and returns -1 (ignoring the a). (Because | |||
the original getopt does.) | |||
.El | |||
.It Li o | |||
setting of optopt for long options with flag != | |||
.Dv NULL : | |||
.Bl -tag -width "OpenBSD" | |||
.It Li GNU | |||
sets optopt to val. | |||
.It Li OpenBSD | |||
sets optopt to 0 (since val would never be returned). | |||
.El | |||
.It Li o | |||
handling of -W with W; in option string in getopt (not getopt_long): | |||
.Bl -tag -width "OpenBSD" | |||
.It Li GNU | |||
causes a segfault. | |||
.It Li OpenBSD | |||
returns \-1, with optind pointing past the argument of -W | |||
(as if `-W arg' were `--arg', and thus '--' had been found). | |||
.\" How should we treat W; in the option string when called via | |||
.\" getopt? Ignore the ';' or treat it as a ':'? Issue a warning? | |||
.El | |||
.It Li o | |||
setting of optarg for long options without an argument that are | |||
invoked via -W (W; in option string): | |||
.Bl -tag -width "OpenBSD" | |||
.It Li GNU | |||
sets optarg to the option name (the argument of -W). | |||
.It Li OpenBSD | |||
sets optarg to | |||
.Dv NULL | |||
(the argument of the long option). | |||
.El | |||
.It Li o | |||
handling of -W with an argument that is not (a prefix to) a known | |||
long option (W; in option string): | |||
.Bl -tag -width "OpenBSD" | |||
.It Li GNU | |||
returns -W with optarg set to the unknown option. | |||
.It Li OpenBSD | |||
treats this as an error (unknown option) and returns '?' with | |||
optopt set to 0 and optarg set to | |||
.Dv NULL | |||
(as GNU's man page documents). | |||
.El | |||
.It Li o | |||
The error messages are different. | |||
.It Li o | |||
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 optind relative | |||
to current positions) are the same, though. | |||
(We do fewer variable swaps.) | |||
.El | |||
.Sh ENVIRONMENT | |||
.Bl -tag -width POSIXLY_CORRECT | |||
.It Ev POSIXLY_CORRECT | |||
If set, option processing stops when the first non-option is found and | |||
a leading | |||
.Sq - | |||
or | |||
.Sq + | |||
in the | |||
.Ar optstring | |||
is ignored. | |||
.El | |||
.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). | |||
.Pp | |||
In a future release, this implementation should completely replace | |||
.Xr getopt 3 . |
@ -0,0 +1,510 @@ | |||
/* $OpenBSD: getopt_long.c,v 1.1 2002/12/03 20:24:30 millert Exp $ */ | |||
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ | |||
/*- | |||
* 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. | |||
*/ | |||
#if defined(LIBC_SCCS) && !defined(lint) | |||
static char *rcsid = "$OpenBSD: getopt_long.c,v 1.1 2002/12/03 20:24:30 millert Exp $"; | |||
#endif /* LIBC_SCCS and not lint */ | |||
#include <err.h> | |||
#include <errno.h> | |||
#include <getopt.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
int opterr = 1; /* if error message should be printed */ | |||
int optind = 1; /* index into parent argv vector */ | |||
int optopt = '?'; /* character checked for validity */ | |||
int optreset; /* reset getopt */ | |||
char *optarg; /* argument associated with option */ | |||
#define PRINT_ERROR ((opterr) && (*options != ':')) | |||
#define FLAG_PERMUTE 0x01 | |||
#define FLAG_ALLARGS 0x02 | |||
#define FLAG_LONGONLY 0x04 | |||
/* return values */ | |||
#define BADCH (int)'?' | |||
#define BADARG ((*options == ':') ? (int)':' : (int)'?') | |||
#define INORDER (int)1 | |||
#define EMSG "" | |||
static int getopt_internal(int, char * const *, const char *, int); | |||
static int getopt_long_internal(int, char * const *, const char *, | |||
const struct option *, 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 const char recargchar[] = "option requires an argument -- %c"; | |||
static const char recargstring[] = "option requires an argument -- %s"; | |||
static const char ambig[] = "ambiguous option -- %.*s"; | |||
static const char noarg[] = "option doesn't take an argument -- %.*s"; | |||
static const char illoptchar[] = "unknown option -- %c"; | |||
static const char illoptstring[] = "unknown option -- %s"; | |||
/* | |||
* Compute the greatest common divisor of a and b. | |||
*/ | |||
static int | |||
gcd(a, b) | |||
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(panonopt_start, panonopt_end, opt_end, nargv) | |||
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 */ | |||
((char **) nargv)[pos] = nargv[cstart]; | |||
/* LINTED const cast */ | |||
((char **)nargv)[cstart] = swap; | |||
} | |||
} | |||
} | |||
/* | |||
* getopt_internal -- | |||
* Parse argc/argv argument vector. Called by user level routines. | |||
* Returns -2 if -- is found (can be long option or end of options marker). | |||
*/ | |||
static int | |||
getopt_internal(nargc, nargv, options, flags) | |||
int nargc; | |||
char * const *nargv; | |||
const char *options; | |||
int flags; | |||
{ | |||
char *oli; /* option letter list index */ | |||
int optchar; | |||
optarg = NULL; | |||
/* | |||
* XXX Some programs (like rsyncd) expect to be able to | |||
* XXX re-initialize optind to 0 and have getopt_long(3) | |||
* XXX properly function again. Work around this braindamage. | |||
*/ | |||
if (optind == 0) | |||
optind = 1; | |||
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')) { /* found non-option */ | |||
place = EMSG; | |||
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 (place[1] && *++place == '-') { /* found "--" */ | |||
place++; | |||
return -2; | |||
} | |||
} | |||
if ((optchar = (int)*place++) == (int)':' || | |||
(oli = strchr(options, optchar)) == NULL) { | |||
/* could it be a long option with a single '-'? */ | |||
if (flags & FLAG_LONGONLY) | |||
return -2; | |||
/* option letter unknown or ':' */ | |||
if (!*place) | |||
++optind; | |||
if (PRINT_ERROR) | |||
warnx(illoptchar, optchar); | |||
optopt = optchar; | |||
return BADCH; | |||
} | |||
if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ | |||
/* XXX: what if no long options provided (called by getopt)? */ | |||
if (*place) | |||
return -2; | |||
if (++optind >= nargc) { /* no arg */ | |||
place = EMSG; | |||
if (PRINT_ERROR) | |||
warnx(recargchar, optchar); | |||
optopt = optchar; | |||
return BADARG; | |||
} else /* white space */ | |||
place = nargv[optind]; | |||
/* | |||
* Handle -W arg the same as --arg (which causes getopt to | |||
* stop parsing). | |||
*/ | |||
return -2; | |||
} | |||
if (*++oli != ':') { /* doesn't take argument */ | |||
if (!*place) | |||
++optind; | |||
} else { /* takes (optional) argument */ | |||
optarg = NULL; | |||
if (*place) /* no white space */ | |||
optarg = place; | |||
/* XXX: disable test for :: if PC? (GNU doesn't) */ | |||
else if (oli[1] != ':') { /* arg not optional */ | |||
if (++optind >= nargc) { /* no arg */ | |||
place = EMSG; | |||
if (PRINT_ERROR) | |||
warnx(recargchar, optchar); | |||
optopt = optchar; | |||
return BADARG; | |||
} else | |||
optarg = nargv[optind]; | |||
} | |||
place = EMSG; | |||
++optind; | |||
} | |||
/* dump back option letter */ | |||
return optchar; | |||
} | |||
#ifdef REPLACE_GETOPT | |||
/* | |||
* getopt -- | |||
* Parse argc/argv argument vector. | |||
* | |||
* [eventually this will replace the BSD getopt] | |||
*/ | |||
int | |||
getopt(nargc, nargv, options) | |||
int nargc; | |||
char * const *nargv; | |||
const char *options; | |||
{ | |||
int retval; | |||
if ((retval = getopt_internal(nargc, nargv, options, 0)) == -2) { | |||
++optind; | |||
/* | |||
* 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; | |||
retval = -1; | |||
} | |||
return retval; | |||
} | |||
#endif /* REPLACE_GETOPT */ | |||
/* | |||
* getopt_long_internal -- | |||
* Parse argc/argv argument vector. | |||
*/ | |||
static int | |||
getopt_long_internal(nargc, nargv, options, long_options, idx, flags) | |||
int nargc; | |||
char * const *nargv; | |||
const char *options; | |||
const struct option *long_options; | |||
int *idx; | |||
int flags; | |||
{ | |||
int retval; | |||
/* | |||
* Disable GNU extensions if POSIXLY_CORRECT is set or options | |||
* string begins with a '+'. | |||
*/ | |||
if (getenv("POSIXLY_CORRECT")) { | |||
if (*options == '+' || *options == '-') | |||
options++; | |||
} else { | |||
if (*options == '+') { | |||
options++; | |||
} else { | |||
flags |= FLAG_PERMUTE; | |||
if (*options == '-') { | |||
flags |= FLAG_ALLARGS; | |||
options++; | |||
} | |||
} | |||
} | |||
if ((retval = getopt_internal(nargc, nargv, options, flags)) == -2) { | |||
char *current_argv, *has_equal; | |||
size_t current_argv_len; | |||
int i, match; | |||
current_argv = place; | |||
match = -1; | |||
optind++; | |||
place = EMSG; | |||
if (*current_argv == '\0') { /* found "--" */ | |||
/* | |||
* 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; | |||
} | |||
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) == | |||
(unsigned)current_argv_len) { | |||
/* exact match */ | |||
match = i; | |||
break; | |||
} | |||
if (match == -1) /* partial match */ | |||
match = i; | |||
else { | |||
/* ambiguous abbreviation */ | |||
if (PRINT_ERROR) | |||
warnx(ambig, (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, (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 BADARG; | |||
} | |||
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_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 BADARG; | |||
} | |||
} else { /* unknown option */ | |||
if (PRINT_ERROR) | |||
warnx(illoptstring, current_argv); | |||
optopt = 0; | |||
return BADCH; | |||
} | |||
if (long_options[match].flag) { | |||
*long_options[match].flag = long_options[match].val; | |||
retval = 0; | |||
} else | |||
retval = long_options[match].val; | |||
if (idx) | |||
*idx = match; | |||
} | |||
return retval; | |||
} | |||
/* | |||
* getopt_long -- | |||
* Parse argc/argv argument vector. | |||
*/ | |||
int | |||
getopt_long(nargc, nargv, options, long_options, idx) | |||
int nargc; | |||
char * const *nargv; | |||
const char *options; | |||
const struct option *long_options; | |||
int *idx; | |||
{ | |||
return getopt_long_internal(nargc, nargv, options, long_options, idx, 0); | |||
} | |||
/* | |||
* getopt_long_only -- | |||
* Parse argc/argv argument vector. | |||
*/ | |||
int | |||
getopt_long_only(nargc, nargv, options, long_options, idx) | |||
int nargc; | |||
char * const *nargv; | |||
const char *options; | |||
const struct option *long_options; | |||
int *idx; | |||
{ | |||
return getopt_long_internal(nargc, nargv, options, long_options, idx, | |||
FLAG_LONGONLY); | |||
} |