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