139332020SDarren Tucker /*	$OpenBSD: getopt_long.c,v 1.25 2011/03/05 22:10:11 guenther Exp $	*/
239332020SDarren Tucker /*	$NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $	*/
339332020SDarren Tucker 
439332020SDarren Tucker /*
539332020SDarren Tucker  * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
639332020SDarren Tucker  *
739332020SDarren Tucker  * Permission to use, copy, modify, and distribute this software for any
839332020SDarren Tucker  * purpose with or without fee is hereby granted, provided that the above
939332020SDarren Tucker  * copyright notice and this permission notice appear in all copies.
1039332020SDarren Tucker  *
1139332020SDarren Tucker  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1239332020SDarren Tucker  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1339332020SDarren Tucker  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1439332020SDarren Tucker  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1539332020SDarren Tucker  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1639332020SDarren Tucker  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1739332020SDarren Tucker  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1839332020SDarren Tucker  *
1939332020SDarren Tucker  * Sponsored in part by the Defense Advanced Research Projects
2039332020SDarren Tucker  * Agency (DARPA) and Air Force Research Laboratory, Air Force
2139332020SDarren Tucker  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
2239332020SDarren Tucker  */
2339332020SDarren Tucker /*-
2439332020SDarren Tucker  * Copyright (c) 2000 The NetBSD Foundation, Inc.
2539332020SDarren Tucker  * All rights reserved.
2639332020SDarren Tucker  *
2739332020SDarren Tucker  * This code is derived from software contributed to The NetBSD Foundation
2839332020SDarren Tucker  * by Dieter Baron and Thomas Klausner.
2939332020SDarren Tucker  *
3039332020SDarren Tucker  * Redistribution and use in source and binary forms, with or without
3139332020SDarren Tucker  * modification, are permitted provided that the following conditions
3239332020SDarren Tucker  * are met:
3339332020SDarren Tucker  * 1. Redistributions of source code must retain the above copyright
3439332020SDarren Tucker  *    notice, this list of conditions and the following disclaimer.
3539332020SDarren Tucker  * 2. Redistributions in binary form must reproduce the above copyright
3639332020SDarren Tucker  *    notice, this list of conditions and the following disclaimer in the
3739332020SDarren Tucker  *    documentation and/or other materials provided with the distribution.
3839332020SDarren Tucker  *
3939332020SDarren Tucker  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
4039332020SDarren Tucker  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
4139332020SDarren Tucker  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4239332020SDarren Tucker  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
4339332020SDarren Tucker  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4439332020SDarren Tucker  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
4539332020SDarren Tucker  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
4639332020SDarren Tucker  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
4739332020SDarren Tucker  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4839332020SDarren Tucker  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4939332020SDarren Tucker  * POSSIBILITY OF SUCH DAMAGE.
5039332020SDarren Tucker  */
5139332020SDarren Tucker 
52ccfdfceaSDarren Tucker /* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */
53ccfdfceaSDarren Tucker #include "includes.h"
54ccfdfceaSDarren Tucker 
55ccfdfceaSDarren Tucker #if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
56ccfdfceaSDarren Tucker 
57ccfdfceaSDarren Tucker /*
58ccfdfceaSDarren Tucker  * Some defines to make it easier to keep the code in sync with upstream.
59ccfdfceaSDarren Tucker  * getopt opterr optind optopt optreset optarg are all in defines.h which is
60ccfdfceaSDarren Tucker  * pulled in by includes.h.
61ccfdfceaSDarren Tucker  */
62ccfdfceaSDarren Tucker #define warnx		logit
63ccfdfceaSDarren Tucker 
64ccfdfceaSDarren Tucker #if 0
6539332020SDarren Tucker #include <err.h>
66*0abfb559SDarren Tucker #include <getopt.h>
67ccfdfceaSDarren Tucker #endif
6839332020SDarren Tucker #include <errno.h>
6939332020SDarren Tucker #include <stdlib.h>
7039332020SDarren Tucker #include <string.h>
71*0abfb559SDarren Tucker #include <stdarg.h>
72*0abfb559SDarren Tucker 
73*0abfb559SDarren Tucker #include "log.h"
7439332020SDarren Tucker 
7539332020SDarren Tucker int	opterr = 1;		/* if error message should be printed */
7639332020SDarren Tucker int	optind = 1;		/* index into parent argv vector */
7739332020SDarren Tucker int	optopt = '?';		/* character checked for validity */
7839332020SDarren Tucker int	optreset;		/* reset getopt */
7939332020SDarren Tucker char    *optarg;		/* argument associated with option */
8039332020SDarren Tucker 
8139332020SDarren Tucker #define PRINT_ERROR	((opterr) && (*options != ':'))
8239332020SDarren Tucker 
8339332020SDarren Tucker #define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
8439332020SDarren Tucker #define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
8539332020SDarren Tucker #define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */
8639332020SDarren Tucker 
8739332020SDarren Tucker /* return values */
8839332020SDarren Tucker #define	BADCH		(int)'?'
8939332020SDarren Tucker #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
9039332020SDarren Tucker #define	INORDER		(int)1
9139332020SDarren Tucker 
9239332020SDarren Tucker #define	EMSG		""
9339332020SDarren Tucker 
9439332020SDarren Tucker static int getopt_internal(int, char * const *, const char *,
9539332020SDarren Tucker 			   const struct option *, int *, int);
9639332020SDarren Tucker static int parse_long_options(char * const *, const char *,
9739332020SDarren Tucker 			      const struct option *, int *, int);
9839332020SDarren Tucker static int gcd(int, int);
9939332020SDarren Tucker static void permute_args(int, int, int, char * const *);
10039332020SDarren Tucker 
10139332020SDarren Tucker static char *place = EMSG; /* option letter processing */
10239332020SDarren Tucker 
10339332020SDarren Tucker /* XXX: set optreset to 1 rather than these two */
10439332020SDarren Tucker static int nonopt_start = -1; /* first non option argument (for permute) */
10539332020SDarren Tucker static int nonopt_end = -1;   /* first option after non options (for permute) */
10639332020SDarren Tucker 
10739332020SDarren Tucker /* Error messages */
10839332020SDarren Tucker static const char recargchar[] = "option requires an argument -- %c";
10939332020SDarren Tucker static const char recargstring[] = "option requires an argument -- %s";
11039332020SDarren Tucker static const char ambig[] = "ambiguous option -- %.*s";
11139332020SDarren Tucker static const char noarg[] = "option doesn't take an argument -- %.*s";
11239332020SDarren Tucker static const char illoptchar[] = "unknown option -- %c";
11339332020SDarren Tucker static const char illoptstring[] = "unknown option -- %s";
11439332020SDarren Tucker 
11539332020SDarren Tucker /*
11639332020SDarren Tucker  * Compute the greatest common divisor of a and b.
11739332020SDarren Tucker  */
11839332020SDarren Tucker static int
gcd(int a,int b)11939332020SDarren Tucker gcd(int a, int b)
12039332020SDarren Tucker {
12139332020SDarren Tucker 	int c;
12239332020SDarren Tucker 
12339332020SDarren Tucker 	c = a % b;
12439332020SDarren Tucker 	while (c != 0) {
12539332020SDarren Tucker 		a = b;
12639332020SDarren Tucker 		b = c;
12739332020SDarren Tucker 		c = a % b;
12839332020SDarren Tucker 	}
12939332020SDarren Tucker 
13039332020SDarren Tucker 	return (b);
13139332020SDarren Tucker }
13239332020SDarren Tucker 
13339332020SDarren Tucker /*
13439332020SDarren Tucker  * Exchange the block from nonopt_start to nonopt_end with the block
13539332020SDarren Tucker  * from nonopt_end to opt_end (keeping the same order of arguments
13639332020SDarren Tucker  * in each block).
13739332020SDarren Tucker  */
13839332020SDarren Tucker static void
permute_args(int panonopt_start,int panonopt_end,int opt_end,char * const * nargv)13939332020SDarren Tucker permute_args(int panonopt_start, int panonopt_end, int opt_end,
14039332020SDarren Tucker 	char * const *nargv)
14139332020SDarren Tucker {
14239332020SDarren Tucker 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
14339332020SDarren Tucker 	char *swap;
14439332020SDarren Tucker 
14539332020SDarren Tucker 	/*
14639332020SDarren Tucker 	 * compute lengths of blocks and number and size of cycles
14739332020SDarren Tucker 	 */
14839332020SDarren Tucker 	nnonopts = panonopt_end - panonopt_start;
14939332020SDarren Tucker 	nopts = opt_end - panonopt_end;
15039332020SDarren Tucker 	ncycle = gcd(nnonopts, nopts);
15139332020SDarren Tucker 	cyclelen = (opt_end - panonopt_start) / ncycle;
15239332020SDarren Tucker 
15339332020SDarren Tucker 	for (i = 0; i < ncycle; i++) {
15439332020SDarren Tucker 		cstart = panonopt_end+i;
15539332020SDarren Tucker 		pos = cstart;
15639332020SDarren Tucker 		for (j = 0; j < cyclelen; j++) {
15739332020SDarren Tucker 			if (pos >= panonopt_end)
15839332020SDarren Tucker 				pos -= nnonopts;
15939332020SDarren Tucker 			else
16039332020SDarren Tucker 				pos += nopts;
16139332020SDarren Tucker 			swap = nargv[pos];
16239332020SDarren Tucker 			/* LINTED const cast */
16339332020SDarren Tucker 			((char **) nargv)[pos] = nargv[cstart];
16439332020SDarren Tucker 			/* LINTED const cast */
16539332020SDarren Tucker 			((char **)nargv)[cstart] = swap;
16639332020SDarren Tucker 		}
16739332020SDarren Tucker 	}
16839332020SDarren Tucker }
16939332020SDarren Tucker 
17039332020SDarren Tucker /*
17139332020SDarren Tucker  * parse_long_options --
17239332020SDarren Tucker  *	Parse long options in argc/argv argument vector.
17339332020SDarren Tucker  * Returns -1 if short_too is set and the option does not match long_options.
17439332020SDarren Tucker  */
17539332020SDarren Tucker static int
parse_long_options(char * const * nargv,const char * options,const struct option * long_options,int * idx,int short_too)17639332020SDarren Tucker parse_long_options(char * const *nargv, const char *options,
17739332020SDarren Tucker 	const struct option *long_options, int *idx, int short_too)
17839332020SDarren Tucker {
17939332020SDarren Tucker 	char *current_argv, *has_equal;
18039332020SDarren Tucker 	size_t current_argv_len;
18139332020SDarren Tucker 	int i, match;
18239332020SDarren Tucker 
18339332020SDarren Tucker 	current_argv = place;
18439332020SDarren Tucker 	match = -1;
18539332020SDarren Tucker 
18639332020SDarren Tucker 	optind++;
18739332020SDarren Tucker 
18839332020SDarren Tucker 	if ((has_equal = strchr(current_argv, '=')) != NULL) {
18939332020SDarren Tucker 		/* argument found (--option=arg) */
19039332020SDarren Tucker 		current_argv_len = has_equal - current_argv;
19139332020SDarren Tucker 		has_equal++;
19239332020SDarren Tucker 	} else
19339332020SDarren Tucker 		current_argv_len = strlen(current_argv);
19439332020SDarren Tucker 
19539332020SDarren Tucker 	for (i = 0; long_options[i].name; i++) {
19639332020SDarren Tucker 		/* find matching long option */
19739332020SDarren Tucker 		if (strncmp(current_argv, long_options[i].name,
19839332020SDarren Tucker 		    current_argv_len))
19939332020SDarren Tucker 			continue;
20039332020SDarren Tucker 
20139332020SDarren Tucker 		if (strlen(long_options[i].name) == current_argv_len) {
20239332020SDarren Tucker 			/* exact match */
20339332020SDarren Tucker 			match = i;
20439332020SDarren Tucker 			break;
20539332020SDarren Tucker 		}
20639332020SDarren Tucker 		/*
20739332020SDarren Tucker 		 * If this is a known short option, don't allow
20839332020SDarren Tucker 		 * a partial match of a single character.
20939332020SDarren Tucker 		 */
21039332020SDarren Tucker 		if (short_too && current_argv_len == 1)
21139332020SDarren Tucker 			continue;
21239332020SDarren Tucker 
21339332020SDarren Tucker 		if (match == -1)	/* partial match */
21439332020SDarren Tucker 			match = i;
21539332020SDarren Tucker 		else {
21639332020SDarren Tucker 			/* ambiguous abbreviation */
21739332020SDarren Tucker 			if (PRINT_ERROR)
21839332020SDarren Tucker 				warnx(ambig, (int)current_argv_len,
21939332020SDarren Tucker 				     current_argv);
22039332020SDarren Tucker 			optopt = 0;
22139332020SDarren Tucker 			return (BADCH);
22239332020SDarren Tucker 		}
22339332020SDarren Tucker 	}
22439332020SDarren Tucker 	if (match != -1) {		/* option found */
22539332020SDarren Tucker 		if (long_options[match].has_arg == no_argument
22639332020SDarren Tucker 		    && has_equal) {
22739332020SDarren Tucker 			if (PRINT_ERROR)
22839332020SDarren Tucker 				warnx(noarg, (int)current_argv_len,
22939332020SDarren Tucker 				     current_argv);
23039332020SDarren Tucker 			/*
23139332020SDarren Tucker 			 * XXX: GNU sets optopt to val regardless of flag
23239332020SDarren Tucker 			 */
23339332020SDarren Tucker 			if (long_options[match].flag == NULL)
23439332020SDarren Tucker 				optopt = long_options[match].val;
23539332020SDarren Tucker 			else
23639332020SDarren Tucker 				optopt = 0;
23739332020SDarren Tucker 			return (BADARG);
23839332020SDarren Tucker 		}
23939332020SDarren Tucker 		if (long_options[match].has_arg == required_argument ||
24039332020SDarren Tucker 		    long_options[match].has_arg == optional_argument) {
24139332020SDarren Tucker 			if (has_equal)
24239332020SDarren Tucker 				optarg = has_equal;
24339332020SDarren Tucker 			else if (long_options[match].has_arg ==
24439332020SDarren Tucker 			    required_argument) {
24539332020SDarren Tucker 				/*
24639332020SDarren Tucker 				 * optional argument doesn't use next nargv
24739332020SDarren Tucker 				 */
24839332020SDarren Tucker 				optarg = nargv[optind++];
24939332020SDarren Tucker 			}
25039332020SDarren Tucker 		}
25139332020SDarren Tucker 		if ((long_options[match].has_arg == required_argument)
25239332020SDarren Tucker 		    && (optarg == NULL)) {
25339332020SDarren Tucker 			/*
25439332020SDarren Tucker 			 * Missing argument; leading ':' indicates no error
25539332020SDarren Tucker 			 * should be generated.
25639332020SDarren Tucker 			 */
25739332020SDarren Tucker 			if (PRINT_ERROR)
25839332020SDarren Tucker 				warnx(recargstring,
25939332020SDarren Tucker 				    current_argv);
26039332020SDarren Tucker 			/*
26139332020SDarren Tucker 			 * XXX: GNU sets optopt to val regardless of flag
26239332020SDarren Tucker 			 */
26339332020SDarren Tucker 			if (long_options[match].flag == NULL)
26439332020SDarren Tucker 				optopt = long_options[match].val;
26539332020SDarren Tucker 			else
26639332020SDarren Tucker 				optopt = 0;
26739332020SDarren Tucker 			--optind;
26839332020SDarren Tucker 			return (BADARG);
26939332020SDarren Tucker 		}
27039332020SDarren Tucker 	} else {			/* unknown option */
27139332020SDarren Tucker 		if (short_too) {
27239332020SDarren Tucker 			--optind;
27339332020SDarren Tucker 			return (-1);
27439332020SDarren Tucker 		}
27539332020SDarren Tucker 		if (PRINT_ERROR)
27639332020SDarren Tucker 			warnx(illoptstring, current_argv);
27739332020SDarren Tucker 		optopt = 0;
27839332020SDarren Tucker 		return (BADCH);
27939332020SDarren Tucker 	}
28039332020SDarren Tucker 	if (idx)
28139332020SDarren Tucker 		*idx = match;
28239332020SDarren Tucker 	if (long_options[match].flag) {
28339332020SDarren Tucker 		*long_options[match].flag = long_options[match].val;
28439332020SDarren Tucker 		return (0);
28539332020SDarren Tucker 	} else
28639332020SDarren Tucker 		return (long_options[match].val);
28739332020SDarren Tucker }
28839332020SDarren Tucker 
28939332020SDarren Tucker /*
29039332020SDarren Tucker  * getopt_internal --
29139332020SDarren Tucker  *	Parse argc/argv argument vector.  Called by user level routines.
29239332020SDarren Tucker  */
29339332020SDarren Tucker static int
getopt_internal(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx,int flags)29439332020SDarren Tucker getopt_internal(int nargc, char * const *nargv, const char *options,
29539332020SDarren Tucker 	const struct option *long_options, int *idx, int flags)
29639332020SDarren Tucker {
29739332020SDarren Tucker 	char *oli;				/* option letter list index */
29839332020SDarren Tucker 	int optchar, short_too;
29939332020SDarren Tucker 	static int posixly_correct = -1;
30039332020SDarren Tucker 
30139332020SDarren Tucker 	if (options == NULL)
30239332020SDarren Tucker 		return (-1);
30339332020SDarren Tucker 
30439332020SDarren Tucker 	/*
30539332020SDarren Tucker 	 * XXX Some GNU programs (like cvs) set optind to 0 instead of
30639332020SDarren Tucker 	 * XXX using optreset.  Work around this braindamage.
30739332020SDarren Tucker 	 */
30839332020SDarren Tucker 	if (optind == 0)
30939332020SDarren Tucker 		optind = optreset = 1;
31039332020SDarren Tucker 
31139332020SDarren Tucker 	/*
31239332020SDarren Tucker 	 * Disable GNU extensions if POSIXLY_CORRECT is set or options
31339332020SDarren Tucker 	 * string begins with a '+'.
31439332020SDarren Tucker 	 */
31539332020SDarren Tucker 	if (posixly_correct == -1 || optreset)
31639332020SDarren Tucker 		posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
31739332020SDarren Tucker 	if (*options == '-')
31839332020SDarren Tucker 		flags |= FLAG_ALLARGS;
31939332020SDarren Tucker 	else if (posixly_correct || *options == '+')
32039332020SDarren Tucker 		flags &= ~FLAG_PERMUTE;
32139332020SDarren Tucker 	if (*options == '+' || *options == '-')
32239332020SDarren Tucker 		options++;
32339332020SDarren Tucker 
32439332020SDarren Tucker 	optarg = NULL;
32539332020SDarren Tucker 	if (optreset)
32639332020SDarren Tucker 		nonopt_start = nonopt_end = -1;
32739332020SDarren Tucker start:
32839332020SDarren Tucker 	if (optreset || !*place) {		/* update scanning pointer */
32939332020SDarren Tucker 		optreset = 0;
33039332020SDarren Tucker 		if (optind >= nargc) {          /* end of argument vector */
33139332020SDarren Tucker 			place = EMSG;
33239332020SDarren Tucker 			if (nonopt_end != -1) {
33339332020SDarren Tucker 				/* do permutation, if we have to */
33439332020SDarren Tucker 				permute_args(nonopt_start, nonopt_end,
33539332020SDarren Tucker 				    optind, nargv);
33639332020SDarren Tucker 				optind -= nonopt_end - nonopt_start;
33739332020SDarren Tucker 			}
33839332020SDarren Tucker 			else if (nonopt_start != -1) {
33939332020SDarren Tucker 				/*
34039332020SDarren Tucker 				 * If we skipped non-options, set optind
34139332020SDarren Tucker 				 * to the first of them.
34239332020SDarren Tucker 				 */
34339332020SDarren Tucker 				optind = nonopt_start;
34439332020SDarren Tucker 			}
34539332020SDarren Tucker 			nonopt_start = nonopt_end = -1;
34639332020SDarren Tucker 			return (-1);
34739332020SDarren Tucker 		}
34839332020SDarren Tucker 		if (*(place = nargv[optind]) != '-' ||
34939332020SDarren Tucker 		    (place[1] == '\0' && strchr(options, '-') == NULL)) {
35039332020SDarren Tucker 			place = EMSG;		/* found non-option */
35139332020SDarren Tucker 			if (flags & FLAG_ALLARGS) {
35239332020SDarren Tucker 				/*
35339332020SDarren Tucker 				 * GNU extension:
35439332020SDarren Tucker 				 * return non-option as argument to option 1
35539332020SDarren Tucker 				 */
35639332020SDarren Tucker 				optarg = nargv[optind++];
35739332020SDarren Tucker 				return (INORDER);
35839332020SDarren Tucker 			}
35939332020SDarren Tucker 			if (!(flags & FLAG_PERMUTE)) {
36039332020SDarren Tucker 				/*
36139332020SDarren Tucker 				 * If no permutation wanted, stop parsing
36239332020SDarren Tucker 				 * at first non-option.
36339332020SDarren Tucker 				 */
36439332020SDarren Tucker 				return (-1);
36539332020SDarren Tucker 			}
36639332020SDarren Tucker 			/* do permutation */
36739332020SDarren Tucker 			if (nonopt_start == -1)
36839332020SDarren Tucker 				nonopt_start = optind;
36939332020SDarren Tucker 			else if (nonopt_end != -1) {
37039332020SDarren Tucker 				permute_args(nonopt_start, nonopt_end,
37139332020SDarren Tucker 				    optind, nargv);
37239332020SDarren Tucker 				nonopt_start = optind -
37339332020SDarren Tucker 				    (nonopt_end - nonopt_start);
37439332020SDarren Tucker 				nonopt_end = -1;
37539332020SDarren Tucker 			}
37639332020SDarren Tucker 			optind++;
37739332020SDarren Tucker 			/* process next argument */
37839332020SDarren Tucker 			goto start;
37939332020SDarren Tucker 		}
38039332020SDarren Tucker 		if (nonopt_start != -1 && nonopt_end == -1)
38139332020SDarren Tucker 			nonopt_end = optind;
38239332020SDarren Tucker 
38339332020SDarren Tucker 		/*
38439332020SDarren Tucker 		 * If we have "-" do nothing, if "--" we are done.
38539332020SDarren Tucker 		 */
38639332020SDarren Tucker 		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
38739332020SDarren Tucker 			optind++;
38839332020SDarren Tucker 			place = EMSG;
38939332020SDarren Tucker 			/*
39039332020SDarren Tucker 			 * We found an option (--), so if we skipped
39139332020SDarren Tucker 			 * non-options, we have to permute.
39239332020SDarren Tucker 			 */
39339332020SDarren Tucker 			if (nonopt_end != -1) {
39439332020SDarren Tucker 				permute_args(nonopt_start, nonopt_end,
39539332020SDarren Tucker 				    optind, nargv);
39639332020SDarren Tucker 				optind -= nonopt_end - nonopt_start;
39739332020SDarren Tucker 			}
39839332020SDarren Tucker 			nonopt_start = nonopt_end = -1;
39939332020SDarren Tucker 			return (-1);
40039332020SDarren Tucker 		}
40139332020SDarren Tucker 	}
40239332020SDarren Tucker 
40339332020SDarren Tucker 	/*
40439332020SDarren Tucker 	 * Check long options if:
40539332020SDarren Tucker 	 *  1) we were passed some
40639332020SDarren Tucker 	 *  2) the arg is not just "-"
40739332020SDarren Tucker 	 *  3) either the arg starts with -- we are getopt_long_only()
40839332020SDarren Tucker 	 */
40939332020SDarren Tucker 	if (long_options != NULL && place != nargv[optind] &&
41039332020SDarren Tucker 	    (*place == '-' || (flags & FLAG_LONGONLY))) {
41139332020SDarren Tucker 		short_too = 0;
41239332020SDarren Tucker 		if (*place == '-')
41339332020SDarren Tucker 			place++;		/* --foo long option */
41439332020SDarren Tucker 		else if (*place != ':' && strchr(options, *place) != NULL)
41539332020SDarren Tucker 			short_too = 1;		/* could be short option too */
41639332020SDarren Tucker 
41739332020SDarren Tucker 		optchar = parse_long_options(nargv, options, long_options,
41839332020SDarren Tucker 		    idx, short_too);
41939332020SDarren Tucker 		if (optchar != -1) {
42039332020SDarren Tucker 			place = EMSG;
42139332020SDarren Tucker 			return (optchar);
42239332020SDarren Tucker 		}
42339332020SDarren Tucker 	}
42439332020SDarren Tucker 
42539332020SDarren Tucker 	if ((optchar = (int)*place++) == (int)':' ||
42639332020SDarren Tucker 	    (optchar == (int)'-' && *place != '\0') ||
42739332020SDarren Tucker 	    (oli = strchr(options, optchar)) == NULL) {
42839332020SDarren Tucker 		/*
42939332020SDarren Tucker 		 * If the user specified "-" and  '-' isn't listed in
43039332020SDarren Tucker 		 * options, return -1 (non-option) as per POSIX.
43139332020SDarren Tucker 		 * Otherwise, it is an unknown option character (or ':').
43239332020SDarren Tucker 		 */
43339332020SDarren Tucker 		if (optchar == (int)'-' && *place == '\0')
43439332020SDarren Tucker 			return (-1);
43539332020SDarren Tucker 		if (!*place)
43639332020SDarren Tucker 			++optind;
43739332020SDarren Tucker 		if (PRINT_ERROR)
43839332020SDarren Tucker 			warnx(illoptchar, optchar);
43939332020SDarren Tucker 		optopt = optchar;
44039332020SDarren Tucker 		return (BADCH);
44139332020SDarren Tucker 	}
44239332020SDarren Tucker 	if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
44339332020SDarren Tucker 		/* -W long-option */
44439332020SDarren Tucker 		if (*place)			/* no space */
44539332020SDarren Tucker 			/* NOTHING */;
44639332020SDarren Tucker 		else if (++optind >= nargc) {	/* no arg */
44739332020SDarren Tucker 			place = EMSG;
44839332020SDarren Tucker 			if (PRINT_ERROR)
44939332020SDarren Tucker 				warnx(recargchar, optchar);
45039332020SDarren Tucker 			optopt = optchar;
45139332020SDarren Tucker 			return (BADARG);
45239332020SDarren Tucker 		} else				/* white space */
45339332020SDarren Tucker 			place = nargv[optind];
45439332020SDarren Tucker 		optchar = parse_long_options(nargv, options, long_options,
45539332020SDarren Tucker 		    idx, 0);
45639332020SDarren Tucker 		place = EMSG;
45739332020SDarren Tucker 		return (optchar);
45839332020SDarren Tucker 	}
45939332020SDarren Tucker 	if (*++oli != ':') {			/* doesn't take argument */
46039332020SDarren Tucker 		if (!*place)
46139332020SDarren Tucker 			++optind;
46239332020SDarren Tucker 	} else {				/* takes (optional) argument */
46339332020SDarren Tucker 		optarg = NULL;
46439332020SDarren Tucker 		if (*place)			/* no white space */
46539332020SDarren Tucker 			optarg = place;
46639332020SDarren Tucker 		else if (oli[1] != ':') {	/* arg not optional */
46739332020SDarren Tucker 			if (++optind >= nargc) {	/* no arg */
46839332020SDarren Tucker 				place = EMSG;
46939332020SDarren Tucker 				if (PRINT_ERROR)
47039332020SDarren Tucker 					warnx(recargchar, optchar);
47139332020SDarren Tucker 				optopt = optchar;
47239332020SDarren Tucker 				return (BADARG);
47339332020SDarren Tucker 			} else
47439332020SDarren Tucker 				optarg = nargv[optind];
47539332020SDarren Tucker 		}
47639332020SDarren Tucker 		place = EMSG;
47739332020SDarren Tucker 		++optind;
47839332020SDarren Tucker 	}
47939332020SDarren Tucker 	/* dump back option letter */
48039332020SDarren Tucker 	return (optchar);
48139332020SDarren Tucker }
48239332020SDarren Tucker 
48339332020SDarren Tucker /*
48439332020SDarren Tucker  * getopt --
48539332020SDarren Tucker  *	Parse argc/argv argument vector.
48639332020SDarren Tucker  *
48739332020SDarren Tucker  * [eventually this will replace the BSD getopt]
48839332020SDarren Tucker  */
48939332020SDarren Tucker int
getopt(int nargc,char * const * nargv,const char * options)49039332020SDarren Tucker getopt(int nargc, char * const *nargv, const char *options)
49139332020SDarren Tucker {
49239332020SDarren Tucker 
49339332020SDarren Tucker 	/*
49439332020SDarren Tucker 	 * We don't pass FLAG_PERMUTE to getopt_internal() since
49539332020SDarren Tucker 	 * the BSD getopt(3) (unlike GNU) has never done this.
49639332020SDarren Tucker 	 *
49739332020SDarren Tucker 	 * Furthermore, since many privileged programs call getopt()
49839332020SDarren Tucker 	 * before dropping privileges it makes sense to keep things
49939332020SDarren Tucker 	 * as simple (and bug-free) as possible.
50039332020SDarren Tucker 	 */
50139332020SDarren Tucker 	return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
50239332020SDarren Tucker }
50339332020SDarren Tucker 
504ccfdfceaSDarren Tucker #if 0
50539332020SDarren Tucker /*
50639332020SDarren Tucker  * getopt_long --
50739332020SDarren Tucker  *	Parse argc/argv argument vector.
50839332020SDarren Tucker  */
50939332020SDarren Tucker int
51039332020SDarren Tucker getopt_long(int nargc, char * const *nargv, const char *options,
51139332020SDarren Tucker     const struct option *long_options, int *idx)
51239332020SDarren Tucker {
51339332020SDarren Tucker 
51439332020SDarren Tucker 	return (getopt_internal(nargc, nargv, options, long_options, idx,
51539332020SDarren Tucker 	    FLAG_PERMUTE));
51639332020SDarren Tucker }
51739332020SDarren Tucker 
51839332020SDarren Tucker /*
51939332020SDarren Tucker  * getopt_long_only --
52039332020SDarren Tucker  *	Parse argc/argv argument vector.
52139332020SDarren Tucker  */
52239332020SDarren Tucker int
52339332020SDarren Tucker getopt_long_only(int nargc, char * const *nargv, const char *options,
52439332020SDarren Tucker     const struct option *long_options, int *idx)
52539332020SDarren Tucker {
52639332020SDarren Tucker 
52739332020SDarren Tucker 	return (getopt_internal(nargc, nargv, options, long_options, idx,
52839332020SDarren Tucker 	    FLAG_PERMUTE|FLAG_LONGONLY));
52939332020SDarren Tucker }
530ccfdfceaSDarren Tucker #endif
531ccfdfceaSDarren Tucker 
532ccfdfceaSDarren Tucker #endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */
533