1*689fdc58Schristos /* $NetBSD: getopt_long.c,v 1.28 2024/01/19 18:41:38 christos Exp $ */
26dfafca1Schristos
36dfafca1Schristos /*-
46dfafca1Schristos * Copyright (c) 2000 The NetBSD Foundation, Inc.
56dfafca1Schristos * All rights reserved.
66dfafca1Schristos *
76dfafca1Schristos * This code is derived from software contributed to The NetBSD Foundation
86dfafca1Schristos * by Dieter Baron and Thomas Klausner.
962da59d7Smcr *
1062da59d7Smcr * Redistribution and use in source and binary forms, with or without
1162da59d7Smcr * modification, are permitted provided that the following conditions
1262da59d7Smcr * are met:
1362da59d7Smcr * 1. Redistributions of source code must retain the above copyright
1462da59d7Smcr * notice, this list of conditions and the following disclaimer.
1562da59d7Smcr * 2. Redistributions in binary form must reproduce the above copyright
1662da59d7Smcr * notice, this list of conditions and the following disclaimer in the
1762da59d7Smcr * documentation and/or other materials provided with the distribution.
1862da59d7Smcr *
196dfafca1Schristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
206dfafca1Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216dfafca1Schristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226dfafca1Schristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
236dfafca1Schristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246dfafca1Schristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
256dfafca1Schristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
266dfafca1Schristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
276dfafca1Schristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286dfafca1Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296dfafca1Schristos * POSSIBILITY OF SUCH DAMAGE.
3062da59d7Smcr */
3162da59d7Smcr
32b2f78261Sjmc #if HAVE_NBTOOL_CONFIG_H
33b2f78261Sjmc #include "nbtool_config.h"
34b2f78261Sjmc #endif
35b2f78261Sjmc
36b48252f3Slukem #include <sys/cdefs.h>
37*689fdc58Schristos __RCSID("$NetBSD: getopt_long.c,v 1.28 2024/01/19 18:41:38 christos Exp $");
38b48252f3Slukem
396d34da15Schristos #include "namespace.h"
406d34da15Schristos
41b48252f3Slukem #include <assert.h>
429fbd8888Stv #include <err.h>
43b48252f3Slukem #include <errno.h>
44b2f78261Sjmc #if HAVE_NBTOOL_CONFIG_H
45b2f78261Sjmc #include "compat_getopt.h"
46b2f78261Sjmc #else
479fbd8888Stv #include <getopt.h>
48b2f78261Sjmc #endif
4962da59d7Smcr #include <stdlib.h>
5062da59d7Smcr #include <string.h>
5162da59d7Smcr
52b3b90d74Schristos #if HAVE_NBTOOL_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
53b3b90d74Schristos #define REPLACE_GETOPT
54b3b90d74Schristos #endif
55b3b90d74Schristos
56b3b90d74Schristos #ifdef REPLACE_GETOPT
576dfafca1Schristos #ifdef __weak_alias
586dfafca1Schristos __weak_alias(getopt,_getopt)
596dfafca1Schristos #endif
606dfafca1Schristos int opterr = 1; /* if error message should be printed */
616dfafca1Schristos int optind = 1; /* index into parent argv vector */
626dfafca1Schristos int optopt = '?'; /* character checked for validity */
636dfafca1Schristos int optreset; /* reset getopt */
646dfafca1Schristos char *optarg; /* argument associated with option */
65171d6532Slukem #elif HAVE_NBTOOL_CONFIG_H && !HAVE_DECL_OPTRESET
66a328e341Stv static int optreset;
676dfafca1Schristos #endif
6862da59d7Smcr
696dfafca1Schristos #ifdef __weak_alias
706dfafca1Schristos __weak_alias(getopt_long,_getopt_long)
716dfafca1Schristos #endif
7262da59d7Smcr
736dfafca1Schristos #define IGNORE_FIRST (*options == '-' || *options == '+')
746dfafca1Schristos #define PRINT_ERROR ((opterr) && ((*options != ':') \
756dfafca1Schristos || (IGNORE_FIRST && options[1] != ':')))
766dfafca1Schristos #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
776dfafca1Schristos #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
786dfafca1Schristos /* XXX: GNU ignores PC if *options == '-' */
796dfafca1Schristos #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
80b48252f3Slukem
816dfafca1Schristos /* return values */
8262da59d7Smcr #define BADCH (int)'?'
83e7775dbfSwiz #define BADARG ((IGNORE_FIRST && options[1] == ':') \
84e7775dbfSwiz || (*options == ':') ? (int)':' : (int)'?')
856dfafca1Schristos #define INORDER (int)1
866dfafca1Schristos
8762da59d7Smcr #define EMSG ""
8862da59d7Smcr
89cc420b6cSjoerg static int getopt_internal(int, char **, const char *);
90cc420b6cSjoerg static int gcd(int, int);
91cc420b6cSjoerg static void permute_args(int, int, int, char **);
926dfafca1Schristos
9303256c6eSchristos static const char *place = EMSG; /* option letter processing */
946dfafca1Schristos
956dfafca1Schristos /* XXX: set optreset to 1 rather than these two */
966dfafca1Schristos static int nonopt_start = -1; /* first non option argument (for permute) */
976dfafca1Schristos static int nonopt_end = -1; /* first option after non options (for permute) */
986dfafca1Schristos
996dfafca1Schristos /* Error messages */
100045f0427Snathanw static const char recargchar[] = "option requires an argument -- %c";
101045f0427Snathanw static const char recargstring[] = "option requires an argument -- %s";
1026dfafca1Schristos static const char ambig[] = "ambiguous option -- %.*s";
1036dfafca1Schristos static const char noarg[] = "option doesn't take an argument -- %.*s";
10477dec036Sjoda static const char illoptchar[] = "unknown option -- %c";
10577dec036Sjoda static const char illoptstring[] = "unknown option -- %s";
1066dfafca1Schristos
1076dfafca1Schristos
10862da59d7Smcr /*
1096dfafca1Schristos * Compute the greatest common divisor of a and b.
11062da59d7Smcr */
1116dfafca1Schristos static int
gcd(int a,int b)112cc420b6cSjoerg gcd(int a, int b)
1136dfafca1Schristos {
1146dfafca1Schristos int c;
1156dfafca1Schristos
1166dfafca1Schristos c = a % b;
1176dfafca1Schristos while (c != 0) {
1186dfafca1Schristos a = b;
1196dfafca1Schristos b = c;
1206dfafca1Schristos c = a % b;
1216dfafca1Schristos }
1226dfafca1Schristos
1236dfafca1Schristos return b;
1246dfafca1Schristos }
1256dfafca1Schristos
1266dfafca1Schristos /*
1276dfafca1Schristos * Exchange the block from nonopt_start to nonopt_end with the block
1286dfafca1Schristos * from nonopt_end to opt_end (keeping the same order of arguments
1296dfafca1Schristos * in each block).
1306dfafca1Schristos */
1316dfafca1Schristos static void
permute_args(int panonopt_start,int panonopt_end,int opt_end,char ** nargv)132cc420b6cSjoerg permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv)
1336dfafca1Schristos {
1346dfafca1Schristos int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
1356dfafca1Schristos char *swap;
1366dfafca1Schristos
137c5b9e1ceSlukem _DIAGASSERT(nargv != NULL);
138c5b9e1ceSlukem
1396dfafca1Schristos /*
1406dfafca1Schristos * compute lengths of blocks and number and size of cycles
1416dfafca1Schristos */
14250f5afd5Slukem nnonopts = panonopt_end - panonopt_start;
14350f5afd5Slukem nopts = opt_end - panonopt_end;
1446dfafca1Schristos ncycle = gcd(nnonopts, nopts);
14550f5afd5Slukem cyclelen = (opt_end - panonopt_start) / ncycle;
1466dfafca1Schristos
1476dfafca1Schristos for (i = 0; i < ncycle; i++) {
14850f5afd5Slukem cstart = panonopt_end+i;
1496dfafca1Schristos pos = cstart;
1506dfafca1Schristos for (j = 0; j < cyclelen; j++) {
15150f5afd5Slukem if (pos >= panonopt_end)
1526dfafca1Schristos pos -= nnonopts;
1536dfafca1Schristos else
1546dfafca1Schristos pos += nopts;
1556dfafca1Schristos swap = nargv[pos];
1569de32b7fSyamt nargv[pos] = nargv[cstart];
1579de32b7fSyamt nargv[cstart] = swap;
1586dfafca1Schristos }
1596dfafca1Schristos }
1606dfafca1Schristos }
1616dfafca1Schristos
1626dfafca1Schristos /*
1636dfafca1Schristos * getopt_internal --
1646dfafca1Schristos * Parse argc/argv argument vector. Called by user level routines.
1656dfafca1Schristos * Returns -2 if -- is found (can be long option or end of options marker).
1666dfafca1Schristos */
1676dfafca1Schristos static int
getopt_internal(int nargc,char ** nargv,const char * options)168cc420b6cSjoerg getopt_internal(int nargc, char **nargv, const char *options)
16962da59d7Smcr {
170*689fdc58Schristos const char *oli; /* option letter list index */
1716dfafca1Schristos int optchar;
17262da59d7Smcr
173b48252f3Slukem _DIAGASSERT(nargv != NULL);
1746dfafca1Schristos _DIAGASSERT(options != NULL);
175b48252f3Slukem
1766dfafca1Schristos optarg = NULL;
1776dfafca1Schristos
178a3fe3d3cSthorpej /*
179a3fe3d3cSthorpej * XXX Some programs (like rsyncd) expect to be able to
180a3fe3d3cSthorpej * XXX re-initialize optind to 0 and have getopt_long(3)
181a3fe3d3cSthorpej * XXX properly function again. Work around this braindamage.
182a3fe3d3cSthorpej */
183a3fe3d3cSthorpej if (optind == 0)
184a3fe3d3cSthorpej optind = 1;
185a3fe3d3cSthorpej
1866dfafca1Schristos if (optreset)
1876dfafca1Schristos nonopt_start = nonopt_end = -1;
1886dfafca1Schristos start:
18962da59d7Smcr if (optreset || !*place) { /* update scanning pointer */
19062da59d7Smcr optreset = 0;
1916dfafca1Schristos if (optind >= nargc) { /* end of argument vector */
19262da59d7Smcr place = EMSG;
1936dfafca1Schristos if (nonopt_end != -1) {
1946dfafca1Schristos /* do permutation, if we have to */
1956dfafca1Schristos permute_args(nonopt_start, nonopt_end,
1966dfafca1Schristos optind, nargv);
1976dfafca1Schristos optind -= nonopt_end - nonopt_start;
19862da59d7Smcr }
1996dfafca1Schristos else if (nonopt_start != -1) {
20062da59d7Smcr /*
2016dfafca1Schristos * If we skipped non-options, set optind
2026dfafca1Schristos * to the first of them.
20362da59d7Smcr */
2046dfafca1Schristos optind = nonopt_start;
20562da59d7Smcr }
2066dfafca1Schristos nonopt_start = nonopt_end = -1;
2076dfafca1Schristos return -1;
2086dfafca1Schristos }
209e7775dbfSwiz if ((*(place = nargv[optind]) != '-')
210e7775dbfSwiz || (place[1] == '\0')) { /* found non-option */
2116dfafca1Schristos place = EMSG;
2126dfafca1Schristos if (IN_ORDER) {
2136dfafca1Schristos /*
2146dfafca1Schristos * GNU extension:
2156dfafca1Schristos * return non-option as argument to option 1
2166dfafca1Schristos */
2176dfafca1Schristos optarg = nargv[optind++];
2186dfafca1Schristos return INORDER;
2196dfafca1Schristos }
2206dfafca1Schristos if (!PERMUTE) {
2216dfafca1Schristos /*
2226dfafca1Schristos * if no permutation wanted, stop parsing
2236dfafca1Schristos * at first non-option
2246dfafca1Schristos */
2256dfafca1Schristos return -1;
2266dfafca1Schristos }
2276dfafca1Schristos /* do permutation */
2286dfafca1Schristos if (nonopt_start == -1)
2296dfafca1Schristos nonopt_start = optind;
2306dfafca1Schristos else if (nonopt_end != -1) {
2316dfafca1Schristos permute_args(nonopt_start, nonopt_end,
2326dfafca1Schristos optind, nargv);
2336dfafca1Schristos nonopt_start = optind -
2346dfafca1Schristos (nonopt_end - nonopt_start);
2356dfafca1Schristos nonopt_end = -1;
2366dfafca1Schristos }
2376dfafca1Schristos optind++;
2386dfafca1Schristos /* process next argument */
2396dfafca1Schristos goto start;
2406dfafca1Schristos }
2416dfafca1Schristos if (nonopt_start != -1 && nonopt_end == -1)
2426dfafca1Schristos nonopt_end = optind;
2436dfafca1Schristos if (place[1] && *++place == '-') { /* found "--" */
2446dfafca1Schristos place++;
2456dfafca1Schristos return -2;
2466dfafca1Schristos }
2476dfafca1Schristos }
2486dfafca1Schristos if ((optchar = (int)*place++) == (int)':' ||
2496dfafca1Schristos (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
2506dfafca1Schristos /* option letter unknown or ':' */
25162da59d7Smcr if (!*place)
25262da59d7Smcr ++optind;
2536dfafca1Schristos if (PRINT_ERROR)
254045f0427Snathanw warnx(illoptchar, optchar);
2556dfafca1Schristos optopt = optchar;
2566dfafca1Schristos return BADCH;
2576dfafca1Schristos }
2586dfafca1Schristos if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
2596dfafca1Schristos /* XXX: what if no long options provided (called by getopt)? */
2606dfafca1Schristos if (*place)
2616dfafca1Schristos return -2;
2626dfafca1Schristos
2636dfafca1Schristos if (++optind >= nargc) { /* no arg */
2646dfafca1Schristos place = EMSG;
2656dfafca1Schristos if (PRINT_ERROR)
266045f0427Snathanw warnx(recargchar, optchar);
2676dfafca1Schristos optopt = optchar;
2686dfafca1Schristos return BADARG;
2696dfafca1Schristos } else /* white space */
2706dfafca1Schristos place = nargv[optind];
2716dfafca1Schristos /*
2726dfafca1Schristos * Handle -W arg the same as --arg (which causes getopt to
2736dfafca1Schristos * stop parsing).
2746dfafca1Schristos */
2756dfafca1Schristos return -2;
2766dfafca1Schristos }
2776dfafca1Schristos if (*++oli != ':') { /* doesn't take argument */
2786dfafca1Schristos if (!*place)
2796dfafca1Schristos ++optind;
2806dfafca1Schristos } else { /* takes (optional) argument */
2816dfafca1Schristos optarg = NULL;
28262da59d7Smcr if (*place) /* no white space */
28303256c6eSchristos optarg = __UNCONST(place);
2846dfafca1Schristos /* XXX: disable test for :: if PC? (GNU doesn't) */
2856dfafca1Schristos else if (oli[1] != ':') { /* arg not optional */
2866dfafca1Schristos if (++optind >= nargc) { /* no arg */
28762da59d7Smcr place = EMSG;
2886dfafca1Schristos if (PRINT_ERROR)
289045f0427Snathanw warnx(recargchar, optchar);
2906dfafca1Schristos optopt = optchar;
2916dfafca1Schristos return BADARG;
2926dfafca1Schristos } else
29362da59d7Smcr optarg = nargv[optind];
2946dfafca1Schristos }
29562da59d7Smcr place = EMSG;
29662da59d7Smcr ++optind;
29762da59d7Smcr }
2986dfafca1Schristos /* dump back option letter */
2996dfafca1Schristos return optchar;
30062da59d7Smcr }
30162da59d7Smcr
3026dfafca1Schristos #ifdef REPLACE_GETOPT
30362da59d7Smcr /*
30462da59d7Smcr * getopt --
30562da59d7Smcr * Parse argc/argv argument vector.
3066dfafca1Schristos *
3076dfafca1Schristos * [eventually this will replace the real getopt]
30862da59d7Smcr */
30962da59d7Smcr int
getopt(int nargc,char * const * nargv,const char * options)3101c79b1c7Skamil getopt(int nargc, char * const *nargv, const char *options)
31162da59d7Smcr {
31262da59d7Smcr int retval;
31362da59d7Smcr
314c5b9e1ceSlukem _DIAGASSERT(nargv != NULL);
315c5b9e1ceSlukem _DIAGASSERT(options != NULL);
316c5b9e1ceSlukem
3179de32b7fSyamt retval = getopt_internal(nargc, __UNCONST(nargv), options);
3189de32b7fSyamt if (retval == -2) {
31962da59d7Smcr ++optind;
3206dfafca1Schristos /*
3216dfafca1Schristos * We found an option (--), so if we skipped non-options,
3226dfafca1Schristos * we have to permute.
3236dfafca1Schristos */
3246dfafca1Schristos if (nonopt_end != -1) {
3256dfafca1Schristos permute_args(nonopt_start, nonopt_end, optind,
326596fd566Skamil __UNCONST(nargv));
3276dfafca1Schristos optind -= nonopt_end - nonopt_start;
32862da59d7Smcr }
3296dfafca1Schristos nonopt_start = nonopt_end = -1;
3306dfafca1Schristos retval = -1;
3316dfafca1Schristos }
3326dfafca1Schristos return retval;
33362da59d7Smcr }
33462da59d7Smcr #endif
33562da59d7Smcr
33662da59d7Smcr /*
33762da59d7Smcr * getopt_long --
33862da59d7Smcr * Parse argc/argv argument vector.
33962da59d7Smcr */
34062da59d7Smcr int
getopt_long(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx)341cc420b6cSjoerg getopt_long(int nargc, char * const *nargv, const char *options,
342cc420b6cSjoerg const struct option *long_options, int *idx)
34362da59d7Smcr {
34462da59d7Smcr int retval;
34562da59d7Smcr
34615b661abSginsbach #define IDENTICAL_INTERPRETATION(_x, _y) \
34715b661abSginsbach (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
34815b661abSginsbach long_options[(_x)].flag == long_options[(_y)].flag && \
34915b661abSginsbach long_options[(_x)].val == long_options[(_y)].val)
35015b661abSginsbach
351b48252f3Slukem _DIAGASSERT(nargv != NULL);
3526dfafca1Schristos _DIAGASSERT(options != NULL);
353b48252f3Slukem _DIAGASSERT(long_options != NULL);
3546dfafca1Schristos /* idx may be NULL */
355b48252f3Slukem
3569de32b7fSyamt retval = getopt_internal(nargc, __UNCONST(nargv), options);
3579de32b7fSyamt if (retval == -2) {
3586dfafca1Schristos char *current_argv, *has_equal;
3596dfafca1Schristos size_t current_argv_len;
36015b661abSginsbach int i, ambiguous, match;
36162da59d7Smcr
36203256c6eSchristos current_argv = __UNCONST(place);
3636dfafca1Schristos match = -1;
36415b661abSginsbach ambiguous = 0;
3656dfafca1Schristos
3666dfafca1Schristos optind++;
3676dfafca1Schristos place = EMSG;
3686dfafca1Schristos
3696dfafca1Schristos if (*current_argv == '\0') { /* found "--" */
3706dfafca1Schristos /*
3716dfafca1Schristos * We found an option (--), so if we skipped
3726dfafca1Schristos * non-options, we have to permute.
3736dfafca1Schristos */
3746dfafca1Schristos if (nonopt_end != -1) {
3756dfafca1Schristos permute_args(nonopt_start, nonopt_end,
3769de32b7fSyamt optind, __UNCONST(nargv));
3776dfafca1Schristos optind -= nonopt_end - nonopt_start;
3786dfafca1Schristos }
3796dfafca1Schristos nonopt_start = nonopt_end = -1;
3806dfafca1Schristos return -1;
38162da59d7Smcr }
38262da59d7Smcr if ((has_equal = strchr(current_argv, '=')) != NULL) {
3836dfafca1Schristos /* argument found (--option=arg) */
38462da59d7Smcr current_argv_len = has_equal - current_argv;
38562da59d7Smcr has_equal++;
38662da59d7Smcr } else
38762da59d7Smcr current_argv_len = strlen(current_argv);
38862da59d7Smcr
38962da59d7Smcr for (i = 0; long_options[i].name; i++) {
3906dfafca1Schristos /* find matching long option */
3916dfafca1Schristos if (strncmp(current_argv, long_options[i].name,
3926dfafca1Schristos current_argv_len))
39362da59d7Smcr continue;
39462da59d7Smcr
3956dfafca1Schristos if (strlen(long_options[i].name) ==
3966dfafca1Schristos (unsigned)current_argv_len) {
3976dfafca1Schristos /* exact match */
39862da59d7Smcr match = i;
39915b661abSginsbach ambiguous = 0;
40062da59d7Smcr break;
40162da59d7Smcr }
4026dfafca1Schristos if (match == -1) /* partial match */
40362da59d7Smcr match = i;
40415b661abSginsbach else if (!IDENTICAL_INTERPRETATION(i, match))
40515b661abSginsbach ambiguous = 1;
40615b661abSginsbach }
40715b661abSginsbach if (ambiguous) {
4086dfafca1Schristos /* ambiguous abbreviation */
4096dfafca1Schristos if (PRINT_ERROR)
410ac7a8f6bSsommerfeld warnx(ambig, (int)current_argv_len,
4116dfafca1Schristos current_argv);
4126dfafca1Schristos optopt = 0;
4136dfafca1Schristos return BADCH;
41462da59d7Smcr }
4156dfafca1Schristos if (match != -1) { /* option found */
4166dfafca1Schristos if (long_options[match].has_arg == no_argument
4176dfafca1Schristos && has_equal) {
4186dfafca1Schristos if (PRINT_ERROR)
419ac7a8f6bSsommerfeld warnx(noarg, (int)current_argv_len,
4206dfafca1Schristos current_argv);
4216dfafca1Schristos /*
4226dfafca1Schristos * XXX: GNU sets optopt to val regardless of
4236dfafca1Schristos * flag
4246dfafca1Schristos */
4256dfafca1Schristos if (long_options[match].flag == NULL)
4266dfafca1Schristos optopt = long_options[match].val;
4276dfafca1Schristos else
4286dfafca1Schristos optopt = 0;
4296dfafca1Schristos return BADARG;
4306dfafca1Schristos }
43162da59d7Smcr if (long_options[match].has_arg == required_argument ||
43262da59d7Smcr long_options[match].has_arg == optional_argument) {
43362da59d7Smcr if (has_equal)
43462da59d7Smcr optarg = has_equal;
4356dfafca1Schristos else if (long_options[match].has_arg ==
4366dfafca1Schristos required_argument) {
4376dfafca1Schristos /*
4386dfafca1Schristos * optional argument doesn't use
4396dfafca1Schristos * next nargv
4406dfafca1Schristos */
44162da59d7Smcr optarg = nargv[optind++];
44262da59d7Smcr }
4436dfafca1Schristos }
44462da59d7Smcr if ((long_options[match].has_arg == required_argument)
44562da59d7Smcr && (optarg == NULL)) {
44662da59d7Smcr /*
4476dfafca1Schristos * Missing argument; leading ':'
44862da59d7Smcr * indicates no error should be generated
44962da59d7Smcr */
4506dfafca1Schristos if (PRINT_ERROR)
451045f0427Snathanw warnx(recargstring, current_argv);
4526dfafca1Schristos /*
4536dfafca1Schristos * XXX: GNU sets optopt to val regardless
4546dfafca1Schristos * of flag
4556dfafca1Schristos */
4566dfafca1Schristos if (long_options[match].flag == NULL)
4576dfafca1Schristos optopt = long_options[match].val;
4586dfafca1Schristos else
4596dfafca1Schristos optopt = 0;
4606dfafca1Schristos --optind;
4616dfafca1Schristos return BADARG;
46262da59d7Smcr }
4636dfafca1Schristos } else { /* unknown option */
4646dfafca1Schristos if (PRINT_ERROR)
465045f0427Snathanw warnx(illoptstring, current_argv);
4666dfafca1Schristos optopt = 0;
4676dfafca1Schristos return BADCH;
46862da59d7Smcr }
46962da59d7Smcr if (long_options[match].flag) {
47062da59d7Smcr *long_options[match].flag = long_options[match].val;
47162da59d7Smcr retval = 0;
47262da59d7Smcr } else
47362da59d7Smcr retval = long_options[match].val;
4746dfafca1Schristos if (idx)
4756dfafca1Schristos *idx = match;
47662da59d7Smcr }
4776dfafca1Schristos return retval;
47815b661abSginsbach #undef IDENTICAL_INTERPRETATION
47962da59d7Smcr }
480