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