Deleted Added
full compact
getopt_long.c (126039) getopt_long.c (126189)
1/* $OpenBSD: getopt_long.c,v 1.16 2004/02/04 18:17:25 millert Exp $ */
1/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
2/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
2/* $FreeBSD: head/lib/libc/stdlib/getopt_long.c 126039 2004-02-20 11:55:14Z ru $ */
3
3
4/*
5 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 * Sponsored in part by the Defense Advanced Research Projects
20 * Agency (DARPA) and Air Force Research Laboratory, Air Force
21 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22 */
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

--- 20 unchanged lines hidden (view full) ---

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
23/*-
24 * Copyright (c) 2000 The NetBSD Foundation, Inc.
25 * All rights reserved.
26 *
27 * This code is derived from software contributed to The NetBSD Foundation
28 * by Dieter Baron and Thomas Klausner.
29 *
30 * Redistribution and use in source and binary forms, with or without

--- 20 unchanged lines hidden (view full) ---

51 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
56 * POSSIBILITY OF SUCH DAMAGE.
57 */
58
40#include <sys/cdefs.h>
59#if 0
41#if defined(LIBC_SCCS) && !defined(lint)
60#if defined(LIBC_SCCS) && !defined(lint)
42__RCSID("$NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $");
61static char *rcsid = "$OpenBSD: getopt_long.c,v 1.16 2004/02/04 18:17:25 millert Exp $";
43#endif /* LIBC_SCCS and not lint */
62#endif /* LIBC_SCCS and not lint */
63#endif
64#include <sys/cdefs.h>
65__FBSDID("$FreeBSD: head/lib/libc/stdlib/getopt_long.c 126189 2004-02-24 08:07:26Z ache $");
44
66
45#include <assert.h>
46#include <err.h>
47#include <errno.h>
48#include <getopt.h>
49#include <stdlib.h>
50#include <string.h>
51
67#include <err.h>
68#include <errno.h>
69#include <getopt.h>
70#include <stdlib.h>
71#include <string.h>
72
52/* not part of the original file */
53#ifndef _DIAGASSERT
54#define _DIAGASSERT(X)
73#ifdef notyet
74#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
55#endif
56
75#endif
76
57#if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
58#define REPLACE_GETOPT
59#endif
60
61#ifdef REPLACE_GETOPT
77#ifdef REPLACE_GETOPT
62#ifdef __weak_alias
63__weak_alias(getopt,_getopt)
64#endif
65int opterr = 1; /* if error message should be printed */
66int optind = 1; /* index into parent argv vector */
67int optopt = '?'; /* character checked for validity */
68int optreset; /* reset getopt */
69char *optarg; /* argument associated with option */
78int opterr = 1; /* if error message should be printed */
79int optind = 1; /* index into parent argv vector */
80int optopt = '?'; /* character checked for validity */
81int optreset; /* reset getopt */
82char *optarg; /* argument associated with option */
70#elif HAVE_CONFIG_H && !HAVE_DECL_OPTRESET
71static int optreset;
72#endif
73
83#endif
84
74#ifdef __weak_alias
75__weak_alias(getopt_long,_getopt_long)
76#endif
85#define PRINT_ERROR ((opterr) && (*options != ':'))
77
86
78#if !HAVE_GETOPT_LONG
79#define IGNORE_FIRST (*options == '-' || *options == '+')
80#define PRINT_ERROR ((opterr) && ((*options != ':') \
81 || (IGNORE_FIRST && options[1] != ':')))
82#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
83#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
84/* XXX: GNU ignores PC if *options == '-' */
85#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
87#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
88#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
89#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
86
87/* return values */
90
91/* return values */
88#define BADCH (int)'?'
89#define BADARG ((IGNORE_FIRST && options[1] == ':') \
90 || (*options == ':') ? (int)':' : (int)'?')
91#define INORDER (int)1
92#define BADCH (int)'?'
93#define BADARG ((*options == ':') ? (int)':' : (int)'?')
94#define INORDER (int)1
92
95
93#define EMSG ""
96#define EMSG ""
94
97
95static int getopt_internal(int, char * const *, const char *);
98static int getopt_internal(int, char * const *, const char *,
99 const struct option *, int *, int);
100static int parse_long_options(char * const *, const char *,
101 const struct option *, int *, int);
96static int gcd(int, int);
97static void permute_args(int, int, int, char * const *);
98
99static char *place = EMSG; /* option letter processing */
100
101/* XXX: set optreset to 1 rather than these two */
102static int nonopt_start = -1; /* first non option argument (for permute) */
103static int nonopt_end = -1; /* first option after non options (for permute) */
104
105/* Error messages */
106static const char recargchar[] = "option requires an argument -- %c";
107static const char recargstring[] = "option requires an argument -- %s";
108static const char ambig[] = "ambiguous option -- %.*s";
109static const char noarg[] = "option doesn't take an argument -- %.*s";
110static const char illoptchar[] = "unknown option -- %c";
111static const char illoptstring[] = "unknown option -- %s";
112
102static int gcd(int, int);
103static void permute_args(int, int, int, char * const *);
104
105static char *place = EMSG; /* option letter processing */
106
107/* XXX: set optreset to 1 rather than these two */
108static int nonopt_start = -1; /* first non option argument (for permute) */
109static int nonopt_end = -1; /* first option after non options (for permute) */
110
111/* Error messages */
112static const char recargchar[] = "option requires an argument -- %c";
113static const char recargstring[] = "option requires an argument -- %s";
114static const char ambig[] = "ambiguous option -- %.*s";
115static const char noarg[] = "option doesn't take an argument -- %.*s";
116static const char illoptchar[] = "unknown option -- %c";
117static const char illoptstring[] = "unknown option -- %s";
118
113
114/*
115 * Compute the greatest common divisor of a and b.
116 */
117static int
119/*
120 * Compute the greatest common divisor of a and b.
121 */
122static int
118gcd(a, b)
119 int a;
120 int b;
123gcd(int a, int b)
121{
122 int c;
123
124 c = a % b;
125 while (c != 0) {
126 a = b;
127 b = c;
128 c = a % b;
129 }
124{
125 int c;
126
127 c = a % b;
128 while (c != 0) {
129 a = b;
130 b = c;
131 c = a % b;
132 }
130
131 return b;
133
134 return (b);
132}
133
134/*
135 * Exchange the block from nonopt_start to nonopt_end with the block
136 * from nonopt_end to opt_end (keeping the same order of arguments
137 * in each block).
138 */
139static void
135}
136
137/*
138 * Exchange the block from nonopt_start to nonopt_end with the block
139 * from nonopt_end to opt_end (keeping the same order of arguments
140 * in each block).
141 */
142static void
140permute_args(panonopt_start, panonopt_end, opt_end, nargv)
141 int panonopt_start;
142 int panonopt_end;
143 int opt_end;
144 char * const *nargv;
143permute_args(int panonopt_start, int panonopt_end, int opt_end,
144 char * const *nargv)
145{
146 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
147 char *swap;
148
145{
146 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
147 char *swap;
148
149 _DIAGASSERT(nargv != NULL);
150
151 /*
152 * compute lengths of blocks and number and size of cycles
153 */
154 nnonopts = panonopt_end - panonopt_start;
155 nopts = opt_end - panonopt_end;
156 ncycle = gcd(nnonopts, nopts);
157 cyclelen = (opt_end - panonopt_start) / ncycle;
158

--- 10 unchanged lines hidden (view full) ---

169 ((char **) nargv)[pos] = nargv[cstart];
170 /* LINTED const cast */
171 ((char **)nargv)[cstart] = swap;
172 }
173 }
174}
175
176/*
149 /*
150 * compute lengths of blocks and number and size of cycles
151 */
152 nnonopts = panonopt_end - panonopt_start;
153 nopts = opt_end - panonopt_end;
154 ncycle = gcd(nnonopts, nopts);
155 cyclelen = (opt_end - panonopt_start) / ncycle;
156

