1/* Getopt for GNU.
2   NOTE: getopt is now part of the C library, so if you don't know what
3   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
4   before changing it!
5
6   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
7        Free Software Foundation, Inc.
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
22
23
24#ifndef EOF
25#include <stdio.h>
26#include <string.h>
27#endif
28
29
30#undef PROGNAME
31#define PROGNAME(x)     (x)
32
33
34/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
35   long-named option.  Because this is not POSIX.2 compliant, it is
36   being phased out.  */
37/* #define GETOPT_COMPAT */
38#undef GETOPT_COMPAT
39
40/* This version of `getopt' appears to the caller like standard Unix `getopt'
41   but it behaves differently for the user, since it allows the user
42   to intersperse the options with the other arguments.
43
44   As `getopt' works, it permutes the elements of ARGV so that,
45   when it is done, all the options precede everything else.  Thus
46   all application programs are extended to handle flexible argument order.
47
48   Setting the environment variable POSIXLY_CORRECT disables permutation.
49   Then the behavior is completely standard.
50
51   GNU application programs can use a third alternative mode in which
52   they can distinguish the relative order of options and other arguments.  */
53
54#include "mygetopt.h"
55#define option                  mfx_option
56#define optarg                  mfx_optarg
57#define optind                  mfx_optind
58#define opterr                  mfx_opterr
59#define optopt                  mfx_optopt
60#undef BAD_OPTION
61
62/* For communication from `getopt' to the caller.
63   When `getopt' finds an option that takes an argument,
64   the argument value is returned here.
65   Also, when `ordering' is RETURN_IN_ORDER,
66   each non-option ARGV-element is returned here.  */
67
68char *optarg = NULL;
69
70/* Index in ARGV of the next element to be scanned.
71   This is used for communication to and from the caller
72   and for communication between successive calls to `getopt'.
73
74   On entry to `getopt', zero means this is the first call; initialize.
75
76   When `getopt' returns EOF, this is the index of the first of the
77   non-option elements that the caller should itself scan.
78
79   Otherwise, `optind' communicates from one call to the next
80   how much of ARGV has been scanned so far.  */
81
82/* XXX 1003.2 says this must be 1 before any call.  */
83int optind = 0;
84
85/* The next char to be scanned in the option-element
86   in which the last option character we returned was found.
87   This allows us to pick up the scan where we left off.
88
89   If this is zero, or a null string, it means resume the scan
90   by advancing to the next ARGV-element.  */
91
92static char *nextchar;
93
94/* Callers store zero here to inhibit the error message
95   for unrecognized options.  */
96
97int opterr = 1;
98
99/* Set to an option character which was unrecognized.
100   This must be initialized on some systems to avoid linking in the
101   system's own getopt implementation.  */
102
103#define BAD_OPTION '\0'
104int optopt = BAD_OPTION;
105
106/* Describe how to deal with options that follow non-option ARGV-elements.
107
108   If the caller did not specify anything,
109   the default is REQUIRE_ORDER if the environment variable
110   POSIXLY_CORRECT is defined, PERMUTE otherwise.
111
112   REQUIRE_ORDER means don't recognize them as options;
113   stop option processing when the first non-option is seen.
114   This is what Unix does.
115   This mode of operation is selected by either setting the environment
116   variable POSIXLY_CORRECT, or using `+' as the first character
117   of the list of option characters.
118
119   PERMUTE is the default.  We permute the contents of ARGV as we scan,
120   so that eventually all the non-options are at the end.  This allows options
121   to be given in any order, even with programs that were not written to
122   expect this.
123
124   RETURN_IN_ORDER is an option available to programs that were written
125   to expect options and other ARGV-elements in any order and that care about
126   the ordering of the two.  We describe each non-option ARGV-element
127   as if it were the argument of an option with character code 1.
128   Using `-' as the first character of the list of option characters
129   selects this mode of operation.
130
131   The special argument `--' forces an end of option-scanning regardless
132   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
133   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
134
135static enum
136{
137  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
138} ordering;
139
140/* Handle permutation of arguments.  */
141
142/* Describe the part of ARGV that contains non-options that have
143   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
144   `last_nonopt' is the index after the last of them.  */
145
146static int first_nonopt;
147static int last_nonopt;
148
149/* Exchange two adjacent subsequences of ARGV.
150   One subsequence is elements [first_nonopt,last_nonopt)
151   which contains all the non-options that have been skipped so far.
152   The other is elements [last_nonopt,optind), which contains all
153   the options processed since those non-options were skipped.
154
155   `first_nonopt' and `last_nonopt' are relocated so that they describe
156   the new indices of the non-options in ARGV after they are moved.
157
158   To perform the swap, we first reverse the order of all elements. So
159   all options now come before all non options, but they are in the
160   wrong order. So we put back the options and non options in original
161   order by reversing them again. For example:
162       original input:      a b c -x -y
163       reverse all:         -y -x c b a
164       reverse options:     -x -y c b a
165       reverse non options: -x -y a b c
166*/
167
168
169static void exchange (char **argv)
170{
171  char *temp; char **first, **last;
172
173  /* Reverse all the elements [first_nonopt, optind) */
174  first = &argv[first_nonopt];
175  last  = &argv[optind-1];
176  while (first < last) {
177    temp = *first; *first = *last; *last = temp; first++; last--;
178  }
179  /* Put back the options in order */
180  first = &argv[first_nonopt];
181  first_nonopt += (optind - last_nonopt);
182  last  = &argv[first_nonopt - 1];
183  while (first < last) {
184    temp = *first; *first = *last; *last = temp; first++; last--;
185  }
186
187  /* Put back the non options in order */
188  first = &argv[first_nonopt];
189  last_nonopt = optind;
190  last  = &argv[last_nonopt-1];
191  while (first < last) {
192    temp = *first; *first = *last; *last = temp; first++; last--;
193  }
194}
195
196/* Scan elements of ARGV (whose length is ARGC) for option characters
197   given in OPTSTRING.
198
199   If an element of ARGV starts with '-', and is not exactly "-" or "--",
200   then it is an option element.  The characters of this element
201   (aside from the initial '-') are option characters.  If `getopt'
202   is called repeatedly, it returns successively each of the option characters
203   from each of the option elements.
204
205   If `getopt' finds another option character, it returns that character,
206   updating `optind' and `nextchar' so that the next call to `getopt' can
207   resume the scan with the following option character or ARGV-element.
208
209   If there are no more option characters, `getopt' returns `EOF'.
210   Then `optind' is the index in ARGV of the first ARGV-element
211   that is not an option.  (The ARGV-elements have been permuted
212   so that those that are not options now come last.)
213
214   OPTSTRING is a string containing the legitimate option characters.
215   If an option character is seen that is not listed in OPTSTRING,
216   return BAD_OPTION after printing an error message.  If you set `opterr' to
217   zero, the error message is suppressed but we still return BAD_OPTION.
218
219   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
220   so the following text in the same ARGV-element, or the text of the following
221   ARGV-element, is returned in `optarg'.  Two colons mean an option that
222   wants an optional arg; if there is text in the current ARGV-element,
223   it is returned in `optarg', otherwise `optarg' is set to zero.
224
225   If OPTSTRING starts with `-' or `+', it requests different methods of
226   handling the non-option ARGV-elements.
227   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
228
229   Long-named options begin with `--' instead of `-'.
230   Their names may be abbreviated as long as the abbreviation is unique
231   or is an exact match for some defined option.  If they have an
232   argument, it follows the option name in the same ARGV-element, separated
233   from the option name by a `=', or else the in next ARGV-element.
234   When `getopt' finds a long-named option, it returns 0 if that option's
235   `flag' field is nonzero, the value of the option's `val' field
236   if the `flag' field is zero.
237
238   LONGOPTS is a vector of `struct option' terminated by an
239   element containing a name which is zero.
240
241   LONGIND returns the index in LONGOPT of the long-named option found.
242   It is only valid when a long-named option has been found by the most
243   recent call.
244
245   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
246   long-named options.  */
247
248static int _getopt_internal (int argc, char **argv, const char *optstring,
249                 const struct option *longopts, int *longind,
250                 int long_only)
251{
252  static char empty_string[1];
253  int option_index;
254
255  if (longind != NULL)
256    *longind = -1;
257
258  optarg = 0;
259
260  /* Initialize the internal data when the first call is made.
261     Start processing options with ARGV-element 1 (since ARGV-element 0
262     is the program name); the sequence of previously skipped
263     non-option ARGV-elements is empty.  */
264
265  if (optind == 0)
266    {
267      first_nonopt = last_nonopt = optind = 1;
268
269      nextchar = NULL;
270
271      /* Determine how to handle the ordering of options and nonoptions.  */
272
273      if (optstring[0] == '-')
274        {
275          ordering = RETURN_IN_ORDER;
276          ++optstring;
277        }
278      else if (optstring[0] == '+')
279        {
280          ordering = REQUIRE_ORDER;
281          ++optstring;
282        }
283#if 0
284      else if (getenv ("POSIXLY_CORRECT") != NULL)
285        ordering = REQUIRE_ORDER;
286#endif
287      else
288        ordering = PERMUTE;
289    }
290
291  if (nextchar == NULL || *nextchar == '\0')
292    {
293      if (ordering == PERMUTE)
294        {
295          /* If we have just processed some options following some non-options,
296             exchange them so that the options come first.  */
297
298          if (first_nonopt != last_nonopt && last_nonopt != optind)
299            exchange (argv);
300          else if (last_nonopt != optind)
301            first_nonopt = optind;
302
303          /* Now skip any additional non-options
304             and extend the range of non-options previously skipped.  */
305
306          while (optind < argc
307                 && (argv[optind][0] != '-' || argv[optind][1] == '\0')
308#ifdef GETOPT_COMPAT
309                 && (longopts == NULL
310                     || argv[optind][0] != '+' || argv[optind][1] == '\0')
311#endif                          /* GETOPT_COMPAT */
312                 )
313            optind++;
314          last_nonopt = optind;
315        }
316
317      /* Special ARGV-element `--' means premature end of options.
318         Skip it like a null option,
319         then exchange with previous non-options as if it were an option,
320         then skip everything else like a non-option.  */
321
322      if (optind != argc && !strcmp (argv[optind], "--"))
323        {
324          optind++;
325
326          if (first_nonopt != last_nonopt && last_nonopt != optind)
327            exchange (argv);
328          else if (first_nonopt == last_nonopt)
329            first_nonopt = optind;
330          last_nonopt = argc;
331
332          optind = argc;
333        }
334
335      /* If we have done all the ARGV-elements, stop the scan
336         and back over any non-options that we skipped and permuted.  */
337
338      if (optind == argc)
339        {
340          /* Set the next-arg-index to point at the non-options
341             that we previously skipped, so the caller will digest them.  */
342          if (first_nonopt != last_nonopt)
343            optind = first_nonopt;
344          return EOF;
345        }
346
347      /* If we have come to a non-option and did not permute it,
348         either stop the scan or describe it to the caller and pass it by.  */
349
350      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
351#ifdef GETOPT_COMPAT
352          && (longopts == NULL
353              || argv[optind][0] != '+' || argv[optind][1] == '\0')
354#endif                          /* GETOPT_COMPAT */
355          )
356        {
357          if (ordering == REQUIRE_ORDER)
358            return EOF;
359          optarg = argv[optind++];
360          return 1;
361        }
362
363      /* We have found another option-ARGV-element.
364         Start decoding its characters.  */
365
366      nextchar = (argv[optind] + 1
367                  + (longopts != NULL && argv[optind][1] == '-'));
368    }
369
370  if (longopts != NULL
371      && ((argv[optind][0] == '-'
372           && (argv[optind][1] == '-' || long_only))
373#ifdef GETOPT_COMPAT
374          || argv[optind][0] == '+'
375#endif                          /* GETOPT_COMPAT */
376          ))
377    {
378      const struct option *p;
379      char *s = nextchar;
380      int exact = 0;
381      int ambig = 0;
382      const struct option *pfound = NULL;
383      int indfound = 0;
384      int needexact = 0;
385
386      /* allow `--option#value' because you cannout assign a '='
387         to an environment variable under DOS command.com */
388      while (*s && *s != '=' && * s != '#')
389        s++;
390
391      /* Test all options for either exact match or abbreviated matches.  */
392      for (p = longopts, option_index = 0; p->name;
393           p++, option_index++)
394        if (!strncmp (p->name, nextchar, (unsigned) (s - nextchar)))
395          {
396            if (p->has_arg & 0x10)
397              needexact = 1;
398            if ((unsigned) (s - nextchar) == strlen (p->name))
399              {
400                /* Exact match found.  */
401                pfound = p;
402                indfound = option_index;
403                exact = 1;
404                break;
405              }
406            else if (pfound == NULL)
407              {
408                /* First nonexact match found.  */
409                pfound = p;
410                indfound = option_index;
411              }
412            else
413              /* Second nonexact match found.  */
414              ambig = 1;
415          }
416
417      /* don't allow nonexact longoptions */
418      if (needexact && !exact)
419        {
420          if (opterr)
421            fprintf (stderr, "%s: unrecognized option `%s'\n",
422                     PROGNAME(argv[0]), argv[optind]);
423          nextchar += strlen (nextchar);
424          optind++;
425          return BAD_OPTION;
426        }
427      if (ambig && !exact)
428        {
429          if (opterr)
430            fprintf (stderr, "%s: option `%s' is ambiguous\n",
431                     PROGNAME(argv[0]), argv[optind]);
432          nextchar += strlen (nextchar);
433          optind++;
434          return BAD_OPTION;
435        }
436
437      if (pfound != NULL)
438        {
439          int have_arg = (s[0] != '\0');
440          if (have_arg && (pfound->has_arg & 0xf))
441            have_arg = (s[1] != '\0');
442          option_index = indfound;
443          optind++;
444          if (have_arg)
445            {
446              /* Don't test has_arg with >, because some C compilers don't
447                 allow it to be used on enums.  */
448              if (pfound->has_arg & 0xf)
449                optarg = s + 1;
450              else
451                {
452                  if (opterr)
453                    {
454                      if (argv[optind - 1][1] == '-')
455                        /* --option */
456                        fprintf (stderr,
457                                 "%s: option `--%s' doesn't allow an argument\n",
458                                 PROGNAME(argv[0]), pfound->name);
459                      else
460                        /* +option or -option */
461                        fprintf (stderr,
462                             "%s: option `%c%s' doesn't allow an argument\n",
463                             PROGNAME(argv[0]), argv[optind - 1][0], pfound->name);
464                    }
465                  nextchar += strlen (nextchar);
466                  return BAD_OPTION;
467                }
468            }
469          else if ((pfound->has_arg & 0xf) == 1)
470            {
471#if 0
472              if (optind < argc)
473#else
474              if (optind < argc && (pfound->has_arg & 0x20) == 0)
475#endif
476                optarg = argv[optind++];
477              else
478                {
479                  if (opterr)
480                    fprintf (stderr, "%s: option `--%s%s' requires an argument\n",
481                             PROGNAME(argv[0]), pfound->name,
482                             (pfound->has_arg & 0x20) ? "=" : "");
483                  nextchar += strlen (nextchar);
484                  return optstring[0] == ':' ? ':' : BAD_OPTION;
485                }
486            }
487          nextchar += strlen (nextchar);
488          if (longind != NULL)
489            *longind = option_index;
490          if (pfound->flag)
491            {
492              *(pfound->flag) = pfound->val;
493              return 0;
494            }
495          return pfound->val;
496        }
497      /* Can't find it as a long option.  If this is not getopt_long_only,
498         or the option starts with '--' or is not a valid short
499         option, then it's an error.
500         Otherwise interpret it as a short option.  */
501      if (!long_only || argv[optind][1] == '-'
502#ifdef GETOPT_COMPAT
503          || argv[optind][0] == '+'
504#endif                          /* GETOPT_COMPAT */
505          || strchr (optstring, *nextchar) == NULL)
506        {
507          if (opterr)
508            {
509              if (argv[optind][1] == '-')
510                /* --option */
511                fprintf (stderr, "%s: unrecognized option `--%s'\n",
512                         PROGNAME(argv[0]), nextchar);
513              else
514                /* +option or -option */
515                fprintf (stderr, "%s: unrecognized option `%c%s'\n",
516                         PROGNAME(argv[0]), argv[optind][0], nextchar);
517            }
518          nextchar = empty_string;
519          optind++;
520          return BAD_OPTION;
521        }
522        (void) &ambig;  /* UNUSED */
523    }
524
525  /* Look at and handle the next option-character.  */
526
527  {
528    char c = *nextchar++;
529    const char *temp = strchr (optstring, c);
530
531    /* Increment `optind' when we start to process its last character.  */
532    if (*nextchar == '\0')
533      ++optind;
534
535    if (temp == NULL || c == ':')
536      {
537        if (opterr)
538          {
539#if 0
540            if (c < 040 || c >= 0177)
541              fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
542                       PROGNAME(argv[0]), c);
543            else
544              fprintf (stderr, "%s: unrecognized option `-%c'\n", PROGNAME(argv[0]), c);
545#else
546            /* 1003.2 specifies the format of this message.  */
547            fprintf (stderr, "%s: illegal option -- %c\n", PROGNAME(argv[0]), c);
548#endif
549          }
550        optopt = c;
551        return BAD_OPTION;
552      }
553    if (temp[1] == ':')
554      {
555        if (temp[2] == ':')
556          {
557            /* This is an option that accepts an argument optionally.  */
558            if (*nextchar != '\0')
559              {
560                optarg = nextchar;
561                optind++;
562              }
563            else
564              optarg = 0;
565            nextchar = NULL;
566          }
567        else
568          {
569            /* This is an option that requires an argument.  */
570            if (*nextchar != '\0')
571              {
572                optarg = nextchar;
573                /* If we end this ARGV-element by taking the rest as an arg,
574                   we must advance to the next element now.  */
575                optind++;
576              }
577            else if (optind == argc)
578              {
579                if (opterr)
580                  {
581#if 0
582                    fprintf (stderr, "%s: option `-%c' requires an argument\n",
583                             PROGNAME(argv[0]), c);
584#else
585                    /* 1003.2 specifies the format of this message.  */
586                    fprintf (stderr, "%s: option requires an argument -- %c\n",
587                             PROGNAME(argv[0]), c);
588#endif
589                  }
590                optopt = c;
591                if (optstring[0] == ':')
592                  c = ':';
593                else
594                  c = BAD_OPTION;
595              }
596            else
597              /* We already incremented `optind' once;
598                 increment it again when taking next ARGV-elt as argument.  */
599              optarg = argv[optind++];
600            nextchar = NULL;
601          }
602      }
603    return c;
604  }
605}
606
607int mfx_getopt(int argc, char **argv, const char *optstring)
608{
609  return _getopt_internal (argc, argv, optstring,
610                           (const struct option *) 0,
611                           (int *) 0,
612                           0);
613}
614
615int mfx_getopt_long(int argc, char **argv, const char *options,
616                    const struct option *long_options, int *opt_index)
617{
618  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
619}
620
621
622#ifdef TEST
623
624/* Compile with -DTEST to make an executable for use in testing
625   the above definition of `getopt'.  */
626
627int
628main (argc, argv)
629     int argc;
630     char **argv;
631{
632  int c;
633  int digit_optind = 0;
634
635  while (1)
636    {
637      int this_option_optind = optind ? optind : 1;
638
639      c = getopt (argc, argv, "abc:d:0123456789");
640      if (c == EOF)
641        break;
642
643      switch (c)
644        {
645        case '0':
646        case '1':
647        case '2':
648        case '3':
649        case '4':
650        case '5':
651        case '6':
652        case '7':
653        case '8':
654        case '9':
655          if (digit_optind != 0 && digit_optind != this_option_optind)
656            printf ("digits occur in two different argv-elements.\n");
657          digit_optind = this_option_optind;
658          printf ("option %c\n", c);
659          break;
660
661        case 'a':
662          printf ("option a\n");
663          break;
664
665        case 'b':
666          printf ("option b\n");
667          break;
668
669        case 'c':
670          printf ("option c with value `%s'\n", optarg);
671          break;
672
673        case BAD_OPTION:
674          break;
675
676        default:
677          printf ("?? getopt returned character code 0%o ??\n", c);
678        }
679    }
680
681  if (optind < argc)
682    {
683      printf ("non-option ARGV-elements: ");
684      while (optind < argc)
685        printf ("%s ", argv[optind++]);
686      printf ("\n");
687    }
688
689  exit (0);
690}
691
692#endif /* TEST */
693
694
695/*
696vi:ts=4:et:nowrap
697*/
698
699