getopt_long.c revision 191736
1139804Simp/*	$NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $	*/
2139013Sdavidxu
3112904Sjeff/*-
4112904Sjeff * Copyright (c) 2000 The NetBSD Foundation, Inc.
5112904Sjeff * All rights reserved.
6112904Sjeff *
7112904Sjeff * This code is derived from software contributed to The NetBSD Foundation
8112904Sjeff * by Dieter Baron and Thomas Klausner.
9112904Sjeff *
10112904Sjeff * Redistribution and use in source and binary forms, with or without
11112904Sjeff * modification, are permitted provided that the following conditions
12112904Sjeff * are met:
13112904Sjeff * 1. Redistributions of source code must retain the above copyright
14112904Sjeff *    notice, this list of conditions and the following disclaimer.
15112904Sjeff * 2. Redistributions in binary form must reproduce the above copyright
16112904Sjeff *    notice, this list of conditions and the following disclaimer in the
17112904Sjeff *    documentation and/or other materials provided with the distribution.
18112904Sjeff *
19112904Sjeff * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20112904Sjeff * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21112904Sjeff * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22112904Sjeff * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23112904Sjeff * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24112904Sjeff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25112904Sjeff * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26112904Sjeff * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27112904Sjeff * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28116182Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29116182Sobrien * POSSIBILITY OF SUCH DAMAGE.
30116182Sobrien */
31162536Sdavidxu
32112904Sjeff#include "file.h"
33112904Sjeff
34131431Smarcel#ifndef	lint
35112904SjeffFILE_RCSID("@(#)$File: getopt_long.c,v 1.5 2009/02/03 20:27:51 christos Exp $")
36115765Sjeff#endif	/* lint */
37112904Sjeff
38112904Sjeff#include <assert.h>
39161678Sdavidxu#ifdef HAVE_ERR_H
40161678Sdavidxu#include <err.h>
41112904Sjeff#else
42112904Sjeff#define warnx printf
43112904Sjeff#endif
44139013Sdavidxu#include <errno.h>
45112904Sjeff#ifdef HAVE_GETOPT_H
46112904Sjeff#include <getopt.h>
47139013Sdavidxu#else
48139013Sdavidxu#include "mygetopt.h"
49139013Sdavidxu#endif
50139013Sdavidxu#include <stdlib.h>
51139013Sdavidxu#include <string.h>
52139013Sdavidxu
53162536Sdavidxu#define REPLACE_GETOPT
54162536Sdavidxu
55162536Sdavidxu#ifndef _DIAGASSERT
56162536Sdavidxu#define _DIAGASSERT assert
57161678Sdavidxu#endif
58161678Sdavidxu
59161678Sdavidxu#ifdef REPLACE_GETOPT
60161678Sdavidxu#ifdef __weak_alias
61161678Sdavidxu__weak_alias(getopt,_getopt)
62161678Sdavidxu#endif
63139013Sdavidxuint	opterr = 1;		/* if error message should be printed */
64161678Sdavidxuint	optind = 1;		/* index into parent argv vector */
65139013Sdavidxuint	optopt = '?';		/* character checked for validity */
66161678Sdavidxuint	optreset;		/* reset getopt */
67139013Sdavidxuchar    *optarg;		/* argument associated with option */
68161678Sdavidxu#elif HAVE_NBTOOL_CONFIG_H && !HAVE_DECL_OPTRESET
69139013Sdavidxustatic int optreset;
70139013Sdavidxu#endif
71139013Sdavidxu
72161678Sdavidxu#ifdef __weak_alias
73139013Sdavidxu__weak_alias(getopt_long,_getopt_long)
74139013Sdavidxu#endif
75161678Sdavidxu
76161678Sdavidxu#define IGNORE_FIRST	(*options == '-' || *options == '+')
77139013Sdavidxu#define PRINT_ERROR	((opterr) && ((*options != ':') \
78139013Sdavidxu				      || (IGNORE_FIRST && options[1] != ':')))
79161678Sdavidxu#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
80161678Sdavidxu#define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
81139013Sdavidxu/* XXX: GNU ignores PC if *options == '-' */
82139013Sdavidxu#define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')
83139013Sdavidxu
84139013Sdavidxu/* return values */
85161678Sdavidxu#define	BADCH	(int)'?'
86161678Sdavidxu#define	BADARG		((IGNORE_FIRST && options[1] == ':') \
87161678Sdavidxu			 || (*options == ':') ? (int)':' : (int)'?')
88161678Sdavidxu#define INORDER (int)1
89161678Sdavidxu
90161678Sdavidxu#define	EMSG	""
91161678Sdavidxu
92161678Sdavidxustatic int getopt_internal(int, char **, const char *);
93161678Sdavidxustatic int gcd(int, int);
94161678Sdavidxustatic void permute_args(int, int, int, char **);
95161678Sdavidxu
96161678Sdavidxustatic const char *place = EMSG; /* option letter processing */
97161678Sdavidxu
98161678Sdavidxu/* XXX: set optreset to 1 rather than these two */
99161678Sdavidxustatic int nonopt_start = -1; /* first non option argument (for permute) */
100161678Sdavidxustatic int nonopt_end = -1;   /* first option after non options (for permute) */
101161678Sdavidxu
102161678Sdavidxu/* Error messages */
103161678Sdavidxustatic const char recargchar[] = "option requires an argument -- %c";
104161678Sdavidxustatic const char recargstring[] = "option requires an argument -- %s";
105161678Sdavidxustatic const char ambig[] = "ambiguous option -- %.*s";
106161678Sdavidxustatic const char noarg[] = "option doesn't take an argument -- %.*s";
107115765Sjeffstatic const char illoptchar[] = "unknown option -- %c";
108161678Sdavidxustatic const char illoptstring[] = "unknown option -- %s";
109161678Sdavidxu
110161678Sdavidxu
111161678Sdavidxu/*
112161678Sdavidxu * Compute the greatest common divisor of a and b.
113161678Sdavidxu */
114161678Sdavidxustatic int
115161678Sdavidxugcd(a, b)
116161678Sdavidxu	int a;
117161678Sdavidxu	int b;
118161678Sdavidxu{
119161678Sdavidxu	int c;
120161678Sdavidxu
121161678Sdavidxu	c = a % b;
122161678Sdavidxu	while (c != 0) {
123161678Sdavidxu		a = b;
124161678Sdavidxu		b = c;
125161678Sdavidxu		c = a % b;
126161678Sdavidxu	}
127161678Sdavidxu
128161678Sdavidxu	return b;
129161678Sdavidxu}
130161678Sdavidxu
131161678Sdavidxu/*
132161678Sdavidxu * Exchange the block from nonopt_start to nonopt_end with the block
133161678Sdavidxu * from nonopt_end to opt_end (keeping the same order of arguments
134161742Sdavidxu * in each block).
135161678Sdavidxu */
136115765Sjeffstatic void
137115765Sjeffpermute_args(panonopt_start, panonopt_end, opt_end, nargv)
138161678Sdavidxu	int panonopt_start;
139161678Sdavidxu	int panonopt_end;
140161678Sdavidxu	int opt_end;
141138224Sdavidxu	char **nargv;
142161678Sdavidxu{
143161678Sdavidxu	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
144161678Sdavidxu	char *swap;
145161678Sdavidxu
146161678Sdavidxu	_DIAGASSERT(nargv != NULL);
147161678Sdavidxu
148161678Sdavidxu	/*
149161678Sdavidxu	 * compute lengths of blocks and number and size of cycles
150161678Sdavidxu	 */
151161678Sdavidxu	nnonopts = panonopt_end - panonopt_start;
152158377Sdavidxu	nopts = opt_end - panonopt_end;
153161678Sdavidxu	ncycle = gcd(nnonopts, nopts);
154161678Sdavidxu	cyclelen = (opt_end - panonopt_start) / ncycle;
155161678Sdavidxu
156138224Sdavidxu	for (i = 0; i < ncycle; i++) {
157115765Sjeff		cstart = panonopt_end+i;
158161678Sdavidxu		pos = cstart;
159161678Sdavidxu		for (j = 0; j < cyclelen; j++) {
160161678Sdavidxu			if (pos >= panonopt_end)
161161678Sdavidxu				pos -= nnonopts;
162161678Sdavidxu			else
163161678Sdavidxu				pos += nopts;
164161678Sdavidxu			swap = nargv[pos];
165161678Sdavidxu			nargv[pos] = nargv[cstart];
166161678Sdavidxu			nargv[cstart] = swap;
167161678Sdavidxu		}
168161678Sdavidxu	}
169161678Sdavidxu}
170161678Sdavidxu
171161678Sdavidxu/*
172161678Sdavidxu * getopt_internal --
173138224Sdavidxu *	Parse argc/argv argument vector.  Called by user level routines.
174138224Sdavidxu *  Returns -2 if -- is found (can be long option or end of options marker).
175138224Sdavidxu */
176115765Sjeffstatic int
177161678Sdavidxugetopt_internal(nargc, nargv, options)
178161678Sdavidxu	int nargc;
179161678Sdavidxu	char **nargv;
180161678Sdavidxu	const char *options;
181161678Sdavidxu{
182161678Sdavidxu	char *oli;				/* option letter list index */
183161678Sdavidxu	int optchar;
184161678Sdavidxu
185161678Sdavidxu	_DIAGASSERT(nargv != NULL);
186138224Sdavidxu	_DIAGASSERT(options != NULL);
187161678Sdavidxu
188115310Sjeff	optarg = NULL;
189161678Sdavidxu
190161678Sdavidxu	/*
191161678Sdavidxu	 * XXX Some programs (like rsyncd) expect to be able to
192161678Sdavidxu	 * XXX re-initialize optind to 0 and have getopt_long(3)
193161678Sdavidxu	 * XXX properly function again.  Work around this braindamage.
194161678Sdavidxu	 */
195161678Sdavidxu	if (optind == 0)
196139013Sdavidxu		optind = 1;
197139013Sdavidxu
198139257Sdavidxu	if (optreset)
199139257Sdavidxu		nonopt_start = nonopt_end = -1;
200139013Sdavidxustart:
201139013Sdavidxu	if (optreset || !*place) {		/* update scanning pointer */
202161678Sdavidxu		optreset = 0;
203139257Sdavidxu		if (optind >= nargc) {          /* end of argument vector */
204139257Sdavidxu			place = EMSG;
205139013Sdavidxu			if (nonopt_end != -1) {
206161678Sdavidxu				/* do permutation, if we have to */
207139013Sdavidxu				permute_args(nonopt_start, nonopt_end,
208139013Sdavidxu				    optind, nargv);
209163697Sdavidxu				optind -= nonopt_end - nonopt_start;
210161678Sdavidxu			}
211161678Sdavidxu			else if (nonopt_start != -1) {
212161678Sdavidxu				/*
213161678Sdavidxu				 * If we skipped non-options, set optind
214161678Sdavidxu				 * to the first of them.
215161678Sdavidxu				 */
216115310Sjeff				optind = nonopt_start;
217161678Sdavidxu			}
218161678Sdavidxu			nonopt_start = nonopt_end = -1;
219161678Sdavidxu			return -1;
220161678Sdavidxu		}
221138224Sdavidxu		if ((*(place = nargv[optind]) != '-')
222161678Sdavidxu		    || (place[1] == '\0')) {    /* found non-option */
223161678Sdavidxu			place = EMSG;
224161678Sdavidxu			if (IN_ORDER) {
225161678Sdavidxu				/*
226161678Sdavidxu				 * GNU extension:
227161678Sdavidxu				 * return non-option as argument to option 1
228161678Sdavidxu				 */
229161678Sdavidxu				optarg = nargv[optind++];
230161678Sdavidxu				return INORDER;
231161678Sdavidxu			}
232161678Sdavidxu			if (!PERMUTE) {
233161678Sdavidxu				/*
234161678Sdavidxu				 * if no permutation wanted, stop parsing
235161678Sdavidxu				 * at first non-option
236143149Sdavidxu				 */
237143149Sdavidxu				return -1;
238143149Sdavidxu			}
239161678Sdavidxu			/* do permutation */
240161678Sdavidxu			if (nonopt_start == -1)
241161678Sdavidxu				nonopt_start = optind;
242161678Sdavidxu			else if (nonopt_end != -1) {
243161678Sdavidxu				permute_args(nonopt_start, nonopt_end,
244161678Sdavidxu				    optind, nargv);
245143149Sdavidxu				nonopt_start = optind -
246143149Sdavidxu				    (nonopt_end - nonopt_start);
247143149Sdavidxu				nonopt_end = -1;
248143149Sdavidxu			}
249143149Sdavidxu			optind++;
250143149Sdavidxu			/* process next argument */
251143149Sdavidxu			goto start;
252143149Sdavidxu		}
253161678Sdavidxu		if (nonopt_start != -1 && nonopt_end == -1)
254139013Sdavidxu			nonopt_end = optind;
255138224Sdavidxu		if (place[1] && *++place == '-') {	/* found "--" */
256161678Sdavidxu			place++;
257161678Sdavidxu			return -2;
258138224Sdavidxu		}
259138224Sdavidxu	}
260139013Sdavidxu	if ((optchar = (int)*place++) == (int)':' ||
261139013Sdavidxu	    (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
262139013Sdavidxu		/* option letter unknown or ':' */
263139013Sdavidxu		if (!*place)
264161678Sdavidxu			++optind;
265161678Sdavidxu		if (PRINT_ERROR)
266139013Sdavidxu			warnx(illoptchar, optchar);
267139013Sdavidxu		optopt = optchar;
268161678Sdavidxu		return BADCH;
269161678Sdavidxu	}
270139013Sdavidxu	if (optchar == 'W' && oli[1] == ';') {		/* -W long-option */
271161678Sdavidxu		/* XXX: what if no long options provided (called by getopt)? */
272139013Sdavidxu		if (*place)
273139013Sdavidxu			return -2;
274161678Sdavidxu
275161678Sdavidxu		if (++optind >= nargc) {	/* no arg */
276161678Sdavidxu			place = EMSG;
277161678Sdavidxu			if (PRINT_ERROR)
278138224Sdavidxu				warnx(recargchar, optchar);
279139257Sdavidxu			optopt = optchar;
280139257Sdavidxu			return BADARG;
281161678Sdavidxu		} else				/* white space */
282139257Sdavidxu			place = nargv[optind];
283161678Sdavidxu		/*
284161678Sdavidxu		 * Handle -W arg the same as --arg (which causes getopt to
285161678Sdavidxu		 * stop parsing).
286161678Sdavidxu		 */
287161678Sdavidxu		return -2;
288161678Sdavidxu	}
289139257Sdavidxu	if (*++oli != ':') {			/* doesn't take argument */
290161678Sdavidxu		if (!*place)
291139257Sdavidxu			++optind;
292139257Sdavidxu	} else {				/* takes (optional) argument */
293161678Sdavidxu		optarg = NULL;
294161678Sdavidxu		if (*place)			/* no white space */
295161678Sdavidxu			optarg = (char *)place;
296139257Sdavidxu		/* XXX: disable test for :: if PC? (GNU doesn't) */
297139257Sdavidxu		else if (oli[1] != ':') {	/* arg not optional */
298139257Sdavidxu			if (++optind >= nargc) {	/* no arg */
299161678Sdavidxu				place = EMSG;
300139257Sdavidxu				if (PRINT_ERROR)
301161678Sdavidxu					warnx(recargchar, optchar);
302161678Sdavidxu				optopt = optchar;
303161678Sdavidxu				return BADARG;
304161678Sdavidxu			} else
305161678Sdavidxu				optarg = nargv[optind];
306161678Sdavidxu		}
307139257Sdavidxu		place = EMSG;
308139257Sdavidxu		++optind;
309161678Sdavidxu	}
310161678Sdavidxu	/* dump back option letter */
311161678Sdavidxu	return optchar;
312139257Sdavidxu}
313139013Sdavidxu
314138224Sdavidxu#ifdef REPLACE_GETOPT
315161678Sdavidxu/*
316161678Sdavidxu * getopt --
317161678Sdavidxu *	Parse argc/argv argument vector.
318161678Sdavidxu *
319138224Sdavidxu * [eventually this will replace the real getopt]
320138224Sdavidxu */
321161678Sdavidxuint
322161678Sdavidxugetopt(nargc, nargv, options)
323161678Sdavidxu	int nargc;
324138225Sdavidxu	char * const *nargv;
325139013Sdavidxu	const char *options;
326138224Sdavidxu{
327161678Sdavidxu	int retval;
328161678Sdavidxu
329161678Sdavidxu	_DIAGASSERT(nargv != NULL);
330161678Sdavidxu	_DIAGASSERT(options != NULL);
331138224Sdavidxu
332138224Sdavidxu	retval = getopt_internal(nargc, (char **)nargv, options);
333139013Sdavidxu	if (retval == -2) {
334139013Sdavidxu		++optind;
335139013Sdavidxu		/*
336139013Sdavidxu		 * We found an option (--), so if we skipped non-options,
337139013Sdavidxu		 * we have to permute.
338115765Sjeff		 */
339161678Sdavidxu		if (nonopt_end != -1) {
340139013Sdavidxu			permute_args(nonopt_start, nonopt_end, optind,
341161678Sdavidxu				     (char **)nargv);
342161678Sdavidxu			optind -= nonopt_end - nonopt_start;
343161678Sdavidxu		}
344158718Sdavidxu		nonopt_start = nonopt_end = -1;
345139013Sdavidxu		retval = -1;
346139013Sdavidxu	}
347139013Sdavidxu	return retval;
348139013Sdavidxu}
349139013Sdavidxu#endif
350139013Sdavidxu
351139013Sdavidxu/*
352139013Sdavidxu * getopt_long --
353161678Sdavidxu *	Parse argc/argv argument vector.
354161678Sdavidxu */
355161678Sdavidxuint
356161678Sdavidxugetopt_long(nargc, nargv, options, long_options, idx)
357158718Sdavidxu	int nargc;
358161678Sdavidxu	char * const *nargv;
359158718Sdavidxu	const char *options;
360139013Sdavidxu	const struct option *long_options;
361139013Sdavidxu	int *idx;
362139013Sdavidxu{
363161678Sdavidxu	int retval;
364161678Sdavidxu
365161678Sdavidxu#define IDENTICAL_INTERPRETATION(_x, _y)				\
366139013Sdavidxu	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&	\
367139013Sdavidxu	 long_options[(_x)].flag == long_options[(_y)].flag &&		\
368139013Sdavidxu	 long_options[(_x)].val == long_options[(_y)].val)
369161678Sdavidxu
370115765Sjeff	_DIAGASSERT(nargv != NULL);
371161678Sdavidxu	_DIAGASSERT(options != NULL);
372115765Sjeff	_DIAGASSERT(long_options != NULL);
373161678Sdavidxu	/* idx may be NULL */
374161678Sdavidxu
375161678Sdavidxu	retval = getopt_internal(nargc, (char **)nargv, options);
376139013Sdavidxu	if (retval == -2) {
377139013Sdavidxu		char *current_argv, *has_equal;
378139013Sdavidxu		size_t current_argv_len;
379139013Sdavidxu		int i, ambiguous, match;
380115765Sjeff
381139013Sdavidxu		current_argv = (char *)place;
382115765Sjeff		match = -1;
383115765Sjeff		ambiguous = 0;
384161678Sdavidxu
385161678Sdavidxu		optind++;
386161678Sdavidxu		place = EMSG;
387161678Sdavidxu
388139257Sdavidxu		if (*current_argv == '\0') {		/* found "--" */
389161678Sdavidxu			/*
390161678Sdavidxu			 * We found an option (--), so if we skipped
391161678Sdavidxu			 * non-options, we have to permute.
392161678Sdavidxu			 */
393161678Sdavidxu			if (nonopt_end != -1) {
394161678Sdavidxu				permute_args(nonopt_start, nonopt_end,
395161678Sdavidxu					     optind, (char **)nargv);
396161678Sdavidxu				optind -= nonopt_end - nonopt_start;
397161678Sdavidxu			}
398161678Sdavidxu			nonopt_start = nonopt_end = -1;
399161678Sdavidxu			return -1;
400161678Sdavidxu		}
401161678Sdavidxu		if ((has_equal = strchr(current_argv, '=')) != NULL) {
402161678Sdavidxu			/* argument found (--option=arg) */
403161678Sdavidxu			current_argv_len = has_equal - current_argv;
404161678Sdavidxu			has_equal++;
405161678Sdavidxu		} else
406161678Sdavidxu			current_argv_len = strlen(current_argv);
407161678Sdavidxu
408161678Sdavidxu		for (i = 0; long_options[i].name; i++) {
409161678Sdavidxu			/* find matching long option */
410161678Sdavidxu			if (strncmp(current_argv, long_options[i].name,
411161678Sdavidxu			    current_argv_len))
412139257Sdavidxu				continue;
413115765Sjeff
414161678Sdavidxu			if (strlen(long_options[i].name) ==
415139257Sdavidxu			    (unsigned)current_argv_len) {
416161678Sdavidxu				/* exact match */
417115765Sjeff				match = i;
418139257Sdavidxu				ambiguous = 0;
419161678Sdavidxu				break;
420161678Sdavidxu			}
421161678Sdavidxu			if (match == -1)		/* partial match */
422139013Sdavidxu				match = i;
423139013Sdavidxu			else if (!IDENTICAL_INTERPRETATION(i, match))
424161678Sdavidxu				ambiguous = 1;
425139257Sdavidxu		}
426139257Sdavidxu		if (ambiguous) {
427139013Sdavidxu			/* ambiguous abbreviation */
428139013Sdavidxu			if (PRINT_ERROR)
429139257Sdavidxu				warnx(ambig, (int)current_argv_len,
430138224Sdavidxu				     current_argv);
431138224Sdavidxu			optopt = 0;
432161678Sdavidxu			return BADCH;
433161678Sdavidxu		}
434161678Sdavidxu		if (match != -1) {			/* option found */
435161678Sdavidxu		        if (long_options[match].has_arg == no_argument
436161678Sdavidxu			    && has_equal) {
437161678Sdavidxu				if (PRINT_ERROR)
438161678Sdavidxu					warnx(noarg, (int)current_argv_len,
439161678Sdavidxu					     current_argv);
440161678Sdavidxu				/*
441161678Sdavidxu				 * XXX: GNU sets optopt to val regardless of
442161678Sdavidxu				 * flag
443161678Sdavidxu				 */
444161678Sdavidxu				if (long_options[match].flag == NULL)
445161678Sdavidxu					optopt = long_options[match].val;
446161678Sdavidxu				else
447161678Sdavidxu					optopt = 0;
448161678Sdavidxu				return BADARG;
449161678Sdavidxu			}
450138224Sdavidxu			if (long_options[match].has_arg == required_argument ||
451161678Sdavidxu			    long_options[match].has_arg == optional_argument) {
452138224Sdavidxu				if (has_equal)
453161678Sdavidxu					optarg = has_equal;
454161678Sdavidxu				else if (long_options[match].has_arg ==
455161678Sdavidxu				    required_argument) {
456161678Sdavidxu					/*
457161678Sdavidxu					 * optional argument doesn't use
458161678Sdavidxu					 * next nargv
459161678Sdavidxu					 */
460161678Sdavidxu					optarg = nargv[optind++];
461139751Sdavidxu				}
462139751Sdavidxu			}
463139751Sdavidxu			if ((long_options[match].has_arg == required_argument)
464138224Sdavidxu			    && (optarg == NULL)) {
465138224Sdavidxu				/*
466161678Sdavidxu				 * Missing argument; leading ':'
467161678Sdavidxu				 * indicates no error should be generated
468161678Sdavidxu				 */
469139013Sdavidxu				if (PRINT_ERROR)
470161678Sdavidxu					warnx(recargstring, current_argv);
471139013Sdavidxu				/*
472161678Sdavidxu				 * XXX: GNU sets optopt to val regardless
473139013Sdavidxu				 * of flag
474139013Sdavidxu				 */
475139013Sdavidxu				if (long_options[match].flag == NULL)
476139013Sdavidxu					optopt = long_options[match].val;
477139013Sdavidxu				else
478139013Sdavidxu					optopt = 0;
479161678Sdavidxu				--optind;
480161678Sdavidxu				return BADARG;
481161678Sdavidxu			}
482161678Sdavidxu		} else {			/* unknown option */
483161678Sdavidxu			if (PRINT_ERROR)
484163677Sdavidxu				warnx(illoptstring, current_argv);
485163677Sdavidxu			optopt = 0;
486161678Sdavidxu			return BADCH;
487161678Sdavidxu		}
488161678Sdavidxu		if (long_options[match].flag) {
489161678Sdavidxu			*long_options[match].flag = long_options[match].val;
490161678Sdavidxu			retval = 0;
491161678Sdavidxu		} else
492161678Sdavidxu			retval = long_options[match].val;
493161678Sdavidxu		if (idx)
494161678Sdavidxu			*idx = match;
495161678Sdavidxu	}
496161678Sdavidxu	return retval;
497161678Sdavidxu#undef IDENTICAL_INTERPRETATION
498161678Sdavidxu}
499161678Sdavidxu