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
warnx_getopt(const char * argv0,const char * msg,const char * arg)131 warnx_getopt(const char *argv0, const char *msg, const char *arg)
132 {
133 char errbuf[256];
134 (void) snprintf(errbuf, sizeof (errbuf), msg, argv0, arg);
135 (void) write(2, errbuf, strlen(errbuf));
136 (void) write(2, "\n", 1);
137 }
138
139 /*
140 * Generalized error message output.
141 */
142 static void
warnxchar(const char * argv0,const char * msg,const char c)143 warnxchar(const char *argv0, const char *msg, const char c)
144 {
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
warnxlen(const char * argv0,const char * msg,int argLen,const char * arg)155 warnxlen(const char *argv0, const char *msg, int argLen, const char *arg)
156 {
157 char argbuf[256];
158 (void) strncpy(argbuf, arg, argLen);
159 argbuf[argLen < (sizeof (argbuf)-1)? argLen:(sizeof (argbuf)-1)] = '\0';
160 warnx_getopt(argv0, msg, argbuf);
161 }
162
163 /*
164 * Compute the greatest common divisor of a and b.
165 */
166 static int
gcd(int a,int b)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
permute_args(int panonopt_start,int panonopt_end,int opt_end,char * const * nargv)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
verify_short_long_equivalents(int nargc __unused,char * const * nargv,const char * options,const struct option * long_options,uint_t flags)236 verify_short_long_equivalents(int nargc __unused, char *const *nargv,
237 const char *options, const struct option *long_options, uint_t flags)
238 {
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("%s: equivalent short "
292 "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
parse_long_options(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx,int short_too,uint_t flags)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
getopt_internal(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx,uint_t flags)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
getopt_long(int nargc,char * const * nargv,const char * optstring,const struct option * long_options,int * long_index)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
getopt_long_only(int nargc,char * const * nargv,const char * optstring,const struct option * long_options,int * long_index)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
getopt_clip(int nargc,char * const * nargv,const char * optstring,const struct option * long_options,int * long_index)781 getopt_clip(int nargc, char *const *nargv, const char *optstring,
782 const struct option *long_options, int *long_index)
783 {
784 return getopt_internal(
785 nargc, nargv, optstring, long_options, long_index,
786 /*
787 * no permutation,
788 * no optional args,
789 * no long-only,
790 * no abbreviations
791 * no support for +- at start of optstring
792 * yes support for "W;" in optstring
793 */
794 FLAG_W_SEMICOLON
795 | FLAG_REQUIRE_EQUIVALENTS);
796 } /* getopt_clip() */
797