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