Home | History | Annotate | Line # | Download | only in missing
      1      1.1  christos /*	$OpenBSD: getopt_long.c,v 1.22 2006/10/04 21:29:04 jmc Exp $	*/
      2      1.1  christos /*	NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp 	*/
      3      1.1  christos 
      4      1.1  christos /*
      5      1.1  christos  * Copyright (c) 2002 Todd C. Miller <Todd.Miller (at) courtesan.com>
      6      1.1  christos  *
      7      1.1  christos  * Permission to use, copy, modify, and distribute this software for any
      8      1.1  christos  * purpose with or without fee is hereby granted, provided that the above
      9      1.1  christos  * copyright notice and this permission notice appear in all copies.
     10      1.1  christos  *
     11      1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12      1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13      1.1  christos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14      1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15      1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16      1.1  christos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17      1.1  christos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18      1.1  christos  *
     19      1.1  christos  * Sponsored in part by the Defense Advanced Research Projects
     20      1.1  christos  * Agency (DARPA) and Air Force Research Laboratory, Air Force
     21      1.1  christos  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
     22      1.1  christos  */
     23      1.1  christos /*-
     24      1.1  christos  * Copyright (c) 2000 The NetBSD Foundation, Inc.
     25      1.1  christos  * All rights reserved.
     26      1.1  christos  *
     27      1.1  christos  * This code is derived from software contributed to The NetBSD Foundation
     28      1.1  christos  * by Dieter Baron and Thomas Klausner.
     29      1.1  christos  *
     30      1.1  christos  * Redistribution and use in source and binary forms, with or without
     31      1.1  christos  * modification, are permitted provided that the following conditions
     32      1.1  christos  * are met:
     33      1.1  christos  * 1. Redistributions of source code must retain the above copyright
     34      1.1  christos  *    notice, this list of conditions and the following disclaimer.
     35      1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     36      1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     37      1.1  christos  *    documentation and/or other materials provided with the distribution.
     38      1.1  christos  *
     39      1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     40      1.1  christos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     41      1.1  christos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     42      1.1  christos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     43      1.1  christos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     44      1.1  christos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     45      1.1  christos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     46      1.1  christos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     47      1.1  christos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     48      1.1  christos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     49      1.1  christos  * POSSIBILITY OF SUCH DAMAGE.
     50      1.1  christos  */
     51      1.1  christos 
     52      1.1  christos 
     53      1.1  christos #include <errno.h>
     54      1.1  christos #include "getopt_long.h"
     55      1.1  christos #include <stdlib.h>
     56      1.1  christos #include <stdio.h>
     57      1.1  christos #include <string.h>
     58      1.1  christos #include <stdarg.h>
     59      1.1  christos 
     60  1.1.1.2  christos #include "diag-control.h"
     61  1.1.1.2  christos 
     62      1.1  christos #define GNU_COMPATIBLE		/* Be more compatible, configure's use us! */
     63      1.1  christos 
     64      1.1  christos #define PRINT_ERROR	((opterr) && (*options != ':'))
     65      1.1  christos 
     66      1.1  christos #define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
     67      1.1  christos #define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
     68      1.1  christos #define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */
     69      1.1  christos 
     70      1.1  christos /* return values */
     71      1.1  christos #define	BADCH		(int)'?'
     72      1.1  christos #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
     73  1.1.1.2  christos #define	INORDER		(int)1
     74      1.1  christos 
     75      1.1  christos #define	EMSG		""
     76      1.1  christos 
     77      1.1  christos #ifdef GNU_COMPATIBLE
     78      1.1  christos #define NO_PREFIX	(-1)
     79      1.1  christos #define D_PREFIX	0
     80      1.1  christos #define DD_PREFIX	1
     81      1.1  christos #define W_PREFIX	2
     82      1.1  christos #endif
     83      1.1  christos 
     84      1.1  christos char *optarg;
     85      1.1  christos int optind, opterr = 1, optopt;
     86      1.1  christos 
     87      1.1  christos static int getopt_internal(int, char * const *, const char *,
     88      1.1  christos 			   const struct option *, int *, int);
     89      1.1  christos static int parse_long_options(char * const *, const char *,
     90      1.1  christos 			      const struct option *, int *, int, int);
     91      1.1  christos static int gcd(int, int);
     92      1.1  christos static void permute_args(int, int, int, char * const *);
     93      1.1  christos 
     94      1.1  christos static const char *place = EMSG; /* option letter processing */
     95      1.1  christos 
     96      1.1  christos static int nonopt_start = -1; /* first non option argument (for permute) */
     97      1.1  christos static int nonopt_end = -1;   /* first option after non options (for permute) */
     98      1.1  christos 
     99      1.1  christos /* Error messages */
    100      1.1  christos static const char recargchar[] = "option requires an argument -- %c";
    101      1.1  christos static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */
    102      1.1  christos #ifdef GNU_COMPATIBLE
    103      1.1  christos static int dash_prefix = NO_PREFIX;
    104      1.1  christos static const char gnuoptchar[] = "invalid option -- %c";
    105      1.1  christos 
    106      1.1  christos static const char recargstring[] = "option `%s%s' requires an argument";
    107      1.1  christos static const char ambig[] = "option `%s%.*s' is ambiguous";
    108      1.1  christos static const char noarg[] = "option `%s%.*s' doesn't allow an argument";
    109      1.1  christos static const char illoptstring[] = "unrecognized option `%s%s'";
    110      1.1  christos #else
    111      1.1  christos static const char recargstring[] = "option requires an argument -- %s";
    112      1.1  christos static const char ambig[] = "ambiguous option -- %.*s";
    113      1.1  christos static const char noarg[] = "option doesn't take an argument -- %.*s";
    114      1.1  christos static const char illoptstring[] = "unknown option -- %s";
    115      1.1  christos #endif
    116      1.1  christos 
    117      1.1  christos /*
    118      1.1  christos  * Compute the greatest common divisor of a and b.
    119      1.1  christos  */
    120      1.1  christos static int
    121      1.1  christos gcd(int a, int b)
    122      1.1  christos {
    123      1.1  christos 	int c;
    124      1.1  christos 
    125      1.1  christos 	c = a % b;
    126      1.1  christos 	while (c != 0) {
    127      1.1  christos 		a = b;
    128      1.1  christos 		b = c;
    129      1.1  christos 		c = a % b;
    130      1.1  christos 	}
    131      1.1  christos 
    132      1.1  christos 	return (b);
    133      1.1  christos }
    134      1.1  christos 
    135      1.1  christos /*
    136      1.1  christos  * Exchange the block from nonopt_start to nonopt_end with the block
    137      1.1  christos  * from nonopt_end to opt_end (keeping the same order of arguments
    138      1.1  christos  * in each block).
    139      1.1  christos  */
    140      1.1  christos static void
    141      1.1  christos permute_args(int panonopt_start, int panonopt_end, int opt_end,
    142      1.1  christos 	char * const *nargv)
    143      1.1  christos {
    144      1.1  christos 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
    145      1.1  christos 	char *swap;
    146      1.1  christos 
    147      1.1  christos 	/*
    148      1.1  christos 	 * compute lengths of blocks and number and size of cycles
    149      1.1  christos 	 */
    150      1.1  christos 	nnonopts = panonopt_end - panonopt_start;
    151      1.1  christos 	nopts = opt_end - panonopt_end;
    152      1.1  christos 	ncycle = gcd(nnonopts, nopts);
    153      1.1  christos 	cyclelen = (opt_end - panonopt_start) / ncycle;
    154      1.1  christos 
    155      1.1  christos 	for (i = 0; i < ncycle; i++) {
    156      1.1  christos 		cstart = panonopt_end+i;
    157      1.1  christos 		pos = cstart;
    158      1.1  christos 		for (j = 0; j < cyclelen; j++) {
    159      1.1  christos 			if (pos >= panonopt_end)
    160      1.1  christos 				pos -= nnonopts;
    161      1.1  christos 			else
    162      1.1  christos 				pos += nopts;
    163  1.1.1.2  christos 			/*
    164  1.1.1.2  christos 			 * This is annoying - I guess the
    165  1.1.1.2  christos 			 * "char * const argv[]" in the declaration
    166  1.1.1.2  christos 			 * of getopt() - and thus getopt_long() -
    167  1.1.1.2  christos 			 * means that it makes a promise not to
    168  1.1.1.2  christos 			 * shuffle the arguments, but here we are,
    169  1.1.1.2  christos 			 * shuffling the arguments.
    170  1.1.1.2  christos 			 *
    171  1.1.1.2  christos 			 * (No, it's not a promise that it won't
    172  1.1.1.2  christos 			 * modify any of the argument strings.
    173  1.1.1.2  christos 			 * It's a promise that it won't modify
    174  1.1.1.2  christos 			 * the array of pointers to the argument
    175  1.1.1.2  christos 			 * strings.)
    176  1.1.1.2  christos 			 *
    177  1.1.1.2  christos 			 * So squelch the cast warnings.
    178  1.1.1.2  christos 			 */
    179      1.1  christos 			swap = nargv[pos];
    180  1.1.1.2  christos DIAG_OFF_CAST_QUAL
    181      1.1  christos 			/* LINTED const cast */
    182      1.1  christos 			((char **) nargv)[pos] = nargv[cstart];
    183      1.1  christos 			/* LINTED const cast */
    184      1.1  christos 			((char **)nargv)[cstart] = swap;
    185  1.1.1.2  christos DIAG_ON_CAST_QUAL
    186      1.1  christos 		}
    187      1.1  christos 	}
    188      1.1  christos }
    189      1.1  christos 
    190      1.1  christos static void
    191      1.1  christos warnx(const char *fmt, ...)
    192      1.1  christos {
    193      1.1  christos 	extern char *program_name;
    194      1.1  christos 	va_list ap;
    195      1.1  christos 
    196      1.1  christos 	va_start(ap, fmt);
    197      1.1  christos 	fprintf(stderr, "%s: ", program_name);
    198      1.1  christos 	vfprintf(stderr, fmt, ap);
    199      1.1  christos 	fprintf(stderr, "\n");
    200      1.1  christos 	va_end(ap);
    201      1.1  christos }
    202      1.1  christos 
    203      1.1  christos /*
    204      1.1  christos  * parse_long_options --
    205      1.1  christos  *	Parse long options in argc/argv argument vector.
    206      1.1  christos  * Returns -1 if short_too is set and the option does not match long_options.
    207      1.1  christos  */
    208      1.1  christos static int
    209      1.1  christos parse_long_options(char * const *nargv, const char *options,
    210      1.1  christos 	const struct option *long_options, int *idx, int short_too, int flags)
    211      1.1  christos {
    212      1.1  christos 	const char *current_argv, *has_equal;
    213      1.1  christos #ifdef GNU_COMPATIBLE
    214      1.1  christos 	const char *current_dash;
    215      1.1  christos #endif
    216      1.1  christos 	size_t current_argv_len;
    217      1.1  christos 	int i, match, exact_match, second_partial_match;
    218      1.1  christos 
    219      1.1  christos 	current_argv = place;
    220      1.1  christos #ifdef GNU_COMPATIBLE
    221      1.1  christos 	switch (dash_prefix) {
    222      1.1  christos 		case D_PREFIX:
    223      1.1  christos 			current_dash = "-";
    224      1.1  christos 			break;
    225      1.1  christos 		case DD_PREFIX:
    226      1.1  christos 			current_dash = "--";
    227      1.1  christos 			break;
    228      1.1  christos 		case W_PREFIX:
    229      1.1  christos 			current_dash = "-W ";
    230      1.1  christos 			break;
    231      1.1  christos 		default:
    232      1.1  christos 			current_dash = "";
    233      1.1  christos 			break;
    234      1.1  christos 	}
    235      1.1  christos #endif
    236      1.1  christos 	match = -1;
    237      1.1  christos 	exact_match = 0;
    238      1.1  christos 	second_partial_match = 0;
    239      1.1  christos 
    240      1.1  christos 	optind++;
    241      1.1  christos 
    242      1.1  christos 	if ((has_equal = strchr(current_argv, '=')) != NULL) {
    243      1.1  christos 		/* argument found (--option=arg) */
    244      1.1  christos 		current_argv_len = has_equal - current_argv;
    245      1.1  christos 		has_equal++;
    246      1.1  christos 	} else
    247      1.1  christos 		current_argv_len = strlen(current_argv);
    248      1.1  christos 
    249      1.1  christos 	for (i = 0; long_options[i].name; i++) {
    250      1.1  christos 		/* find matching long option */
    251      1.1  christos 		if (strncmp(current_argv, long_options[i].name,
    252      1.1  christos 		    current_argv_len))
    253      1.1  christos 			continue;
    254      1.1  christos 
    255      1.1  christos 		if (strlen(long_options[i].name) == current_argv_len) {
    256      1.1  christos 			/* exact match */
    257      1.1  christos 			match = i;
    258      1.1  christos 			exact_match = 1;
    259      1.1  christos 			break;
    260      1.1  christos 		}
    261      1.1  christos 		/*
    262      1.1  christos 		 * If this is a known short option, don't allow
    263      1.1  christos 		 * a partial match of a single character.
    264      1.1  christos 		 */
    265      1.1  christos 		if (short_too && current_argv_len == 1)
    266      1.1  christos 			continue;
    267      1.1  christos 
    268      1.1  christos 		if (match == -1)        /* first partial match */
    269      1.1  christos 			match = i;
    270      1.1  christos 		else if ((flags & FLAG_LONGONLY) ||
    271      1.1  christos 			 long_options[i].has_arg !=
    272      1.1  christos 			     long_options[match].has_arg ||
    273      1.1  christos 			 long_options[i].flag != long_options[match].flag ||
    274      1.1  christos 			 long_options[i].val != long_options[match].val)
    275      1.1  christos 			second_partial_match = 1;
    276      1.1  christos 	}
    277      1.1  christos 	if (!exact_match && second_partial_match) {
    278      1.1  christos 		/* ambiguous abbreviation */
    279      1.1  christos 		if (PRINT_ERROR)
    280      1.1  christos 			warnx(ambig,
    281      1.1  christos #ifdef GNU_COMPATIBLE
    282      1.1  christos 			     current_dash,
    283      1.1  christos #endif
    284      1.1  christos 			     (int)current_argv_len,
    285      1.1  christos 			     current_argv);
    286      1.1  christos 		optopt = 0;
    287      1.1  christos 		return (BADCH);
    288      1.1  christos 	}
    289      1.1  christos 	if (match != -1) {		/* option found */
    290      1.1  christos 		if (long_options[match].has_arg == no_argument
    291      1.1  christos 		    && has_equal) {
    292      1.1  christos 			if (PRINT_ERROR)
    293      1.1  christos 				warnx(noarg,
    294      1.1  christos #ifdef GNU_COMPATIBLE
    295      1.1  christos 				     current_dash,
    296      1.1  christos #endif
    297      1.1  christos 				     (int)current_argv_len,
    298      1.1  christos 				     current_argv);
    299      1.1  christos 			/*
    300      1.1  christos 			 * XXX: GNU sets optopt to val regardless of flag
    301      1.1  christos 			 */
    302      1.1  christos 			if (long_options[match].flag == NULL)
    303      1.1  christos 				optopt = long_options[match].val;
    304      1.1  christos 			else
    305      1.1  christos 				optopt = 0;
    306      1.1  christos #ifdef GNU_COMPATIBLE
    307      1.1  christos 			return (BADCH);
    308      1.1  christos #else
    309      1.1  christos 			return (BADARG);
    310      1.1  christos #endif
    311      1.1  christos 		}
    312      1.1  christos 		if (long_options[match].has_arg == required_argument ||
    313      1.1  christos 		    long_options[match].has_arg == optional_argument) {
    314  1.1.1.2  christos DIAG_OFF_CAST_QUAL
    315      1.1  christos 			if (has_equal)
    316      1.1  christos 				optarg = (char *)has_equal;
    317      1.1  christos 			else if (long_options[match].has_arg ==
    318      1.1  christos 			    required_argument) {
    319      1.1  christos 				/*
    320      1.1  christos 				 * optional argument doesn't use next nargv
    321      1.1  christos 				 */
    322      1.1  christos 				optarg = nargv[optind++];
    323      1.1  christos 			}
    324  1.1.1.2  christos DIAG_ON_CAST_QUAL
    325      1.1  christos 		}
    326      1.1  christos 		if ((long_options[match].has_arg == required_argument)
    327      1.1  christos 		    && (optarg == NULL)) {
    328      1.1  christos 			/*
    329      1.1  christos 			 * Missing argument; leading ':' indicates no error
    330      1.1  christos 			 * should be generated.
    331      1.1  christos 			 */
    332      1.1  christos 			if (PRINT_ERROR)
    333      1.1  christos 				warnx(recargstring,
    334      1.1  christos #ifdef GNU_COMPATIBLE
    335      1.1  christos 				    current_dash,
    336      1.1  christos #endif
    337      1.1  christos 				    current_argv);
    338      1.1  christos 			/*
    339      1.1  christos 			 * XXX: GNU sets optopt to val regardless of flag
    340      1.1  christos 			 */
    341      1.1  christos 			if (long_options[match].flag == NULL)
    342      1.1  christos 				optopt = long_options[match].val;
    343      1.1  christos 			else
    344      1.1  christos 				optopt = 0;
    345      1.1  christos 			--optind;
    346      1.1  christos 			return (BADARG);
    347      1.1  christos 		}
    348      1.1  christos 	} else {			/* unknown option */
    349      1.1  christos 		if (short_too) {
    350      1.1  christos 			--optind;
    351      1.1  christos 			return (-1);
    352      1.1  christos 		}
    353      1.1  christos 		if (PRINT_ERROR)
    354      1.1  christos 			warnx(illoptstring,
    355      1.1  christos #ifdef GNU_COMPATIBLE
    356      1.1  christos 			      current_dash,
    357      1.1  christos #endif
    358      1.1  christos 			      current_argv);
    359      1.1  christos 		optopt = 0;
    360      1.1  christos 		return (BADCH);
    361      1.1  christos 	}
    362      1.1  christos 	if (idx)
    363      1.1  christos 		*idx = match;
    364      1.1  christos 	if (long_options[match].flag) {
    365      1.1  christos 		*long_options[match].flag = long_options[match].val;
    366      1.1  christos 		return (0);
    367      1.1  christos 	} else
    368      1.1  christos 		return (long_options[match].val);
    369      1.1  christos }
    370      1.1  christos 
    371      1.1  christos /*
    372      1.1  christos  * getopt_internal --
    373      1.1  christos  *	Parse argc/argv argument vector.  Called by user level routines.
    374      1.1  christos  */
    375      1.1  christos static int
    376      1.1  christos getopt_internal(int nargc, char * const *nargv, const char *options,
    377      1.1  christos 	const struct option *long_options, int *idx, int flags)
    378      1.1  christos {
    379      1.1  christos 	char *oli;				/* option letter list index */
    380      1.1  christos 	int optchar, short_too;
    381      1.1  christos 	int posixly_correct;	/* no static, can be changed on the fly */
    382      1.1  christos 
    383      1.1  christos 	if (options == NULL)
    384      1.1  christos 		return (-1);
    385      1.1  christos 
    386      1.1  christos 	/*
    387      1.1  christos 	 * Disable GNU extensions if POSIXLY_CORRECT is set or options
    388      1.1  christos 	 * string begins with a '+'.
    389      1.1  christos 	 */
    390      1.1  christos 	posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
    391      1.1  christos #ifdef GNU_COMPATIBLE
    392      1.1  christos 	if (*options == '-')
    393      1.1  christos 		flags |= FLAG_ALLARGS;
    394      1.1  christos 	else if (posixly_correct || *options == '+')
    395      1.1  christos 		flags &= ~FLAG_PERMUTE;
    396      1.1  christos #else
    397      1.1  christos 	if (posixly_correct || *options == '+')
    398      1.1  christos 		flags &= ~FLAG_PERMUTE;
    399      1.1  christos 	else if (*options == '-')
    400      1.1  christos 		flags |= FLAG_ALLARGS;
    401      1.1  christos #endif
    402      1.1  christos 	if (*options == '+' || *options == '-')
    403      1.1  christos 		options++;
    404      1.1  christos 
    405      1.1  christos 	/*
    406      1.1  christos 	 * XXX Some GNU programs (like cvs) set optind to 0 instead of
    407      1.1  christos 	 * XXX using optreset.  Work around this braindamage.
    408      1.1  christos 	 */
    409      1.1  christos 	if (optind == 0)
    410      1.1  christos 		optind = 1;
    411      1.1  christos 
    412      1.1  christos 	optarg = NULL;
    413      1.1  christos start:
    414      1.1  christos 	if (!*place) {				/* update scanning pointer */
    415      1.1  christos 		if (optind >= nargc) {          /* end of argument vector */
    416      1.1  christos 			place = EMSG;
    417      1.1  christos 			if (nonopt_end != -1) {
    418      1.1  christos 				/* do permutation, if we have to */
    419      1.1  christos 				permute_args(nonopt_start, nonopt_end,
    420      1.1  christos 				    optind, nargv);
    421      1.1  christos 				optind -= nonopt_end - nonopt_start;
    422  1.1.1.3  christos 			} else if (nonopt_start != -1) {
    423      1.1  christos 				/*
    424      1.1  christos 				 * If we skipped non-options, set optind
    425      1.1  christos 				 * to the first of them.
    426      1.1  christos 				 */
    427      1.1  christos 				optind = nonopt_start;
    428      1.1  christos 			}
    429      1.1  christos 			nonopt_start = nonopt_end = -1;
    430      1.1  christos 			return (-1);
    431      1.1  christos 		}
    432      1.1  christos 		if (*(place = nargv[optind]) != '-' ||
    433      1.1  christos #ifdef GNU_COMPATIBLE
    434      1.1  christos 		    place[1] == '\0') {
    435      1.1  christos #else
    436      1.1  christos 		    (place[1] == '\0' && strchr(options, '-') == NULL)) {
    437      1.1  christos #endif
    438      1.1  christos 			place = EMSG;		/* found non-option */
    439      1.1  christos 			if (flags & FLAG_ALLARGS) {
    440      1.1  christos 				/*
    441      1.1  christos 				 * GNU extension:
    442      1.1  christos 				 * return non-option as argument to option 1
    443      1.1  christos 				 */
    444      1.1  christos 				optarg = nargv[optind++];
    445      1.1  christos 				return (INORDER);
    446      1.1  christos 			}
    447      1.1  christos 			if (!(flags & FLAG_PERMUTE)) {
    448      1.1  christos 				/*
    449      1.1  christos 				 * If no permutation wanted, stop parsing
    450      1.1  christos 				 * at first non-option.
    451      1.1  christos 				 */
    452      1.1  christos 				return (-1);
    453      1.1  christos 			}
    454      1.1  christos 			/* do permutation */
    455      1.1  christos 			if (nonopt_start == -1)
    456      1.1  christos 				nonopt_start = optind;
    457      1.1  christos 			else if (nonopt_end != -1) {
    458      1.1  christos 				permute_args(nonopt_start, nonopt_end,
    459      1.1  christos 				    optind, nargv);
    460      1.1  christos 				nonopt_start = optind -
    461      1.1  christos 				    (nonopt_end - nonopt_start);
    462      1.1  christos 				nonopt_end = -1;
    463      1.1  christos 			}
    464      1.1  christos 			optind++;
    465      1.1  christos 			/* process next argument */
    466      1.1  christos 			goto start;
    467      1.1  christos 		}
    468      1.1  christos 		if (nonopt_start != -1 && nonopt_end == -1)
    469      1.1  christos 			nonopt_end = optind;
    470      1.1  christos 
    471      1.1  christos 		/*
    472      1.1  christos 		 * If we have "-" do nothing, if "--" we are done.
    473      1.1  christos 		 */
    474      1.1  christos 		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
    475      1.1  christos 			optind++;
    476      1.1  christos 			place = EMSG;
    477      1.1  christos 			/*
    478      1.1  christos 			 * We found an option (--), so if we skipped
    479      1.1  christos 			 * non-options, we have to permute.
    480      1.1  christos 			 */
    481      1.1  christos 			if (nonopt_end != -1) {
    482      1.1  christos 				permute_args(nonopt_start, nonopt_end,
    483      1.1  christos 				    optind, nargv);
    484      1.1  christos 				optind -= nonopt_end - nonopt_start;
    485      1.1  christos 			}
    486      1.1  christos 			nonopt_start = nonopt_end = -1;
    487      1.1  christos 			return (-1);
    488      1.1  christos 		}
    489      1.1  christos 	}
    490      1.1  christos 
    491      1.1  christos 	/*
    492      1.1  christos 	 * Check long options if:
    493      1.1  christos 	 *  1) we were passed some
    494      1.1  christos 	 *  2) the arg is not just "-"
    495      1.1  christos 	 *  3) either the arg starts with -- we are getopt_long_only()
    496      1.1  christos 	 */
    497      1.1  christos 	if (long_options != NULL && place != nargv[optind] &&
    498      1.1  christos 	    (*place == '-' || (flags & FLAG_LONGONLY))) {
    499      1.1  christos 		short_too = 0;
    500      1.1  christos #ifdef GNU_COMPATIBLE
    501      1.1  christos 		dash_prefix = D_PREFIX;
    502      1.1  christos #endif
    503      1.1  christos 		if (*place == '-') {
    504      1.1  christos 			place++;		/* --foo long option */
    505      1.1  christos #ifdef GNU_COMPATIBLE
    506      1.1  christos 			dash_prefix = DD_PREFIX;
    507      1.1  christos #endif
    508      1.1  christos 		} else if (*place != ':' && strchr(options, *place) != NULL)
    509      1.1  christos 			short_too = 1;		/* could be short option too */
    510      1.1  christos 
    511      1.1  christos 		optchar = parse_long_options(nargv, options, long_options,
    512      1.1  christos 		    idx, short_too, flags);
    513      1.1  christos 		if (optchar != -1) {
    514      1.1  christos 			place = EMSG;
    515      1.1  christos 			return (optchar);
    516      1.1  christos 		}
    517      1.1  christos 	}
    518      1.1  christos 
    519      1.1  christos 	if ((optchar = (int)*place++) == (int)':' ||
    520      1.1  christos 	    (optchar == (int)'-' && *place != '\0') ||
    521      1.1  christos 	    (oli = strchr(options, optchar)) == NULL) {
    522      1.1  christos 		/*
    523      1.1  christos 		 * If the user specified "-" and  '-' isn't listed in
    524      1.1  christos 		 * options, return -1 (non-option) as per POSIX.
    525      1.1  christos 		 * Otherwise, it is an unknown option character (or ':').
    526      1.1  christos 		 */
    527      1.1  christos 		if (optchar == (int)'-' && *place == '\0')
    528      1.1  christos 			return (-1);
    529      1.1  christos 		if (!*place)
    530      1.1  christos 			++optind;
    531      1.1  christos #ifdef GNU_COMPATIBLE
    532      1.1  christos 		if (PRINT_ERROR)
    533      1.1  christos 			warnx(posixly_correct ? illoptchar : gnuoptchar,
    534      1.1  christos 			      optchar);
    535      1.1  christos #else
    536      1.1  christos 		if (PRINT_ERROR)
    537      1.1  christos 			warnx(illoptchar, optchar);
    538      1.1  christos #endif
    539      1.1  christos 		optopt = optchar;
    540      1.1  christos 		return (BADCH);
    541      1.1  christos 	}
    542      1.1  christos 	if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
    543      1.1  christos 		/* -W long-option */
    544      1.1  christos 		if (*place)			/* no space */
    545      1.1  christos 			/* NOTHING */;
    546      1.1  christos 		else if (++optind >= nargc) {	/* no arg */
    547      1.1  christos 			place = EMSG;
    548      1.1  christos 			if (PRINT_ERROR)
    549      1.1  christos 				warnx(recargchar, optchar);
    550      1.1  christos 			optopt = optchar;
    551      1.1  christos 			return (BADARG);
    552      1.1  christos 		} else				/* white space */
    553      1.1  christos 			place = nargv[optind];
    554      1.1  christos #ifdef GNU_COMPATIBLE
    555      1.1  christos 		dash_prefix = W_PREFIX;
    556      1.1  christos #endif
    557      1.1  christos 		optchar = parse_long_options(nargv, options, long_options,
    558      1.1  christos 		    idx, 0, flags);
    559      1.1  christos 		place = EMSG;
    560      1.1  christos 		return (optchar);
    561      1.1  christos 	}
    562      1.1  christos 	if (*++oli != ':') {			/* doesn't take argument */
    563      1.1  christos 		if (!*place)
    564      1.1  christos 			++optind;
    565      1.1  christos 	} else {				/* takes (optional) argument */
    566      1.1  christos 		optarg = NULL;
    567  1.1.1.2  christos 		if (*place) {			/* no white space */
    568  1.1.1.2  christos DIAG_OFF_CAST_QUAL
    569      1.1  christos 			optarg = (char *)place;
    570  1.1.1.2  christos DIAG_ON_CAST_QUAL
    571  1.1.1.2  christos 		} else if (oli[1] != ':') {	/* arg not optional */
    572      1.1  christos 			if (++optind >= nargc) {	/* no arg */
    573      1.1  christos 				place = EMSG;
    574      1.1  christos 				if (PRINT_ERROR)
    575      1.1  christos 					warnx(recargchar, optchar);
    576      1.1  christos 				optopt = optchar;
    577      1.1  christos 				return (BADARG);
    578      1.1  christos 			} else
    579      1.1  christos 				optarg = nargv[optind];
    580      1.1  christos 		}
    581      1.1  christos 		place = EMSG;
    582      1.1  christos 		++optind;
    583      1.1  christos 	}
    584      1.1  christos 	/* dump back option letter */
    585      1.1  christos 	return (optchar);
    586      1.1  christos }
    587      1.1  christos 
    588      1.1  christos #ifdef REPLACE_GETOPT
    589      1.1  christos /*
    590      1.1  christos  * getopt --
    591      1.1  christos  *	Parse argc/argv argument vector.
    592      1.1  christos  *
    593      1.1  christos  * [eventually this will replace the BSD getopt]
    594      1.1  christos  */
    595      1.1  christos int
    596      1.1  christos getopt(int nargc, char * const *nargv, const char *options)
    597      1.1  christos {
    598      1.1  christos 
    599      1.1  christos 	/*
    600      1.1  christos 	 * We don't pass FLAG_PERMUTE to getopt_internal() since
    601      1.1  christos 	 * the BSD getopt(3) (unlike GNU) has never done this.
    602      1.1  christos 	 *
    603      1.1  christos 	 * Furthermore, since many privileged programs call getopt()
    604      1.1  christos 	 * before dropping privileges it makes sense to keep things
    605      1.1  christos 	 * as simple (and bug-free) as possible.
    606      1.1  christos 	 */
    607      1.1  christos 	return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
    608      1.1  christos }
    609      1.1  christos #endif /* REPLACE_GETOPT */
    610      1.1  christos 
    611      1.1  christos /*
    612      1.1  christos  * getopt_long --
    613      1.1  christos  *	Parse argc/argv argument vector.
    614      1.1  christos  */
    615      1.1  christos int
    616      1.1  christos getopt_long(int nargc, char * const *nargv, const char *options,
    617      1.1  christos 	const struct option *long_options, int *idx)
    618      1.1  christos {
    619      1.1  christos 
    620      1.1  christos 	return (getopt_internal(nargc, nargv, options, long_options, idx,
    621      1.1  christos 	    FLAG_PERMUTE));
    622      1.1  christos }
    623      1.1  christos 
    624      1.1  christos /*
    625      1.1  christos  * getopt_long_only --
    626      1.1  christos  *	Parse argc/argv argument vector.
    627      1.1  christos  */
    628      1.1  christos int
    629      1.1  christos getopt_long_only(int nargc, char * const *nargv, const char *options,
    630      1.1  christos 	const struct option *long_options, int *idx)
    631      1.1  christos {
    632      1.1  christos 
    633      1.1  christos 	return (getopt_internal(nargc, nargv, options, long_options, idx,
    634      1.1  christos 	    FLAG_PERMUTE|FLAG_LONGONLY));
    635      1.1  christos }
    636