1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com> 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 23 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 24 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 /* 33 * Copyright (c) 2000 The NetBSD Foundation, Inc. 34 * All rights reserved. 35 * 36 * This code is derived from software contributed to The NetBSD Foundation 37 * by Dieter Baron and Thomas Klausner. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. All advertising materials mentioning features or use of this software 48 * must display the following acknowledgement: 49 * This product includes software developed by the NetBSD 50 * Foundation, Inc. and its contributors. 51 * 4. Neither the name of The NetBSD Foundation nor the names of its 52 * contributors may be used to endorse or promote products derived 53 * from this software without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 56 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 57 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 58 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 59 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 60 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 61 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 62 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 63 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 64 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65 * POSSIBILITY OF SUCH DAMAGE. 66 */ 67 68 #pragma ident "%Z%%M% %I% %E% SMI" 69 70 #pragma weak _getopt_clip = getopt_clip 71 #pragma weak _getopt_long = getopt_long 72 #pragma weak _getopt_long_only = getopt_long_only 73 74 #include "lint.h" 75 #include <getopt.h> 76 #include <stdio.h> 77 #include <errno.h> 78 #include <unistd.h> 79 #include <stdlib.h> 80 #include <string.h> 81 #include "_libc_gettext.h" 82 83 static int optreset = 0; /* keep track of first entry to getopt() */ 84 #define PRINT_ERROR ((opterr) && (*options != ':')) 85 #define FLAG_IS_SET(flag) ((flags & flag) != 0) /* is flag turned on? */ 86 87 /* Determine if an argument is required for this long option */ 88 #define LONGOPT_REQUIRES_ARG(longopt) \ 89 ((((longopt).has_arg == optional_argument) && \ 90 (!FLAG_IS_SET(FLAG_OPTIONAL_ARGS))) || \ 91 ((longopt).has_arg == required_argument)) 92 93 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ 94 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "1" */ 95 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only() */ 96 #define FLAG_OPTIONAL_ARGS 0x08 /* allow optional arguments to options */ 97 #define FLAG_REQUIRE_EQUIVALENTS 0x10 /* require short<->long equivalents */ 98 #define FLAG_ABBREV 0x20 /* long option abbreviation allowed. */ 99 #define FLAG_W_SEMICOLON 0x40 /* Support for W; in optstring */ 100 #define FLAG_PLUS_DASH_START 0x80 /* leading '+' or '-' in optstring */ 101 102 /* return values */ 103 #define BADCH (int)'?' 104 #define BADARG ((*options == ':') ? (int)':' : (int)'?') 105 #define INORDER (int)1 106 107 #define EMSG "" 108 109 static int getopt_internal(int, char * const *, const char *, 110 const struct option *, int *, uint_t); 111 static int parse_long_options(int nargc, char * const *nargv, const char *, 112 const struct option *, int *, int, 113 uint_t flags); 114 static int gcd(int, int); 115 static void permute_args(int, int, int, char * const *); 116 117 static char *place = EMSG; /* option letter processing */ 118 119 /* XXX: set optreset to 1 rather than these two */ 120 static int nonopt_start = -1; /* first non option argument (for permute) */ 121 static int nonopt_end = -1; /* first option after non options (for permute) */ 122 123 /* 124 * Generalized error message output. 125 * 126 * NOTE ON ERROR MESSAGES: All the error messages in this file 127 * use %s (not %c) because they are all routed through warnx_getopt(), 128 * which takes a string argument. Character arguments passed 129 * to warnxchar() are converted to strings automatically before 130 * being passed to warnx_getopt(). 131 */ 132 static void 133 warnx_getopt(const char *argv0, const char *msg, const char *arg) { 134 char errbuf[256]; 135 (void) snprintf(errbuf, sizeof (errbuf), msg, argv0, arg); 136 (void) write(2, errbuf, strlen(errbuf)); 137 (void) write(2, "\n", 1); 138 } 139 140 /* 141 * Generalized error message output. 142 */ 143 static void 144 warnxchar(const char *argv0, const char *msg, const char c) { 145 char charbuf[2]; 146 charbuf[0] = c; 147 charbuf[1] = '\0'; 148 warnx_getopt(argv0, msg, charbuf); 149 } 150 151 /* 152 * Generalized error message output. 153 */ 154 static void 155 warnxlen(const char *argv0, const char *msg, int argLen, const char *arg) { 156 char argbuf[256]; 157 (void) strncpy(argbuf, arg, argLen); 158 argbuf[argLen < (sizeof (argbuf)-1)? argLen:(sizeof (argbuf)-1)] = '\0'; 159 warnx_getopt(argv0, msg, argbuf); 160 } 161 162 /* 163 * Compute the greatest common divisor of a and b. 164 */ 165 static int 166 gcd(int a, int b) 167 { 168 int c; 169 170 c = a % b; 171 while (c != 0) { 172 a = b; 173 b = c; 174 c = a % b; 175 } 176 177 return (b); 178 } 179 180 /* 181 * Exchange the block from nonopt_start to nonopt_end with the block 182 * from nonopt_end to opt_end (keeping the same order of arguments 183 * in each block). 184 */ 185 static void 186 permute_args(int panonopt_start, int panonopt_end, int opt_end, 187 char * const *nargv) 188 { 189 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; 190 char *swap; 191 192 /* 193 * compute lengths of blocks and number and size of cycles 194 */ 195 nnonopts = panonopt_end - panonopt_start; 196 nopts = opt_end - panonopt_end; 197 ncycle = gcd(nnonopts, nopts); 198 cyclelen = (opt_end - panonopt_start) / ncycle; 199 200 for (i = 0; i < ncycle; i++) { 201 cstart = panonopt_end+i; 202 pos = cstart; 203 for (j = 0; j < cyclelen; j++) { 204 if (pos >= panonopt_end) 205 pos -= nnonopts; 206 else 207 pos += nopts; 208 swap = nargv[pos]; 209 ((char **)nargv)[pos] = nargv[cstart]; 210 ((char **)nargv)[cstart] = swap; 211 } 212 } 213 } /* permute_args() */ 214 215 /* 216 * Verify that each short option (character flag) has a long equivalent, 217 * and that each long option has a short option equivalent. Note that 218 * multiple long options can map to the same character. 219 * 220 * This behavior is defined by Sun's CLIP specification (11/12/02), 221 * and currently getopt_clip() is the only getopt variant that 222 * requires it. 223 * 224 * If error output is enabled and an error is found, this function 225 * prints ONE error message (the first error found) and returns an 226 * error value. 227 * 228 * ASSUMES: options != NULL 229 * ASSUMES: long_options may be NULL 230 * 231 * Returns < 0 if an error is found 232 * Returns >= 0 on success 233 */ 234 static int 235 /* LINTED: argument unused in function: nargc */ 236 verify_short_long_equivalents(int nargc, 237 char *const *nargv, 238 const char *options, 239 const struct option *long_options, 240 uint_t flags) { 241 int short_i = 0; 242 int long_i = 0; 243 int equivFound = 0; 244 int ch = 0; 245 246 /* 247 * Find a long option for each short option 248 */ 249 equivFound = 1; 250 for (short_i = 0; equivFound && (options[short_i] != 0); ++short_i) { 251 ch = options[short_i]; 252 253 if (ch == ':') { 254 continue; 255 } 256 if (FLAG_IS_SET(FLAG_W_SEMICOLON) && 257 (ch == 'W') && (options[short_i+1] == ';')) { 258 /* W; is a special case */ 259 ++short_i; 260 continue; 261 } 262 263 equivFound = 0; 264 if (long_options != NULL) { 265 for (long_i = 0; ((!equivFound) && 266 (long_options[long_i].name != NULL)); 267 ++long_i) { 268 equivFound = (ch == long_options[long_i].val); 269 } 270 } 271 if ((!equivFound) && (PRINT_ERROR)) { 272 warnxchar(nargv[0], 273 _libc_gettext( 274 "%s: equivalent long option required -- %s"), 275 ch); 276 } 277 } /* short_i */ 278 279 /* 280 * Find a short option for each long option. Note that if we came 281 * out of the above loop with equivFound==0, we are already done. 282 */ 283 if (equivFound && (long_options != NULL)) { 284 for (long_i = 0; (equivFound && 285 (long_options[long_i].name != NULL)); 286 ++long_i) { 287 equivFound = ((long_options[long_i].val != 0) && 288 (strchr(options, long_options[long_i].val) 289 != NULL)); 290 291 if ((!equivFound) && (PRINT_ERROR)) { 292 warnx_getopt(nargv[0], 293 _libc_gettext( 294 "%s: equivalent short option required -- %s"), 295 long_options[long_i].name); 296 } 297 } /* for long_i */ 298 } 299 300 return (equivFound? 0:-1); 301 } /* verify_short_long_equivalents() */ 302 303 /* 304 * parse_long_options -- 305 * Parse long options in argc/argv argument vector. 306 * Returns -1 if short_too is set and the option does not match long_options. 307 */ 308 static int 309 parse_long_options(int nargc, char * const *nargv, const char *options, 310 const struct option *long_options, int *idx, int short_too, 311 uint_t flags) 312 { 313 char *current_argv = NULL; 314 char *argv_equal_ptr = NULL; 315 size_t current_argv_len = 0; 316 size_t long_option_len = 0; 317 int i = 0; 318 int match = 0; 319 320 current_argv = place; 321 match = -1; 322 323 optind++; 324 325 if ((argv_equal_ptr = strchr(current_argv, '=')) != NULL) { 326 /* argument found (--option=arg) */ 327 current_argv_len = (argv_equal_ptr - current_argv); 328 argv_equal_ptr++; 329 } else { 330 current_argv_len = strlen(current_argv); 331 } 332 333 for (i = 0; (long_options[i].name != NULL); i++) { 334 335 /* find matching long option */ 336 if (strncmp(current_argv, long_options[i].name, 337 current_argv_len) != 0) { 338 continue; /* no match */ 339 } 340 long_option_len = strlen(long_options[i].name); 341 if ((!FLAG_IS_SET(FLAG_ABBREV)) && 342 (long_option_len > current_argv_len)) { 343 continue; /* Abbreviations are disabled */ 344 } 345 346 if (long_option_len == current_argv_len) { 347 /* exact match */ 348 match = i; 349 break; 350 } 351 /* 352 * If this is a known short option, don't allow 353 * a partial match of a single character. 354 */ 355 if (short_too && current_argv_len == 1) 356 continue; 357 358 if (match == -1) /* partial match */ 359 match = i; 360 else { 361 /* ambiguous abbreviation */ 362 if (PRINT_ERROR) { 363 warnxlen(nargv[0], 364 _libc_gettext( 365 "%s: ambiguous option -- %s"), 366 (int)current_argv_len, 367 current_argv); 368 } 369 optopt = 0; 370 return (BADCH); 371 } 372 } /* for i */ 373 if (match != -1) { /* option found */ 374 if ((long_options[match].has_arg == no_argument) && 375 (argv_equal_ptr != NULL)) { 376 if (PRINT_ERROR) { 377 warnxlen(nargv[0], 378 _libc_gettext( 379 "%s: option doesn't take an argument -- %s"), 380 (int)current_argv_len, 381 current_argv); 382 } 383 /* 384 * XXX: GNU sets optopt to val regardless of flag 385 */ 386 if (long_options[match].flag == NULL) 387 optopt = long_options[match].val; 388 else 389 optopt = 0; 390 return (BADARG); 391 } 392 if (long_options[match].has_arg == required_argument || 393 long_options[match].has_arg == optional_argument) { 394 if (argv_equal_ptr != NULL) { 395 optarg = argv_equal_ptr; 396 } else if (LONGOPT_REQUIRES_ARG(long_options[match])) { 397 /* The next argv must be the option argument */ 398 if (optind < nargc) { 399 optarg = nargv[optind]; 400 } 401 ++optind; /* code below depends on this */ 402 } 403 } 404 if (LONGOPT_REQUIRES_ARG(long_options[match]) && 405 (optarg == NULL)) { 406 /* 407 * Missing argument; leading ':' indicates no error 408 * should be generated. 409 */ 410 if (PRINT_ERROR) { 411 warnx_getopt(nargv[0], 412 _libc_gettext( 413 "%s: option requires an argument -- %s"), 414 current_argv); 415 } 416 /* 417 * XXX: GNU sets optopt to val regardless of flag 418 */ 419 if (long_options[match].flag == NULL) 420 optopt = long_options[match].val; 421 else 422 optopt = 0; 423 --optind; 424 return (BADARG); 425 } 426 } else { /* unknown option */ 427 if (short_too) { 428 --optind; 429 return (-1); 430 } 431 if (PRINT_ERROR) { 432 warnx_getopt(nargv[0], 433 _libc_gettext("%s: illegal option -- %s"), 434 current_argv); 435 } 436 optopt = 0; 437 return (BADCH); 438 } 439 if (idx) 440 *idx = match; 441 if (long_options[match].flag != NULL) { 442 *long_options[match].flag = long_options[match].val; 443 return (0); 444 } else { 445 optopt = long_options[match].val; 446 return (optopt); 447 } 448 } /* parse_long_options() */ 449 450 /* 451 * getopt_internal() -- 452 * Parse argc/argv argument vector. Called by user level routines. 453 * 454 * This implements all of the getopt_long(), getopt_long_only(), 455 * getopt_clip() variants. 456 */ 457 static int 458 getopt_internal(int nargc, char * const *nargv, const char *options, 459 const struct option *long_options, int *idx, uint_t flags) 460 { 461 char *oli; /* option letter list index */ 462 int optchar, short_too; 463 static int posixly_correct = -1; 464 465 if (options == NULL) 466 return (-1); 467 468 /* 469 * Disable GNU extensions if POSIXLY_CORRECT is set or options 470 * string begins with a '+'. 471 */ 472 if (posixly_correct == -1) { 473 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); 474 } 475 if (FLAG_IS_SET(FLAG_PLUS_DASH_START)) { 476 /* 477 * + or - at start of optstring takes precedence 478 * over POSIXLY_CORRECT. 479 */ 480 if (*options == '+') { 481 /* 482 * leading + means POSIX-compliant; first non-option 483 * ends option list. Therefore, don't permute args. 484 */ 485 posixly_correct = 1; 486 } else if (*options == '-') { 487 posixly_correct = 0; 488 flags |= FLAG_ALLARGS; 489 } 490 if ((*options == '+') || (*options == '-')) { 491 options++; 492 } 493 } /* if FLAG_PLUS_DASH_START */ 494 495 if (posixly_correct) { 496 flags &= ~FLAG_PERMUTE; 497 flags &= ~FLAG_ALLARGS; 498 flags &= ~FLAG_OPTIONAL_ARGS; 499 } 500 501 /* 502 * Some programs (like GNU cvs) set optind to 0 to restart 503 * option processing. Work around this braindamage. 504 * 505 * The above problem comes from using global variables. We 506 * should avoid their use in the future. 507 */ 508 if (optind == 0) { 509 optind = optreset = 1; 510 } 511 512 optarg = NULL; 513 optopt = 0; 514 515 if (optreset) { 516 nonopt_start = nonopt_end = -1; 517 } 518 519 /* 520 * On the first call, make sure that there is a short equivalent 521 * for each long option, and vice versa. This is required by 522 * Sun's CLIP specification (11/12/02). 523 */ 524 if ((optind == 1) && FLAG_IS_SET(FLAG_REQUIRE_EQUIVALENTS)) { 525 if (verify_short_long_equivalents( 526 nargc, nargv, options, long_options, flags) < 0) { 527 /* function printed any necessary messages */ 528 errno = EINVAL; /* invalid argument */ 529 return (-1); 530 } 531 } 532 533 start: 534 if (optreset || !*place) { /* update scanning pointer */ 535 optreset = 0; 536 if (optind >= nargc) { /* end of argument vector */ 537 place = EMSG; 538 if (nonopt_end != -1) { 539 /* do permutation, if we have to */ 540 permute_args(nonopt_start, nonopt_end, 541 optind, nargv); 542 optind -= nonopt_end - nonopt_start; 543 544 } else if (nonopt_start != -1) { 545 /* 546 * If we skipped non-options, set optind 547 * to the first of them. 548 */ 549 optind = nonopt_start; 550 } 551 nonopt_start = nonopt_end = -1; 552 return (-1); 553 } 554 if ((*(place = nargv[optind]) != '-') || (place[1] == '\0')) { 555 place = EMSG; /* found non-option */ 556 if (flags & FLAG_ALLARGS) { 557 /* 558 * GNU extension: 559 * return non-option as argument to option '\1' 560 */ 561 optarg = nargv[optind++]; 562 return (INORDER); 563 } 564 if (!(flags & FLAG_PERMUTE)) { 565 /* 566 * If no permutation wanted, stop parsing 567 * at first non-option. 568 */ 569 return (-1); 570 } 571 /* do permutation */ 572 if (nonopt_start == -1) 573 nonopt_start = optind; 574 else if (nonopt_end != -1) { 575 permute_args(nonopt_start, nonopt_end, 576 optind, nargv); 577 nonopt_start = optind - 578 (nonopt_end - nonopt_start); 579 nonopt_end = -1; 580 } 581 optind++; 582 /* process next argument */ 583 goto start; 584 } 585 if (nonopt_start != -1 && nonopt_end == -1) 586 nonopt_end = optind; 587 588 /* 589 * Check for "--" or "--foo" with no long options 590 * but if place is simply "-" leave it unmolested. 591 */ 592 if (place[1] != '\0' && *++place == '-' && 593 (place[1] == '\0' || long_options == NULL)) { 594 optind++; 595 place = EMSG; 596 /* 597 * We found an option (--), so if we skipped 598 * non-options, we have to permute. 599 */ 600 if (nonopt_end != -1) { 601 permute_args(nonopt_start, nonopt_end, 602 optind, nargv); 603 optind -= nonopt_end - nonopt_start; 604 } 605 nonopt_start = nonopt_end = -1; 606 return (-1); 607 } 608 } 609 610 /* 611 * Check long options if: 612 * 1) we were passed some 613 * 2) the arg is not just "-" 614 * 3) either the arg starts with -- or we are getopt_long_only() 615 */ 616 if (long_options != NULL && place != nargv[optind] && 617 (*place == '-' || (FLAG_IS_SET(FLAG_LONGONLY)))) { 618 short_too = 0; 619 if (*place == '-') 620 place++; /* --foo long option */ 621 else if (*place != ':' && strchr(options, *place) != NULL) 622 short_too = 1; /* could be short option too */ 623 624 optchar = parse_long_options(nargc, nargv, options, 625 long_options, idx, short_too, flags); 626 if (optchar != -1) { 627 place = EMSG; 628 return (optchar); 629 } 630 } 631 632 if ((optchar = (int)*place++) == (int)':' || 633 (oli = strchr(options, optchar)) == NULL) { 634 /* 635 * If the user didn't specify '-' as an option, 636 * assume it means -1 as POSIX specifies. 637 */ 638 if (optchar == (int)'-') 639 return (-1); 640 /* option letter unknown or ':' */ 641 if (!*place) 642 ++optind; 643 if (PRINT_ERROR) 644 warnxchar(nargv[0], 645 _libc_gettext("%s: illegal option -- %s"), 646 optchar); 647 optopt = optchar; 648 return (BADCH); 649 } 650 if (FLAG_IS_SET(FLAG_W_SEMICOLON) && 651 (long_options != NULL) && (optchar == 'W') && (oli[1] == ';')) { 652 /* -W long-option */ 653 /* LINTED: statement has no consequent: if */ 654 if (*place) { /* no space */ 655 /* NOTHING */; 656 } else if (++optind >= nargc) { /* no long-option after -W */ 657 place = EMSG; 658 if (PRINT_ERROR) 659 warnxchar(nargv[0], 660 _libc_gettext( 661 "%s: option requires an argument -- %s"), 662 optchar); 663 optopt = optchar; 664 return (BADARG); 665 } else { /* white space */ 666 place = nargv[optind]; 667 } 668 optchar = parse_long_options( 669 nargc, nargv, options, long_options, 670 idx, 0, flags); 671 672 /* 673 * PSARC 2003/645 - Match GNU behavior, set optarg to 674 * the long-option. 675 */ 676 if (optarg == NULL) { 677 optarg = nargv[optind-1]; 678 } 679 place = EMSG; 680 return (optchar); 681 } 682 if (*++oli != ':') { /* doesn't take argument */ 683 if (!*place) 684 ++optind; 685 } else { /* takes (optional) argument */ 686 optarg = NULL; 687 if (*place) { /* no white space */ 688 optarg = place; 689 /* XXX: disable test for :: if PC? (GNU doesn't) */ 690 } else if (!(FLAG_IS_SET(FLAG_OPTIONAL_ARGS) && 691 (oli[1] == ':'))) { 692 /* arg is required (not optional) */ 693 694 if (++optind >= nargc) { /* no arg */ 695 place = EMSG; 696 if (PRINT_ERROR) { 697 warnxchar(nargv[0], 698 _libc_gettext( 699 "%s: option requires an argument -- %s"), 700 optchar); 701 } 702 optopt = optchar; 703 return (BADARG); 704 } else 705 optarg = nargv[optind]; 706 } 707 place = EMSG; 708 ++optind; 709 } 710 /* return valid option letter */ 711 optopt = optchar; /* preserve getopt() behavior */ 712 return (optchar); 713 } /* getopt_internal() */ 714 715 /* 716 * getopt_long() -- 717 * Parse argc/argv argument vector. 718 * 719 * Requires that long options be preceded with a two dashes 720 * (e.g., --longoption). 721 */ 722 int 723 getopt_long(int nargc, char *const *nargv, 724 const char *optstring, 725 const struct option *long_options, int *long_index) 726 { 727 728 return (getopt_internal( 729 nargc, nargv, optstring, long_options, long_index, 730 FLAG_PERMUTE 731 | FLAG_OPTIONAL_ARGS 732 | FLAG_ABBREV 733 | FLAG_W_SEMICOLON 734 | FLAG_PLUS_DASH_START)); 735 } /* getopt_long() */ 736 737 /* 738 * getopt_long_only() -- 739 * Parse argc/argv argument vector. 740 * 741 * Long options may be preceded with a single dash (e.g., -longoption) 742 */ 743 int 744 getopt_long_only(int nargc, char *const *nargv, 745 const char *optstring, 746 const struct option *long_options, int *long_index) 747 { 748 749 return (getopt_internal( 750 nargc, nargv, optstring, long_options, long_index, 751 FLAG_PERMUTE 752 | FLAG_OPTIONAL_ARGS 753 | FLAG_ABBREV 754 | FLAG_W_SEMICOLON 755 | FLAG_PLUS_DASH_START 756 | FLAG_LONGONLY)); 757 } /* getopt_long_only() */ 758 759 /* 760 * getopt_clip() -- 761 * Parse argc/argv argument vector, requiring compliance with 762 * Sun's CLIP specification (11/12/02) 763 * 764 * o Does not allow arguments to be optional (optional_argument is 765 * treated as required_argument). 766 * 767 * o Does not allow long options to be abbreviated on the command line 768 * 769 * o Does not allow long argument to be preceded by a single dash 770 * (Double-dash '--' is required) 771 * 772 * o Stops option processing at the first non-option 773 * 774 * o Requires that every long option have a short-option (single 775 * character) equivalent and vice-versa. If a short option or 776 * long option without an equivalent is found, an error message 777 * is printed and -1 is returned on the first call, and errno 778 * is set to EINVAL. 779 * 780 * o Leading + or - in optstring is ignored, and opstring is 781 * treated as if it began after the + or - . 782 */ 783 int 784 getopt_clip(int nargc, char *const *nargv, 785 const char *optstring, 786 const struct option *long_options, int *long_index) 787 { 788 return getopt_internal( 789 nargc, nargv, optstring, long_options, long_index, 790 /* 791 * no permutation, 792 * no optional args, 793 * no long-only, 794 * no abbreviations 795 * no support for +- at start of optstring 796 * yes support for "W;" in optstring 797 */ 798 FLAG_W_SEMICOLON 799 | FLAG_REQUIRE_EQUIVALENTS); 800 } /* getopt_clip() */ 801