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