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