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