1276761Sdelphij/* $OpenBSD: getopt_long.c,v 1.22 2006/10/04 21:29:04 jmc Exp $ */ 2276761Sdelphij/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ 3276761Sdelphij 4276761Sdelphij/* 5276761Sdelphij * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com> 6276761Sdelphij * 7276761Sdelphij * Permission to use, copy, modify, and distribute this software for any 8276761Sdelphij * purpose with or without fee is hereby granted, provided that the above 9276761Sdelphij * copyright notice and this permission notice appear in all copies. 10276761Sdelphij * 11276761Sdelphij * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12276761Sdelphij * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13276761Sdelphij * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14276761Sdelphij * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15276761Sdelphij * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16276761Sdelphij * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17276761Sdelphij * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18276761Sdelphij * 19276761Sdelphij * Sponsored in part by the Defense Advanced Research Projects 20276761Sdelphij * Agency (DARPA) and Air Force Research Laboratory, Air Force 21276761Sdelphij * Materiel Command, USAF, under agreement number F39502-99-1-0512. 22276761Sdelphij */ 23276761Sdelphij/*- 24276761Sdelphij * Copyright (c) 2000 The NetBSD Foundation, Inc. 25276761Sdelphij * All rights reserved. 26276761Sdelphij * 27276761Sdelphij * This code is derived from software contributed to The NetBSD Foundation 28276761Sdelphij * by Dieter Baron and Thomas Klausner. 29276761Sdelphij * 30276761Sdelphij * Redistribution and use in source and binary forms, with or without 31276761Sdelphij * modification, are permitted provided that the following conditions 32276761Sdelphij * are met: 33276761Sdelphij * 1. Redistributions of source code must retain the above copyright 34276761Sdelphij * notice, this list of conditions and the following disclaimer. 35276761Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 36276761Sdelphij * notice, this list of conditions and the following disclaimer in the 37276761Sdelphij * documentation and/or other materials provided with the distribution. 38276761Sdelphij * 39276761Sdelphij * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 40276761Sdelphij * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 41276761Sdelphij * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42276761Sdelphij * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 43276761Sdelphij * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 44276761Sdelphij * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 45276761Sdelphij * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 46276761Sdelphij * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47276761Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 48276761Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 49276761Sdelphij * POSSIBILITY OF SUCH DAMAGE. 50276761Sdelphij */ 51276761Sdelphij 52276761Sdelphij 53276761Sdelphij#include <errno.h> 54276761Sdelphij#include "getopt_long.h" 55276761Sdelphij#include <stdlib.h> 56276761Sdelphij#include <stdio.h> 57276761Sdelphij#include <string.h> 58276761Sdelphij#include <stdarg.h> 59276761Sdelphij 60276761Sdelphij#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */ 61276761Sdelphij 62276761Sdelphij#define PRINT_ERROR ((opterr) && (*options != ':')) 63276761Sdelphij 64276761Sdelphij#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ 65276761Sdelphij#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ 66276761Sdelphij#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ 67276761Sdelphij 68276761Sdelphij/* return values */ 69276761Sdelphij#define BADCH (int)'?' 70276761Sdelphij#define BADARG ((*options == ':') ? (int)':' : (int)'?') 71276761Sdelphij#define INORDER (int)1 72276761Sdelphij 73276761Sdelphij#define EMSG "" 74276761Sdelphij 75276761Sdelphij#ifdef GNU_COMPATIBLE 76276761Sdelphij#define NO_PREFIX (-1) 77276761Sdelphij#define D_PREFIX 0 78276761Sdelphij#define DD_PREFIX 1 79276761Sdelphij#define W_PREFIX 2 80276761Sdelphij#endif 81276761Sdelphij 82276761Sdelphijchar *optarg; 83276761Sdelphijint optind, opterr = 1, optopt; 84276761Sdelphij 85276761Sdelphijstatic int getopt_internal(int, char * const *, const char *, 86276761Sdelphij const struct option *, int *, int); 87276761Sdelphijstatic int parse_long_options(char * const *, const char *, 88276761Sdelphij const struct option *, int *, int, int); 89276761Sdelphijstatic int gcd(int, int); 90276761Sdelphijstatic void permute_args(int, int, int, char * const *); 91276761Sdelphij 92276761Sdelphijstatic const char *place = EMSG; /* option letter processing */ 93276761Sdelphij 94276761Sdelphijstatic int nonopt_start = -1; /* first non option argument (for permute) */ 95276761Sdelphijstatic int nonopt_end = -1; /* first option after non options (for permute) */ 96276761Sdelphij 97276761Sdelphij/* Error messages */ 98276761Sdelphijstatic const char recargchar[] = "option requires an argument -- %c"; 99276761Sdelphijstatic const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */ 100276761Sdelphij#ifdef GNU_COMPATIBLE 101276761Sdelphijstatic int dash_prefix = NO_PREFIX; 102276761Sdelphijstatic const char gnuoptchar[] = "invalid option -- %c"; 103276761Sdelphij 104276761Sdelphijstatic const char recargstring[] = "option `%s%s' requires an argument"; 105276761Sdelphijstatic const char ambig[] = "option `%s%.*s' is ambiguous"; 106276761Sdelphijstatic const char noarg[] = "option `%s%.*s' doesn't allow an argument"; 107276761Sdelphijstatic const char illoptstring[] = "unrecognized option `%s%s'"; 108276761Sdelphij#else 109276761Sdelphijstatic const char recargstring[] = "option requires an argument -- %s"; 110276761Sdelphijstatic const char ambig[] = "ambiguous option -- %.*s"; 111276761Sdelphijstatic const char noarg[] = "option doesn't take an argument -- %.*s"; 112276761Sdelphijstatic const char illoptstring[] = "unknown option -- %s"; 113276761Sdelphij#endif 114276761Sdelphij 115276761Sdelphij/* 116276761Sdelphij * Compute the greatest common divisor of a and b. 117276761Sdelphij */ 118276761Sdelphijstatic int 119276761Sdelphijgcd(int a, int b) 120276761Sdelphij{ 121276761Sdelphij int c; 122276761Sdelphij 123276761Sdelphij c = a % b; 124276761Sdelphij while (c != 0) { 125276761Sdelphij a = b; 126276761Sdelphij b = c; 127276761Sdelphij c = a % b; 128276761Sdelphij } 129276761Sdelphij 130276761Sdelphij return (b); 131276761Sdelphij} 132276761Sdelphij 133276761Sdelphij/* 134276761Sdelphij * Exchange the block from nonopt_start to nonopt_end with the block 135276761Sdelphij * from nonopt_end to opt_end (keeping the same order of arguments 136276761Sdelphij * in each block). 137276761Sdelphij */ 138276761Sdelphijstatic void 139276761Sdelphijpermute_args(int panonopt_start, int panonopt_end, int opt_end, 140276761Sdelphij char * const *nargv) 141276761Sdelphij{ 142276761Sdelphij int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; 143276761Sdelphij char *swap; 144276761Sdelphij 145276761Sdelphij /* 146276761Sdelphij * compute lengths of blocks and number and size of cycles 147276761Sdelphij */ 148276761Sdelphij nnonopts = panonopt_end - panonopt_start; 149276761Sdelphij nopts = opt_end - panonopt_end; 150276761Sdelphij ncycle = gcd(nnonopts, nopts); 151276761Sdelphij cyclelen = (opt_end - panonopt_start) / ncycle; 152276761Sdelphij 153276761Sdelphij for (i = 0; i < ncycle; i++) { 154276761Sdelphij cstart = panonopt_end+i; 155276761Sdelphij pos = cstart; 156276761Sdelphij for (j = 0; j < cyclelen; j++) { 157276761Sdelphij if (pos >= panonopt_end) 158276761Sdelphij pos -= nnonopts; 159276761Sdelphij else 160276761Sdelphij pos += nopts; 161276761Sdelphij swap = nargv[pos]; 162276761Sdelphij /* LINTED const cast */ 163276761Sdelphij ((char **) nargv)[pos] = nargv[cstart]; 164276761Sdelphij /* LINTED const cast */ 165276761Sdelphij ((char **)nargv)[cstart] = swap; 166276761Sdelphij } 167276761Sdelphij } 168276761Sdelphij} 169276761Sdelphij 170276761Sdelphijstatic void 171276761Sdelphijwarnx(const char *fmt, ...) 172276761Sdelphij{ 173276761Sdelphij extern char *program_name; 174276761Sdelphij va_list ap; 175276761Sdelphij 176276761Sdelphij va_start(ap, fmt); 177276761Sdelphij fprintf(stderr, "%s: ", program_name); 178276761Sdelphij vfprintf(stderr, fmt, ap); 179276761Sdelphij fprintf(stderr, "\n"); 180276761Sdelphij va_end(ap); 181276761Sdelphij} 182276761Sdelphij 183276761Sdelphij/* 184276761Sdelphij * parse_long_options -- 185276761Sdelphij * Parse long options in argc/argv argument vector. 186276761Sdelphij * Returns -1 if short_too is set and the option does not match long_options. 187276761Sdelphij */ 188276761Sdelphijstatic int 189276761Sdelphijparse_long_options(char * const *nargv, const char *options, 190276761Sdelphij const struct option *long_options, int *idx, int short_too, int flags) 191276761Sdelphij{ 192276761Sdelphij const char *current_argv, *has_equal; 193276761Sdelphij#ifdef GNU_COMPATIBLE 194276761Sdelphij const char *current_dash; 195276761Sdelphij#endif 196276761Sdelphij size_t current_argv_len; 197276761Sdelphij int i, match, exact_match, second_partial_match; 198276761Sdelphij 199276761Sdelphij current_argv = place; 200276761Sdelphij#ifdef GNU_COMPATIBLE 201276761Sdelphij switch (dash_prefix) { 202276761Sdelphij case D_PREFIX: 203276761Sdelphij current_dash = "-"; 204276761Sdelphij break; 205276761Sdelphij case DD_PREFIX: 206276761Sdelphij current_dash = "--"; 207276761Sdelphij break; 208276761Sdelphij case W_PREFIX: 209276761Sdelphij current_dash = "-W "; 210276761Sdelphij break; 211276761Sdelphij default: 212276761Sdelphij current_dash = ""; 213276761Sdelphij break; 214276761Sdelphij } 215276761Sdelphij#endif 216276761Sdelphij match = -1; 217276761Sdelphij exact_match = 0; 218276761Sdelphij second_partial_match = 0; 219276761Sdelphij 220276761Sdelphij optind++; 221276761Sdelphij 222276761Sdelphij if ((has_equal = strchr(current_argv, '=')) != NULL) { 223276761Sdelphij /* argument found (--option=arg) */ 224276761Sdelphij current_argv_len = has_equal - current_argv; 225276761Sdelphij has_equal++; 226276761Sdelphij } else 227276761Sdelphij current_argv_len = strlen(current_argv); 228276761Sdelphij 229276761Sdelphij for (i = 0; long_options[i].name; i++) { 230276761Sdelphij /* find matching long option */ 231276761Sdelphij if (strncmp(current_argv, long_options[i].name, 232276761Sdelphij current_argv_len)) 233276761Sdelphij continue; 234276761Sdelphij 235276761Sdelphij if (strlen(long_options[i].name) == current_argv_len) { 236276761Sdelphij /* exact match */ 237276761Sdelphij match = i; 238276761Sdelphij exact_match = 1; 239276761Sdelphij break; 240276761Sdelphij } 241276761Sdelphij /* 242276761Sdelphij * If this is a known short option, don't allow 243276761Sdelphij * a partial match of a single character. 244276761Sdelphij */ 245276761Sdelphij if (short_too && current_argv_len == 1) 246276761Sdelphij continue; 247276761Sdelphij 248276761Sdelphij if (match == -1) /* first partial match */ 249276761Sdelphij match = i; 250276761Sdelphij else if ((flags & FLAG_LONGONLY) || 251276761Sdelphij long_options[i].has_arg != 252276761Sdelphij long_options[match].has_arg || 253276761Sdelphij long_options[i].flag != long_options[match].flag || 254276761Sdelphij long_options[i].val != long_options[match].val) 255276761Sdelphij second_partial_match = 1; 256276761Sdelphij } 257276761Sdelphij if (!exact_match && second_partial_match) { 258276761Sdelphij /* ambiguous abbreviation */ 259276761Sdelphij if (PRINT_ERROR) 260276761Sdelphij warnx(ambig, 261276761Sdelphij#ifdef GNU_COMPATIBLE 262276761Sdelphij current_dash, 263276761Sdelphij#endif 264276761Sdelphij (int)current_argv_len, 265276761Sdelphij current_argv); 266276761Sdelphij optopt = 0; 267276761Sdelphij return (BADCH); 268276761Sdelphij } 269276761Sdelphij if (match != -1) { /* option found */ 270276761Sdelphij if (long_options[match].has_arg == no_argument 271276761Sdelphij && has_equal) { 272276761Sdelphij if (PRINT_ERROR) 273276761Sdelphij warnx(noarg, 274276761Sdelphij#ifdef GNU_COMPATIBLE 275276761Sdelphij current_dash, 276276761Sdelphij#endif 277276761Sdelphij (int)current_argv_len, 278276761Sdelphij current_argv); 279276761Sdelphij /* 280276761Sdelphij * XXX: GNU sets optopt to val regardless of flag 281276761Sdelphij */ 282276761Sdelphij if (long_options[match].flag == NULL) 283276761Sdelphij optopt = long_options[match].val; 284276761Sdelphij else 285276761Sdelphij optopt = 0; 286276761Sdelphij#ifdef GNU_COMPATIBLE 287276761Sdelphij return (BADCH); 288276761Sdelphij#else 289276761Sdelphij return (BADARG); 290276761Sdelphij#endif 291276761Sdelphij } 292276761Sdelphij if (long_options[match].has_arg == required_argument || 293276761Sdelphij long_options[match].has_arg == optional_argument) { 294276761Sdelphij if (has_equal) 295276761Sdelphij optarg = (char *)has_equal; 296276761Sdelphij else if (long_options[match].has_arg == 297276761Sdelphij required_argument) { 298276761Sdelphij /* 299276761Sdelphij * optional argument doesn't use next nargv 300276761Sdelphij */ 301276761Sdelphij optarg = nargv[optind++]; 302276761Sdelphij } 303276761Sdelphij } 304276761Sdelphij if ((long_options[match].has_arg == required_argument) 305276761Sdelphij && (optarg == NULL)) { 306276761Sdelphij /* 307276761Sdelphij * Missing argument; leading ':' indicates no error 308276761Sdelphij * should be generated. 309276761Sdelphij */ 310276761Sdelphij if (PRINT_ERROR) 311276761Sdelphij warnx(recargstring, 312276761Sdelphij#ifdef GNU_COMPATIBLE 313276761Sdelphij current_dash, 314276761Sdelphij#endif 315276761Sdelphij current_argv); 316276761Sdelphij /* 317276761Sdelphij * XXX: GNU sets optopt to val regardless of flag 318276761Sdelphij */ 319276761Sdelphij if (long_options[match].flag == NULL) 320276761Sdelphij optopt = long_options[match].val; 321276761Sdelphij else 322276761Sdelphij optopt = 0; 323276761Sdelphij --optind; 324276761Sdelphij return (BADARG); 325276761Sdelphij } 326276761Sdelphij } else { /* unknown option */ 327276761Sdelphij if (short_too) { 328276761Sdelphij --optind; 329276761Sdelphij return (-1); 330276761Sdelphij } 331276761Sdelphij if (PRINT_ERROR) 332276761Sdelphij warnx(illoptstring, 333276761Sdelphij#ifdef GNU_COMPATIBLE 334276761Sdelphij current_dash, 335276761Sdelphij#endif 336276761Sdelphij current_argv); 337276761Sdelphij optopt = 0; 338276761Sdelphij return (BADCH); 339276761Sdelphij } 340276761Sdelphij if (idx) 341276761Sdelphij *idx = match; 342276761Sdelphij if (long_options[match].flag) { 343276761Sdelphij *long_options[match].flag = long_options[match].val; 344276761Sdelphij return (0); 345276761Sdelphij } else 346276761Sdelphij return (long_options[match].val); 347276761Sdelphij} 348276761Sdelphij 349276761Sdelphij/* 350276761Sdelphij * getopt_internal -- 351276761Sdelphij * Parse argc/argv argument vector. Called by user level routines. 352276761Sdelphij */ 353276761Sdelphijstatic int 354276761Sdelphijgetopt_internal(int nargc, char * const *nargv, const char *options, 355276761Sdelphij const struct option *long_options, int *idx, int flags) 356276761Sdelphij{ 357276761Sdelphij char *oli; /* option letter list index */ 358276761Sdelphij int optchar, short_too; 359276761Sdelphij int posixly_correct; /* no static, can be changed on the fly */ 360276761Sdelphij 361276761Sdelphij if (options == NULL) 362276761Sdelphij return (-1); 363276761Sdelphij 364276761Sdelphij /* 365276761Sdelphij * Disable GNU extensions if POSIXLY_CORRECT is set or options 366276761Sdelphij * string begins with a '+'. 367276761Sdelphij */ 368276761Sdelphij posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); 369276761Sdelphij#ifdef GNU_COMPATIBLE 370276761Sdelphij if (*options == '-') 371276761Sdelphij flags |= FLAG_ALLARGS; 372276761Sdelphij else if (posixly_correct || *options == '+') 373276761Sdelphij flags &= ~FLAG_PERMUTE; 374276761Sdelphij#else 375276761Sdelphij if (posixly_correct || *options == '+') 376276761Sdelphij flags &= ~FLAG_PERMUTE; 377276761Sdelphij else if (*options == '-') 378276761Sdelphij flags |= FLAG_ALLARGS; 379276761Sdelphij#endif 380276761Sdelphij if (*options == '+' || *options == '-') 381276761Sdelphij options++; 382276761Sdelphij 383276761Sdelphij /* 384276761Sdelphij * XXX Some GNU programs (like cvs) set optind to 0 instead of 385276761Sdelphij * XXX using optreset. Work around this braindamage. 386276761Sdelphij */ 387276761Sdelphij if (optind == 0) 388276761Sdelphij optind = 1; 389276761Sdelphij 390276761Sdelphij optarg = NULL; 391276761Sdelphijstart: 392276761Sdelphij if (!*place) { /* update scanning pointer */ 393276761Sdelphij if (optind >= nargc) { /* end of argument vector */ 394276761Sdelphij place = EMSG; 395276761Sdelphij if (nonopt_end != -1) { 396276761Sdelphij /* do permutation, if we have to */ 397276761Sdelphij permute_args(nonopt_start, nonopt_end, 398276761Sdelphij optind, nargv); 399276761Sdelphij optind -= nonopt_end - nonopt_start; 400276761Sdelphij } 401276761Sdelphij else if (nonopt_start != -1) { 402276761Sdelphij /* 403276761Sdelphij * If we skipped non-options, set optind 404276761Sdelphij * to the first of them. 405276761Sdelphij */ 406276761Sdelphij optind = nonopt_start; 407276761Sdelphij } 408276761Sdelphij nonopt_start = nonopt_end = -1; 409276761Sdelphij return (-1); 410276761Sdelphij } 411276761Sdelphij if (*(place = nargv[optind]) != '-' || 412276761Sdelphij#ifdef GNU_COMPATIBLE 413276761Sdelphij place[1] == '\0') { 414276761Sdelphij#else 415276761Sdelphij (place[1] == '\0' && strchr(options, '-') == NULL)) { 416276761Sdelphij#endif 417276761Sdelphij place = EMSG; /* found non-option */ 418276761Sdelphij if (flags & FLAG_ALLARGS) { 419276761Sdelphij /* 420276761Sdelphij * GNU extension: 421276761Sdelphij * return non-option as argument to option 1 422276761Sdelphij */ 423276761Sdelphij optarg = nargv[optind++]; 424276761Sdelphij return (INORDER); 425276761Sdelphij } 426276761Sdelphij if (!(flags & FLAG_PERMUTE)) { 427276761Sdelphij /* 428276761Sdelphij * If no permutation wanted, stop parsing 429276761Sdelphij * at first non-option. 430276761Sdelphij */ 431276761Sdelphij return (-1); 432276761Sdelphij } 433276761Sdelphij /* do permutation */ 434276761Sdelphij if (nonopt_start == -1) 435276761Sdelphij nonopt_start = optind; 436276761Sdelphij else if (nonopt_end != -1) { 437276761Sdelphij permute_args(nonopt_start, nonopt_end, 438276761Sdelphij optind, nargv); 439276761Sdelphij nonopt_start = optind - 440276761Sdelphij (nonopt_end - nonopt_start); 441276761Sdelphij nonopt_end = -1; 442276761Sdelphij } 443276761Sdelphij optind++; 444276761Sdelphij /* process next argument */ 445276761Sdelphij goto start; 446276761Sdelphij } 447276761Sdelphij if (nonopt_start != -1 && nonopt_end == -1) 448276761Sdelphij nonopt_end = optind; 449276761Sdelphij 450276761Sdelphij /* 451276761Sdelphij * If we have "-" do nothing, if "--" we are done. 452276761Sdelphij */ 453276761Sdelphij if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { 454276761Sdelphij optind++; 455276761Sdelphij place = EMSG; 456276761Sdelphij /* 457276761Sdelphij * We found an option (--), so if we skipped 458276761Sdelphij * non-options, we have to permute. 459276761Sdelphij */ 460276761Sdelphij if (nonopt_end != -1) { 461276761Sdelphij permute_args(nonopt_start, nonopt_end, 462276761Sdelphij optind, nargv); 463276761Sdelphij optind -= nonopt_end - nonopt_start; 464276761Sdelphij } 465276761Sdelphij nonopt_start = nonopt_end = -1; 466276761Sdelphij return (-1); 467276761Sdelphij } 468276761Sdelphij } 469276761Sdelphij 470276761Sdelphij /* 471276761Sdelphij * Check long options if: 472276761Sdelphij * 1) we were passed some 473276761Sdelphij * 2) the arg is not just "-" 474276761Sdelphij * 3) either the arg starts with -- we are getopt_long_only() 475276761Sdelphij */ 476276761Sdelphij if (long_options != NULL && place != nargv[optind] && 477276761Sdelphij (*place == '-' || (flags & FLAG_LONGONLY))) { 478276761Sdelphij short_too = 0; 479276761Sdelphij#ifdef GNU_COMPATIBLE 480276761Sdelphij dash_prefix = D_PREFIX; 481276761Sdelphij#endif 482276761Sdelphij if (*place == '-') { 483276761Sdelphij place++; /* --foo long option */ 484276761Sdelphij#ifdef GNU_COMPATIBLE 485276761Sdelphij dash_prefix = DD_PREFIX; 486276761Sdelphij#endif 487276761Sdelphij } else if (*place != ':' && strchr(options, *place) != NULL) 488276761Sdelphij short_too = 1; /* could be short option too */ 489276761Sdelphij 490276761Sdelphij optchar = parse_long_options(nargv, options, long_options, 491276761Sdelphij idx, short_too, flags); 492276761Sdelphij if (optchar != -1) { 493276761Sdelphij place = EMSG; 494276761Sdelphij return (optchar); 495276761Sdelphij } 496276761Sdelphij } 497276761Sdelphij 498276761Sdelphij if ((optchar = (int)*place++) == (int)':' || 499276761Sdelphij (optchar == (int)'-' && *place != '\0') || 500276761Sdelphij (oli = strchr(options, optchar)) == NULL) { 501276761Sdelphij /* 502276761Sdelphij * If the user specified "-" and '-' isn't listed in 503276761Sdelphij * options, return -1 (non-option) as per POSIX. 504276761Sdelphij * Otherwise, it is an unknown option character (or ':'). 505276761Sdelphij */ 506276761Sdelphij if (optchar == (int)'-' && *place == '\0') 507276761Sdelphij return (-1); 508276761Sdelphij if (!*place) 509276761Sdelphij ++optind; 510276761Sdelphij#ifdef GNU_COMPATIBLE 511276761Sdelphij if (PRINT_ERROR) 512276761Sdelphij warnx(posixly_correct ? illoptchar : gnuoptchar, 513276761Sdelphij optchar); 514276761Sdelphij#else 515276761Sdelphij if (PRINT_ERROR) 516276761Sdelphij warnx(illoptchar, optchar); 517276761Sdelphij#endif 518276761Sdelphij optopt = optchar; 519276761Sdelphij return (BADCH); 520276761Sdelphij } 521276761Sdelphij if (long_options != NULL && optchar == 'W' && oli[1] == ';') { 522276761Sdelphij /* -W long-option */ 523276761Sdelphij if (*place) /* no space */ 524276761Sdelphij /* NOTHING */; 525276761Sdelphij else if (++optind >= nargc) { /* no arg */ 526276761Sdelphij place = EMSG; 527276761Sdelphij if (PRINT_ERROR) 528276761Sdelphij warnx(recargchar, optchar); 529276761Sdelphij optopt = optchar; 530276761Sdelphij return (BADARG); 531276761Sdelphij } else /* white space */ 532276761Sdelphij place = nargv[optind]; 533276761Sdelphij#ifdef GNU_COMPATIBLE 534276761Sdelphij dash_prefix = W_PREFIX; 535276761Sdelphij#endif 536276761Sdelphij optchar = parse_long_options(nargv, options, long_options, 537276761Sdelphij idx, 0, flags); 538276761Sdelphij place = EMSG; 539276761Sdelphij return (optchar); 540276761Sdelphij } 541276761Sdelphij if (*++oli != ':') { /* doesn't take argument */ 542276761Sdelphij if (!*place) 543276761Sdelphij ++optind; 544276761Sdelphij } else { /* takes (optional) argument */ 545276761Sdelphij optarg = NULL; 546276761Sdelphij if (*place) /* no white space */ 547276761Sdelphij optarg = (char *)place; 548276761Sdelphij else if (oli[1] != ':') { /* arg not optional */ 549276761Sdelphij if (++optind >= nargc) { /* no arg */ 550276761Sdelphij place = EMSG; 551276761Sdelphij if (PRINT_ERROR) 552276761Sdelphij warnx(recargchar, optchar); 553276761Sdelphij optopt = optchar; 554276761Sdelphij return (BADARG); 555276761Sdelphij } else 556276761Sdelphij optarg = nargv[optind]; 557276761Sdelphij } 558276761Sdelphij place = EMSG; 559276761Sdelphij ++optind; 560276761Sdelphij } 561276761Sdelphij /* dump back option letter */ 562276761Sdelphij return (optchar); 563276761Sdelphij} 564276761Sdelphij 565276761Sdelphij#ifdef REPLACE_GETOPT 566276761Sdelphij/* 567276761Sdelphij * getopt -- 568276761Sdelphij * Parse argc/argv argument vector. 569276761Sdelphij * 570276761Sdelphij * [eventually this will replace the BSD getopt] 571276761Sdelphij */ 572276761Sdelphijint 573276761Sdelphijgetopt(int nargc, char * const *nargv, const char *options) 574276761Sdelphij{ 575276761Sdelphij 576276761Sdelphij /* 577276761Sdelphij * We don't pass FLAG_PERMUTE to getopt_internal() since 578276761Sdelphij * the BSD getopt(3) (unlike GNU) has never done this. 579276761Sdelphij * 580276761Sdelphij * Furthermore, since many privileged programs call getopt() 581276761Sdelphij * before dropping privileges it makes sense to keep things 582276761Sdelphij * as simple (and bug-free) as possible. 583276761Sdelphij */ 584276761Sdelphij return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); 585276761Sdelphij} 586276761Sdelphij#endif /* REPLACE_GETOPT */ 587276761Sdelphij 588276761Sdelphij/* 589276761Sdelphij * getopt_long -- 590276761Sdelphij * Parse argc/argv argument vector. 591276761Sdelphij */ 592276761Sdelphijint 593276761Sdelphijgetopt_long(int nargc, char * const *nargv, const char *options, 594276761Sdelphij const struct option *long_options, int *idx) 595276761Sdelphij{ 596276761Sdelphij 597276761Sdelphij return (getopt_internal(nargc, nargv, options, long_options, idx, 598276761Sdelphij FLAG_PERMUTE)); 599276761Sdelphij} 600276761Sdelphij 601276761Sdelphij/* 602276761Sdelphij * getopt_long_only -- 603276761Sdelphij * Parse argc/argv argument vector. 604276761Sdelphij */ 605276761Sdelphijint 606276761Sdelphijgetopt_long_only(int nargc, char * const *nargv, const char *options, 607276761Sdelphij const struct option *long_options, int *idx) 608276761Sdelphij{ 609276761Sdelphij 610276761Sdelphij return (getopt_internal(nargc, nargv, options, long_options, idx, 611276761Sdelphij FLAG_PERMUTE|FLAG_LONGONLY)); 612276761Sdelphij} 613