1 /* This file is from getopt of glibc 2.2.2
2 * And it is modified for TiMidity++ support at 01/19, 2002
3 * by Masanao Izumo <mo@goice.co.jp>.
4 */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif /* HAVE_CONFIG_H */
9
10 #if !defined(HAVE_GETOPT_LONG) || !defined(HAVE_GETOPT)
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif /* HAVE_UNISTD_H */
17 #include <string.h>
18
19 #include "tmdy_getopt.h"
20
21 #ifndef HAVE_GETOPT
22 char *optarg;
23 int optind = 1;
24 int opterr = 1;
25 int optopt = '?';
26 #endif /* HAVE_GETOPT */
27
28 static enum
29 {
30 REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
31 } ordering;
32
33 static int __getopt_initialized;
34 static char *nextchar;
35 static char *posixly_correct;
36 static int first_nonopt;
37 static int last_nonopt;
38
39
40 # define SWAP_FLAGS(ch1, ch2)
41
42
43 /* Exchange two adjacent subsequences of ARGV.
44 One subsequence is elements [first_nonopt,last_nonopt)
45 which contains all the non-options that have been skipped so far.
46 The other is elements [last_nonopt,optind), which contains all
47 the options processed since those non-options were skipped.
48
49 `first_nonopt' and `last_nonopt' are relocated so that they describe
50 the new indices of the non-options in ARGV after they are moved. */
51 static void
exchange(char ** argv)52 exchange (char **argv)
53 {
54 int bottom = first_nonopt;
55 int middle = last_nonopt;
56 int top = optind;
57 char *tem;
58
59 /* Exchange the shorter segment with the far end of the longer segment.
60 That puts the shorter segment into the right place.
61 It leaves the longer segment in the right place overall,
62 but it consists of two parts that need to be swapped next. */
63
64 while (top > middle && middle > bottom)
65 {
66 if (top - middle > middle - bottom)
67 {
68 /* Bottom segment is the short one. */
69 int len = middle - bottom;
70 register int i;
71
72 /* Swap it with the top part of the top segment. */
73 for (i = 0; i < len; i++)
74 {
75 tem = argv[bottom + i];
76 argv[bottom + i] = argv[top - (middle - bottom) + i];
77 argv[top - (middle - bottom) + i] = tem;
78 SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
79 }
80 /* Exclude the moved bottom segment from further swapping. */
81 top -= len;
82 }
83 else
84 {
85 /* Top segment is the short one. */
86 int len = top - middle;
87 register int i;
88
89 /* Swap it with the bottom part of the bottom segment. */
90 for (i = 0; i < len; i++)
91 {
92 tem = argv[bottom + i];
93 argv[bottom + i] = argv[middle + i];
94 argv[middle + i] = tem;
95 SWAP_FLAGS (bottom + i, middle + i);
96 }
97 /* Exclude the moved top segment from further swapping. */
98 bottom += len;
99 }
100 }
101
102 /* Update records for the slots the non-options now occupy. */
103
104 first_nonopt += (optind - last_nonopt);
105 last_nonopt = optind;
106 }
107
108
109 /* Initialize the internal data when the first call is made. */
110 static const char *
_getopt_initialize(int argc,char * const * argv,const char * optstring)111 _getopt_initialize (int argc, char *const*argv, const char *optstring)
112 {
113 /* Start processing options with ARGV-element 1 (since ARGV-element 0
114 is the program name); the sequence of previously skipped
115 non-option ARGV-elements is empty. */
116
117 first_nonopt = last_nonopt = optind;
118
119 nextchar = NULL;
120
121 posixly_correct = getenv ("POSIXLY_CORRECT");
122
123 /* Determine how to handle the ordering of options and nonoptions. */
124
125 if (optstring[0] == '-')
126 {
127 ordering = RETURN_IN_ORDER;
128 ++optstring;
129 }
130 else if (optstring[0] == '+')
131 {
132 ordering = REQUIRE_ORDER;
133 ++optstring;
134 }
135 else if (posixly_correct != NULL)
136 ordering = REQUIRE_ORDER;
137 else
138 ordering = PERMUTE;
139
140 return optstring;
141 }
142
143 /* Scan elements of ARGV (whose length is ARGC) for option characters
144 given in OPTSTRING.
145
146 If an element of ARGV starts with '-', and is not exactly "-" or "--",
147 then it is an option element. The characters of this element
148 (aside from the initial '-') are option characters. If `getopt'
149 is called repeatedly, it returns successively each of the option characters
150 from each of the option elements.
151
152 If `getopt' finds another option character, it returns that character,
153 updating `optind' and `nextchar' so that the next call to `getopt' can
154 resume the scan with the following option character or ARGV-element.
155
156 If there are no more option characters, `getopt' returns -1.
157 Then `optind' is the index in ARGV of the first ARGV-element
158 that is not an option. (The ARGV-elements have been permuted
159 so that those that are not options now come last.)
160
161 OPTSTRING is a string containing the legitimate option characters.
162 If an option character is seen that is not listed in OPTSTRING,
163 return '?' after printing an error message. If you set `opterr' to
164 zero, the error message is suppressed but we still return '?'.
165
166 If a char in OPTSTRING is followed by a colon, that means it wants an arg,
167 so the following text in the same ARGV-element, or the text of the following
168 ARGV-element, is returned in `optarg'. Two colons mean an option that
169 wants an optional arg; if there is text in the current ARGV-element,
170 it is returned in `optarg', otherwise `optarg' is set to zero.
171
172 If OPTSTRING starts with `-' or `+', it requests different methods of
173 handling the non-option ARGV-elements.
174 See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
175
176 Long-named options begin with `--' instead of `-'.
177 Their names may be abbreviated as long as the abbreviation is unique
178 or is an exact match for some defined option. If they have an
179 argument, it follows the option name in the same ARGV-element, separated
180 from the option name by a `=', or else the in next ARGV-element.
181 When `getopt' finds a long-named option, it returns 0 if that option's
182 `flag' field is nonzero, the value of the option's `val' field
183 if the `flag' field is zero.
184
185 The elements of ARGV aren't really const, because we permute them.
186 But we pretend they're const in the prototype to be compatible
187 with other systems.
188
189 LONGOPTS is a vector of `struct option' terminated by an
190 element containing a name which is zero.
191
192 LONGIND returns the index in LONGOPT of the long-named option found.
193 It is only valid when a long-named option has been found by the most
194 recent call.
195
196 If LONG_ONLY is nonzero, '-' as well as '--' can introduce
197 long-named options. */
198
199 static int
_getopt_internal(int argc,char * const * argv,const char * optstring,const struct option * longopts,int * longind,int long_only)200 _getopt_internal (int argc, char *const*argv, const char *optstring,
201 const struct option *longopts, int *longind, int long_only)
202 {
203 int print_errors = opterr;
204 if (optstring[0] == ':')
205 print_errors = 0;
206
207 if (argc < 1)
208 return -1;
209
210 optarg = NULL;
211
212 if (optind == 0 || !__getopt_initialized)
213 {
214 if (optind == 0)
215 optind = 1; /* Don't scan ARGV[0], the program name. */
216 optstring = _getopt_initialize (argc, argv, optstring);
217 __getopt_initialized = 1;
218 }
219
220 /* Test whether ARGV[optind] points to a non-option argument.
221 Either it does not have option syntax, or there is an environment flag
222 from the shell indicating it is not an option. The later information
223 is only used when the used in the GNU libc. */
224 # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
225
226 if (nextchar == NULL || *nextchar == '\0')
227 {
228 /* Advance to the next ARGV-element. */
229
230 /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
231 moved back by the user (who may also have changed the arguments). */
232 if (last_nonopt > optind)
233 last_nonopt = optind;
234 if (first_nonopt > optind)
235 first_nonopt = optind;
236
237 if (ordering == PERMUTE)
238 {
239 /* If we have just processed some options following some non-options,
240 exchange them so that the options come first. */
241
242 if (first_nonopt != last_nonopt && last_nonopt != optind)
243 exchange ((char **) argv);
244 else if (last_nonopt != optind)
245 first_nonopt = optind;
246
247 /* Skip any additional non-options
248 and extend the range of non-options previously skipped. */
249
250 while (optind < argc && NONOPTION_P)
251 optind++;
252 last_nonopt = optind;
253 }
254
255 /* The special ARGV-element `--' means premature end of options.
256 Skip it like a null option,
257 then exchange with previous non-options as if it were an option,
258 then skip everything else like a non-option. */
259
260 if (optind != argc && !strcmp (argv[optind], "--"))
261 {
262 optind++;
263
264 if (first_nonopt != last_nonopt && last_nonopt != optind)
265 exchange ((char **) argv);
266 else if (first_nonopt == last_nonopt)
267 first_nonopt = optind;
268 last_nonopt = argc;
269
270 optind = argc;
271 }
272
273 /* If we have done all the ARGV-elements, stop the scan
274 and back over any non-options that we skipped and permuted. */
275
276 if (optind == argc)
277 {
278 /* Set the next-arg-index to point at the non-options
279 that we previously skipped, so the caller will digest them. */
280 if (first_nonopt != last_nonopt)
281 optind = first_nonopt;
282 return -1;
283 }
284
285 /* If we have come to a non-option and did not permute it,
286 either stop the scan or describe it to the caller and pass it by. */
287
288 if (NONOPTION_P)
289 {
290 if (ordering == REQUIRE_ORDER)
291 return -1;
292 optarg = argv[optind++];
293 return 1;
294 }
295
296 /* We have found another option-ARGV-element.
297 Skip the initial punctuation. */
298
299 nextchar = (argv[optind] + 1
300 + (longopts != NULL && argv[optind][1] == '-'));
301 }
302
303 /* Decode the current option-ARGV-element. */
304
305 /* Check whether the ARGV-element is a long option.
306
307 If long_only and the ARGV-element has the form "-f", where f is
308 a valid short option, don't consider it an abbreviated form of
309 a long option that starts with f. Otherwise there would be no
310 way to give the -f short option.
311
312 On the other hand, if there's a long option "fubar" and
313 the ARGV-element is "-fu", do consider that an abbreviation of
314 the long option, just like "--fu", and not "-f" with arg "u".
315
316 This distinction seems to be the most useful approach. */
317
318 if (longopts != NULL
319 && (argv[optind][1] == '-'
320 || (long_only && (argv[optind][2] || !strchr (optstring, argv[optind][1])))))
321 {
322 char *nameend;
323 const struct option *p;
324 const struct option *pfound = NULL;
325 int exact = 0;
326 int ambig = 0;
327 int indfound = -1;
328 int option_index;
329
330 for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
331 /* Do nothing. */ ;
332
333 /* Test all long options for either exact match
334 or abbreviated matches. */
335 for (p = longopts, option_index = 0; p->name; p++, option_index++)
336 if (!strncmp (p->name, nextchar, nameend - nextchar))
337 {
338 if ((unsigned int) (nameend - nextchar)
339 == (unsigned int) strlen (p->name))
340 {
341 /* Exact match found. */
342 pfound = p;
343 indfound = option_index;
344 exact = 1;
345 break;
346 }
347 else if (pfound == NULL)
348 {
349 /* First nonexact match found. */
350 pfound = p;
351 indfound = option_index;
352 }
353 else if (long_only
354 || pfound->has_arg != p->has_arg
355 || pfound->flag != p->flag
356 || pfound->val != p->val)
357 /* Second or later nonexact match found. */
358 ambig = 1;
359 }
360
361 if (ambig && !exact)
362 {
363 if (print_errors)
364 fprintf (stderr, "%s: option `%s' is ambiguous\n",
365 argv[0], argv[optind]);
366 nextchar += strlen (nextchar);
367 optind++;
368 optopt = 0;
369 return '?';
370 }
371
372 if (pfound != NULL)
373 {
374 option_index = indfound;
375 optind++;
376 if (*nameend)
377 {
378 /* Don't test has_arg with >, because some C compilers don't
379 allow it to be used on enums. */
380 if (pfound->has_arg)
381 optarg = nameend + 1;
382 else
383 {
384 if (print_errors)
385 {
386 if (argv[optind - 1][1] == '-')
387 /* --option */
388 fprintf (stderr,
389 "%s: option `--%s' doesn't allow an argument\n",
390 argv[0], pfound->name);
391 else
392 /* +option or -option */
393 fprintf (stderr,
394 "%s: option `%c%s' doesn't allow an argument\n",
395 argv[0], argv[optind - 1][0], pfound->name);
396 }
397
398 nextchar += strlen (nextchar);
399
400 optopt = pfound->val;
401 return '?';
402 }
403 }
404 else if (pfound->has_arg == 1)
405 {
406 if (optind < argc)
407 optarg = argv[optind++];
408 else
409 {
410 if (print_errors)
411 fprintf (stderr,
412 "%s: option `%s' requires an argument\n",
413 argv[0], argv[optind - 1]);
414 nextchar += strlen (nextchar);
415 optopt = pfound->val;
416 return optstring[0] == ':' ? ':' : '?';
417 }
418 }
419 nextchar += strlen (nextchar);
420 if (longind != NULL)
421 *longind = option_index;
422 if (pfound->flag)
423 {
424 *(pfound->flag) = pfound->val;
425 return 0;
426 }
427 return pfound->val;
428 }
429
430 /* Can't find it as a long option. If this is not getopt_long_only,
431 or the option starts with '--' or is not a valid short
432 option, then it's an error.
433 Otherwise interpret it as a short option. */
434 if (!long_only || argv[optind][1] == '-'
435 || strchr (optstring, *nextchar) == NULL)
436 {
437 if (print_errors)
438 {
439 if (argv[optind][1] == '-')
440 /* --option */
441 fprintf (stderr, "%s: unrecognized option `--%s'\n",
442 argv[0], nextchar);
443 else
444 /* +option or -option */
445 fprintf (stderr, "%s: unrecognized option `%c%s'\n",
446 argv[0], argv[optind][0], nextchar);
447 }
448 nextchar = (char *) "";
449 optind++;
450 optopt = 0;
451 return '?';
452 }
453 }
454
455 /* Look at and handle the next short option-character. */
456
457 {
458 char c = *nextchar++;
459 char *temp = strchr (optstring, c);
460
461 /* Increment `optind' when we start to process its last character. */
462 if (*nextchar == '\0')
463 ++optind;
464
465 if (temp == NULL || c == ':')
466 {
467 if (print_errors)
468 {
469 if (posixly_correct)
470 /* 1003.2 specifies the format of this message. */
471 fprintf (stderr, "%s: illegal option -- %c\n",
472 argv[0], c);
473 else
474 fprintf (stderr, "%s: invalid option -- %c\n",
475 argv[0], c);
476 }
477 optopt = c;
478 return '?';
479 }
480 /* Convenience. Treat POSIX -W foo same as long option --foo */
481 if (temp[0] == 'W' && temp[1] == ';')
482 {
483 char *nameend;
484 const struct option *p;
485 const struct option *pfound = NULL;
486 int exact = 0;
487 int ambig = 0;
488 int indfound = 0;
489 int option_index;
490
491 /* This is an option that requires an argument. */
492 if (*nextchar != '\0')
493 {
494 optarg = nextchar;
495 /* If we end this ARGV-element by taking the rest as an arg,
496 we must advance to the next element now. */
497 optind++;
498 }
499 else if (optind == argc)
500 {
501 if (print_errors)
502 {
503 /* 1003.2 specifies the format of this message. */
504 fprintf (stderr, "%s: option requires an argument -- %c\n",
505 argv[0], c);
506 }
507 optopt = c;
508 if (optstring[0] == ':')
509 c = ':';
510 else
511 c = '?';
512 return c;
513 }
514 else
515 /* We already incremented `optind' once;
516 increment it again when taking next ARGV-elt as argument. */
517 optarg = argv[optind++];
518
519 /* optarg is now the argument, see if it's in the
520 table of longopts. */
521
522 for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
523 /* Do nothing. */ ;
524
525 /* Test all long options for either exact match
526 or abbreviated matches. */
527 for (p = longopts, option_index = 0; p->name; p++, option_index++)
528 if (!strncmp (p->name, nextchar, nameend - nextchar))
529 {
530 if ((unsigned int) (nameend - nextchar) == strlen (p->name))
531 {
532 /* Exact match found. */
533 pfound = p;
534 indfound = option_index;
535 exact = 1;
536 break;
537 }
538 else if (pfound == NULL)
539 {
540 /* First nonexact match found. */
541 pfound = p;
542 indfound = option_index;
543 }
544 else
545 /* Second or later nonexact match found. */
546 ambig = 1;
547 }
548 if (ambig && !exact)
549 {
550 if (print_errors)
551 fprintf (stderr, "%s: option `-W %s' is ambiguous\n",
552 argv[0], argv[optind]);
553 nextchar += strlen (nextchar);
554 optind++;
555 return '?';
556 }
557 if (pfound != NULL)
558 {
559 option_index = indfound;
560 if (*nameend)
561 {
562 /* Don't test has_arg with >, because some C compilers don't
563 allow it to be used on enums. */
564 if (pfound->has_arg)
565 optarg = nameend + 1;
566 else
567 {
568 if (print_errors)
569 fprintf (stderr, "\
570 %s: option `-W %s' doesn't allow an argument\n",
571 argv[0], pfound->name);
572
573 nextchar += strlen (nextchar);
574 return '?';
575 }
576 }
577 else if (pfound->has_arg == 1)
578 {
579 if (optind < argc)
580 optarg = argv[optind++];
581 else
582 {
583 if (print_errors)
584 fprintf (stderr,
585 "%s: option `%s' requires an argument\n",
586 argv[0], argv[optind - 1]);
587 nextchar += strlen (nextchar);
588 return optstring[0] == ':' ? ':' : '?';
589 }
590 }
591 nextchar += strlen (nextchar);
592 if (longind != NULL)
593 *longind = option_index;
594 if (pfound->flag)
595 {
596 *(pfound->flag) = pfound->val;
597 return 0;
598 }
599 return pfound->val;
600 }
601 nextchar = NULL;
602 return 'W'; /* Let the application handle it. */
603 }
604 if (temp[1] == ':')
605 {
606 if (temp[2] == ':')
607 {
608 /* This is an option that accepts an argument optionally. */
609 if (*nextchar != '\0')
610 {
611 optarg = nextchar;
612 optind++;
613 }
614 else
615 optarg = NULL;
616 nextchar = NULL;
617 }
618 else
619 {
620 /* This is an option that requires an argument. */
621 if (*nextchar != '\0')
622 {
623 optarg = nextchar;
624 /* If we end this ARGV-element by taking the rest as an arg,
625 we must advance to the next element now. */
626 optind++;
627 }
628 else if (optind == argc)
629 {
630 if (print_errors)
631 {
632 /* 1003.2 specifies the format of this message. */
633 fprintf (stderr,
634 "%s: option requires an argument -- %c\n",
635 argv[0], c);
636 }
637 optopt = c;
638 if (optstring[0] == ':')
639 c = ':';
640 else
641 c = '?';
642 }
643 else
644 /* We already incremented `optind' once;
645 increment it again when taking next ARGV-elt as argument. */
646 optarg = argv[optind++];
647 nextchar = NULL;
648 }
649 }
650 return c;
651 }
652 }
653
654 #ifndef HAVE_GETOPT_LONG
655 int
getopt_long(int argc,char * const * argv,const char * options,const struct option * long_options,int * opt_index)656 getopt_long (int argc, char *const *argv, const char *options,
657 const struct option *long_options, int *opt_index)
658 {
659 return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
660 }
661
662 /* Like getopt_long, but '-' as well as '--' can indicate a long option.
663 If an option that starts with '-' (not '--') doesn't match a long option,
664 but does match a short option, it is parsed as a short option
665 instead. */
666
667 int
getopt_long_only(int argc,char * const * argv,const char * options,const struct option * long_options,int * opt_index)668 getopt_long_only (int argc, char *const *argv, const char *options,
669 const struct option *long_options, int *opt_index)
670 {
671 return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
672 }
673 #endif
674
675 #ifndef HAVE_GETOPT
676 int
getopt(int argc,char * const * argv,const char * optstring)677 getopt (int argc, char *const *argv, const char *optstring)
678 {
679 return _getopt_internal (argc, argv, optstring,
680 (const struct option *) 0,
681 (int *) 0,
682 0);
683 }
684 #endif
685
686 #endif
687