1b6cee71dSXin LI /* $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $ */
2b6cee71dSXin LI
3b6cee71dSXin LI /*-
4b6cee71dSXin LI * Copyright (c) 2000 The NetBSD Foundation, Inc.
5b6cee71dSXin LI * All rights reserved.
6b6cee71dSXin LI *
7b6cee71dSXin LI * This code is derived from software contributed to The NetBSD Foundation
8b6cee71dSXin LI * by Dieter Baron and Thomas Klausner.
9b6cee71dSXin LI *
10b6cee71dSXin LI * Redistribution and use in source and binary forms, with or without
11b6cee71dSXin LI * modification, are permitted provided that the following conditions
12b6cee71dSXin LI * are met:
13b6cee71dSXin LI * 1. Redistributions of source code must retain the above copyright
14b6cee71dSXin LI * notice, this list of conditions and the following disclaimer.
15b6cee71dSXin LI * 2. Redistributions in binary form must reproduce the above copyright
16b6cee71dSXin LI * notice, this list of conditions and the following disclaimer in the
17b6cee71dSXin LI * documentation and/or other materials provided with the distribution.
18b6cee71dSXin LI *
19b6cee71dSXin LI * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20b6cee71dSXin LI * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21b6cee71dSXin LI * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22b6cee71dSXin LI * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23b6cee71dSXin LI * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24b6cee71dSXin LI * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25b6cee71dSXin LI * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26b6cee71dSXin LI * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27b6cee71dSXin LI * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28b6cee71dSXin LI * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29b6cee71dSXin LI * POSSIBILITY OF SUCH DAMAGE.
30b6cee71dSXin LI */
31b6cee71dSXin LI
32b6cee71dSXin LI #include "file.h"
33b6cee71dSXin LI
34b6cee71dSXin LI #ifndef lint
35*898496eeSXin LI FILE_RCSID("@(#)$File: getopt_long.c,v 1.9 2022/09/24 20:30:13 christos Exp $")
36b6cee71dSXin LI #endif /* lint */
37b6cee71dSXin LI
38b6cee71dSXin LI #include <assert.h>
39b6cee71dSXin LI #ifdef HAVE_ERR_H
40b6cee71dSXin LI #include <err.h>
41b6cee71dSXin LI #else
42b6cee71dSXin LI #define warnx printf
43b6cee71dSXin LI #endif
44b6cee71dSXin LI #include <errno.h>
45b6cee71dSXin LI #if defined(HAVE_GETOPT_H) && defined(HAVE_STRUCT_OPTION)
46b6cee71dSXin LI #include <getopt.h>
47b6cee71dSXin LI #else
48b6cee71dSXin LI #include "mygetopt.h"
49b6cee71dSXin LI #endif
50b6cee71dSXin LI #include <stdlib.h>
51b6cee71dSXin LI #include <string.h>
52b6cee71dSXin LI
53b6cee71dSXin LI #define REPLACE_GETOPT
54b6cee71dSXin LI
55b6cee71dSXin LI #ifndef _DIAGASSERT
56b6cee71dSXin LI #define _DIAGASSERT assert
57b6cee71dSXin LI #endif
58b6cee71dSXin LI
59b6cee71dSXin LI #ifdef REPLACE_GETOPT
60b6cee71dSXin LI #ifdef __weak_alias
61b6cee71dSXin LI __weak_alias(getopt,_getopt)
62b6cee71dSXin LI #endif
63b6cee71dSXin LI int opterr = 1; /* if error message should be printed */
64b6cee71dSXin LI int optind = 1; /* index into parent argv vector */
65b6cee71dSXin LI int optopt = '?'; /* character checked for validity */
66b6cee71dSXin LI int optreset; /* reset getopt */
67b6cee71dSXin LI char *optarg; /* argument associated with option */
68b6cee71dSXin LI #elif HAVE_NBTOOL_CONFIG_H && !HAVE_DECL_OPTRESET
69b6cee71dSXin LI static int optreset;
70b6cee71dSXin LI #endif
71b6cee71dSXin LI
72b6cee71dSXin LI #ifdef __weak_alias
73b6cee71dSXin LI __weak_alias(getopt_long,_getopt_long)
74b6cee71dSXin LI #endif
75b6cee71dSXin LI
76b6cee71dSXin LI #define IGNORE_FIRST (*options == '-' || *options == '+')
77b6cee71dSXin LI #define PRINT_ERROR ((opterr) && ((*options != ':') \
78b6cee71dSXin LI || (IGNORE_FIRST && options[1] != ':')))
79b6cee71dSXin LI #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
80b6cee71dSXin LI #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
81b6cee71dSXin LI /* XXX: GNU ignores PC if *options == '-' */
82b6cee71dSXin LI #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
83b6cee71dSXin LI
84b6cee71dSXin LI /* return values */
85b6cee71dSXin LI #define BADCH (int)'?'
86b6cee71dSXin LI #define BADARG ((IGNORE_FIRST && options[1] == ':') \
87b6cee71dSXin LI || (*options == ':') ? (int)':' : (int)'?')
88b6cee71dSXin LI #define INORDER (int)1
89b6cee71dSXin LI
90b6cee71dSXin LI #define EMSG ""
91b6cee71dSXin LI
92b6cee71dSXin LI static int getopt_internal(int, char **, const char *);
93b6cee71dSXin LI static int gcd(int, int);
94b6cee71dSXin LI static void permute_args(int, int, int, char **);
95b6cee71dSXin LI
96b6cee71dSXin LI static const char *place = EMSG; /* option letter processing */
97b6cee71dSXin LI
98b6cee71dSXin LI /* XXX: set optreset to 1 rather than these two */
99b6cee71dSXin LI static int nonopt_start = -1; /* first non option argument (for permute) */
100b6cee71dSXin LI static int nonopt_end = -1; /* first option after non options (for permute) */
101b6cee71dSXin LI
102b6cee71dSXin LI /* Error messages */
103b6cee71dSXin LI static const char recargchar[] = "option requires an argument -- %c";
104b6cee71dSXin LI static const char recargstring[] = "option requires an argument -- %s";
105b6cee71dSXin LI static const char ambig[] = "ambiguous option -- %.*s";
106b6cee71dSXin LI static const char noarg[] = "option doesn't take an argument -- %.*s";
107b6cee71dSXin LI static const char illoptchar[] = "unknown option -- %c";
108b6cee71dSXin LI static const char illoptstring[] = "unknown option -- %s";
109b6cee71dSXin LI
110b6cee71dSXin LI
111b6cee71dSXin LI /*
112b6cee71dSXin LI * Compute the greatest common divisor of a and b.
113b6cee71dSXin LI */
114b6cee71dSXin LI static int
gcd(a,b)115b6cee71dSXin LI gcd(a, b)
116b6cee71dSXin LI int a;
117b6cee71dSXin LI int b;
118b6cee71dSXin LI {
119b6cee71dSXin LI int c;
120b6cee71dSXin LI
121b6cee71dSXin LI c = a % b;
122b6cee71dSXin LI while (c != 0) {
123b6cee71dSXin LI a = b;
124b6cee71dSXin LI b = c;
125b6cee71dSXin LI c = a % b;
126b6cee71dSXin LI }
127b6cee71dSXin LI
128b6cee71dSXin LI return b;
129b6cee71dSXin LI }
130b6cee71dSXin LI
131b6cee71dSXin LI /*
132b6cee71dSXin LI * Exchange the block from nonopt_start to nonopt_end with the block
133b6cee71dSXin LI * from nonopt_end to opt_end (keeping the same order of arguments
134b6cee71dSXin LI * in each block).
135b6cee71dSXin LI */
136b6cee71dSXin LI static void
permute_args(panonopt_start,panonopt_end,opt_end,nargv)137b6cee71dSXin LI permute_args(panonopt_start, panonopt_end, opt_end, nargv)
138b6cee71dSXin LI int panonopt_start;
139b6cee71dSXin LI int panonopt_end;
140b6cee71dSXin LI int opt_end;
141b6cee71dSXin LI char **nargv;
142b6cee71dSXin LI {
143b6cee71dSXin LI int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
144b6cee71dSXin LI char *swap;
145b6cee71dSXin LI
146b6cee71dSXin LI _DIAGASSERT(nargv != NULL);
147b6cee71dSXin LI
148b6cee71dSXin LI /*
149b6cee71dSXin LI * compute lengths of blocks and number and size of cycles
150b6cee71dSXin LI */
151b6cee71dSXin LI nnonopts = panonopt_end - panonopt_start;
152b6cee71dSXin LI nopts = opt_end - panonopt_end;
153b6cee71dSXin LI ncycle = gcd(nnonopts, nopts);
154b6cee71dSXin LI cyclelen = (opt_end - panonopt_start) / ncycle;
155b6cee71dSXin LI
156b6cee71dSXin LI for (i = 0; i < ncycle; i++) {
157b6cee71dSXin LI cstart = panonopt_end+i;
158b6cee71dSXin LI pos = cstart;
159b6cee71dSXin LI for (j = 0; j < cyclelen; j++) {
160b6cee71dSXin LI if (pos >= panonopt_end)
161b6cee71dSXin LI pos -= nnonopts;
162b6cee71dSXin LI else
163b6cee71dSXin LI pos += nopts;
164b6cee71dSXin LI swap = nargv[pos];
165b6cee71dSXin LI nargv[pos] = nargv[cstart];
166b6cee71dSXin LI nargv[cstart] = swap;
167b6cee71dSXin LI }
168b6cee71dSXin LI }
169b6cee71dSXin LI }
170b6cee71dSXin LI
171b6cee71dSXin LI /*
172b6cee71dSXin LI * getopt_internal --
173b6cee71dSXin LI * Parse argc/argv argument vector. Called by user level routines.
174b6cee71dSXin LI * Returns -2 if -- is found (can be long option or end of options marker).
175b6cee71dSXin LI */
176b6cee71dSXin LI static int
getopt_internal(nargc,nargv,options)177b6cee71dSXin LI getopt_internal(nargc, nargv, options)
178b6cee71dSXin LI int nargc;
179b6cee71dSXin LI char **nargv;
180b6cee71dSXin LI const char *options;
181b6cee71dSXin LI {
182b6cee71dSXin LI char *oli; /* option letter list index */
183b6cee71dSXin LI int optchar;
184b6cee71dSXin LI
185b6cee71dSXin LI _DIAGASSERT(nargv != NULL);
186b6cee71dSXin LI _DIAGASSERT(options != NULL);
187b6cee71dSXin LI
188b6cee71dSXin LI optarg = NULL;
189b6cee71dSXin LI
190b6cee71dSXin LI /*
191b6cee71dSXin LI * XXX Some programs (like rsyncd) expect to be able to
192b6cee71dSXin LI * XXX re-initialize optind to 0 and have getopt_long(3)
193b6cee71dSXin LI * XXX properly function again. Work around this braindamage.
194b6cee71dSXin LI */
195b6cee71dSXin LI if (optind == 0)
196b6cee71dSXin LI optind = 1;
197b6cee71dSXin LI
198b6cee71dSXin LI if (optreset)
199b6cee71dSXin LI nonopt_start = nonopt_end = -1;
200b6cee71dSXin LI start:
201b6cee71dSXin LI if (optreset || !*place) { /* update scanning pointer */
202b6cee71dSXin LI optreset = 0;
203b6cee71dSXin LI if (optind >= nargc) { /* end of argument vector */
204b6cee71dSXin LI place = EMSG;
205b6cee71dSXin LI if (nonopt_end != -1) {
206b6cee71dSXin LI /* do permutation, if we have to */
207b6cee71dSXin LI permute_args(nonopt_start, nonopt_end,
208b6cee71dSXin LI optind, nargv);
209b6cee71dSXin LI optind -= nonopt_end - nonopt_start;
210b6cee71dSXin LI }
211b6cee71dSXin LI else if (nonopt_start != -1) {
212b6cee71dSXin LI /*
213b6cee71dSXin LI * If we skipped non-options, set optind
214b6cee71dSXin LI * to the first of them.
215b6cee71dSXin LI */
216b6cee71dSXin LI optind = nonopt_start;
217b6cee71dSXin LI }
218b6cee71dSXin LI nonopt_start = nonopt_end = -1;
219b6cee71dSXin LI return -1;
220b6cee71dSXin LI }
221b6cee71dSXin LI if ((*(place = nargv[optind]) != '-')
222b6cee71dSXin LI || (place[1] == '\0')) { /* found non-option */
223b6cee71dSXin LI place = EMSG;
224b6cee71dSXin LI if (IN_ORDER) {
225b6cee71dSXin LI /*
226b6cee71dSXin LI * GNU extension:
227b6cee71dSXin LI * return non-option as argument to option 1
228b6cee71dSXin LI */
229b6cee71dSXin LI optarg = nargv[optind++];
230b6cee71dSXin LI return INORDER;
231b6cee71dSXin LI }
232b6cee71dSXin LI if (!PERMUTE) {
233b6cee71dSXin LI /*
234b6cee71dSXin LI * if no permutation wanted, stop parsing
235b6cee71dSXin LI * at first non-option
236b6cee71dSXin LI */
237b6cee71dSXin LI return -1;
238b6cee71dSXin LI }
239b6cee71dSXin LI /* do permutation */
240b6cee71dSXin LI if (nonopt_start == -1)
241b6cee71dSXin LI nonopt_start = optind;
242b6cee71dSXin LI else if (nonopt_end != -1) {
243b6cee71dSXin LI permute_args(nonopt_start, nonopt_end,
244b6cee71dSXin LI optind, nargv);
245b6cee71dSXin LI nonopt_start = optind -
246b6cee71dSXin LI (nonopt_end - nonopt_start);
247b6cee71dSXin LI nonopt_end = -1;
248b6cee71dSXin LI }
249b6cee71dSXin LI optind++;
250b6cee71dSXin LI /* process next argument */
251b6cee71dSXin LI goto start;
252b6cee71dSXin LI }
253b6cee71dSXin LI if (nonopt_start != -1 && nonopt_end == -1)
254b6cee71dSXin LI nonopt_end = optind;
255b6cee71dSXin LI if (place[1] && *++place == '-') { /* found "--" */
256b6cee71dSXin LI place++;
257b6cee71dSXin LI return -2;
258b6cee71dSXin LI }
259b6cee71dSXin LI }
260b6cee71dSXin LI if ((optchar = (int)*place++) == (int)':' ||
261b6cee71dSXin LI (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
262b6cee71dSXin LI /* option letter unknown or ':' */
263b6cee71dSXin LI if (!*place)
264b6cee71dSXin LI ++optind;
265b6cee71dSXin LI if (PRINT_ERROR)
266b6cee71dSXin LI warnx(illoptchar, optchar);
267b6cee71dSXin LI optopt = optchar;
268b6cee71dSXin LI return BADCH;
269b6cee71dSXin LI }
270b6cee71dSXin LI if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
271b6cee71dSXin LI /* XXX: what if no long options provided (called by getopt)? */
272b6cee71dSXin LI if (*place)
273b6cee71dSXin LI return -2;
274b6cee71dSXin LI
275b6cee71dSXin LI if (++optind >= nargc) { /* no arg */
276b6cee71dSXin LI place = EMSG;
277b6cee71dSXin LI if (PRINT_ERROR)
278b6cee71dSXin LI warnx(recargchar, optchar);
279b6cee71dSXin LI optopt = optchar;
280b6cee71dSXin LI return BADARG;
281b6cee71dSXin LI } else /* white space */
282b6cee71dSXin LI place = nargv[optind];
283b6cee71dSXin LI /*
284b6cee71dSXin LI * Handle -W arg the same as --arg (which causes getopt to
285b6cee71dSXin LI * stop parsing).
286b6cee71dSXin LI */
287b6cee71dSXin LI return -2;
288b6cee71dSXin LI }
289b6cee71dSXin LI if (*++oli != ':') { /* doesn't take argument */
290b6cee71dSXin LI if (!*place)
291b6cee71dSXin LI ++optind;
292b6cee71dSXin LI } else { /* takes (optional) argument */
293b6cee71dSXin LI optarg = NULL;
294b6cee71dSXin LI if (*place) /* no white space */
295b6cee71dSXin LI optarg = (char *)place;
296b6cee71dSXin LI /* XXX: disable test for :: if PC? (GNU doesn't) */
297b6cee71dSXin LI else if (oli[1] != ':') { /* arg not optional */
298b6cee71dSXin LI if (++optind >= nargc) { /* no arg */
299b6cee71dSXin LI place = EMSG;
300b6cee71dSXin LI if (PRINT_ERROR)
301b6cee71dSXin LI warnx(recargchar, optchar);
302b6cee71dSXin LI optopt = optchar;
303b6cee71dSXin LI return BADARG;
304b6cee71dSXin LI } else
305b6cee71dSXin LI optarg = nargv[optind];
306b6cee71dSXin LI }
307b6cee71dSXin LI place = EMSG;
308b6cee71dSXin LI ++optind;
309b6cee71dSXin LI }
310b6cee71dSXin LI /* dump back option letter */
311b6cee71dSXin LI return optchar;
312b6cee71dSXin LI }
313b6cee71dSXin LI
314b6cee71dSXin LI #ifdef REPLACE_GETOPT
315b6cee71dSXin LI /*
316b6cee71dSXin LI * getopt --
317b6cee71dSXin LI * Parse argc/argv argument vector.
318b6cee71dSXin LI *
319b6cee71dSXin LI * [eventually this will replace the real getopt]
320b6cee71dSXin LI */
321b6cee71dSXin LI int
getopt(nargc,nargv,options)322b6cee71dSXin LI getopt(nargc, nargv, options)
323b6cee71dSXin LI int nargc;
324b6cee71dSXin LI char * const *nargv;
325b6cee71dSXin LI const char *options;
326b6cee71dSXin LI {
327b6cee71dSXin LI int retval;
328b6cee71dSXin LI
329b6cee71dSXin LI _DIAGASSERT(nargv != NULL);
330b6cee71dSXin LI _DIAGASSERT(options != NULL);
331b6cee71dSXin LI
332b6cee71dSXin LI retval = getopt_internal(nargc, (char **)nargv, options);
333b6cee71dSXin LI if (retval == -2) {
334b6cee71dSXin LI ++optind;
335b6cee71dSXin LI /*
336b6cee71dSXin LI * We found an option (--), so if we skipped non-options,
337b6cee71dSXin LI * we have to permute.
338b6cee71dSXin LI */
339b6cee71dSXin LI if (nonopt_end != -1) {
340b6cee71dSXin LI permute_args(nonopt_start, nonopt_end, optind,
341b6cee71dSXin LI (char **)nargv);
342b6cee71dSXin LI optind -= nonopt_end - nonopt_start;
343b6cee71dSXin LI }
344b6cee71dSXin LI nonopt_start = nonopt_end = -1;
345b6cee71dSXin LI retval = -1;
346b6cee71dSXin LI }
347b6cee71dSXin LI return retval;
348b6cee71dSXin LI }
349b6cee71dSXin LI #endif
350b6cee71dSXin LI
351b6cee71dSXin LI /*
352b6cee71dSXin LI * getopt_long --
353b6cee71dSXin LI * Parse argc/argv argument vector.
354b6cee71dSXin LI */
355b6cee71dSXin LI int
getopt_long(nargc,nargv,options,long_options,idx)356b6cee71dSXin LI getopt_long(nargc, nargv, options, long_options, idx)
357b6cee71dSXin LI int nargc;
358b6cee71dSXin LI char * const *nargv;
359b6cee71dSXin LI const char *options;
360b6cee71dSXin LI const struct option *long_options;
361b6cee71dSXin LI int *idx;
362b6cee71dSXin LI {
363b6cee71dSXin LI int retval;
364b6cee71dSXin LI
365b6cee71dSXin LI #define IDENTICAL_INTERPRETATION(_x, _y) \
366b6cee71dSXin LI (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
367b6cee71dSXin LI long_options[(_x)].flag == long_options[(_y)].flag && \
368b6cee71dSXin LI long_options[(_x)].val == long_options[(_y)].val)
369b6cee71dSXin LI
370b6cee71dSXin LI _DIAGASSERT(nargv != NULL);
371b6cee71dSXin LI _DIAGASSERT(options != NULL);
372b6cee71dSXin LI _DIAGASSERT(long_options != NULL);
373b6cee71dSXin LI /* idx may be NULL */
374b6cee71dSXin LI
375b6cee71dSXin LI retval = getopt_internal(nargc, (char **)nargv, options);
376b6cee71dSXin LI if (retval == -2) {
377b6cee71dSXin LI char *current_argv, *has_equal;
378b6cee71dSXin LI size_t current_argv_len;
379b6cee71dSXin LI int i, ambiguous, match;
380b6cee71dSXin LI
381b6cee71dSXin LI current_argv = (char *)place;
382b6cee71dSXin LI match = -1;
383b6cee71dSXin LI ambiguous = 0;
384b6cee71dSXin LI
385b6cee71dSXin LI optind++;
386b6cee71dSXin LI place = EMSG;
387b6cee71dSXin LI
388b6cee71dSXin LI if (*current_argv == '\0') { /* found "--" */
389b6cee71dSXin LI /*
390b6cee71dSXin LI * We found an option (--), so if we skipped
391b6cee71dSXin LI * non-options, we have to permute.
392b6cee71dSXin LI */
393b6cee71dSXin LI if (nonopt_end != -1) {
394b6cee71dSXin LI permute_args(nonopt_start, nonopt_end,
395b6cee71dSXin LI optind, (char **)nargv);
396b6cee71dSXin LI optind -= nonopt_end - nonopt_start;
397b6cee71dSXin LI }
398b6cee71dSXin LI nonopt_start = nonopt_end = -1;
399b6cee71dSXin LI return -1;
400b6cee71dSXin LI }
401b6cee71dSXin LI if ((has_equal = strchr(current_argv, '=')) != NULL) {
402b6cee71dSXin LI /* argument found (--option=arg) */
403b6cee71dSXin LI current_argv_len = has_equal - current_argv;
404b6cee71dSXin LI has_equal++;
405b6cee71dSXin LI } else
406b6cee71dSXin LI current_argv_len = strlen(current_argv);
407b6cee71dSXin LI
408b6cee71dSXin LI for (i = 0; long_options[i].name; i++) {
409b6cee71dSXin LI /* find matching long option */
410b6cee71dSXin LI if (strncmp(current_argv, long_options[i].name,
411b6cee71dSXin LI current_argv_len))
412b6cee71dSXin LI continue;
413b6cee71dSXin LI
414b6cee71dSXin LI if (strlen(long_options[i].name) ==
415b6cee71dSXin LI (unsigned)current_argv_len) {
416b6cee71dSXin LI /* exact match */
417b6cee71dSXin LI match = i;
418b6cee71dSXin LI ambiguous = 0;
419b6cee71dSXin LI break;
420b6cee71dSXin LI }
421b6cee71dSXin LI if (match == -1) /* partial match */
422b6cee71dSXin LI match = i;
423b6cee71dSXin LI else if (!IDENTICAL_INTERPRETATION(i, match))
424b6cee71dSXin LI ambiguous = 1;
425b6cee71dSXin LI }
426b6cee71dSXin LI if (ambiguous) {
427b6cee71dSXin LI /* ambiguous abbreviation */
428b6cee71dSXin LI if (PRINT_ERROR)
429b6cee71dSXin LI warnx(ambig, (int)current_argv_len,
430b6cee71dSXin LI current_argv);
431b6cee71dSXin LI optopt = 0;
432b6cee71dSXin LI return BADCH;
433b6cee71dSXin LI }
434b6cee71dSXin LI if (match != -1) { /* option found */
435b6cee71dSXin LI if (long_options[match].has_arg == no_argument
436b6cee71dSXin LI && has_equal) {
437b6cee71dSXin LI if (PRINT_ERROR)
438b6cee71dSXin LI warnx(noarg, (int)current_argv_len,
439b6cee71dSXin LI current_argv);
440b6cee71dSXin LI /*
441b6cee71dSXin LI * XXX: GNU sets optopt to val regardless of
442b6cee71dSXin LI * flag
443b6cee71dSXin LI */
444b6cee71dSXin LI if (long_options[match].flag == NULL)
445b6cee71dSXin LI optopt = long_options[match].val;
446b6cee71dSXin LI else
447b6cee71dSXin LI optopt = 0;
448b6cee71dSXin LI return BADARG;
449b6cee71dSXin LI }
450b6cee71dSXin LI if (long_options[match].has_arg == required_argument ||
451b6cee71dSXin LI long_options[match].has_arg == optional_argument) {
452b6cee71dSXin LI if (has_equal)
453b6cee71dSXin LI optarg = has_equal;
454b6cee71dSXin LI else if (long_options[match].has_arg ==
455b6cee71dSXin LI required_argument) {
456b6cee71dSXin LI /*
457b6cee71dSXin LI * optional argument doesn't use
458b6cee71dSXin LI * next nargv
459b6cee71dSXin LI */
460b6cee71dSXin LI optarg = nargv[optind++];
461b6cee71dSXin LI }
462b6cee71dSXin LI }
463b6cee71dSXin LI if ((long_options[match].has_arg == required_argument)
464b6cee71dSXin LI && (optarg == NULL)) {
465b6cee71dSXin LI /*
466b6cee71dSXin LI * Missing argument; leading ':'
467b6cee71dSXin LI * indicates no error should be generated
468b6cee71dSXin LI */
469b6cee71dSXin LI if (PRINT_ERROR)
470b6cee71dSXin LI warnx(recargstring, current_argv);
471b6cee71dSXin LI /*
472b6cee71dSXin LI * XXX: GNU sets optopt to val regardless
473b6cee71dSXin LI * of flag
474b6cee71dSXin LI */
475b6cee71dSXin LI if (long_options[match].flag == NULL)
476b6cee71dSXin LI optopt = long_options[match].val;
477b6cee71dSXin LI else
478b6cee71dSXin LI optopt = 0;
479b6cee71dSXin LI --optind;
480b6cee71dSXin LI return BADARG;
481b6cee71dSXin LI }
482b6cee71dSXin LI } else { /* unknown option */
483b6cee71dSXin LI if (PRINT_ERROR)
484b6cee71dSXin LI warnx(illoptstring, current_argv);
485b6cee71dSXin LI optopt = 0;
486b6cee71dSXin LI return BADCH;
487b6cee71dSXin LI }
488b6cee71dSXin LI if (long_options[match].flag) {
489b6cee71dSXin LI *long_options[match].flag = long_options[match].val;
490b6cee71dSXin LI retval = 0;
491b6cee71dSXin LI } else
492b6cee71dSXin LI retval = long_options[match].val;
493b6cee71dSXin LI if (idx)
494b6cee71dSXin LI *idx = match;
495b6cee71dSXin LI }
496b6cee71dSXin LI return retval;
497b6cee71dSXin LI #undef IDENTICAL_INTERPRETATION
498b6cee71dSXin LI }
499