1*a35a7e76SEric Melville /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ 2*a35a7e76SEric Melville /* $FreeBSD$ */ 3*a35a7e76SEric Melville 4*a35a7e76SEric Melville /*- 5*a35a7e76SEric Melville * Copyright (c) 2000 The NetBSD Foundation, Inc. 6*a35a7e76SEric Melville * All rights reserved. 7*a35a7e76SEric Melville * 8*a35a7e76SEric Melville * This code is derived from software contributed to The NetBSD Foundation 9*a35a7e76SEric Melville * by Dieter Baron and Thomas Klausner. 10*a35a7e76SEric Melville * 11*a35a7e76SEric Melville * Redistribution and use in source and binary forms, with or without 12*a35a7e76SEric Melville * modification, are permitted provided that the following conditions 13*a35a7e76SEric Melville * are met: 14*a35a7e76SEric Melville * 1. Redistributions of source code must retain the above copyright 15*a35a7e76SEric Melville * notice, this list of conditions and the following disclaimer. 16*a35a7e76SEric Melville * 2. Redistributions in binary form must reproduce the above copyright 17*a35a7e76SEric Melville * notice, this list of conditions and the following disclaimer in the 18*a35a7e76SEric Melville * documentation and/or other materials provided with the distribution. 19*a35a7e76SEric Melville * 3. All advertising materials mentioning features or use of this software 20*a35a7e76SEric Melville * must display the following acknowledgement: 21*a35a7e76SEric Melville * This product includes software developed by the NetBSD 22*a35a7e76SEric Melville * Foundation, Inc. and its contributors. 23*a35a7e76SEric Melville * 4. Neither the name of The NetBSD Foundation nor the names of its 24*a35a7e76SEric Melville * contributors may be used to endorse or promote products derived 25*a35a7e76SEric Melville * from this software without specific prior written permission. 26*a35a7e76SEric Melville * 27*a35a7e76SEric Melville * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28*a35a7e76SEric Melville * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29*a35a7e76SEric Melville * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30*a35a7e76SEric Melville * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31*a35a7e76SEric Melville * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32*a35a7e76SEric Melville * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33*a35a7e76SEric Melville * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34*a35a7e76SEric Melville * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35*a35a7e76SEric Melville * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36*a35a7e76SEric Melville * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37*a35a7e76SEric Melville * POSSIBILITY OF SUCH DAMAGE. 38*a35a7e76SEric Melville */ 39*a35a7e76SEric Melville 40*a35a7e76SEric Melville #include <sys/cdefs.h> 41*a35a7e76SEric Melville #if defined(LIBC_SCCS) && !defined(lint) 42*a35a7e76SEric Melville __RCSID("$NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $"); 43*a35a7e76SEric Melville #endif /* LIBC_SCCS and not lint */ 44*a35a7e76SEric Melville 45*a35a7e76SEric Melville #include "namespace.h" 46*a35a7e76SEric Melville 47*a35a7e76SEric Melville #include <assert.h> 48*a35a7e76SEric Melville #include <err.h> 49*a35a7e76SEric Melville #include <errno.h> 50*a35a7e76SEric Melville #include <getopt.h> 51*a35a7e76SEric Melville #include <stdlib.h> 52*a35a7e76SEric Melville #include <string.h> 53*a35a7e76SEric Melville 54*a35a7e76SEric Melville /* not part of the original file */ 55*a35a7e76SEric Melville #ifndef _DIAGASSERT 56*a35a7e76SEric Melville #define _DIAGASSERT(X) 57*a35a7e76SEric Melville #endif 58*a35a7e76SEric Melville 59*a35a7e76SEric Melville #if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND 60*a35a7e76SEric Melville #define REPLACE_GETOPT 61*a35a7e76SEric Melville #endif 62*a35a7e76SEric Melville 63*a35a7e76SEric Melville #ifdef REPLACE_GETOPT 64*a35a7e76SEric Melville #ifdef __weak_alias 65*a35a7e76SEric Melville __weak_alias(getopt,_getopt) 66*a35a7e76SEric Melville #endif 67*a35a7e76SEric Melville int opterr = 1; /* if error message should be printed */ 68*a35a7e76SEric Melville int optind = 1; /* index into parent argv vector */ 69*a35a7e76SEric Melville int optopt = '?'; /* character checked for validity */ 70*a35a7e76SEric Melville int optreset; /* reset getopt */ 71*a35a7e76SEric Melville char *optarg; /* argument associated with option */ 72*a35a7e76SEric Melville #elif HAVE_CONFIG_H && !HAVE_DECL_OPTRESET 73*a35a7e76SEric Melville static int optreset; 74*a35a7e76SEric Melville #endif 75*a35a7e76SEric Melville 76*a35a7e76SEric Melville #ifdef __weak_alias 77*a35a7e76SEric Melville __weak_alias(getopt_long,_getopt_long) 78*a35a7e76SEric Melville #endif 79*a35a7e76SEric Melville 80*a35a7e76SEric Melville #if !HAVE_GETOPT_LONG 81*a35a7e76SEric Melville #define IGNORE_FIRST (*options == '-' || *options == '+') 82*a35a7e76SEric Melville #define PRINT_ERROR ((opterr) && ((*options != ':') \ 83*a35a7e76SEric Melville || (IGNORE_FIRST && options[1] != ':'))) 84*a35a7e76SEric Melville #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) 85*a35a7e76SEric Melville #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) 86*a35a7e76SEric Melville /* XXX: GNU ignores PC if *options == '-' */ 87*a35a7e76SEric Melville #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') 88*a35a7e76SEric Melville 89*a35a7e76SEric Melville /* return values */ 90*a35a7e76SEric Melville #define BADCH (int)'?' 91*a35a7e76SEric Melville #define BADARG ((IGNORE_FIRST && options[1] == ':') \ 92*a35a7e76SEric Melville || (*options == ':') ? (int)':' : (int)'?') 93*a35a7e76SEric Melville #define INORDER (int)1 94*a35a7e76SEric Melville 95*a35a7e76SEric Melville #define EMSG "" 96*a35a7e76SEric Melville 97*a35a7e76SEric Melville static int getopt_internal __P((int, char * const *, const char *)); 98*a35a7e76SEric Melville static int gcd __P((int, int)); 99*a35a7e76SEric Melville static void permute_args __P((int, int, int, char * const *)); 100*a35a7e76SEric Melville 101*a35a7e76SEric Melville static char *place = EMSG; /* option letter processing */ 102*a35a7e76SEric Melville 103*a35a7e76SEric Melville /* XXX: set optreset to 1 rather than these two */ 104*a35a7e76SEric Melville static int nonopt_start = -1; /* first non option argument (for permute) */ 105*a35a7e76SEric Melville static int nonopt_end = -1; /* first option after non options (for permute) */ 106*a35a7e76SEric Melville 107*a35a7e76SEric Melville /* Error messages */ 108*a35a7e76SEric Melville static const char recargchar[] = "option requires an argument -- %c"; 109*a35a7e76SEric Melville static const char recargstring[] = "option requires an argument -- %s"; 110*a35a7e76SEric Melville static const char ambig[] = "ambiguous option -- %.*s"; 111*a35a7e76SEric Melville static const char noarg[] = "option doesn't take an argument -- %.*s"; 112*a35a7e76SEric Melville static const char illoptchar[] = "unknown option -- %c"; 113*a35a7e76SEric Melville static const char illoptstring[] = "unknown option -- %s"; 114*a35a7e76SEric Melville 115*a35a7e76SEric Melville 116*a35a7e76SEric Melville /* 117*a35a7e76SEric Melville * Compute the greatest common divisor of a and b. 118*a35a7e76SEric Melville */ 119*a35a7e76SEric Melville static int 120*a35a7e76SEric Melville gcd(a, b) 121*a35a7e76SEric Melville int a; 122*a35a7e76SEric Melville int b; 123*a35a7e76SEric Melville { 124*a35a7e76SEric Melville int c; 125*a35a7e76SEric Melville 126*a35a7e76SEric Melville c = a % b; 127*a35a7e76SEric Melville while (c != 0) { 128*a35a7e76SEric Melville a = b; 129*a35a7e76SEric Melville b = c; 130*a35a7e76SEric Melville c = a % b; 131*a35a7e76SEric Melville } 132*a35a7e76SEric Melville 133*a35a7e76SEric Melville return b; 134*a35a7e76SEric Melville } 135*a35a7e76SEric Melville 136*a35a7e76SEric Melville /* 137*a35a7e76SEric Melville * Exchange the block from nonopt_start to nonopt_end with the block 138*a35a7e76SEric Melville * from nonopt_end to opt_end (keeping the same order of arguments 139*a35a7e76SEric Melville * in each block). 140*a35a7e76SEric Melville */ 141*a35a7e76SEric Melville static void 142*a35a7e76SEric Melville permute_args(panonopt_start, panonopt_end, opt_end, nargv) 143*a35a7e76SEric Melville int panonopt_start; 144*a35a7e76SEric Melville int panonopt_end; 145*a35a7e76SEric Melville int opt_end; 146*a35a7e76SEric Melville char * const *nargv; 147*a35a7e76SEric Melville { 148*a35a7e76SEric Melville int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; 149*a35a7e76SEric Melville char *swap; 150*a35a7e76SEric Melville 151*a35a7e76SEric Melville _DIAGASSERT(nargv != NULL); 152*a35a7e76SEric Melville 153*a35a7e76SEric Melville /* 154*a35a7e76SEric Melville * compute lengths of blocks and number and size of cycles 155*a35a7e76SEric Melville */ 156*a35a7e76SEric Melville nnonopts = panonopt_end - panonopt_start; 157*a35a7e76SEric Melville nopts = opt_end - panonopt_end; 158*a35a7e76SEric Melville ncycle = gcd(nnonopts, nopts); 159*a35a7e76SEric Melville cyclelen = (opt_end - panonopt_start) / ncycle; 160*a35a7e76SEric Melville 161*a35a7e76SEric Melville for (i = 0; i < ncycle; i++) { 162*a35a7e76SEric Melville cstart = panonopt_end+i; 163*a35a7e76SEric Melville pos = cstart; 164*a35a7e76SEric Melville for (j = 0; j < cyclelen; j++) { 165*a35a7e76SEric Melville if (pos >= panonopt_end) 166*a35a7e76SEric Melville pos -= nnonopts; 167*a35a7e76SEric Melville else 168*a35a7e76SEric Melville pos += nopts; 169*a35a7e76SEric Melville swap = nargv[pos]; 170*a35a7e76SEric Melville /* LINTED const cast */ 171*a35a7e76SEric Melville ((char **) nargv)[pos] = nargv[cstart]; 172*a35a7e76SEric Melville /* LINTED const cast */ 173*a35a7e76SEric Melville ((char **)nargv)[cstart] = swap; 174*a35a7e76SEric Melville } 175*a35a7e76SEric Melville } 176*a35a7e76SEric Melville } 177*a35a7e76SEric Melville 178*a35a7e76SEric Melville /* 179*a35a7e76SEric Melville * getopt_internal -- 180*a35a7e76SEric Melville * Parse argc/argv argument vector. Called by user level routines. 181*a35a7e76SEric Melville * Returns -2 if -- is found (can be long option or end of options marker). 182*a35a7e76SEric Melville */ 183*a35a7e76SEric Melville static int 184*a35a7e76SEric Melville getopt_internal(nargc, nargv, options) 185*a35a7e76SEric Melville int nargc; 186*a35a7e76SEric Melville char * const *nargv; 187*a35a7e76SEric Melville const char *options; 188*a35a7e76SEric Melville { 189*a35a7e76SEric Melville char *oli; /* option letter list index */ 190*a35a7e76SEric Melville int optchar; 191*a35a7e76SEric Melville 192*a35a7e76SEric Melville _DIAGASSERT(nargv != NULL); 193*a35a7e76SEric Melville _DIAGASSERT(options != NULL); 194*a35a7e76SEric Melville 195*a35a7e76SEric Melville optarg = NULL; 196*a35a7e76SEric Melville 197*a35a7e76SEric Melville /* 198*a35a7e76SEric Melville * XXX Some programs (like rsyncd) expect to be able to 199*a35a7e76SEric Melville * XXX re-initialize optind to 0 and have getopt_long(3) 200*a35a7e76SEric Melville * XXX properly function again. Work around this braindamage. 201*a35a7e76SEric Melville */ 202*a35a7e76SEric Melville if (optind == 0) 203*a35a7e76SEric Melville optind = 1; 204*a35a7e76SEric Melville 205*a35a7e76SEric Melville if (optreset) 206*a35a7e76SEric Melville nonopt_start = nonopt_end = -1; 207*a35a7e76SEric Melville start: 208*a35a7e76SEric Melville if (optreset || !*place) { /* update scanning pointer */ 209*a35a7e76SEric Melville optreset = 0; 210*a35a7e76SEric Melville if (optind >= nargc) { /* end of argument vector */ 211*a35a7e76SEric Melville place = EMSG; 212*a35a7e76SEric Melville if (nonopt_end != -1) { 213*a35a7e76SEric Melville /* do permutation, if we have to */ 214*a35a7e76SEric Melville permute_args(nonopt_start, nonopt_end, 215*a35a7e76SEric Melville optind, nargv); 216*a35a7e76SEric Melville optind -= nonopt_end - nonopt_start; 217*a35a7e76SEric Melville } 218*a35a7e76SEric Melville else if (nonopt_start != -1) { 219*a35a7e76SEric Melville /* 220*a35a7e76SEric Melville * If we skipped non-options, set optind 221*a35a7e76SEric Melville * to the first of them. 222*a35a7e76SEric Melville */ 223*a35a7e76SEric Melville optind = nonopt_start; 224*a35a7e76SEric Melville } 225*a35a7e76SEric Melville nonopt_start = nonopt_end = -1; 226*a35a7e76SEric Melville return -1; 227*a35a7e76SEric Melville } 228*a35a7e76SEric Melville if ((*(place = nargv[optind]) != '-') 229*a35a7e76SEric Melville || (place[1] == '\0')) { /* found non-option */ 230*a35a7e76SEric Melville place = EMSG; 231*a35a7e76SEric Melville if (IN_ORDER) { 232*a35a7e76SEric Melville /* 233*a35a7e76SEric Melville * GNU extension: 234*a35a7e76SEric Melville * return non-option as argument to option 1 235*a35a7e76SEric Melville */ 236*a35a7e76SEric Melville optarg = nargv[optind++]; 237*a35a7e76SEric Melville return INORDER; 238*a35a7e76SEric Melville } 239*a35a7e76SEric Melville if (!PERMUTE) { 240*a35a7e76SEric Melville /* 241*a35a7e76SEric Melville * if no permutation wanted, stop parsing 242*a35a7e76SEric Melville * at first non-option 243*a35a7e76SEric Melville */ 244*a35a7e76SEric Melville return -1; 245*a35a7e76SEric Melville } 246*a35a7e76SEric Melville /* do permutation */ 247*a35a7e76SEric Melville if (nonopt_start == -1) 248*a35a7e76SEric Melville nonopt_start = optind; 249*a35a7e76SEric Melville else if (nonopt_end != -1) { 250*a35a7e76SEric Melville permute_args(nonopt_start, nonopt_end, 251*a35a7e76SEric Melville optind, nargv); 252*a35a7e76SEric Melville nonopt_start = optind - 253*a35a7e76SEric Melville (nonopt_end - nonopt_start); 254*a35a7e76SEric Melville nonopt_end = -1; 255*a35a7e76SEric Melville } 256*a35a7e76SEric Melville optind++; 257*a35a7e76SEric Melville /* process next argument */ 258*a35a7e76SEric Melville goto start; 259*a35a7e76SEric Melville } 260*a35a7e76SEric Melville if (nonopt_start != -1 && nonopt_end == -1) 261*a35a7e76SEric Melville nonopt_end = optind; 262*a35a7e76SEric Melville if (place[1] && *++place == '-') { /* found "--" */ 263*a35a7e76SEric Melville place++; 264*a35a7e76SEric Melville return -2; 265*a35a7e76SEric Melville } 266*a35a7e76SEric Melville } 267*a35a7e76SEric Melville if ((optchar = (int)*place++) == (int)':' || 268*a35a7e76SEric Melville (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { 269*a35a7e76SEric Melville /* option letter unknown or ':' */ 270*a35a7e76SEric Melville if (!*place) 271*a35a7e76SEric Melville ++optind; 272*a35a7e76SEric Melville if (PRINT_ERROR) 273*a35a7e76SEric Melville warnx(illoptchar, optchar); 274*a35a7e76SEric Melville optopt = optchar; 275*a35a7e76SEric Melville return BADCH; 276*a35a7e76SEric Melville } 277*a35a7e76SEric Melville if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ 278*a35a7e76SEric Melville /* XXX: what if no long options provided (called by getopt)? */ 279*a35a7e76SEric Melville if (*place) 280*a35a7e76SEric Melville return -2; 281*a35a7e76SEric Melville 282*a35a7e76SEric Melville if (++optind >= nargc) { /* no arg */ 283*a35a7e76SEric Melville place = EMSG; 284*a35a7e76SEric Melville if (PRINT_ERROR) 285*a35a7e76SEric Melville warnx(recargchar, optchar); 286*a35a7e76SEric Melville optopt = optchar; 287*a35a7e76SEric Melville return BADARG; 288*a35a7e76SEric Melville } else /* white space */ 289*a35a7e76SEric Melville place = nargv[optind]; 290*a35a7e76SEric Melville /* 291*a35a7e76SEric Melville * Handle -W arg the same as --arg (which causes getopt to 292*a35a7e76SEric Melville * stop parsing). 293*a35a7e76SEric Melville */ 294*a35a7e76SEric Melville return -2; 295*a35a7e76SEric Melville } 296*a35a7e76SEric Melville if (*++oli != ':') { /* doesn't take argument */ 297*a35a7e76SEric Melville if (!*place) 298*a35a7e76SEric Melville ++optind; 299*a35a7e76SEric Melville } else { /* takes (optional) argument */ 300*a35a7e76SEric Melville optarg = NULL; 301*a35a7e76SEric Melville if (*place) /* no white space */ 302*a35a7e76SEric Melville optarg = place; 303*a35a7e76SEric Melville /* XXX: disable test for :: if PC? (GNU doesn't) */ 304*a35a7e76SEric Melville else if (oli[1] != ':') { /* arg not optional */ 305*a35a7e76SEric Melville if (++optind >= nargc) { /* no arg */ 306*a35a7e76SEric Melville place = EMSG; 307*a35a7e76SEric Melville if (PRINT_ERROR) 308*a35a7e76SEric Melville warnx(recargchar, optchar); 309*a35a7e76SEric Melville optopt = optchar; 310*a35a7e76SEric Melville return BADARG; 311*a35a7e76SEric Melville } else 312*a35a7e76SEric Melville optarg = nargv[optind]; 313*a35a7e76SEric Melville } 314*a35a7e76SEric Melville place = EMSG; 315*a35a7e76SEric Melville ++optind; 316*a35a7e76SEric Melville } 317*a35a7e76SEric Melville /* dump back option letter */ 318*a35a7e76SEric Melville return optchar; 319*a35a7e76SEric Melville } 320*a35a7e76SEric Melville 321*a35a7e76SEric Melville #ifdef REPLACE_GETOPT 322*a35a7e76SEric Melville /* 323*a35a7e76SEric Melville * getopt -- 324*a35a7e76SEric Melville * Parse argc/argv argument vector. 325*a35a7e76SEric Melville * 326*a35a7e76SEric Melville * [eventually this will replace the real getopt] 327*a35a7e76SEric Melville */ 328*a35a7e76SEric Melville int 329*a35a7e76SEric Melville getopt(nargc, nargv, options) 330*a35a7e76SEric Melville int nargc; 331*a35a7e76SEric Melville char * const *nargv; 332*a35a7e76SEric Melville const char *options; 333*a35a7e76SEric Melville { 334*a35a7e76SEric Melville int retval; 335*a35a7e76SEric Melville 336*a35a7e76SEric Melville _DIAGASSERT(nargv != NULL); 337*a35a7e76SEric Melville _DIAGASSERT(options != NULL); 338*a35a7e76SEric Melville 339*a35a7e76SEric Melville if ((retval = getopt_internal(nargc, nargv, options)) == -2) { 340*a35a7e76SEric Melville ++optind; 341*a35a7e76SEric Melville /* 342*a35a7e76SEric Melville * We found an option (--), so if we skipped non-options, 343*a35a7e76SEric Melville * we have to permute. 344*a35a7e76SEric Melville */ 345*a35a7e76SEric Melville if (nonopt_end != -1) { 346*a35a7e76SEric Melville permute_args(nonopt_start, nonopt_end, optind, 347*a35a7e76SEric Melville nargv); 348*a35a7e76SEric Melville optind -= nonopt_end - nonopt_start; 349*a35a7e76SEric Melville } 350*a35a7e76SEric Melville nonopt_start = nonopt_end = -1; 351*a35a7e76SEric Melville retval = -1; 352*a35a7e76SEric Melville } 353*a35a7e76SEric Melville return retval; 354*a35a7e76SEric Melville } 355*a35a7e76SEric Melville #endif 356*a35a7e76SEric Melville 357*a35a7e76SEric Melville /* 358*a35a7e76SEric Melville * getopt_long -- 359*a35a7e76SEric Melville * Parse argc/argv argument vector. 360*a35a7e76SEric Melville */ 361*a35a7e76SEric Melville int 362*a35a7e76SEric Melville getopt_long(nargc, nargv, options, long_options, idx) 363*a35a7e76SEric Melville int nargc; 364*a35a7e76SEric Melville char * const *nargv; 365*a35a7e76SEric Melville const char *options; 366*a35a7e76SEric Melville const struct option *long_options; 367*a35a7e76SEric Melville int *idx; 368*a35a7e76SEric Melville { 369*a35a7e76SEric Melville int retval; 370*a35a7e76SEric Melville 371*a35a7e76SEric Melville _DIAGASSERT(nargv != NULL); 372*a35a7e76SEric Melville _DIAGASSERT(options != NULL); 373*a35a7e76SEric Melville _DIAGASSERT(long_options != NULL); 374*a35a7e76SEric Melville /* idx may be NULL */ 375*a35a7e76SEric Melville 376*a35a7e76SEric Melville if ((retval = getopt_internal(nargc, nargv, options)) == -2) { 377*a35a7e76SEric Melville char *current_argv, *has_equal; 378*a35a7e76SEric Melville size_t current_argv_len; 379*a35a7e76SEric Melville int i, match; 380*a35a7e76SEric Melville 381*a35a7e76SEric Melville current_argv = place; 382*a35a7e76SEric Melville match = -1; 383*a35a7e76SEric Melville 384*a35a7e76SEric Melville optind++; 385*a35a7e76SEric Melville place = EMSG; 386*a35a7e76SEric Melville 387*a35a7e76SEric Melville if (*current_argv == '\0') { /* found "--" */ 388*a35a7e76SEric Melville /* 389*a35a7e76SEric Melville * We found an option (--), so if we skipped 390*a35a7e76SEric Melville * non-options, we have to permute. 391*a35a7e76SEric Melville */ 392*a35a7e76SEric Melville if (nonopt_end != -1) { 393*a35a7e76SEric Melville permute_args(nonopt_start, nonopt_end, 394*a35a7e76SEric Melville optind, nargv); 395*a35a7e76SEric Melville optind -= nonopt_end - nonopt_start; 396*a35a7e76SEric Melville } 397*a35a7e76SEric Melville nonopt_start = nonopt_end = -1; 398*a35a7e76SEric Melville return -1; 399*a35a7e76SEric Melville } 400*a35a7e76SEric Melville if ((has_equal = strchr(current_argv, '=')) != NULL) { 401*a35a7e76SEric Melville /* argument found (--option=arg) */ 402*a35a7e76SEric Melville current_argv_len = has_equal - current_argv; 403*a35a7e76SEric Melville has_equal++; 404*a35a7e76SEric Melville } else 405*a35a7e76SEric Melville current_argv_len = strlen(current_argv); 406*a35a7e76SEric Melville 407*a35a7e76SEric Melville for (i = 0; long_options[i].name; i++) { 408*a35a7e76SEric Melville /* find matching long option */ 409*a35a7e76SEric Melville if (strncmp(current_argv, long_options[i].name, 410*a35a7e76SEric Melville current_argv_len)) 411*a35a7e76SEric Melville continue; 412*a35a7e76SEric Melville 413*a35a7e76SEric Melville if (strlen(long_options[i].name) == 414*a35a7e76SEric Melville (unsigned)current_argv_len) { 415*a35a7e76SEric Melville /* exact match */ 416*a35a7e76SEric Melville match = i; 417*a35a7e76SEric Melville break; 418*a35a7e76SEric Melville } 419*a35a7e76SEric Melville if (match == -1) /* partial match */ 420*a35a7e76SEric Melville match = i; 421*a35a7e76SEric Melville else { 422*a35a7e76SEric Melville /* ambiguous abbreviation */ 423*a35a7e76SEric Melville if (PRINT_ERROR) 424*a35a7e76SEric Melville warnx(ambig, (int)current_argv_len, 425*a35a7e76SEric Melville current_argv); 426*a35a7e76SEric Melville optopt = 0; 427*a35a7e76SEric Melville return BADCH; 428*a35a7e76SEric Melville } 429*a35a7e76SEric Melville } 430*a35a7e76SEric Melville if (match != -1) { /* option found */ 431*a35a7e76SEric Melville if (long_options[match].has_arg == no_argument 432*a35a7e76SEric Melville && has_equal) { 433*a35a7e76SEric Melville if (PRINT_ERROR) 434*a35a7e76SEric Melville warnx(noarg, (int)current_argv_len, 435*a35a7e76SEric Melville current_argv); 436*a35a7e76SEric Melville /* 437*a35a7e76SEric Melville * XXX: GNU sets optopt to val regardless of 438*a35a7e76SEric Melville * flag 439*a35a7e76SEric Melville */ 440*a35a7e76SEric Melville if (long_options[match].flag == NULL) 441*a35a7e76SEric Melville optopt = long_options[match].val; 442*a35a7e76SEric Melville else 443*a35a7e76SEric Melville optopt = 0; 444*a35a7e76SEric Melville return BADARG; 445*a35a7e76SEric Melville } 446*a35a7e76SEric Melville if (long_options[match].has_arg == required_argument || 447*a35a7e76SEric Melville long_options[match].has_arg == optional_argument) { 448*a35a7e76SEric Melville if (has_equal) 449*a35a7e76SEric Melville optarg = has_equal; 450*a35a7e76SEric Melville else if (long_options[match].has_arg == 451*a35a7e76SEric Melville required_argument) { 452*a35a7e76SEric Melville /* 453*a35a7e76SEric Melville * optional argument doesn't use 454*a35a7e76SEric Melville * next nargv 455*a35a7e76SEric Melville */ 456*a35a7e76SEric Melville optarg = nargv[optind++]; 457*a35a7e76SEric Melville } 458*a35a7e76SEric Melville } 459*a35a7e76SEric Melville if ((long_options[match].has_arg == required_argument) 460*a35a7e76SEric Melville && (optarg == NULL)) { 461*a35a7e76SEric Melville /* 462*a35a7e76SEric Melville * Missing argument; leading ':' 463*a35a7e76SEric Melville * indicates no error should be generated 464*a35a7e76SEric Melville */ 465*a35a7e76SEric Melville if (PRINT_ERROR) 466*a35a7e76SEric Melville warnx(recargstring, current_argv); 467*a35a7e76SEric Melville /* 468*a35a7e76SEric Melville * XXX: GNU sets optopt to val regardless 469*a35a7e76SEric Melville * of flag 470*a35a7e76SEric Melville */ 471*a35a7e76SEric Melville if (long_options[match].flag == NULL) 472*a35a7e76SEric Melville optopt = long_options[match].val; 473*a35a7e76SEric Melville else 474*a35a7e76SEric Melville optopt = 0; 475*a35a7e76SEric Melville --optind; 476*a35a7e76SEric Melville return BADARG; 477*a35a7e76SEric Melville } 478*a35a7e76SEric Melville } else { /* unknown option */ 479*a35a7e76SEric Melville if (PRINT_ERROR) 480*a35a7e76SEric Melville warnx(illoptstring, current_argv); 481*a35a7e76SEric Melville optopt = 0; 482*a35a7e76SEric Melville return BADCH; 483*a35a7e76SEric Melville } 484*a35a7e76SEric Melville if (long_options[match].flag) { 485*a35a7e76SEric Melville *long_options[match].flag = long_options[match].val; 486*a35a7e76SEric Melville retval = 0; 487*a35a7e76SEric Melville } else 488*a35a7e76SEric Melville retval = long_options[match].val; 489*a35a7e76SEric Melville if (idx) 490*a35a7e76SEric Melville *idx = match; 491*a35a7e76SEric Melville } 492*a35a7e76SEric Melville return retval; 493*a35a7e76SEric Melville } 494*a35a7e76SEric Melville #endif /* !GETOPT_LONG */ 495