xref: /dpdk/lib/eal/windows/getopt.c (revision a06fb0fae6ab6a79fa3e8288dbb0c5166be843c2)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: ISC AND BSD-2-Clause
299a2dd95SBruce Richardson  * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
399a2dd95SBruce Richardson  *
499a2dd95SBruce Richardson  * Sponsored in part by the Defense Advanced Research Projects
599a2dd95SBruce Richardson  * Agency (DARPA) and Air Force Research Laboratory, Air Force
699a2dd95SBruce Richardson  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
799a2dd95SBruce Richardson  */
899a2dd95SBruce Richardson /*
999a2dd95SBruce Richardson  * Copyright (c) 2000 The NetBSD Foundation, Inc.
1099a2dd95SBruce Richardson  * All rights reserved.
1199a2dd95SBruce Richardson  *
1299a2dd95SBruce Richardson  * This code is derived from software contributed to The NetBSD Foundation
1399a2dd95SBruce Richardson  * by Dieter Baron and Thomas Klausner.
1499a2dd95SBruce Richardson  */
1599a2dd95SBruce Richardson 
1699a2dd95SBruce Richardson #include <getopt.h>
1799a2dd95SBruce Richardson 
1899a2dd95SBruce Richardson #ifdef NEED_USUAL_GETOPT
1999a2dd95SBruce Richardson 
2099a2dd95SBruce Richardson #include <string.h>
2199a2dd95SBruce Richardson #include <stdlib.h>
2299a2dd95SBruce Richardson 
23*a06fb0faSStephen Hemminger char    *optarg;		/* argument associated with option */
2499a2dd95SBruce Richardson int	opterr = 1;		/* if error message should be printed */
2599a2dd95SBruce Richardson int	optind = 1;		/* index into parent argv vector */
2699a2dd95SBruce Richardson int	optopt = '?';		/* character checked for validity */
2799a2dd95SBruce Richardson 
2899a2dd95SBruce Richardson static void pass(const char *a) {(void) a; }
2999a2dd95SBruce Richardson #define warnx(a, ...) pass(a)
3099a2dd95SBruce Richardson 
3199a2dd95SBruce Richardson #define PRINT_ERROR	((opterr) && (*options != ':'))
3299a2dd95SBruce Richardson 
3399a2dd95SBruce Richardson #define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
3499a2dd95SBruce Richardson #define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
3599a2dd95SBruce Richardson #define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */
3699a2dd95SBruce Richardson 
3799a2dd95SBruce Richardson /* return values */
3899a2dd95SBruce Richardson #define	BADCH		((int)'?')
3999a2dd95SBruce Richardson #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
4099a2dd95SBruce Richardson #define	INORDER		1
4199a2dd95SBruce Richardson 
42*a06fb0faSStephen Hemminger static char EMSG[] = "";
4399a2dd95SBruce Richardson 
44*a06fb0faSStephen Hemminger static char *place = EMSG; /* option letter processing */
4599a2dd95SBruce Richardson 
4699a2dd95SBruce Richardson /* XXX: set optreset to 1 rather than these two */
4799a2dd95SBruce Richardson static int nonopt_start = -1; /* first non option argument (for permute) */
4899a2dd95SBruce Richardson static int nonopt_end = -1;   /* first option after non options (for permute) */
4999a2dd95SBruce Richardson 
5099a2dd95SBruce Richardson /* Error messages */
5199a2dd95SBruce Richardson static const char recargchar[] = "option requires an argument -- %c";
5299a2dd95SBruce Richardson static const char recargstring[] = "option requires an argument -- %s";
5399a2dd95SBruce Richardson static const char ambig[] = "ambiguous option -- %.*s";
5499a2dd95SBruce Richardson static const char noarg[] = "option doesn't take an argument -- %.*s";
5599a2dd95SBruce Richardson static const char illoptchar[] = "unknown option -- %c";
5699a2dd95SBruce Richardson static const char illoptstring[] = "unknown option -- %s";
5799a2dd95SBruce Richardson 
5899a2dd95SBruce Richardson /*
5999a2dd95SBruce Richardson  * Compute the greatest common divisor of a and b.
6099a2dd95SBruce Richardson  */
6199a2dd95SBruce Richardson static int
6299a2dd95SBruce Richardson gcd(int a, int b)
6399a2dd95SBruce Richardson {
6499a2dd95SBruce Richardson 	int c;
6599a2dd95SBruce Richardson 
6699a2dd95SBruce Richardson 	c = a % b;
6799a2dd95SBruce Richardson 	while (c != 0) {
6899a2dd95SBruce Richardson 		a = b;
6999a2dd95SBruce Richardson 		b = c;
7099a2dd95SBruce Richardson 		c = a % b;
7199a2dd95SBruce Richardson 	}
7299a2dd95SBruce Richardson 
7399a2dd95SBruce Richardson 	return (b);
7499a2dd95SBruce Richardson }
7599a2dd95SBruce Richardson 
7699a2dd95SBruce Richardson /*
7799a2dd95SBruce Richardson  * Exchange the block from nonopt_start to nonopt_end with the block
7899a2dd95SBruce Richardson  * from nonopt_end to opt_end (keeping the same order of arguments
7999a2dd95SBruce Richardson  * in each block).
8099a2dd95SBruce Richardson  */
8199a2dd95SBruce Richardson static void
8299a2dd95SBruce Richardson permute_args(int panonopt_start, int panonopt_end, int opt_end,
83*a06fb0faSStephen Hemminger 	char * const *nargv)
8499a2dd95SBruce Richardson {
8599a2dd95SBruce Richardson 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
8699a2dd95SBruce Richardson 	char *swap;
8799a2dd95SBruce Richardson 
8899a2dd95SBruce Richardson 	/*
8999a2dd95SBruce Richardson 	 * compute lengths of blocks and number and size of cycles
9099a2dd95SBruce Richardson 	 */
9199a2dd95SBruce Richardson 	nnonopts = panonopt_end - panonopt_start;
9299a2dd95SBruce Richardson 	nopts = opt_end - panonopt_end;
9399a2dd95SBruce Richardson 	ncycle = gcd(nnonopts, nopts);
9499a2dd95SBruce Richardson 	cyclelen = (opt_end - panonopt_start) / ncycle;
9599a2dd95SBruce Richardson 
9699a2dd95SBruce Richardson 	for (i = 0; i < ncycle; i++) {
9799a2dd95SBruce Richardson 		cstart = panonopt_end+i;
9899a2dd95SBruce Richardson 		pos = cstart;
9999a2dd95SBruce Richardson 		for (j = 0; j < cyclelen; j++) {
10099a2dd95SBruce Richardson 			if (pos >= panonopt_end)
10199a2dd95SBruce Richardson 				pos -= nnonopts;
10299a2dd95SBruce Richardson 			else
10399a2dd95SBruce Richardson 				pos += nopts;
104*a06fb0faSStephen Hemminger 
10599a2dd95SBruce Richardson 			swap = nargv[pos];
10699a2dd95SBruce Richardson 			/* LINTED const cast */
107*a06fb0faSStephen Hemminger 			((char **)(uintptr_t)nargv)[pos] = nargv[cstart];
10899a2dd95SBruce Richardson 			/* LINTED const cast */
109*a06fb0faSStephen Hemminger 			((char **)(uintptr_t)nargv)[cstart] = swap;
11099a2dd95SBruce Richardson 		}
11199a2dd95SBruce Richardson 	}
11299a2dd95SBruce Richardson }
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson /*
11599a2dd95SBruce Richardson  * parse_long_options --
11699a2dd95SBruce Richardson  *	Parse long options in argc/argv argument vector.
11799a2dd95SBruce Richardson  * Returns -1 if short_too is set and the option does not match long_options.
11899a2dd95SBruce Richardson  */
11999a2dd95SBruce Richardson static int
120*a06fb0faSStephen Hemminger parse_long_options(char * const *nargv, const char *options,
12199a2dd95SBruce Richardson 	const struct option *long_options, int *idx, int short_too)
12299a2dd95SBruce Richardson {
12399a2dd95SBruce Richardson 	const char *current_argv;
12499a2dd95SBruce Richardson 	char *has_equal;
12599a2dd95SBruce Richardson 	size_t current_argv_len;
12699a2dd95SBruce Richardson 	int i, match;
12799a2dd95SBruce Richardson 
12899a2dd95SBruce Richardson 	current_argv = place;
12999a2dd95SBruce Richardson 	match = -1;
13099a2dd95SBruce Richardson 
13199a2dd95SBruce Richardson 	optind++;
13299a2dd95SBruce Richardson 
13399a2dd95SBruce Richardson 	has_equal = strchr(current_argv, '=');
13499a2dd95SBruce Richardson 	if (has_equal != NULL) {
13599a2dd95SBruce Richardson 		/* argument found (--option=arg) */
13699a2dd95SBruce Richardson 		current_argv_len = has_equal - current_argv;
13799a2dd95SBruce Richardson 		has_equal++;
13899a2dd95SBruce Richardson 	} else
13999a2dd95SBruce Richardson 		current_argv_len = strlen(current_argv);
14099a2dd95SBruce Richardson 
14199a2dd95SBruce Richardson 	for (i = 0; long_options[i].name; i++) {
14299a2dd95SBruce Richardson 		/* find matching long option */
14399a2dd95SBruce Richardson 		if (strncmp(current_argv, long_options[i].name,
14499a2dd95SBruce Richardson 		    current_argv_len))
14599a2dd95SBruce Richardson 			continue;
14699a2dd95SBruce Richardson 
14799a2dd95SBruce Richardson 		if (strlen(long_options[i].name) == current_argv_len) {
14899a2dd95SBruce Richardson 			/* exact match */
14999a2dd95SBruce Richardson 			match = i;
15099a2dd95SBruce Richardson 			break;
15199a2dd95SBruce Richardson 		}
15299a2dd95SBruce Richardson 		/*
15399a2dd95SBruce Richardson 		 * If this is a known short option, don't allow
15499a2dd95SBruce Richardson 		 * a partial match of a single character.
15599a2dd95SBruce Richardson 		 */
15699a2dd95SBruce Richardson 		if (short_too && current_argv_len == 1)
15799a2dd95SBruce Richardson 			continue;
15899a2dd95SBruce Richardson 
15999a2dd95SBruce Richardson 		if (match == -1)	/* partial match */
16099a2dd95SBruce Richardson 			match = i;
16199a2dd95SBruce Richardson 		else {
16299a2dd95SBruce Richardson 			/* ambiguous abbreviation */
16399a2dd95SBruce Richardson 			if (PRINT_ERROR)
16499a2dd95SBruce Richardson 				warnx(ambig, (int)current_argv_len,
16599a2dd95SBruce Richardson 				     current_argv);
16699a2dd95SBruce Richardson 			optopt = 0;
16799a2dd95SBruce Richardson 			return BADCH;
16899a2dd95SBruce Richardson 		}
16999a2dd95SBruce Richardson 	}
17099a2dd95SBruce Richardson 	if (match != -1) {		/* option found */
17199a2dd95SBruce Richardson 		if (long_options[match].has_arg == no_argument
17299a2dd95SBruce Richardson 		    && has_equal) {
17399a2dd95SBruce Richardson 			if (PRINT_ERROR)
17499a2dd95SBruce Richardson 				warnx(noarg, (int)current_argv_len,
17599a2dd95SBruce Richardson 				     current_argv);
17699a2dd95SBruce Richardson 			/*
17799a2dd95SBruce Richardson 			 * XXX: GNU sets optopt to val regardless of flag
17899a2dd95SBruce Richardson 			 */
17999a2dd95SBruce Richardson 			if (long_options[match].flag == NULL)
18099a2dd95SBruce Richardson 				optopt = long_options[match].val;
18199a2dd95SBruce Richardson 			else
18299a2dd95SBruce Richardson 				optopt = 0;
18399a2dd95SBruce Richardson 			return BADARG;
18499a2dd95SBruce Richardson 		}
18599a2dd95SBruce Richardson 		if (long_options[match].has_arg == required_argument ||
18699a2dd95SBruce Richardson 		    long_options[match].has_arg == optional_argument) {
18799a2dd95SBruce Richardson 			if (has_equal)
18899a2dd95SBruce Richardson 				optarg = has_equal;
18999a2dd95SBruce Richardson 			else if (long_options[match].has_arg ==
19099a2dd95SBruce Richardson 			    required_argument) {
19199a2dd95SBruce Richardson 				/*
19299a2dd95SBruce Richardson 				 * optional argument doesn't use next nargv
19399a2dd95SBruce Richardson 				 */
19499a2dd95SBruce Richardson 				optarg = nargv[optind++];
19599a2dd95SBruce Richardson 			}
19699a2dd95SBruce Richardson 		}
19799a2dd95SBruce Richardson 		if ((long_options[match].has_arg == required_argument)
19899a2dd95SBruce Richardson 		    && (optarg == NULL)) {
19999a2dd95SBruce Richardson 			/*
20099a2dd95SBruce Richardson 			 * Missing argument; leading ':' indicates no error
20199a2dd95SBruce Richardson 			 * should be generated.
20299a2dd95SBruce Richardson 			 */
20399a2dd95SBruce Richardson 			if (PRINT_ERROR)
20499a2dd95SBruce Richardson 				warnx(recargstring,
20599a2dd95SBruce Richardson 				    current_argv);
20699a2dd95SBruce Richardson 			/*
20799a2dd95SBruce Richardson 			 * XXX: GNU sets optopt to val regardless of flag
20899a2dd95SBruce Richardson 			 */
20999a2dd95SBruce Richardson 			if (long_options[match].flag == NULL)
21099a2dd95SBruce Richardson 				optopt = long_options[match].val;
21199a2dd95SBruce Richardson 			else
21299a2dd95SBruce Richardson 				optopt = 0;
21399a2dd95SBruce Richardson 			--optind;
21499a2dd95SBruce Richardson 			return BADARG;
21599a2dd95SBruce Richardson 		}
21699a2dd95SBruce Richardson 	} else {			/* unknown option */
21799a2dd95SBruce Richardson 		if (short_too) {
21899a2dd95SBruce Richardson 			--optind;
21999a2dd95SBruce Richardson 			return (-1);
22099a2dd95SBruce Richardson 		}
22199a2dd95SBruce Richardson 		if (PRINT_ERROR)
22299a2dd95SBruce Richardson 			warnx(illoptstring, current_argv);
22399a2dd95SBruce Richardson 		optopt = 0;
22499a2dd95SBruce Richardson 		return BADCH;
22599a2dd95SBruce Richardson 	}
22699a2dd95SBruce Richardson 	if (idx)
22799a2dd95SBruce Richardson 		*idx = match;
22899a2dd95SBruce Richardson 	if (long_options[match].flag) {
22999a2dd95SBruce Richardson 		*long_options[match].flag = long_options[match].val;
23099a2dd95SBruce Richardson 		return 0;
23199a2dd95SBruce Richardson 	} else
23299a2dd95SBruce Richardson 		return (long_options[match].val);
23399a2dd95SBruce Richardson }
23499a2dd95SBruce Richardson 
23599a2dd95SBruce Richardson /*
23699a2dd95SBruce Richardson  * getopt_internal --
23799a2dd95SBruce Richardson  *	Parse argc/argv argument vector.  Called by user level routines.
23899a2dd95SBruce Richardson  */
23999a2dd95SBruce Richardson static int
240*a06fb0faSStephen Hemminger getopt_internal(int nargc, char *const nargv[], const char *options,
24199a2dd95SBruce Richardson 	const struct option *long_options, int *idx, int flags)
24299a2dd95SBruce Richardson {
24399a2dd95SBruce Richardson 	char *oli;				/* option letter list index */
24499a2dd95SBruce Richardson 	int optchar, short_too;
24599a2dd95SBruce Richardson 	static int posixly_correct = -1;
24699a2dd95SBruce Richardson 	size_t len;
24799a2dd95SBruce Richardson 	int optreset = 0;
24899a2dd95SBruce Richardson 
24999a2dd95SBruce Richardson 	if (options == NULL)
25099a2dd95SBruce Richardson 		return (-1);
25199a2dd95SBruce Richardson 
25299a2dd95SBruce Richardson 	/*
25399a2dd95SBruce Richardson 	 * Disable GNU extensions if POSIXLY_CORRECT is set or options
25499a2dd95SBruce Richardson 	 * string begins with a '+'.
25599a2dd95SBruce Richardson 	 */
25699a2dd95SBruce Richardson 	if (posixly_correct == -1) {
25799a2dd95SBruce Richardson 		errno_t err = _wgetenv_s(&len, NULL, 0, L"POSIXLY_CORRECT");
25899a2dd95SBruce Richardson 		posixly_correct = (err == 0) && (len > 0);
25999a2dd95SBruce Richardson 	}
26099a2dd95SBruce Richardson 	if (!posixly_correct || *options == '+')
26199a2dd95SBruce Richardson 		flags &= ~FLAG_PERMUTE;
26299a2dd95SBruce Richardson 	else if (*options == '-')
26399a2dd95SBruce Richardson 		flags |= FLAG_ALLARGS;
26499a2dd95SBruce Richardson 	if (*options == '+' || *options == '-')
26599a2dd95SBruce Richardson 		options++;
26699a2dd95SBruce Richardson 	/*
26799a2dd95SBruce Richardson 	 * reset if requested
26899a2dd95SBruce Richardson 	 */
26999a2dd95SBruce Richardson 	if (optind == 0)
27099a2dd95SBruce Richardson 		optind = optreset = 1;
27199a2dd95SBruce Richardson 
27299a2dd95SBruce Richardson 	optarg = NULL;
27399a2dd95SBruce Richardson 	if (optreset)
27499a2dd95SBruce Richardson 		nonopt_start = nonopt_end = -1;
27599a2dd95SBruce Richardson start:
27699a2dd95SBruce Richardson 	if (optreset || !*place) {		/* update scanning pointer */
27799a2dd95SBruce Richardson 		optreset = 0;
27899a2dd95SBruce Richardson 		if (optind >= nargc) {          /* end of argument vector */
27999a2dd95SBruce Richardson 			place = EMSG;
28099a2dd95SBruce Richardson 			if (nonopt_end != -1) {
28199a2dd95SBruce Richardson 				/* do permutation, if we have to */
28299a2dd95SBruce Richardson 				permute_args(nonopt_start, nonopt_end,
28399a2dd95SBruce Richardson 				    optind, nargv);
28499a2dd95SBruce Richardson 				optind -= nonopt_end - nonopt_start;
28599a2dd95SBruce Richardson 			} else if (nonopt_start != -1) {
28699a2dd95SBruce Richardson 				/*
28799a2dd95SBruce Richardson 				 * If we skipped non-options, set optind
28899a2dd95SBruce Richardson 				 * to the first of them.
28999a2dd95SBruce Richardson 				 */
29099a2dd95SBruce Richardson 				optind = nonopt_start;
29199a2dd95SBruce Richardson 			}
29299a2dd95SBruce Richardson 			nonopt_start = nonopt_end = -1;
29399a2dd95SBruce Richardson 			return (-1);
29499a2dd95SBruce Richardson 		}
29599a2dd95SBruce Richardson 		place = nargv[optind];
29699a2dd95SBruce Richardson 		if (*place != '-' ||
29799a2dd95SBruce Richardson 		    (place[1] == '\0' && strchr(options, '-') == NULL)) {
29899a2dd95SBruce Richardson 			place = EMSG;		/* found non-option */
29999a2dd95SBruce Richardson 			if (flags & FLAG_ALLARGS) {
30099a2dd95SBruce Richardson 				/*
30199a2dd95SBruce Richardson 				 * GNU extension:
30299a2dd95SBruce Richardson 				 * return non-option as argument to option 1
30399a2dd95SBruce Richardson 				 */
30499a2dd95SBruce Richardson 				optarg = nargv[optind++];
30599a2dd95SBruce Richardson 				return INORDER;
30699a2dd95SBruce Richardson 			}
30799a2dd95SBruce Richardson 			if (!(flags & FLAG_PERMUTE)) {
30899a2dd95SBruce Richardson 				/*
30999a2dd95SBruce Richardson 				 * If no permutation wanted, stop parsing
31099a2dd95SBruce Richardson 				 * at first non-option.
31199a2dd95SBruce Richardson 				 */
31299a2dd95SBruce Richardson 				return (-1);
31399a2dd95SBruce Richardson 			}
31499a2dd95SBruce Richardson 			/* do permutation */
31599a2dd95SBruce Richardson 			if (nonopt_start == -1)
31699a2dd95SBruce Richardson 				nonopt_start = optind;
31799a2dd95SBruce Richardson 			else if (nonopt_end != -1) {
31899a2dd95SBruce Richardson 				permute_args(nonopt_start, nonopt_end,
31999a2dd95SBruce Richardson 				    optind, nargv);
32099a2dd95SBruce Richardson 				nonopt_start = optind -
32199a2dd95SBruce Richardson 				    (nonopt_end - nonopt_start);
32299a2dd95SBruce Richardson 				nonopt_end = -1;
32399a2dd95SBruce Richardson 			}
32499a2dd95SBruce Richardson 			optind++;
32599a2dd95SBruce Richardson 			/* process next argument */
32699a2dd95SBruce Richardson 			goto start;
32799a2dd95SBruce Richardson 		}
32899a2dd95SBruce Richardson 		if (nonopt_start != -1 && nonopt_end == -1)
32999a2dd95SBruce Richardson 			nonopt_end = optind;
33099a2dd95SBruce Richardson 
33199a2dd95SBruce Richardson 		/*
33299a2dd95SBruce Richardson 		 * If we have "-" do nothing, if "--" we are done.
33399a2dd95SBruce Richardson 		 */
33499a2dd95SBruce Richardson 		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
33599a2dd95SBruce Richardson 			optind++;
33699a2dd95SBruce Richardson 			place = EMSG;
33799a2dd95SBruce Richardson 			/*
33899a2dd95SBruce Richardson 			 * We found an option (--), so if we skipped
33999a2dd95SBruce Richardson 			 * non-options, we have to permute.
34099a2dd95SBruce Richardson 			 */
34199a2dd95SBruce Richardson 			if (nonopt_end != -1) {
34299a2dd95SBruce Richardson 				permute_args(nonopt_start, nonopt_end,
34399a2dd95SBruce Richardson 				    optind, nargv);
34499a2dd95SBruce Richardson 				optind -= nonopt_end - nonopt_start;
34599a2dd95SBruce Richardson 			}
34699a2dd95SBruce Richardson 			nonopt_start = nonopt_end = -1;
34799a2dd95SBruce Richardson 			return (-1);
34899a2dd95SBruce Richardson 		}
34999a2dd95SBruce Richardson 	}
35099a2dd95SBruce Richardson 
35199a2dd95SBruce Richardson 	/*
35299a2dd95SBruce Richardson 	 * Check long options if:
35399a2dd95SBruce Richardson 	 *  1) we were passed some
35499a2dd95SBruce Richardson 	 *  2) the arg is not just "-"
35599a2dd95SBruce Richardson 	 *  3) either the arg starts with -- we are getopt_long_only()
35699a2dd95SBruce Richardson 	 */
35799a2dd95SBruce Richardson 	if (long_options != NULL && place != nargv[optind] &&
35899a2dd95SBruce Richardson 	    (*place == '-' || (flags & FLAG_LONGONLY))) {
35999a2dd95SBruce Richardson 		short_too = 0;
36099a2dd95SBruce Richardson 		if (*place == '-')
36199a2dd95SBruce Richardson 			place++;		/* --foo long option */
36299a2dd95SBruce Richardson 		else if (*place != ':' && strchr(options, *place) != NULL)
36399a2dd95SBruce Richardson 			short_too = 1;		/* could be short option too */
36499a2dd95SBruce Richardson 
36599a2dd95SBruce Richardson 		optchar = parse_long_options(nargv, options, long_options,
36699a2dd95SBruce Richardson 		    idx, short_too);
36799a2dd95SBruce Richardson 		if (optchar != -1) {
36899a2dd95SBruce Richardson 			place = EMSG;
36999a2dd95SBruce Richardson 			return optchar;
37099a2dd95SBruce Richardson 		}
37199a2dd95SBruce Richardson 	}
37299a2dd95SBruce Richardson 
37399a2dd95SBruce Richardson 	optchar = (int)*place++;
37499a2dd95SBruce Richardson 	oli = strchr(options, optchar);
37599a2dd95SBruce Richardson 	if (optchar == (int)':' ||
37699a2dd95SBruce Richardson 	    (optchar == (int)'-' && *place != '\0') ||
37799a2dd95SBruce Richardson 	    oli == NULL) {
37899a2dd95SBruce Richardson 		/*
37999a2dd95SBruce Richardson 		 * If the user specified "-" and  '-' isn't listed in
38099a2dd95SBruce Richardson 		 * options, return -1 (non-option) as per POSIX.
38199a2dd95SBruce Richardson 		 * Otherwise, it is an unknown option character (or ':').
38299a2dd95SBruce Richardson 		 */
38399a2dd95SBruce Richardson 		if (optchar == (int)'-' && *place == '\0')
38499a2dd95SBruce Richardson 			return (-1);
38599a2dd95SBruce Richardson 		if (!*place)
38699a2dd95SBruce Richardson 			++optind;
38799a2dd95SBruce Richardson 		if (PRINT_ERROR)
38899a2dd95SBruce Richardson 			warnx(illoptchar, optchar);
38999a2dd95SBruce Richardson 		optopt = optchar;
39099a2dd95SBruce Richardson 		return BADCH;
39199a2dd95SBruce Richardson 	}
39299a2dd95SBruce Richardson 	if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
39399a2dd95SBruce Richardson 		/* -W long-option */
39499a2dd95SBruce Richardson 		if (*place)
39599a2dd95SBruce Richardson 			;
39699a2dd95SBruce Richardson 		else if (++optind >= nargc) {	/* no arg */
39799a2dd95SBruce Richardson 			place = EMSG;
39899a2dd95SBruce Richardson 			if (PRINT_ERROR)
39999a2dd95SBruce Richardson 				warnx(recargchar, optchar);
40099a2dd95SBruce Richardson 			optopt = optchar;
40199a2dd95SBruce Richardson 			return BADARG;
40299a2dd95SBruce Richardson 		}				/* white space */
40399a2dd95SBruce Richardson 		place = nargv[optind];
40499a2dd95SBruce Richardson 		optchar = parse_long_options(nargv, options, long_options,
40599a2dd95SBruce Richardson 		    idx, 0);
40699a2dd95SBruce Richardson 		place = EMSG;
40799a2dd95SBruce Richardson 		return optchar;
40899a2dd95SBruce Richardson 	}
40999a2dd95SBruce Richardson 	if (*++oli != ':') {			/* doesn't take argument */
41099a2dd95SBruce Richardson 		if (!*place)
41199a2dd95SBruce Richardson 			++optind;
41299a2dd95SBruce Richardson 	} else {				/* takes (optional) argument */
41399a2dd95SBruce Richardson 		optarg = NULL;
41499a2dd95SBruce Richardson 		if (*place)			/* no white space */
41599a2dd95SBruce Richardson 			optarg = place;
41699a2dd95SBruce Richardson 		else if (oli[1] != ':') {	/* arg not optional */
41799a2dd95SBruce Richardson 			if (++optind >= nargc) {	/* no arg */
41899a2dd95SBruce Richardson 				place = EMSG;
41999a2dd95SBruce Richardson 				if (PRINT_ERROR)
42099a2dd95SBruce Richardson 					warnx(recargchar, optchar);
42199a2dd95SBruce Richardson 				optopt = optchar;
42299a2dd95SBruce Richardson 				return BADARG;
42399a2dd95SBruce Richardson 			}
42499a2dd95SBruce Richardson 			optarg = nargv[optind];
42599a2dd95SBruce Richardson 		}
42699a2dd95SBruce Richardson 		place = EMSG;
42799a2dd95SBruce Richardson 		++optind;
42899a2dd95SBruce Richardson 	}
42999a2dd95SBruce Richardson 	/* dump back option letter */
43099a2dd95SBruce Richardson 	return optchar;
43199a2dd95SBruce Richardson }
43299a2dd95SBruce Richardson 
43399a2dd95SBruce Richardson /*
43499a2dd95SBruce Richardson  * getopt --
43599a2dd95SBruce Richardson  *	Parse argc/argv argument vector.
43699a2dd95SBruce Richardson  */
43799a2dd95SBruce Richardson int
438*a06fb0faSStephen Hemminger getopt(int nargc, char *const nargv[], const char *options)
43999a2dd95SBruce Richardson {
44099a2dd95SBruce Richardson 	return getopt_internal(nargc, nargv, options, NULL, NULL,
44199a2dd95SBruce Richardson 			       FLAG_PERMUTE);
44299a2dd95SBruce Richardson }
44399a2dd95SBruce Richardson 
44499a2dd95SBruce Richardson /*
44599a2dd95SBruce Richardson  * getopt_long --
44699a2dd95SBruce Richardson  *	Parse argc/argv argument vector.
44799a2dd95SBruce Richardson  */
44899a2dd95SBruce Richardson int
449*a06fb0faSStephen Hemminger getopt_long(int nargc, char *const nargv[], const char *options,
45099a2dd95SBruce Richardson 	const struct option *long_options, int *idx)
45199a2dd95SBruce Richardson {
45299a2dd95SBruce Richardson 
45399a2dd95SBruce Richardson 	return (getopt_internal(nargc, nargv, options, long_options, idx,
45499a2dd95SBruce Richardson 	    FLAG_PERMUTE));
45599a2dd95SBruce Richardson }
45699a2dd95SBruce Richardson 
45799a2dd95SBruce Richardson /*
45899a2dd95SBruce Richardson  * getopt_long_only --
45999a2dd95SBruce Richardson  *	Parse argc/argv argument vector.
46099a2dd95SBruce Richardson  */
46199a2dd95SBruce Richardson int
462*a06fb0faSStephen Hemminger getopt_long_only(int nargc, char *const nargv[], const char *options,
46399a2dd95SBruce Richardson 	const struct option *long_options, int *idx)
46499a2dd95SBruce Richardson {
46599a2dd95SBruce Richardson 
46699a2dd95SBruce Richardson 	return (getopt_internal(nargc, nargv, options, long_options, idx,
46799a2dd95SBruce Richardson 	    FLAG_PERMUTE|FLAG_LONGONLY));
46899a2dd95SBruce Richardson }
46999a2dd95SBruce Richardson 
47099a2dd95SBruce Richardson #endif /* NEED_USUAL_GETOPT */
471