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