xref: /minix3/lib/libc/stdlib/getopt_long.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: getopt_long.c,v 1.27 2015/09/01 19:39:57 kamil Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras  * Copyright (c) 2000 The NetBSD Foundation, Inc.
52fe8fb19SBen Gras  * All rights reserved.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * This code is derived from software contributed to The NetBSD Foundation
82fe8fb19SBen Gras  * by Dieter Baron and Thomas Klausner.
92fe8fb19SBen Gras  *
102fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
112fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
122fe8fb19SBen Gras  * are met:
132fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
142fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
152fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
162fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
172fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
182fe8fb19SBen Gras  *
192fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
202fe8fb19SBen Gras  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
212fe8fb19SBen Gras  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
222fe8fb19SBen Gras  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
232fe8fb19SBen Gras  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
242fe8fb19SBen Gras  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
252fe8fb19SBen Gras  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
262fe8fb19SBen Gras  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
272fe8fb19SBen Gras  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
282fe8fb19SBen Gras  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
292fe8fb19SBen Gras  * POSSIBILITY OF SUCH DAMAGE.
302fe8fb19SBen Gras  */
312fe8fb19SBen Gras 
322fe8fb19SBen Gras #if HAVE_NBTOOL_CONFIG_H
332fe8fb19SBen Gras #include "nbtool_config.h"
342fe8fb19SBen Gras #endif
352fe8fb19SBen Gras 
362fe8fb19SBen Gras #include <sys/cdefs.h>
37*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: getopt_long.c,v 1.27 2015/09/01 19:39:57 kamil Exp $");
382fe8fb19SBen Gras 
392fe8fb19SBen Gras #include "namespace.h"
402fe8fb19SBen Gras 
412fe8fb19SBen Gras #include <assert.h>
422fe8fb19SBen Gras #include <err.h>
432fe8fb19SBen Gras #include <errno.h>
442fe8fb19SBen Gras #if HAVE_NBTOOL_CONFIG_H
452fe8fb19SBen Gras #include "compat_getopt.h"
462fe8fb19SBen Gras #else
472fe8fb19SBen Gras #include <getopt.h>
482fe8fb19SBen Gras #endif
492fe8fb19SBen Gras #include <stdlib.h>
502fe8fb19SBen Gras #include <string.h>
512fe8fb19SBen Gras 
522fe8fb19SBen Gras #if HAVE_NBTOOL_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
532fe8fb19SBen Gras #define REPLACE_GETOPT
542fe8fb19SBen Gras #endif
552fe8fb19SBen Gras 
562fe8fb19SBen Gras #ifdef REPLACE_GETOPT
572fe8fb19SBen Gras #ifdef __weak_alias
582fe8fb19SBen Gras __weak_alias(getopt,_getopt)
592fe8fb19SBen Gras #endif
602fe8fb19SBen Gras int	opterr = 1;		/* if error message should be printed */
612fe8fb19SBen Gras int	optind = 1;		/* index into parent argv vector */
622fe8fb19SBen Gras int	optopt = '?';		/* character checked for validity */
632fe8fb19SBen Gras int	optreset;		/* reset getopt */
642fe8fb19SBen Gras char    *optarg;		/* argument associated with option */
652fe8fb19SBen Gras #elif HAVE_NBTOOL_CONFIG_H && !HAVE_DECL_OPTRESET
662fe8fb19SBen Gras static int optreset;
672fe8fb19SBen Gras #endif
682fe8fb19SBen Gras 
692fe8fb19SBen Gras #ifdef __weak_alias
702fe8fb19SBen Gras __weak_alias(getopt_long,_getopt_long)
712fe8fb19SBen Gras #endif
722fe8fb19SBen Gras 
732fe8fb19SBen Gras #define IGNORE_FIRST	(*options == '-' || *options == '+')
742fe8fb19SBen Gras #define PRINT_ERROR	((opterr) && ((*options != ':') \
752fe8fb19SBen Gras 				      || (IGNORE_FIRST && options[1] != ':')))
762fe8fb19SBen Gras #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
772fe8fb19SBen Gras #define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
782fe8fb19SBen Gras /* XXX: GNU ignores PC if *options == '-' */
792fe8fb19SBen Gras #define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')
802fe8fb19SBen Gras 
812fe8fb19SBen Gras /* return values */
822fe8fb19SBen Gras #define	BADCH	(int)'?'
832fe8fb19SBen Gras #define	BADARG		((IGNORE_FIRST && options[1] == ':') \
842fe8fb19SBen Gras 			 || (*options == ':') ? (int)':' : (int)'?')
852fe8fb19SBen Gras #define INORDER (int)1
862fe8fb19SBen Gras 
872fe8fb19SBen Gras #define	EMSG	""
882fe8fb19SBen Gras 
892fe8fb19SBen Gras static int getopt_internal(int, char **, const char *);
902fe8fb19SBen Gras static int gcd(int, int);
912fe8fb19SBen Gras static void permute_args(int, int, int, char **);
922fe8fb19SBen Gras 
932fe8fb19SBen Gras static const char *place = EMSG; /* option letter processing */
942fe8fb19SBen Gras 
952fe8fb19SBen Gras /* XXX: set optreset to 1 rather than these two */
962fe8fb19SBen Gras static int nonopt_start = -1; /* first non option argument (for permute) */
972fe8fb19SBen Gras static int nonopt_end = -1;   /* first option after non options (for permute) */
982fe8fb19SBen Gras 
992fe8fb19SBen Gras /* Error messages */
1002fe8fb19SBen Gras static const char recargchar[] = "option requires an argument -- %c";
1012fe8fb19SBen Gras static const char recargstring[] = "option requires an argument -- %s";
1022fe8fb19SBen Gras static const char ambig[] = "ambiguous option -- %.*s";
1032fe8fb19SBen Gras static const char noarg[] = "option doesn't take an argument -- %.*s";
1042fe8fb19SBen Gras static const char illoptchar[] = "unknown option -- %c";
1052fe8fb19SBen Gras static const char illoptstring[] = "unknown option -- %s";
1062fe8fb19SBen Gras 
1072fe8fb19SBen Gras 
1082fe8fb19SBen Gras /*
1092fe8fb19SBen Gras  * Compute the greatest common divisor of a and b.
1102fe8fb19SBen Gras  */
1112fe8fb19SBen Gras static int
gcd(int a,int b)1122fe8fb19SBen Gras gcd(int a, int b)
1132fe8fb19SBen Gras {
1142fe8fb19SBen Gras 	int c;
1152fe8fb19SBen Gras 
1162fe8fb19SBen Gras 	c = a % b;
1172fe8fb19SBen Gras 	while (c != 0) {
1182fe8fb19SBen Gras 		a = b;
1192fe8fb19SBen Gras 		b = c;
1202fe8fb19SBen Gras 		c = a % b;
1212fe8fb19SBen Gras 	}
1222fe8fb19SBen Gras 
1232fe8fb19SBen Gras 	return b;
1242fe8fb19SBen Gras }
1252fe8fb19SBen Gras 
1262fe8fb19SBen Gras /*
1272fe8fb19SBen Gras  * Exchange the block from nonopt_start to nonopt_end with the block
1282fe8fb19SBen Gras  * from nonopt_end to opt_end (keeping the same order of arguments
1292fe8fb19SBen Gras  * in each block).
1302fe8fb19SBen Gras  */
1312fe8fb19SBen Gras static void
permute_args(int panonopt_start,int panonopt_end,int opt_end,char ** nargv)1322fe8fb19SBen Gras permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv)
1332fe8fb19SBen Gras {
1342fe8fb19SBen Gras 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
1352fe8fb19SBen Gras 	char *swap;
1362fe8fb19SBen Gras 
1372fe8fb19SBen Gras 	_DIAGASSERT(nargv != NULL);
1382fe8fb19SBen Gras 
1392fe8fb19SBen Gras 	/*
1402fe8fb19SBen Gras 	 * compute lengths of blocks and number and size of cycles
1412fe8fb19SBen Gras 	 */
1422fe8fb19SBen Gras 	nnonopts = panonopt_end - panonopt_start;
1432fe8fb19SBen Gras 	nopts = opt_end - panonopt_end;
1442fe8fb19SBen Gras 	ncycle = gcd(nnonopts, nopts);
1452fe8fb19SBen Gras 	cyclelen = (opt_end - panonopt_start) / ncycle;
1462fe8fb19SBen Gras 
1472fe8fb19SBen Gras 	for (i = 0; i < ncycle; i++) {
1482fe8fb19SBen Gras 		cstart = panonopt_end+i;
1492fe8fb19SBen Gras 		pos = cstart;
1502fe8fb19SBen Gras 		for (j = 0; j < cyclelen; j++) {
1512fe8fb19SBen Gras 			if (pos >= panonopt_end)
1522fe8fb19SBen Gras 				pos -= nnonopts;
1532fe8fb19SBen Gras 			else
1542fe8fb19SBen Gras 				pos += nopts;
1552fe8fb19SBen Gras 			swap = nargv[pos];
1562fe8fb19SBen Gras 			nargv[pos] = nargv[cstart];
1572fe8fb19SBen Gras 			nargv[cstart] = swap;
1582fe8fb19SBen Gras 		}
1592fe8fb19SBen Gras 	}
1602fe8fb19SBen Gras }
1612fe8fb19SBen Gras 
1622fe8fb19SBen Gras /*
1632fe8fb19SBen Gras  * getopt_internal --
1642fe8fb19SBen Gras  *	Parse argc/argv argument vector.  Called by user level routines.
1652fe8fb19SBen Gras  *  Returns -2 if -- is found (can be long option or end of options marker).
1662fe8fb19SBen Gras  */
1672fe8fb19SBen Gras static int
getopt_internal(int nargc,char ** nargv,const char * options)1682fe8fb19SBen Gras getopt_internal(int nargc, char **nargv, const char *options)
1692fe8fb19SBen Gras {
1702fe8fb19SBen Gras 	char *oli;				/* option letter list index */
1712fe8fb19SBen Gras 	int optchar;
1722fe8fb19SBen Gras 
1732fe8fb19SBen Gras 	_DIAGASSERT(nargv != NULL);
1742fe8fb19SBen Gras 	_DIAGASSERT(options != NULL);
1752fe8fb19SBen Gras 
1762fe8fb19SBen Gras 	optarg = NULL;
1772fe8fb19SBen Gras 
1782fe8fb19SBen Gras 	/*
1792fe8fb19SBen Gras 	 * XXX Some programs (like rsyncd) expect to be able to
1802fe8fb19SBen Gras 	 * XXX re-initialize optind to 0 and have getopt_long(3)
1812fe8fb19SBen Gras 	 * XXX properly function again.  Work around this braindamage.
1822fe8fb19SBen Gras 	 */
1832fe8fb19SBen Gras 	if (optind == 0)
1842fe8fb19SBen Gras 		optind = 1;
1852fe8fb19SBen Gras 
1862fe8fb19SBen Gras 	if (optreset)
1872fe8fb19SBen Gras 		nonopt_start = nonopt_end = -1;
1882fe8fb19SBen Gras start:
1892fe8fb19SBen Gras 	if (optreset || !*place) {		/* update scanning pointer */
1902fe8fb19SBen Gras 		optreset = 0;
1912fe8fb19SBen Gras 		if (optind >= nargc) {          /* end of argument vector */
1922fe8fb19SBen Gras 			place = EMSG;
1932fe8fb19SBen Gras 			if (nonopt_end != -1) {
1942fe8fb19SBen Gras 				/* do permutation, if we have to */
1952fe8fb19SBen Gras 				permute_args(nonopt_start, nonopt_end,
1962fe8fb19SBen Gras 				    optind, nargv);
1972fe8fb19SBen Gras 				optind -= nonopt_end - nonopt_start;
1982fe8fb19SBen Gras 			}
1992fe8fb19SBen Gras 			else if (nonopt_start != -1) {
2002fe8fb19SBen Gras 				/*
2012fe8fb19SBen Gras 				 * If we skipped non-options, set optind
2022fe8fb19SBen Gras 				 * to the first of them.
2032fe8fb19SBen Gras 				 */
2042fe8fb19SBen Gras 				optind = nonopt_start;
2052fe8fb19SBen Gras 			}
2062fe8fb19SBen Gras 			nonopt_start = nonopt_end = -1;
2072fe8fb19SBen Gras 			return -1;
2082fe8fb19SBen Gras 		}
2092fe8fb19SBen Gras 		if ((*(place = nargv[optind]) != '-')
2102fe8fb19SBen Gras 		    || (place[1] == '\0')) {    /* found non-option */
2112fe8fb19SBen Gras 			place = EMSG;
2122fe8fb19SBen Gras 			if (IN_ORDER) {
2132fe8fb19SBen Gras 				/*
2142fe8fb19SBen Gras 				 * GNU extension:
2152fe8fb19SBen Gras 				 * return non-option as argument to option 1
2162fe8fb19SBen Gras 				 */
2172fe8fb19SBen Gras 				optarg = nargv[optind++];
2182fe8fb19SBen Gras 				return INORDER;
2192fe8fb19SBen Gras 			}
2202fe8fb19SBen Gras 			if (!PERMUTE) {
2212fe8fb19SBen Gras 				/*
2222fe8fb19SBen Gras 				 * if no permutation wanted, stop parsing
2232fe8fb19SBen Gras 				 * at first non-option
2242fe8fb19SBen Gras 				 */
2252fe8fb19SBen Gras 				return -1;
2262fe8fb19SBen Gras 			}
2272fe8fb19SBen Gras 			/* do permutation */
2282fe8fb19SBen Gras 			if (nonopt_start == -1)
2292fe8fb19SBen Gras 				nonopt_start = optind;
2302fe8fb19SBen Gras 			else if (nonopt_end != -1) {
2312fe8fb19SBen Gras 				permute_args(nonopt_start, nonopt_end,
2322fe8fb19SBen Gras 				    optind, nargv);
2332fe8fb19SBen Gras 				nonopt_start = optind -
2342fe8fb19SBen Gras 				    (nonopt_end - nonopt_start);
2352fe8fb19SBen Gras 				nonopt_end = -1;
2362fe8fb19SBen Gras 			}
2372fe8fb19SBen Gras 			optind++;
2382fe8fb19SBen Gras 			/* process next argument */
2392fe8fb19SBen Gras 			goto start;
2402fe8fb19SBen Gras 		}
2412fe8fb19SBen Gras 		if (nonopt_start != -1 && nonopt_end == -1)
2422fe8fb19SBen Gras 			nonopt_end = optind;
2432fe8fb19SBen Gras 		if (place[1] && *++place == '-') {	/* found "--" */
2442fe8fb19SBen Gras 			place++;
2452fe8fb19SBen Gras 			return -2;
2462fe8fb19SBen Gras 		}
2472fe8fb19SBen Gras 	}
2482fe8fb19SBen Gras 	if ((optchar = (int)*place++) == (int)':' ||
2492fe8fb19SBen Gras 	    (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
2502fe8fb19SBen Gras 		/* option letter unknown or ':' */
2512fe8fb19SBen Gras 		if (!*place)
2522fe8fb19SBen Gras 			++optind;
2532fe8fb19SBen Gras 		if (PRINT_ERROR)
2542fe8fb19SBen Gras 			warnx(illoptchar, optchar);
2552fe8fb19SBen Gras 		optopt = optchar;
2562fe8fb19SBen Gras 		return BADCH;
2572fe8fb19SBen Gras 	}
2582fe8fb19SBen Gras 	if (optchar == 'W' && oli[1] == ';') {		/* -W long-option */
2592fe8fb19SBen Gras 		/* XXX: what if no long options provided (called by getopt)? */
2602fe8fb19SBen Gras 		if (*place)
2612fe8fb19SBen Gras 			return -2;
2622fe8fb19SBen Gras 
2632fe8fb19SBen Gras 		if (++optind >= nargc) {	/* no arg */
2642fe8fb19SBen Gras 			place = EMSG;
2652fe8fb19SBen Gras 			if (PRINT_ERROR)
2662fe8fb19SBen Gras 				warnx(recargchar, optchar);
2672fe8fb19SBen Gras 			optopt = optchar;
2682fe8fb19SBen Gras 			return BADARG;
2692fe8fb19SBen Gras 		} else				/* white space */
2702fe8fb19SBen Gras 			place = nargv[optind];
2712fe8fb19SBen Gras 		/*
2722fe8fb19SBen Gras 		 * Handle -W arg the same as --arg (which causes getopt to
2732fe8fb19SBen Gras 		 * stop parsing).
2742fe8fb19SBen Gras 		 */
2752fe8fb19SBen Gras 		return -2;
2762fe8fb19SBen Gras 	}
2772fe8fb19SBen Gras 	if (*++oli != ':') {			/* doesn't take argument */
2782fe8fb19SBen Gras 		if (!*place)
2792fe8fb19SBen Gras 			++optind;
2802fe8fb19SBen Gras 	} else {				/* takes (optional) argument */
2812fe8fb19SBen Gras 		optarg = NULL;
2822fe8fb19SBen Gras 		if (*place)			/* no white space */
2832fe8fb19SBen Gras 			optarg = __UNCONST(place);
2842fe8fb19SBen Gras 		/* XXX: disable test for :: if PC? (GNU doesn't) */
2852fe8fb19SBen Gras 		else if (oli[1] != ':') {	/* arg not optional */
2862fe8fb19SBen Gras 			if (++optind >= nargc) {	/* no arg */
2872fe8fb19SBen Gras 				place = EMSG;
2882fe8fb19SBen Gras 				if (PRINT_ERROR)
2892fe8fb19SBen Gras 					warnx(recargchar, optchar);
2902fe8fb19SBen Gras 				optopt = optchar;
2912fe8fb19SBen Gras 				return BADARG;
2922fe8fb19SBen Gras 			} else
2932fe8fb19SBen Gras 				optarg = nargv[optind];
2942fe8fb19SBen Gras 		}
2952fe8fb19SBen Gras 		place = EMSG;
2962fe8fb19SBen Gras 		++optind;
2972fe8fb19SBen Gras 	}
2982fe8fb19SBen Gras 	/* dump back option letter */
2992fe8fb19SBen Gras 	return optchar;
3002fe8fb19SBen Gras }
3012fe8fb19SBen Gras 
3022fe8fb19SBen Gras #ifdef REPLACE_GETOPT
3032fe8fb19SBen Gras /*
3042fe8fb19SBen Gras  * getopt --
3052fe8fb19SBen Gras  *	Parse argc/argv argument vector.
3062fe8fb19SBen Gras  *
3072fe8fb19SBen Gras  * [eventually this will replace the real getopt]
3082fe8fb19SBen Gras  */
3092fe8fb19SBen Gras int
getopt(int nargc,char * const * nargv,const char * options)310*0a6a1f1dSLionel Sambuc getopt(int nargc, char * const *nargv, const char *options)
3112fe8fb19SBen Gras {
3122fe8fb19SBen Gras 	int retval;
3132fe8fb19SBen Gras 
3142fe8fb19SBen Gras 	_DIAGASSERT(nargv != NULL);
3152fe8fb19SBen Gras 	_DIAGASSERT(options != NULL);
3162fe8fb19SBen Gras 
3172fe8fb19SBen Gras 	retval = getopt_internal(nargc, __UNCONST(nargv), options);
3182fe8fb19SBen Gras 	if (retval == -2) {
3192fe8fb19SBen Gras 		++optind;
3202fe8fb19SBen Gras 		/*
3212fe8fb19SBen Gras 		 * We found an option (--), so if we skipped non-options,
3222fe8fb19SBen Gras 		 * we have to permute.
3232fe8fb19SBen Gras 		 */
3242fe8fb19SBen Gras 		if (nonopt_end != -1) {
3252fe8fb19SBen Gras 			permute_args(nonopt_start, nonopt_end, optind,
326*0a6a1f1dSLionel Sambuc 				       __UNCONST(nargv));
3272fe8fb19SBen Gras 			optind -= nonopt_end - nonopt_start;
3282fe8fb19SBen Gras 		}
3292fe8fb19SBen Gras 		nonopt_start = nonopt_end = -1;
3302fe8fb19SBen Gras 		retval = -1;
3312fe8fb19SBen Gras 	}
3322fe8fb19SBen Gras 	return retval;
3332fe8fb19SBen Gras }
3342fe8fb19SBen Gras #endif
3352fe8fb19SBen Gras 
3362fe8fb19SBen Gras /*
3372fe8fb19SBen Gras  * getopt_long --
3382fe8fb19SBen Gras  *	Parse argc/argv argument vector.
3392fe8fb19SBen Gras  */
3402fe8fb19SBen Gras int
getopt_long(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx)3412fe8fb19SBen Gras getopt_long(int nargc, char * const *nargv, const char *options,
3422fe8fb19SBen Gras     const struct option *long_options, int *idx)
3432fe8fb19SBen Gras {
3442fe8fb19SBen Gras 	int retval;
3452fe8fb19SBen Gras 
3462fe8fb19SBen Gras #define IDENTICAL_INTERPRETATION(_x, _y)				\
3472fe8fb19SBen Gras 	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&	\
3482fe8fb19SBen Gras 	 long_options[(_x)].flag == long_options[(_y)].flag &&		\
3492fe8fb19SBen Gras 	 long_options[(_x)].val == long_options[(_y)].val)
3502fe8fb19SBen Gras 
3512fe8fb19SBen Gras 	_DIAGASSERT(nargv != NULL);
3522fe8fb19SBen Gras 	_DIAGASSERT(options != NULL);
3532fe8fb19SBen Gras 	_DIAGASSERT(long_options != NULL);
3542fe8fb19SBen Gras 	/* idx may be NULL */
3552fe8fb19SBen Gras 
3562fe8fb19SBen Gras 	retval = getopt_internal(nargc, __UNCONST(nargv), options);
3572fe8fb19SBen Gras 	if (retval == -2) {
3582fe8fb19SBen Gras 		char *current_argv, *has_equal;
3592fe8fb19SBen Gras 		size_t current_argv_len;
3602fe8fb19SBen Gras 		int i, ambiguous, match;
3612fe8fb19SBen Gras 
3622fe8fb19SBen Gras 		current_argv = __UNCONST(place);
3632fe8fb19SBen Gras 		match = -1;
3642fe8fb19SBen Gras 		ambiguous = 0;
3652fe8fb19SBen Gras 
3662fe8fb19SBen Gras 		optind++;
3672fe8fb19SBen Gras 		place = EMSG;
3682fe8fb19SBen Gras 
3692fe8fb19SBen Gras 		if (*current_argv == '\0') {		/* found "--" */
3702fe8fb19SBen Gras 			/*
3712fe8fb19SBen Gras 			 * We found an option (--), so if we skipped
3722fe8fb19SBen Gras 			 * non-options, we have to permute.
3732fe8fb19SBen Gras 			 */
3742fe8fb19SBen Gras 			if (nonopt_end != -1) {
3752fe8fb19SBen Gras 				permute_args(nonopt_start, nonopt_end,
3762fe8fb19SBen Gras 				    optind, __UNCONST(nargv));
3772fe8fb19SBen Gras 				optind -= nonopt_end - nonopt_start;
3782fe8fb19SBen Gras 			}
3792fe8fb19SBen Gras 			nonopt_start = nonopt_end = -1;
3802fe8fb19SBen Gras 			return -1;
3812fe8fb19SBen Gras 		}
3822fe8fb19SBen Gras 		if ((has_equal = strchr(current_argv, '=')) != NULL) {
3832fe8fb19SBen Gras 			/* argument found (--option=arg) */
3842fe8fb19SBen Gras 			current_argv_len = has_equal - current_argv;
3852fe8fb19SBen Gras 			has_equal++;
3862fe8fb19SBen Gras 		} else
3872fe8fb19SBen Gras 			current_argv_len = strlen(current_argv);
3882fe8fb19SBen Gras 
3892fe8fb19SBen Gras 		for (i = 0; long_options[i].name; i++) {
3902fe8fb19SBen Gras 			/* find matching long option */
3912fe8fb19SBen Gras 			if (strncmp(current_argv, long_options[i].name,
3922fe8fb19SBen Gras 			    current_argv_len))
3932fe8fb19SBen Gras 				continue;
3942fe8fb19SBen Gras 
3952fe8fb19SBen Gras 			if (strlen(long_options[i].name) ==
3962fe8fb19SBen Gras 			    (unsigned)current_argv_len) {
3972fe8fb19SBen Gras 				/* exact match */
3982fe8fb19SBen Gras 				match = i;
3992fe8fb19SBen Gras 				ambiguous = 0;
4002fe8fb19SBen Gras 				break;
4012fe8fb19SBen Gras 			}
4022fe8fb19SBen Gras 			if (match == -1)		/* partial match */
4032fe8fb19SBen Gras 				match = i;
4042fe8fb19SBen Gras 			else if (!IDENTICAL_INTERPRETATION(i, match))
4052fe8fb19SBen Gras 				ambiguous = 1;
4062fe8fb19SBen Gras 		}
4072fe8fb19SBen Gras 		if (ambiguous) {
4082fe8fb19SBen Gras 			/* ambiguous abbreviation */
4092fe8fb19SBen Gras 			if (PRINT_ERROR)
4102fe8fb19SBen Gras 				warnx(ambig, (int)current_argv_len,
4112fe8fb19SBen Gras 				     current_argv);
4122fe8fb19SBen Gras 			optopt = 0;
4132fe8fb19SBen Gras 			return BADCH;
4142fe8fb19SBen Gras 		}
4152fe8fb19SBen Gras 		if (match != -1) {			/* option found */
4162fe8fb19SBen Gras 		        if (long_options[match].has_arg == no_argument
4172fe8fb19SBen Gras 			    && has_equal) {
4182fe8fb19SBen Gras 				if (PRINT_ERROR)
4192fe8fb19SBen Gras 					warnx(noarg, (int)current_argv_len,
4202fe8fb19SBen Gras 					     current_argv);
4212fe8fb19SBen Gras 				/*
4222fe8fb19SBen Gras 				 * XXX: GNU sets optopt to val regardless of
4232fe8fb19SBen Gras 				 * flag
4242fe8fb19SBen Gras 				 */
4252fe8fb19SBen Gras 				if (long_options[match].flag == NULL)
4262fe8fb19SBen Gras 					optopt = long_options[match].val;
4272fe8fb19SBen Gras 				else
4282fe8fb19SBen Gras 					optopt = 0;
4292fe8fb19SBen Gras 				return BADARG;
4302fe8fb19SBen Gras 			}
4312fe8fb19SBen Gras 			if (long_options[match].has_arg == required_argument ||
4322fe8fb19SBen Gras 			    long_options[match].has_arg == optional_argument) {
4332fe8fb19SBen Gras 				if (has_equal)
4342fe8fb19SBen Gras 					optarg = has_equal;
4352fe8fb19SBen Gras 				else if (long_options[match].has_arg ==
4362fe8fb19SBen Gras 				    required_argument) {
4372fe8fb19SBen Gras 					/*
4382fe8fb19SBen Gras 					 * optional argument doesn't use
4392fe8fb19SBen Gras 					 * next nargv
4402fe8fb19SBen Gras 					 */
4412fe8fb19SBen Gras 					optarg = nargv[optind++];
4422fe8fb19SBen Gras 				}
4432fe8fb19SBen Gras 			}
4442fe8fb19SBen Gras 			if ((long_options[match].has_arg == required_argument)
4452fe8fb19SBen Gras 			    && (optarg == NULL)) {
4462fe8fb19SBen Gras 				/*
4472fe8fb19SBen Gras 				 * Missing argument; leading ':'
4482fe8fb19SBen Gras 				 * indicates no error should be generated
4492fe8fb19SBen Gras 				 */
4502fe8fb19SBen Gras 				if (PRINT_ERROR)
4512fe8fb19SBen Gras 					warnx(recargstring, current_argv);
4522fe8fb19SBen Gras 				/*
4532fe8fb19SBen Gras 				 * XXX: GNU sets optopt to val regardless
4542fe8fb19SBen Gras 				 * of flag
4552fe8fb19SBen Gras 				 */
4562fe8fb19SBen Gras 				if (long_options[match].flag == NULL)
4572fe8fb19SBen Gras 					optopt = long_options[match].val;
4582fe8fb19SBen Gras 				else
4592fe8fb19SBen Gras 					optopt = 0;
4602fe8fb19SBen Gras 				--optind;
4612fe8fb19SBen Gras 				return BADARG;
4622fe8fb19SBen Gras 			}
4632fe8fb19SBen Gras 		} else {			/* unknown option */
4642fe8fb19SBen Gras 			if (PRINT_ERROR)
4652fe8fb19SBen Gras 				warnx(illoptstring, current_argv);
4662fe8fb19SBen Gras 			optopt = 0;
4672fe8fb19SBen Gras 			return BADCH;
4682fe8fb19SBen Gras 		}
4692fe8fb19SBen Gras 		if (long_options[match].flag) {
4702fe8fb19SBen Gras 			*long_options[match].flag = long_options[match].val;
4712fe8fb19SBen Gras 			retval = 0;
4722fe8fb19SBen Gras 		} else
4732fe8fb19SBen Gras 			retval = long_options[match].val;
4742fe8fb19SBen Gras 		if (idx)
4752fe8fb19SBen Gras 			*idx = match;
4762fe8fb19SBen Gras 	}
4772fe8fb19SBen Gras 	return retval;
4782fe8fb19SBen Gras #undef IDENTICAL_INTERPRETATION
4792fe8fb19SBen Gras }
480