summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormillert <>2002-12-03 20:24:30 +0000
committermillert <>2002-12-03 20:24:30 +0000
commit4bbebe1cbc72fcf121b5982aba8121a040997270 (patch)
tree4181617be2388b75004461e3be7ffcc9c1b6f922 /src
parent5b1b8dec4403c20d7a64a5a24dd566c852ddcb6b (diff)
downloadopenbsd-4bbebe1cbc72fcf121b5982aba8121a040997270.tar.gz
openbsd-4bbebe1cbc72fcf121b5982aba8121a040997270.tar.bz2
openbsd-4bbebe1cbc72fcf121b5982aba8121a040997270.zip
GNU-like getopt_long() from NetBSD with changes by me to support
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.
Diffstat (limited to 'src')
-rw-r--r--src/lib/libc/stdlib/Makefile.inc17
-rw-r--r--src/lib/libc/stdlib/getopt_long.3326
-rw-r--r--src/lib/libc/stdlib/getopt_long.c510
3 files changed, 845 insertions, 8 deletions
diff --git a/src/lib/libc/stdlib/Makefile.inc b/src/lib/libc/stdlib/Makefile.inc
index 6b23e5cb2d..8f16135e99 100644
--- a/src/lib/libc/stdlib/Makefile.inc
+++ b/src/lib/libc/stdlib/Makefile.inc
@@ -4,10 +4,10 @@
4.PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/stdlib ${LIBCSRCDIR}/stdlib 4.PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/stdlib ${LIBCSRCDIR}/stdlib
5 5
6SRCS+= a64l.c abort.c atexit.c atoi.c atof.c atol.c atoll.c bsearch.c \ 6SRCS+= a64l.c abort.c atexit.c atoi.c atof.c atol.c atoll.c bsearch.c \
7 calloc.c cfree.c exit.c ecvt.c gcvt.c getenv.c getopt.c getsubopt.c \ 7 calloc.c cfree.c exit.c ecvt.c gcvt.c getenv.c getopt.c getopt_long.c \
8 heapsort.c l64a.c malloc.c merge.c multibyte.c putenv.c qsort.c \ 8 getsubopt.c heapsort.c l64a.c malloc.c merge.c multibyte.c putenv.c =
9 radixsort.c rand.c random.c realpath.c setenv.c strtod.c strtol.c \ 9 qsort.c radixsort.c rand.c random.c realpath.c setenv.c strtod.c \
10 strtoll.c strtoul.c strtoull.c system.c tfind.c tsearch.c \ 10 strtol.c strtoll.c strtoul.c strtoull.c system.c tfind.c tsearch.c \
11 _rand48.c drand48.c erand48.c jrand48.c lcong48.c lrand48.c \ 11 _rand48.c drand48.c erand48.c jrand48.c lcong48.c lrand48.c \
12 mrand48.c nrand48.c seed48.c srand48.c qabs.c qdiv.c 12 mrand48.c nrand48.c seed48.c srand48.c qabs.c qdiv.c
13 13
@@ -33,13 +33,14 @@ SRCS+= abs.c div.c labs.c ldiv.c
33.endif 33.endif
34 34
35MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 atoll.3 \ 35MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 atoll.3 \
36 bsearch.3 div.3 ecvt.3 exit.3 getenv.3 getopt.3 getsubopt.3 labs.3 \ 36 bsearch.3 div.3 ecvt.3 exit.3 getenv.3 getopt.3 getopt_long.3 \
37 ldiv.3 malloc.3 memory.3 qabs.3 qdiv.3 qsort.3 radixsort.3 rand48.3 \ 37 getsubopt.3 labs.3 ldiv.3 malloc.3 memory.3 qabs.3 qdiv.3 qsort.3 \
38 rand.3 random.3 realpath.3 strtod.3 strtol.3 strtoul.3 system.3 \ 38 radixsort.3 rand48.3 rand.3 random.3 realpath.3 strtod.3 strtol.3 \
39 tsearch.3 39 strtoul.3 system.3 tsearch.3
40 40
41MLINKS+=ecvt.3 fcvt.3 ecvt.3 gcvt.3 41MLINKS+=ecvt.3 fcvt.3 ecvt.3 gcvt.3
42MLINKS+=getenv.3 setenv.3 getenv.3 unsetenv.3 getenv.3 putenv.3 42MLINKS+=getenv.3 setenv.3 getenv.3 unsetenv.3 getenv.3 putenv.3
43MLINKS+=getopt_long.3 getopt_long_only.3
43MLINKS+=malloc.3 free.3 malloc.3 realloc.3 malloc.3 calloc.3 44MLINKS+=malloc.3 free.3 malloc.3 realloc.3 malloc.3 calloc.3
44MLINKS+=malloc.3 cfree.3 malloc.3 malloc.conf.5 45MLINKS+=malloc.3 cfree.3 malloc.3 malloc.conf.5
45MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3 46MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3
diff --git a/src/lib/libc/stdlib/getopt_long.3 b/src/lib/libc/stdlib/getopt_long.3
new file mode 100644
index 0000000000..d55f4ead53
--- /dev/null
+++ b/src/lib/libc/stdlib/getopt_long.3
@@ -0,0 +1,326 @@
1.\" $OpenBSD: getopt_long.3,v 1.1 2002/12/03 20:24:30 millert Exp $
2.\" $NetBSD: getopt_long.3,v 1.11 2002/10/02 10:54:19 wiz Exp $
3.\"
4.\" Copyright (c) 1988, 1991, 1993
5.\" The Regents of the University of California. All rights reserved.
6.\"
7.\" Redistribution and use in source and binary forms, with or without
8.\" modification, are permitted provided that the following conditions
9.\" are met:
10.\" 1. Redistributions of source code must retain the above copyright
11.\" notice, this list of conditions and the following disclaimer.
12.\" 2. Redistributions in binary form must reproduce the above copyright
13.\" notice, this list of conditions and the following disclaimer in the
14.\" documentation and/or other materials provided with the distribution.
15.\" 3. All advertising materials mentioning features or use of this software
16.\" must display the following acknowledgement:
17.\" This product includes software developed by the University of
18.\" California, Berkeley and its contributors.
19.\" 4. Neither the name of the University nor the names of its contributors
20.\" may be used to endorse or promote products derived from this software
21.\" without specific prior written permission.
22.\"
23.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33.\" SUCH DAMAGE.
34.\"
35.\" @(#)getopt.3 8.5 (Berkeley) 4/27/95
36.\"
37.Dd April 1, 2000
38.Dt GETOPT_LONG 3
39.Os
40.Sh NAME
41.Nm getopt_long ,
42.Nm getopt_long_only
43.Nd get long options from command line argument list
44.Sh SYNOPSIS
45.Fd #include <getopt.h>
46.Vt extern char *optarg;
47.Vt extern int optind;
48.Vt extern int optopt;
49.Vt extern int opterr;
50.Vt extern int optreset;
51.Ft int
52.Fn getopt_long "int argc" "char * const *argv" "const char *optstring" "struct option *long options" "int *index"
53.Ft int
54.Fn getopt_long_only "int argc" "char * const *argv" "const char *optstring" "struct option *long options" "int *index"
55.Sh DESCRIPTION
56The
57.Fn getopt_long
58function is similar to
59.Xr getopt 3
60but it accepts options in two forms: words and characters.
61The
62.Fn getopt_long
63function provides a superset of of the functionality of
64.Xr getopt 3 .
65.Fn getopt_long
66can be used in two ways.
67In the first way, every long option understood by the program has a
68corresponding short option, and the option structure is only used to
69translate from long options to short options.
70When used in this fashion,
71.Fn getopt_long
72behaves identically to
73.Xr getopt 3 .
74This is a good way to add long option processing to an existing program
75with the minimum of rewriting.
76.Pp
77In the second mechanism, a long option sets a flag in the
78.Fa option
79structure passed, or will store a pointer to the command line argument
80in the
81.Fa option
82structure passed to it for options that take arguments.
83Additionally, the long option's argument may be specified as a single
84argument with an equal sign, e.g.
85.Bd -literal
86myprogram --myoption=somevalue
87.Ed
88.Pp
89When a long option is processed the call to
90.Fn getopt_long
91will return 0.
92For this reason, long option processing without
93shortcuts is not backwards compatible with
94.Xr getopt 3 .
95.Pp
96It is possible to combine these methods, providing for long options
97processing with short option equivalents for some options.
98Less frequently used options would be processed as long options only.
99.Pp
100The
101.Fn getopt_long
102call requires a structure to be initialized describing the long
103options.
104The structure is:
105.Bd -literal
106struct option {
107 char *name;
108 int has_arg;
109 int *flag;
110 int val;
111};
112.Ed
113.Pp
114The
115.Fa name
116field should contain the option name without the leading double dash.
117.Pp
118The
119.Fa has_arg
120field should be one of:
121.Bl -tag -width "optional_argument"
122.It Li no_argument
123no argument to the option is expect.
124.It Li required_argument
125an argument to the option is required.
126.It Li optional_argument
127an argument to the option may be presented.
128.El
129.Pp
130If
131.Fa flag
132is not
133.Dv NULL ,
134then the integer pointed to by it will be set to the value in the
135.Fa val
136field.
137If the
138.Fa flag
139field is
140.Dv NULL ,
141then the
142.Fa val
143field will be returned.
144Setting
145.Fa flag
146to
147.Dv NULL
148and setting
149.Fa val
150to the corresponding short option will make this function act just
151like
152.Xr getopt 3 .
153.Pp
154The
155.Fn getopt_long_only
156function behaves identically to
157.Fn getopt_long
158with the exception that long options may start with
159.Sq -
160in addition to
161.Sq -- .
162If an option starting with
163.Sq -
164does not match a long option but does match a single-character option,
165the single-character option is returned.
166.Sh EXAMPLES
167.Bd -literal -compact
168int bflag, ch, fd;
169int daggerset;
170
171/* options descriptor */
172static struct option longopts[] = {
173 { "buffy", no_argument, 0, 'b' },
174 { "fluoride", required_argument, 0, 'f' },
175 { "daggerset", no_argument, &daggerset, 1 },
176 { 0, 0, 0, 0 }
177};
178
179bflag = 0;
180while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1)
181 switch(ch) {
182 case 'b':
183 bflag = 1;
184 break;
185 case 'f':
186 if ((fd = open(optarg, O_RDONLY, 0)) == -1)
187 err(1, "unable to open %s", optarg);
188 break;
189 case 0:
190 if (daggerset) {
191 fprintf(stderr,"Buffy will use her dagger to "
192 "apply fluoride to dracula's teeth\en");
193 }
194 break;
195 case '?':
196 default:
197 usage();
198}
199argc -= optind;
200argv += optind;
201.Ed
202.Sh IMPLEMENTATION DIFFERENCES
203This section describes differences to the GNU implementation
204found in glibc-2.1.3:
205.Bl -tag -width "xxx"
206.It Li o
207handling of - as first char of option string in presence of
208environment variable POSIXLY_CORRECT:
209.Bl -tag -width "OpenBSD"
210.It Li GNU
211ignores POSIXLY_CORRECT and returns non-options as
212arguments to option '\e1'.
213.It Li OpenBSD
214honors POSIXLY_CORRECT and stops at the first non-option.
215.El
216.It Li o
217handling of :: in options string in presence of POSIXLY_CORRECT:
218.Bl -tag -width "OpenBSD"
219.It Li Both
220GNU and OpenBSD ignore POSIXLY_CORRECT here and take :: to
221mean the preceding option takes an optional argument.
222.El
223.It Li o
224return value in case of missing argument if first character
225(after + or -) in option string is not ':':
226.Bl -tag -width "OpenBSD"
227.It Li GNU
228returns '?'
229.It OpenBSD
230returns ':' (since OpenBSD's getopt does).
231.El
232.It Li o
233handling of --a in getopt:
234.Bl -tag -width "OpenBSD"
235.It Li GNU
236parses this as option '-', option 'a'.
237.It Li OpenBSD
238parses this as '--', and returns -1 (ignoring the a). (Because
239the original getopt does.)
240.El
241.It Li o
242setting of optopt for long options with flag !=
243.Dv NULL :
244.Bl -tag -width "OpenBSD"
245.It Li GNU
246sets optopt to val.
247.It Li OpenBSD
248sets optopt to 0 (since val would never be returned).
249.El
250.It Li o
251handling of -W with W; in option string in getopt (not getopt_long):
252.Bl -tag -width "OpenBSD"
253.It Li GNU
254causes a segfault.
255.It Li OpenBSD
256returns \-1, with optind pointing past the argument of -W
257(as if `-W arg' were `--arg', and thus '--' had been found).
258.\" How should we treat W; in the option string when called via
259.\" getopt? Ignore the ';' or treat it as a ':'? Issue a warning?
260.El
261.It Li o
262setting of optarg for long options without an argument that are
263invoked via -W (W; in option string):
264.Bl -tag -width "OpenBSD"
265.It Li GNU
266sets optarg to the option name (the argument of -W).
267.It Li OpenBSD
268sets optarg to
269.Dv NULL
270(the argument of the long option).
271.El
272.It Li o
273handling of -W with an argument that is not (a prefix to) a known
274long option (W; in option string):
275.Bl -tag -width "OpenBSD"
276.It Li GNU
277returns -W with optarg set to the unknown option.
278.It Li OpenBSD
279treats this as an error (unknown option) and returns '?' with
280optopt set to 0 and optarg set to
281.Dv NULL
282(as GNU's man page documents).
283.El
284.It Li o
285The error messages are different.
286.It Li o
287OpenBSD does not permute the argument vector at the same points in
288the calling sequence as GNU does.
289The aspects normally used by the caller
290(ordering after \-1 is returned, value of optind relative
291to current positions) are the same, though.
292(We do fewer variable swaps.)
293.El
294.Sh ENVIRONMENT
295.Bl -tag -width POSIXLY_CORRECT
296.It Ev POSIXLY_CORRECT
297If set, option processing stops when the first non-option is found and
298a leading
299.Sq -
300or
301.Sq +
302in the
303.Ar optstring
304is ignored.
305.El
306.Sh SEE ALSO
307.Xr getopt 3
308.Sh HISTORY
309The
310.Fn getopt_long
311and
312.Fn getopt_long_only
313functions first appeared in GNU libiberty.
314This implementation first appeared in
315.Ox 3.3 .
316.Sh BUGS
317The
318.Ar argv
319argument is not really
320.Dv const
321as its elements may be permuted (unless
322.Ev POSIXLY_CORRECT
323is set).
324.Pp
325In a future release, this implementation should completely replace
326.Xr getopt 3 .
diff --git a/src/lib/libc/stdlib/getopt_long.c b/src/lib/libc/stdlib/getopt_long.c
new file mode 100644
index 0000000000..1256e5d655
--- /dev/null
+++ b/src/lib/libc/stdlib/getopt_long.c
@@ -0,0 +1,510 @@
1/* $OpenBSD: getopt_long.c,v 1.1 2002/12/03 20:24:30 millert Exp $ */
2/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
3
4/*-
5 * Copyright (c) 2000 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Dieter Baron and Thomas Klausner.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#if defined(LIBC_SCCS) && !defined(lint)
41static char *rcsid = "$OpenBSD: getopt_long.c,v 1.1 2002/12/03 20:24:30 millert Exp $";
42#endif /* LIBC_SCCS and not lint */
43
44#include <err.h>
45#include <errno.h>
46#include <getopt.h>
47#include <stdlib.h>
48#include <string.h>
49
50int opterr = 1; /* if error message should be printed */
51int optind = 1; /* index into parent argv vector */
52int optopt = '?'; /* character checked for validity */
53int optreset; /* reset getopt */
54char *optarg; /* argument associated with option */
55
56#define PRINT_ERROR ((opterr) && (*options != ':'))
57
58#define FLAG_PERMUTE 0x01
59#define FLAG_ALLARGS 0x02
60#define FLAG_LONGONLY 0x04
61
62/* return values */
63#define BADCH (int)'?'
64#define BADARG ((*options == ':') ? (int)':' : (int)'?')
65#define INORDER (int)1
66
67#define EMSG ""
68
69static int getopt_internal(int, char * const *, const char *, int);
70static int getopt_long_internal(int, char * const *, const char *,
71 const struct option *, int *, int);
72static int gcd(int, int);
73static void permute_args(int, int, int, char * const *);
74
75static char *place = EMSG; /* option letter processing */
76
77/* XXX: set optreset to 1 rather than these two */
78static int nonopt_start = -1; /* first non option argument (for permute) */
79static int nonopt_end = -1; /* first option after non options (for permute) */
80
81/* Error messages */
82static const char recargchar[] = "option requires an argument -- %c";
83static const char recargstring[] = "option requires an argument -- %s";
84static const char ambig[] = "ambiguous option -- %.*s";
85static const char noarg[] = "option doesn't take an argument -- %.*s";
86static const char illoptchar[] = "unknown option -- %c";
87static const char illoptstring[] = "unknown option -- %s";
88
89/*
90 * Compute the greatest common divisor of a and b.
91 */
92static int
93gcd(a, b)
94 int a;
95 int b;
96{
97 int c;
98
99 c = a % b;
100 while (c != 0) {
101 a = b;
102 b = c;
103 c = a % b;
104 }
105
106 return b;
107}
108
109/*
110 * Exchange the block from nonopt_start to nonopt_end with the block
111 * from nonopt_end to opt_end (keeping the same order of arguments
112 * in each block).
113 */
114static void
115permute_args(panonopt_start, panonopt_end, opt_end, nargv)
116 int panonopt_start;
117 int panonopt_end;
118 int opt_end;
119 char * const *nargv;
120{
121 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
122 char *swap;
123
124 /*
125 * compute lengths of blocks and number and size of cycles
126 */
127 nnonopts = panonopt_end - panonopt_start;
128 nopts = opt_end - panonopt_end;
129 ncycle = gcd(nnonopts, nopts);
130 cyclelen = (opt_end - panonopt_start) / ncycle;
131
132 for (i = 0; i < ncycle; i++) {
133 cstart = panonopt_end+i;
134 pos = cstart;
135 for (j = 0; j < cyclelen; j++) {
136 if (pos >= panonopt_end)
137 pos -= nnonopts;
138 else
139 pos += nopts;
140 swap = nargv[pos];
141 /* LINTED const cast */
142 ((char **) nargv)[pos] = nargv[cstart];
143 /* LINTED const cast */
144 ((char **)nargv)[cstart] = swap;
145 }
146 }
147}
148
149/*
150 * getopt_internal --
151 * Parse argc/argv argument vector. Called by user level routines.
152 * Returns -2 if -- is found (can be long option or end of options marker).
153 */
154static int
155getopt_internal(nargc, nargv, options, flags)
156 int nargc;
157 char * const *nargv;
158 const char *options;
159 int flags;
160{
161 char *oli; /* option letter list index */
162 int optchar;
163
164 optarg = NULL;
165
166 /*
167 * XXX Some programs (like rsyncd) expect to be able to
168 * XXX re-initialize optind to 0 and have getopt_long(3)
169 * XXX properly function again. Work around this braindamage.
170 */
171 if (optind == 0)
172 optind = 1;
173
174 if (optreset)
175 nonopt_start = nonopt_end = -1;
176start:
177 if (optreset || !*place) { /* update scanning pointer */
178 optreset = 0;
179 if (optind >= nargc) { /* end of argument vector */
180 place = EMSG;
181 if (nonopt_end != -1) {
182 /* do permutation, if we have to */
183 permute_args(nonopt_start, nonopt_end,
184 optind, nargv);
185 optind -= nonopt_end - nonopt_start;
186 }
187 else if (nonopt_start != -1) {
188 /*
189 * If we skipped non-options, set optind
190 * to the first of them.
191 */
192 optind = nonopt_start;
193 }
194 nonopt_start = nonopt_end = -1;
195 return -1;
196 }
197 if ((*(place = nargv[optind]) != '-')
198 || (place[1] == '\0')) { /* found non-option */
199 place = EMSG;
200 if (flags & FLAG_ALLARGS) {
201 /*
202 * GNU extension:
203 * return non-option as argument to option 1
204 */
205 optarg = nargv[optind++];
206 return INORDER;
207 }
208 if (!(flags & FLAG_PERMUTE)) {
209 /*
210 * If no permutation wanted, stop parsing
211 * at first non-option.
212 */
213 return -1;
214 }
215 /* do permutation */
216 if (nonopt_start == -1)
217 nonopt_start = optind;
218 else if (nonopt_end != -1) {
219 permute_args(nonopt_start, nonopt_end,
220 optind, nargv);
221 nonopt_start = optind -
222 (nonopt_end - nonopt_start);
223 nonopt_end = -1;
224 }
225 optind++;
226 /* process next argument */
227 goto start;
228 }
229 if (nonopt_start != -1 && nonopt_end == -1)
230 nonopt_end = optind;
231 if (place[1] && *++place == '-') { /* found "--" */
232 place++;
233 return -2;
234 }
235 }
236 if ((optchar = (int)*place++) == (int)':' ||
237 (oli = strchr(options, optchar)) == NULL) {
238 /* could it be a long option with a single '-'? */
239 if (flags & FLAG_LONGONLY)
240 return -2;
241 /* option letter unknown or ':' */
242 if (!*place)
243 ++optind;
244 if (PRINT_ERROR)
245 warnx(illoptchar, optchar);
246 optopt = optchar;
247 return BADCH;
248 }
249 if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
250 /* XXX: what if no long options provided (called by getopt)? */
251 if (*place)
252 return -2;
253
254 if (++optind >= nargc) { /* no arg */
255 place = EMSG;
256 if (PRINT_ERROR)
257 warnx(recargchar, optchar);
258 optopt = optchar;
259 return BADARG;
260 } else /* white space */
261 place = nargv[optind];
262 /*
263 * Handle -W arg the same as --arg (which causes getopt to
264 * stop parsing).
265 */
266 return -2;
267 }
268 if (*++oli != ':') { /* doesn't take argument */
269 if (!*place)
270 ++optind;
271 } else { /* takes (optional) argument */
272 optarg = NULL;
273 if (*place) /* no white space */
274 optarg = place;
275 /* XXX: disable test for :: if PC? (GNU doesn't) */
276 else if (oli[1] != ':') { /* arg not optional */
277 if (++optind >= nargc) { /* no arg */
278 place = EMSG;
279 if (PRINT_ERROR)
280 warnx(recargchar, optchar);
281 optopt = optchar;
282 return BADARG;
283 } else
284 optarg = nargv[optind];
285 }
286 place = EMSG;
287 ++optind;
288 }
289 /* dump back option letter */
290 return optchar;
291}
292
293#ifdef REPLACE_GETOPT
294/*
295 * getopt --
296 * Parse argc/argv argument vector.
297 *
298 * [eventually this will replace the BSD getopt]
299 */
300int
301getopt(nargc, nargv, options)
302 int nargc;
303 char * const *nargv;
304 const char *options;
305{
306 int retval;
307
308 if ((retval = getopt_internal(nargc, nargv, options, 0)) == -2) {
309 ++optind;
310 /*
311 * We found an option (--), so if we skipped non-options,
312 * we have to permute.
313 */
314 if (nonopt_end != -1) {
315 permute_args(nonopt_start, nonopt_end, optind,
316 nargv);
317 optind -= nonopt_end - nonopt_start;
318 }
319 nonopt_start = nonopt_end = -1;
320 retval = -1;
321 }
322 return retval;
323}
324#endif /* REPLACE_GETOPT */
325
326/*
327 * getopt_long_internal --
328 * Parse argc/argv argument vector.
329 */
330static int
331getopt_long_internal(nargc, nargv, options, long_options, idx, flags)
332 int nargc;
333 char * const *nargv;
334 const char *options;
335 const struct option *long_options;
336 int *idx;
337 int flags;
338{
339 int retval;
340
341 /*
342 * Disable GNU extensions if POSIXLY_CORRECT is set or options
343 * string begins with a '+'.
344 */
345 if (getenv("POSIXLY_CORRECT")) {
346 if (*options == '+' || *options == '-')
347 options++;
348 } else {
349 if (*options == '+') {
350 options++;
351 } else {
352 flags |= FLAG_PERMUTE;
353 if (*options == '-') {
354 flags |= FLAG_ALLARGS;
355 options++;
356 }
357 }
358 }
359
360 if ((retval = getopt_internal(nargc, nargv, options, flags)) == -2) {
361 char *current_argv, *has_equal;
362 size_t current_argv_len;
363 int i, match;
364
365 current_argv = place;
366 match = -1;
367
368 optind++;
369 place = EMSG;
370
371 if (*current_argv == '\0') { /* found "--" */
372 /*
373 * We found an option (--), so if we skipped
374 * non-options, we have to permute.
375 */
376 if (nonopt_end != -1) {
377 permute_args(nonopt_start, nonopt_end,
378 optind, nargv);
379 optind -= nonopt_end - nonopt_start;
380 }
381 nonopt_start = nonopt_end = -1;
382 return -1;
383 }
384 if ((has_equal = strchr(current_argv, '=')) != NULL) {
385 /* argument found (--option=arg) */
386 current_argv_len = has_equal - current_argv;
387 has_equal++;
388 } else
389 current_argv_len = strlen(current_argv);
390
391 for (i = 0; long_options[i].name; i++) {
392 /* find matching long option */
393 if (strncmp(current_argv, long_options[i].name,
394 current_argv_len))
395 continue;
396
397 if (strlen(long_options[i].name) ==
398 (unsigned)current_argv_len) {
399 /* exact match */
400 match = i;
401 break;
402 }
403 if (match == -1) /* partial match */
404 match = i;
405 else {
406 /* ambiguous abbreviation */
407 if (PRINT_ERROR)
408 warnx(ambig, (int)current_argv_len,
409 current_argv);
410 optopt = 0;
411 return BADCH;
412 }
413 }
414 if (match != -1) { /* option found */
415 if (long_options[match].has_arg == no_argument
416 && has_equal) {
417 if (PRINT_ERROR)
418 warnx(noarg, (int)current_argv_len,
419 current_argv);
420 /*
421 * XXX: GNU sets optopt to val regardless of
422 * flag
423 */
424 if (long_options[match].flag == NULL)
425 optopt = long_options[match].val;
426 else
427 optopt = 0;
428 return BADARG;
429 }
430 if (long_options[match].has_arg == required_argument ||
431 long_options[match].has_arg == optional_argument) {
432 if (has_equal)
433 optarg = has_equal;
434 else if (long_options[match].has_arg ==
435 required_argument) {
436 /*
437 * optional argument doesn't use
438 * next nargv
439 */
440 optarg = nargv[optind++];
441 }
442 }
443 if ((long_options[match].has_arg == required_argument)
444 && (optarg == NULL)) {
445 /*
446 * Missing argument; leading ':'
447 * indicates no error should be generated
448 */
449 if (PRINT_ERROR)
450 warnx(recargstring, current_argv);
451 /*
452 * XXX: GNU sets optopt to val regardless
453 * of flag
454 */
455 if (long_options[match].flag == NULL)
456 optopt = long_options[match].val;
457 else
458 optopt = 0;
459 --optind;
460 return BADARG;
461 }
462 } else { /* unknown option */
463 if (PRINT_ERROR)
464 warnx(illoptstring, current_argv);
465 optopt = 0;
466 return BADCH;
467 }
468 if (long_options[match].flag) {
469 *long_options[match].flag = long_options[match].val;
470 retval = 0;
471 } else
472 retval = long_options[match].val;
473 if (idx)
474 *idx = match;
475 }
476 return retval;
477}
478
479/*
480 * getopt_long --
481 * Parse argc/argv argument vector.
482 */
483int
484getopt_long(nargc, nargv, options, long_options, idx)
485 int nargc;
486 char * const *nargv;
487 const char *options;
488 const struct option *long_options;
489 int *idx;
490{
491
492 return getopt_long_internal(nargc, nargv, options, long_options, idx, 0);
493}
494
495/*
496 * getopt_long_only --
497 * Parse argc/argv argument vector.
498 */
499int
500getopt_long_only(nargc, nargv, options, long_options, idx)
501 int nargc;
502 char * const *nargv;
503 const char *options;
504 const struct option *long_options;
505 int *idx;
506{
507
508 return getopt_long_internal(nargc, nargv, options, long_options, idx,
509 FLAG_LONGONLY);
510}