--- 10 unchanged lines hidden (view full) ---

167 ((char **) nargv)[pos] = nargv[cstart];
168 /* LINTED const cast */
169 ((char **)nargv)[cstart] = swap;
170 }
171 }
172}
173
174/*
175 * parse_long_options --
176 * Parse long options in argc/argv argument vector.
177 * Returns -1 if short_too is set and the option does not match long_options.
178 */
179static int
180parse_long_options(char * const *nargv, const char *options,
181 const struct option *long_options, int *idx, int short_too)
182{
183 char *current_argv, *has_equal;
184 size_t current_argv_len;
185 int i, match;
186
187 current_argv = place;
188 match = -1;
189
190 optind++;
191
192 if ((has_equal = strchr(current_argv, '=')) != NULL) {
193 /* argument found (--option=arg) */
194 current_argv_len = has_equal - current_argv;
195 has_equal++;
196 } else
197 current_argv_len = strlen(current_argv);
198
199 for (i = 0; long_options[i].name; i++) {
200 /* find matching long option */
201 if (strncmp(current_argv, long_options[i].name,
202 current_argv_len))
203 continue;
204
205 if (strlen(long_options[i].name) == current_argv_len) {
206 /* exact match */
207 match = i;
208 break;
209 }
210 /*
211 * If this is a known short option, don't allow
212 * a partial match of a single character.
213 */
214 if (short_too && current_argv_len == 1)
215 continue;
216
217 if (match == -1) /* partial match */
218 match = i;
219 else {
220 /* ambiguous abbreviation */
221 if (PRINT_ERROR)
222 warnx(ambig, (int)current_argv_len,
223 current_argv);
224 optopt = 0;
225 return (BADCH);
226 }
227 }
228 if (match != -1) { /* option found */
229 if (long_options[match].has_arg == no_argument
230 && has_equal) {
231 if (PRINT_ERROR)
232 warnx(noarg, (int)current_argv_len,
233 current_argv);
234 /*
235 * XXX: GNU sets optopt to val regardless of flag
236 */
237 if (long_options[match].flag == NULL)
238 optopt = long_options[match].val;
239 else
240 optopt = 0;
241 return (BADARG);
242 }
243 if (long_options[match].has_arg == required_argument ||
244 long_options[match].has_arg == optional_argument) {
245 if (has_equal)
246 optarg = has_equal;
247 else if (long_options[match].has_arg ==
248 required_argument) {
249 /*
250 * optional argument doesn't use next nargv
251 */
252 optarg = nargv[optind++];
253 }
254 }
255 if ((long_options[match].has_arg == required_argument)
256 && (optarg == NULL)) {
257 /*
258 * Missing argument; leading ':' indicates no error
259 * should be generated.
260 */
261 if (PRINT_ERROR)
262 warnx(recargstring,
263 current_argv);
264 /*
265 * XXX: GNU sets optopt to val regardless of flag
266 */
267 if (long_options[match].flag == NULL)
268 optopt = long_options[match].val;
269 else
270 optopt = 0;
271 --optind;
272 return (BADARG);
273 }
274 } else { /* unknown option */
275 if (short_too) {
276 --optind;
277 return (-1);
278 }
279 if (PRINT_ERROR)
280 warnx(illoptstring, current_argv);
281 optopt = 0;
282 return (BADCH);
283 }
284 if (idx)
285 *idx = match;
286 if (long_options[match].flag) {
287 *long_options[match].flag = long_options[match].val;
288 return (0);
289 } else
290 return (long_options[match].val);
291}
292
293/*
177 * getopt_internal --
178 * Parse argc/argv argument vector. Called by user level routines.
294 * getopt_internal --
295 * Parse argc/argv argument vector. Called by user level routines.
179 * Returns -2 if -- is found (can be long option or end of options marker).
180 */
181static int
296 */
297static int
182getopt_internal(nargc, nargv, options)
183 int nargc;
184 char * const *nargv;
185 const char *options;
298getopt_internal(int nargc, char * const *nargv, const char *options,
299 const struct option *long_options, int *idx, int flags)
186{
187 char *oli; /* option letter list index */
300{
301 char *oli; /* option letter list index */
188 int optchar;
302 int optchar, short_too;
303 static int posixly_correct = -1;
189
304
190 _DIAGASSERT(nargv != NULL);
191 _DIAGASSERT(options != NULL);
305 if (options == NULL)
306 return (-1);
192
307
193 optarg = NULL;
308 /*
309 * Disable GNU extensions if POSIXLY_CORRECT is set or options
310 * string begins with a '+'.
311 */
312 if (posixly_correct == -1)
313 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
314 if (posixly_correct || *options == '+')
315 flags &= ~FLAG_PERMUTE;
316 else if (*options == '-')
317 flags |= FLAG_ALLARGS;
318 if (*options == '+' || *options == '-')
319 options++;
194
195 /*
320
321 /*
196 * XXX Some programs (like rsyncd) expect to be able to
197 * XXX re-initialize optind to 0 and have getopt_long(3)
198 * XXX properly function again. Work around this braindamage.
322 * XXX Some GNU programs (like cvs) set optind to 0 instead of
323 * XXX using optreset. Work around this braindamage.
199 */
200 if (optind == 0)
324 */
325 if (optind == 0)
201 optind = 1;
326 optind = optreset = 1;
202
327
328 optarg = NULL;
203 if (optreset)
204 nonopt_start = nonopt_end = -1;
205start:
206 if (optreset || !*place) { /* update scanning pointer */
207 optreset = 0;
208 if (optind >= nargc) { /* end of argument vector */
209 place = EMSG;
210 if (nonopt_end != -1) {

--- 5 unchanged lines hidden (view full) ---

216 else if (nonopt_start != -1) {
217 /*
218 * If we skipped non-options, set optind
219 * to the first of them.
220 */
221 optind = nonopt_start;
222 }
223 nonopt_start = nonopt_end = -1;
329 if (optreset)
330 nonopt_start = nonopt_end = -1;
331start:
332 if (optreset || !*place) { /* update scanning pointer */
333 optreset = 0;
334 if (optind >= nargc) { /* end of argument vector */
335 place = EMSG;
336 if (nonopt_end != -1) {

--- 5 unchanged lines hidden (view full) ---

342 else if (nonopt_start != -1) {
343 /*
344 * If we skipped non-options, set optind
345 * to the first of them.
346 */
347 optind = nonopt_start;
348 }
349 nonopt_start = nonopt_end = -1;
224 return -1;
350 return (-1);
225 }
351 }
226 if ((*(place = nargv[optind]) != '-')
227 || (place[1] == '\0')) { /* found non-option */
228 place = EMSG;
229 if (IN_ORDER) {
352 if (*(place = nargv[optind]) != '-' ||
353 (place[1] == '\0' && strchr(options, '-') == NULL)) {
354 place = EMSG; /* found non-option */
355 if (flags & FLAG_ALLARGS) {
230 /*
356 /*
231 * GNU extension:
357 * GNU extension:
232 * return non-option as argument to option 1
233 */
234 optarg = nargv[optind++];
358 * return non-option as argument to option 1
359 */
360 optarg = nargv[optind++];
235 return INORDER;
361 return (INORDER);
236 }
362 }
237 if (!PERMUTE) {
363 if (!(flags & FLAG_PERMUTE)) {
238 /*
364 /*
239 * if no permutation wanted, stop parsing
240 * at first non-option
365 * If no permutation wanted, stop parsing
366 * at first non-option.
241 */
367 */
242 return -1;
368 return (-1);
243 }
244 /* do permutation */
245 if (nonopt_start == -1)
246 nonopt_start = optind;
247 else if (nonopt_end != -1) {
248 permute_args(nonopt_start, nonopt_end,
249 optind, nargv);
250 nonopt_start = optind -
251 (nonopt_end - nonopt_start);
252 nonopt_end = -1;
253 }
254 optind++;
255 /* process next argument */
256 goto start;
257 }
258 if (nonopt_start != -1 && nonopt_end == -1)
259 nonopt_end = optind;
369 }
370 /* do permutation */
371 if (nonopt_start == -1)
372 nonopt_start = optind;
373 else if (nonopt_end != -1) {
374 permute_args(nonopt_start, nonopt_end,
375 optind, nargv);
376 nonopt_start = optind -
377 (nonopt_end - nonopt_start);
378 nonopt_end = -1;
379 }
380 optind++;
381 /* process next argument */
382 goto start;
383 }
384 if (nonopt_start != -1 && nonopt_end == -1)
385 nonopt_end = optind;
260 if (place[1] && *++place == '-') { /* found "--" */
261 place++;
262 return -2;
386
387 /*
388 * If we have "-" do nothing, if "--" we are done.
389 */
390 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
391 optind++;
392 place = EMSG;
393 /*
394 * We found an option (--), so if we skipped
395 * non-options, we have to permute.
396 */
397 if (nonopt_end != -1) {
398 permute_args(nonopt_start, nonopt_end,
399 optind, nargv);
400 optind -= nonopt_end - nonopt_start;
401 }
402 nonopt_start = nonopt_end = -1;
403 return (-1);
263 }
264 }
404 }
405 }
406
407 /*
408 * Check long options if:
409 * 1) we were passed some
410 * 2) the arg is not just "-"
411 * 3) either the arg starts with -- we are getopt_long_only()
412 */
413 if (long_options != NULL && place != nargv[optind] &&
414 (*place == '-' || (flags & FLAG_LONGONLY))) {
415 short_too = 0;
416 if (*place == '-')
417 place++; /* --foo long option */
418 else if (*place != ':' && strchr(options, *place) != NULL)
419 short_too = 1; /* could be short option too */
420
421 optchar = parse_long_options(nargv, options, long_options,
422 idx, short_too);
423 if (optchar != -1) {
424 place = EMSG;
425 return (optchar);
426 }
427 }
428
265 if ((optchar = (int)*place++) == (int)':' ||
429 if ((optchar = (int)*place++) == (int)':' ||
266 (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
267 /* option letter unknown or ':' */
430 (optchar == (int)'-' && *place != '\0') ||
431 (oli = strchr(options, optchar)) == NULL) {
432 /*
433 * If the user specified "-" and '-' isn't listed in
434 * options, return -1 (non-option) as per POSIX.
435 * Otherwise, it is an unknown option character (or ':').
436 */
437 if (optchar == (int)'-' && *place == '\0')
438 return (-1);
268 if (!*place)
269 ++optind;
270 if (PRINT_ERROR)
271 warnx(illoptchar, optchar);
272 optopt = optchar;
439 if (!*place)
440 ++optind;
441 if (PRINT_ERROR)
442 warnx(illoptchar, optchar);
443 optopt = optchar;
273 return BADCH;
444 return (BADCH);
274 }
445 }
275 if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
276 /* XXX: what if no long options provided (called by getopt)? */
277 if (*place)
278 return -2;
279
280 if (++optind >= nargc) { /* no arg */
446 if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
447 /* -W long-option */
448 if (*place) /* no space */
449 /* NOTHING */;
450 else if (++optind >= nargc) { /* no arg */
281 place = EMSG;
282 if (PRINT_ERROR)
283 warnx(recargchar, optchar);
284 optopt = optchar;
451 place = EMSG;
452 if (PRINT_ERROR)
453 warnx(recargchar, optchar);
454 optopt = optchar;
285 return BADARG;
455 return (BADARG);
286 } else /* white space */
287 place = nargv[optind];
456 } else /* white space */
457 place = nargv[optind];
288 /*
289 * Handle -W arg the same as --arg (which causes getopt to
290 * stop parsing).
291 */
292 return -2;
458 optchar = parse_long_options(nargv, options, long_options,
459 idx, 0);
460 place = EMSG;
461 return (optchar);
293 }
294 if (*++oli != ':') { /* doesn't take argument */
295 if (!*place)
296 ++optind;
297 } else { /* takes (optional) argument */
298 optarg = NULL;
299 if (*place) /* no white space */
300 optarg = place;
301 /* XXX: disable test for :: if PC? (GNU doesn't) */
302 else if (oli[1] != ':') { /* arg not optional */
303 if (++optind >= nargc) { /* no arg */
304 place = EMSG;
305 if (PRINT_ERROR)
306 warnx(recargchar, optchar);
307 optopt = optchar;
462 }
463 if (*++oli != ':') { /* doesn't take argument */
464 if (!*place)
465 ++optind;
466 } else { /* takes (optional) argument */
467 optarg = NULL;
468 if (*place) /* no white space */
469 optarg = place;
470 /* XXX: disable test for :: if PC? (GNU doesn't) */
471 else if (oli[1] != ':') { /* arg not optional */
472 if (++optind >= nargc) { /* no arg */
473 place = EMSG;
474 if (PRINT_ERROR)
475 warnx(recargchar, optchar);
476 optopt = optchar;
308 return BADARG;
477 return (BADARG);
309 } else
310 optarg = nargv[optind];
478 } else
479 optarg = nargv[optind];
480 } else if (!(flags & FLAG_PERMUTE)) {
481 /*
482 * If permutation is disabled, we can accept an
483 * optional arg separated by whitespace.
484 */
485 if (optind + 1 < nargc)
486 optarg = nargv[++optind];
311 }
312 place = EMSG;
313 ++optind;
314 }
315 /* dump back option letter */
487 }
488 place = EMSG;
489 ++optind;
490 }
491 /* dump back option letter */
316 return optchar;
492 return (optchar);
317}
318
319#ifdef REPLACE_GETOPT
320/*
321 * getopt --
322 * Parse argc/argv argument vector.
323 *
493}
494
495#ifdef REPLACE_GETOPT
496/*
497 * getopt --
498 * Parse argc/argv argument vector.
499 *
324 * [eventually this will replace the real getopt]
500 * [eventually this will replace the BSD getopt]
325 */
326int
501 */
502int
327getopt(nargc, nargv, options)
328 int nargc;
329 char * const *nargv;
330 const char *options;
503getopt(int nargc, char * const *nargv, const char *options)
331{
504{
332 int retval;
333
505
334 _DIAGASSERT(nargv != NULL);
335 _DIAGASSERT(options != NULL);
336
337 if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
338 ++optind;
339 /*
340 * We found an option (--), so if we skipped non-options,
341 * we have to permute.
342 */
343 if (nonopt_end != -1) {
344 permute_args(nonopt_start, nonopt_end, optind,
345 nargv);
346 optind -= nonopt_end - nonopt_start;
347 }
348 nonopt_start = nonopt_end = -1;
349 retval = -1;
350 }
351 return retval;
506 /*
507 * We don't pass FLAG_PERMUTE to getopt_internal() since
508 * the BSD getopt(3) (unlike GNU) has never done this.
509 *
510 * Furthermore, since many privileged programs call getopt()
511 * before dropping privileges it makes sense to keep things
512 * as simple (and bug-free) as possible.
513 */
514 return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
352}
515}
353#endif
516#endif /* REPLACE_GETOPT */
354
355/*
356 * getopt_long --
357 * Parse argc/argv argument vector.
358 */
359int
360getopt_long(nargc, nargv, options, long_options, idx)
361 int nargc;
362 char * const *nargv;
363 const char *options;
364 const struct option *long_options;
365 int *idx;
366{
517
518/*
519 * getopt_long --
520 * Parse argc/argv argument vector.
521 */
522int
523getopt_long(nargc, nargv, options, long_options, idx)
524 int nargc;
525 char * const *nargv;
526 const char *options;
527 const struct option *long_options;
528 int *idx;
529{
367 int retval;
368
530
369 _DIAGASSERT(nargv != NULL);
370 _DIAGASSERT(options != NULL);
371 _DIAGASSERT(long_options != NULL);
372 /* idx may be NULL */
531 return (getopt_internal(nargc, nargv, options, long_options, idx,
532 FLAG_PERMUTE));
533}
373
534
374 if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
375 char *current_argv, *has_equal;
376 size_t current_argv_len;
377 int i, match;
535/*
536 * getopt_long_only --
537 * Parse argc/argv argument vector.
538 */
539int
540getopt_long_only(nargc, nargv, options, long_options, idx)
541 int nargc;
542 char * const *nargv;
543 const char *options;
544 const struct option *long_options;
545 int *idx;
546{
378
547
379 current_argv = place;
380 match = -1;
381
382 optind++;
383 place = EMSG;
384
385 if (*current_argv == '\0') { /* found "--" */
386 /*
387 * We found an option (--), so if we skipped
388 * non-options, we have to permute.
389 */
390 if (nonopt_end != -1) {
391 permute_args(nonopt_start, nonopt_end,
392 optind, nargv);
393 optind -= nonopt_end - nonopt_start;
394 }
395 nonopt_start = nonopt_end = -1;
396 return -1;
397 }
398 if ((has_equal = strchr(current_argv, '=')) != NULL) {
399 /* argument found (--option=arg) */
400 current_argv_len = has_equal - current_argv;
401 has_equal++;
402 } else
403 current_argv_len = strlen(current_argv);
404
405 for (i = 0; long_options[i].name; i++) {
406 /* find matching long option */
407 if (strncmp(current_argv, long_options[i].name,
408 current_argv_len))
409 continue;
410
411 if (strlen(long_options[i].name) ==
412 (unsigned)current_argv_len) {
413 /* exact match */
414 match = i;
415 break;
416 }
417 if (match == -1) /* partial match */
418 match = i;
419 else {
420 /* ambiguous abbreviation */
421 if (PRINT_ERROR)
422 warnx(ambig, (int)current_argv_len,
423 current_argv);
424 optopt = 0;
425 return BADCH;
426 }
427 }
428 if (match != -1) { /* option found */
429 if (long_options[match].has_arg == no_argument
430 && has_equal) {
431 if (PRINT_ERROR)
432 warnx(noarg, (int)current_argv_len,
433 current_argv);
434 /*
435 * XXX: GNU sets optopt to val regardless of
436 * flag
437 */
438 if (long_options[match].flag == NULL)
439 optopt = long_options[match].val;
440 else
441 optopt = 0;
442 return BADARG;
443 }
444 if (long_options[match].has_arg == required_argument ||
445 long_options[match].has_arg == optional_argument) {
446 if (has_equal)
447 optarg = has_equal;
448 else if (long_options[match].has_arg ==
449 required_argument) {
450 /*
451 * optional argument doesn't use
452 * next nargv
453 */
454 optarg = nargv[optind++];
455 }
456 }
457 if ((long_options[match].has_arg == required_argument)
458 && (optarg == NULL)) {
459 /*
460 * Missing argument; leading ':'
461 * indicates no error should be generated
462 */
463 if (PRINT_ERROR)
464 warnx(recargstring, current_argv);
465 /*
466 * XXX: GNU sets optopt to val regardless
467 * of flag
468 */
469 if (long_options[match].flag == NULL)
470 optopt = long_options[match].val;
471 else
472 optopt = 0;
473 --optind;
474 return BADARG;
475 }
476 } else { /* unknown option */
477 if (PRINT_ERROR)
478 warnx(illoptstring, current_argv);
479 optopt = 0;
480 return BADCH;
481 }
482 if (long_options[match].flag) {
483 *long_options[match].flag = long_options[match].val;
484 retval = 0;
485 } else
486 retval = long_options[match].val;
487 if (idx)
488 *idx = match;
489 }
490 return retval;
548 return (getopt_internal(nargc, nargv, options, long_options, idx,
549 FLAG_PERMUTE|FLAG_LONGONLY));
491}
550}
492#endif /* !GETOPT_LONG */