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