]> git.sesse.net Git - vlc/blob - src/config/getopt.c
getopt: remove useless functions and boiler plate, update licens
[vlc] / src / config / getopt.c
1 /*****************************************************************************
2  * getopt_long()
3  *****************************************************************************
4  * Copyright (C) 1987-1997 Free Software Foundation, Inc.
5  * Copyright (C) 2005-2010 the VideoLAN team
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20  *****************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <vlc_common.h>
26
27 #include <stdio.h>
28 #include <string.h>
29
30 /* This version of `getopt' appears to the caller like standard Unix `getopt'
31    but it behaves differently for the user, since it allows the user
32    to intersperse the options with the other arguments.
33
34    As `getopt' works, it permutes the elements of ARGV so that,
35    when it is done, all the options precede everything else.  Thus
36    all application programs are extended to handle flexible argument order.
37
38    Setting the environment variable POSIXLY_CORRECT disables permutation.
39    Then the behavior is completely standard.
40
41    GNU application programs can use a third alternative mode in which
42    they can distinguish the relative order of options and other arguments.  */
43
44 #include "vlc_getopt.h"
45
46 /* For communication from `getopt' to the caller.
47    When `getopt' finds an option that takes an argument,
48    the argument value is returned here.
49    Also, when `ordering' is RETURN_IN_ORDER,
50    each non-option ARGV-element is returned here.  */
51
52 char *optarg = NULL;
53
54 /* Index in ARGV of the next element to be scanned.
55    This is used for communication to and from the caller
56    and for communication between successive calls to `getopt'.
57
58    On entry to `getopt', zero means this is the first call; initialize.
59
60    When `getopt' returns -1, this is the index of the first of the
61    non-option elements that the caller should itself scan.
62
63    Otherwise, `optind' communicates from one call to the next
64    how much of ARGV has been scanned so far.  */
65
66 /* 1003.2 says this must be 1 before any call.  */
67 int optind = 1;
68
69 /* Formerly, initialization of getopt depended on optind==0, which
70    causes problems with re-calling getopt as programs generally don't
71    know that. */
72
73 int __getopt_initialized = 0;
74
75 /* The next char to be scanned in the option-element
76    in which the last option character we returned was found.
77    This allows us to pick up the scan where we left off.
78
79    If this is zero, or a null string, it means resume the scan
80    by advancing to the next ARGV-element.  */
81
82 static char *nextchar;
83
84 /* Callers store zero here to inhibit the error message
85    for unrecognized options.  */
86
87 int opterr = 1;
88
89 /* Set to an option character which was unrecognized.
90    This must be initialized on some systems to avoid linking in the
91    system's own getopt implementation.  */
92
93 int optopt = '?';
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 -1 with `optind' != ARGC.  */
123
124 static enum
125 {
126     REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
127 }
128 ordering;
129
130 /* Value of POSIXLY_CORRECT environment variable.  */
131 static char *posixly_correct;
132
133 /* Handle permutation of arguments.  */
134
135 /* Describe the part of ARGV that contains non-options that have
136    been skipped.  `first_nonopt' is the index in ARGV of the first of them;
137    `last_nonopt' is the index after the last of them.  */
138
139 static int first_nonopt;
140 static int last_nonopt;
141
142 /* Exchange two adjacent subsequences of ARGV.
143    One subsequence is elements [first_nonopt,last_nonopt)
144    which contains all the non-options that have been skipped so far.
145    The other is elements [last_nonopt,optind), which contains all
146    the options processed since those non-options were skipped.
147
148    `first_nonopt' and `last_nonopt' are relocated so that they describe
149    the new indices of the non-options in ARGV after they are moved.  */
150
151 static void exchange(char **);
152
153 static void
154      exchange(argv)
155      char **argv;
156 {
157     int bottom = first_nonopt;
158     int middle = last_nonopt;
159     int top = optind;
160     char *tem;
161
162     /* Exchange the shorter segment with the far end of the longer segment.
163        That puts the shorter segment into the right place.
164        It leaves the longer segment in the right place overall,
165        but it consists of two parts that need to be swapped next.  */
166
167     while (top > middle && middle > bottom)
168     {
169         if (top - middle > middle - bottom)
170         {
171             /* Bottom segment is the short one.  */
172             int len = middle - bottom;
173             register int i;
174
175             /* Swap it with the top part of the top segment.  */
176             for (i = 0; i < len; i++)
177             {
178                 tem = argv[bottom + i];
179                 argv[bottom + i] = argv[top - (middle - bottom) + i];
180                 argv[top - (middle - bottom) + i] = tem;
181             }
182             /* Exclude the moved bottom segment from further swapping.  */
183             top -= len;
184         }
185         else
186         {
187             /* Top segment is the short one.  */
188             int len = top - middle;
189             register int i;
190
191             /* Swap it with the bottom part of the bottom segment.  */
192             for (i = 0; i < len; i++)
193             {
194                 tem = argv[bottom + i];
195                 argv[bottom + i] = argv[middle + i];
196                 argv[middle + i] = tem;
197             }
198             /* Exclude the moved top segment from further swapping.  */
199             bottom += len;
200         }
201     }
202
203     /* Update records for the slots the non-options now occupy.  */
204
205     first_nonopt += (optind - last_nonopt);
206     last_nonopt = optind;
207 }
208
209 /* Initialize the internal data when the first call is made.  */
210
211 static const char *_getopt_initialize(int, char *const *, const char *);
212
213 static const char *
214      _getopt_initialize(argc, argv, optstring)
215      int argc;
216      char *const *argv;
217      const char *optstring;
218 {
219     (void)argc;
220     (void)argv;
221     /* Start processing options with ARGV-element 1 (since ARGV-element 0
222        is the program name); the sequence of previously skipped
223        non-option ARGV-elements is empty.  */
224
225     first_nonopt = last_nonopt = optind = 1;
226
227     nextchar = NULL;
228
229     posixly_correct = getenv("POSIXLY_CORRECT");
230
231     /* Determine how to handle the ordering of options and nonoptions.  */
232
233     if (optstring[0] == '-')
234     {
235         ordering = RETURN_IN_ORDER;
236         ++optstring;
237     }
238     else if (optstring[0] == '+')
239     {
240         ordering = REQUIRE_ORDER;
241         ++optstring;
242     }
243     else if (posixly_correct != NULL)
244         ordering = REQUIRE_ORDER;
245     else
246         ordering = PERMUTE;
247
248     return optstring;
249 }
250 \f
251 /* Scan elements of ARGV (whose length is ARGC) for option characters
252    given in OPTSTRING.
253
254    If an element of ARGV starts with '-', and is not exactly "-" or "--",
255    then it is an option element.  The characters of this element
256    (aside from the initial '-') are option characters.  If `getopt'
257    is called repeatedly, it returns successively each of the option characters
258    from each of the option elements.
259
260    If `getopt' finds another option character, it returns that character,
261    updating `optind' and `nextchar' so that the next call to `getopt' can
262    resume the scan with the following option character or ARGV-element.
263
264    If there are no more option characters, `getopt' returns -1.
265    Then `optind' is the index in ARGV of the first ARGV-element
266    that is not an option.  (The ARGV-elements have been permuted
267    so that those that are not options now come last.)
268
269    OPTSTRING is a string containing the legitimate option characters.
270    If an option character is seen that is not listed in OPTSTRING,
271    return '?' after printing an error message.  If you set `opterr' to
272    zero, the error message is suppressed but we still return '?'.
273
274    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
275    so the following text in the same ARGV-element, or the text of the following
276    ARGV-element, is returned in `optarg'.  Two colons mean an option that
277    wants an optional arg; if there is text in the current ARGV-element,
278    it is returned in `optarg', otherwise `optarg' is set to zero.
279
280    If OPTSTRING starts with `-' or `+', it requests different methods of
281    handling the non-option ARGV-elements.
282    See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
283
284    Long-named options begin with `--' instead of `-'.
285    Their names may be abbreviated as long as the abbreviation is unique
286    or is an exact match for some defined option.  If they have an
287    argument, it follows the option name in the same ARGV-element, separated
288    from the option name by a `=', or else the in next ARGV-element.
289    When `getopt' finds a long-named option, it returns 0 if that option's
290    `flag' field is nonzero, the value of the option's `val' field
291    if the `flag' field is zero.
292
293    The elements of ARGV aren't really const, because we permute them.
294    But we pretend they're const in the prototype to be compatible
295    with other systems.
296
297    LONGOPTS is a vector of `struct option' terminated by an
298    element containing a name which is zero.
299
300    LONGIND returns the index in LONGOPT of the long-named option found.
301    It is only valid when a long-named option has been found by the most
302    recent call.  */
303
304 int
305     vlc_getopt_long(argc, argv, optstring, longopts, longind)
306      int argc;
307      char *const *argv;
308      const char *optstring;
309      const struct option *longopts;
310      int *longind;
311 {
312     optarg = NULL;
313
314     if (!__getopt_initialized || optind == 0)
315     {
316         optstring = _getopt_initialize(argc, argv, optstring);
317         optind = 1;    /* Don't scan ARGV[0], the program name.  */
318         __getopt_initialized = 1;
319     }
320
321 #define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
322
323     if (nextchar == NULL || *nextchar == '\0')
324     {
325         /* Advance to the next ARGV-element.  */
326
327         /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
328            moved back by the user (who may also have changed the arguments).  */
329         if (last_nonopt > optind)
330             last_nonopt = optind;
331         if (first_nonopt > optind)
332             first_nonopt = optind;
333
334         if (ordering == PERMUTE)
335         {
336             /* If we have just processed some options following some non-options,
337                exchange them so that the options come first.  */
338
339             if (first_nonopt != last_nonopt && last_nonopt != optind)
340                 exchange((char **) argv);
341             else if (last_nonopt != optind)
342                 first_nonopt = optind;
343
344             /* Skip any additional non-options
345                and extend the range of non-options previously skipped.  */
346
347             while (optind < argc && NONOPTION_P)
348                 optind++;
349             last_nonopt = optind;
350         }
351
352         /* The special ARGV-element `--' means premature end of options.
353            Skip it like a null option,
354            then exchange with previous non-options as if it were an option,
355            then skip everything else like a non-option.  */
356
357         if (optind != argc && !strcmp(argv[optind], "--"))
358         {
359             optind++;
360
361             if (first_nonopt != last_nonopt && last_nonopt != optind)
362                 exchange((char **) argv);
363             else if (first_nonopt == last_nonopt)
364                 first_nonopt = optind;
365             last_nonopt = argc;
366
367             optind = argc;
368         }
369
370         /* If we have done all the ARGV-elements, stop the scan
371            and back over any non-options that we skipped and permuted.  */
372
373         if (optind == argc)
374         {
375             /* Set the next-arg-index to point at the non-options
376                that we previously skipped, so the caller will digest them.  */
377             if (first_nonopt != last_nonopt)
378                 optind = first_nonopt;
379             return -1;
380         }
381
382         /* If we have come to a non-option and did not permute it,
383            either stop the scan or describe it to the caller and pass it by.  */
384
385         if (NONOPTION_P)
386         {
387             if (ordering == REQUIRE_ORDER)
388                 return -1;
389             optarg = argv[optind++];
390             return 1;
391         }
392
393         /* We have found another option-ARGV-element.
394            Skip the initial punctuation.  */
395
396         nextchar = (argv[optind] + 1
397                 + (argv[optind][1] == '-'));
398     }
399
400     /* Decode the current option-ARGV-element.  */
401
402     /* Check whether the ARGV-element is a long option.  */
403
404     if (argv[optind][1] == '-')
405     {
406         char *nameend;
407         const struct option *p;
408         const struct option *pfound = NULL;
409         int exact = 0;
410         int ambig = 0;
411         int indfound = -1;
412         int option_index;
413
414         for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
415             /* Do nothing.  */ ;
416
417         /* Test all long options for either exact match
418            or abbreviated matches.  */
419         for (p = longopts, option_index = 0; p->name; p++, option_index++)
420             if (!strncmp(p->name, nextchar, nameend - nextchar))
421             {
422                 if ((unsigned int) (nameend - nextchar)
423                     == (unsigned int) strlen(p->name))
424                 {
425                     /* Exact match found.  */
426                     pfound = p;
427                     indfound = option_index;
428                     exact = 1;
429                     break;
430                 }
431                 else if (pfound == NULL)
432                 {
433                     /* First nonexact match found.  */
434                     pfound = p;
435                     indfound = option_index;
436                 }
437                 else
438                     /* Second or later nonexact match found.  */
439                     ambig = 1;
440             }
441
442         if (ambig && !exact)
443         {
444             if (opterr)
445                 fprintf(stderr, _("%s: option `%s' is ambiguous\n"),
446                     argv[0], argv[optind]);
447             nextchar += strlen(nextchar);
448             optind++;
449             optopt = 0;
450             return '?';
451         }
452
453         if (pfound != NULL)
454         {
455             option_index = indfound;
456             optind++;
457             if (*nameend)
458             {
459                 /* Don't test has_arg with >, because some C compilers don't
460                    allow it to be used on enums.  */
461                 if (pfound->has_arg)
462                     optarg = nameend + 1;
463                 else
464                 {
465                     if (opterr)
466                     {
467                         if (argv[optind - 1][1] == '-')
468                             /* --option */
469                             fprintf(stderr,
470                                 _("%s: option `--%s' doesn't allow an argument\n"),
471                                 argv[0], pfound->name);
472                         else
473                             /* +option or -option */
474                             fprintf(stderr,
475                                 _("%s: option `%c%s' doesn't allow an argument\n"),
476                                 argv[0], argv[optind - 1][0], pfound->name);
477                     }
478
479                     nextchar += strlen(nextchar);
480
481                     optopt = pfound->val;
482                     return '?';
483                 }
484             }
485             else if (pfound->has_arg == 1)
486             {
487                 if (optind < argc)
488                     optarg = argv[optind++];
489                 else
490                 {
491                     if (opterr)
492                         fprintf(stderr,
493                             _("%s: option `%s' requires an argument\n"),
494                          argv[0], argv[optind - 1]);
495                     nextchar += strlen(nextchar);
496                     optopt = pfound->val;
497                     return optstring[0] == ':' ? ':' : '?';
498                 }
499             }
500             nextchar += strlen(nextchar);
501             if (longind != NULL)
502                 *longind = option_index;
503             if (pfound->flag)
504             {
505                 *(pfound->flag) = pfound->val;
506                 return 0;
507             }
508             return pfound->val;
509         }
510
511         /* Can't find it as a long option.  It's an error.   */
512         if (opterr)
513         {
514             if (argv[optind][1] == '-')
515                 /* --option */
516                 fprintf(stderr, _("%s: unrecognized option `%s%s'\n"),
517                         "--", argv[0], nextchar);
518             else
519             {
520                 char t[2] = { argv[optind][0], '\0' };
521                 /* +option or -option */
522                 fprintf(stderr, _("%s: unrecognized option `%s%s'\n"),
523                         argv[0], t, nextchar);
524             }
525         }
526         nextchar = (char *) "";
527         optind++;
528         optopt = 0;
529         return '?';
530     }
531
532     /* Look at and handle the next short option-character.  */
533
534     {
535         char c = *nextchar++;
536         char *temp = strchr(optstring, c);
537
538         /* Increment `optind' when we start to process its last character.  */
539         if (*nextchar == '\0')
540             ++optind;
541
542         if (temp == NULL || c == ':')
543         {
544             if (opterr)
545             {
546                 if (posixly_correct)
547                     /* 1003.2 specifies the format of this message.  */
548                     fprintf(stderr, _("%s: illegal option -- %c\n"),
549                         argv[0], c);
550                 else
551                     fprintf(stderr, _("%s: invalid option -- %c\n"),
552                         argv[0], c);
553             }
554             optopt = c;
555             return '?';
556         }
557         /* Convenience. Treat POSIX -W foo same as long option --foo */
558         if (temp[0] == 'W' && temp[1] == ';')
559         {
560             char *nameend;
561             const struct option *p;
562             const struct option *pfound = NULL;
563             int exact = 0;
564             int ambig = 0;
565             int indfound = 0;
566             int option_index;
567
568             /* This is an option that requires an argument.  */
569             if (*nextchar != '\0')
570             {
571                 optarg = nextchar;
572                 /* If we end this ARGV-element by taking the rest as an arg,
573                    we must advance to the next element now.  */
574                 optind++;
575             }
576             else if (optind == argc)
577             {
578                 if (opterr)
579                 {
580                     /* 1003.2 specifies the format of this message.  */
581                     fprintf(stderr, _("%s: option requires an argument -- %c\n"),
582                         argv[0], c);
583                 }
584                 optopt = c;
585                 if (optstring[0] == ':')
586                     c = ':';
587                 else
588                     c = '?';
589                 return c;
590             }
591             else
592                 /* We already incremented `optind' once;
593                    increment it again when taking next ARGV-elt as argument.  */
594                 optarg = argv[optind++];
595
596             /* optarg is now the argument, see if it's in the
597                table of longopts.  */
598
599             for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
600                 /* Do nothing.  */ ;
601
602             /* Test all long options for either exact match
603                or abbreviated matches.  */
604             for (p = longopts, option_index = 0; p->name; p++, option_index++)
605                 if (!strncmp(p->name, nextchar, nameend - nextchar))
606                 {
607                     if ((unsigned int) (nameend - nextchar) == strlen(p->name))
608                     {
609                         /* Exact match found.  */
610                         pfound = p;
611                         indfound = option_index;
612                         exact = 1;
613                         break;
614                     }
615                     else if (pfound == NULL)
616                     {
617                         /* First nonexact match found.  */
618                         pfound = p;
619                         indfound = option_index;
620                     }
621                     else
622                         /* Second or later nonexact match found.  */
623                         ambig = 1;
624                 }
625             if (ambig && !exact)
626             {
627                 if (opterr)
628                     fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"),
629                         argv[0], argv[optind]);
630                 nextchar += strlen(nextchar);
631                 optind++;
632                 return '?';
633             }
634             if (pfound != NULL)
635             {
636                 option_index = indfound;
637                 if (*nameend)
638                 {
639                     /* Don't test has_arg with >, because some C compilers don't
640                        allow it to be used on enums.  */
641                     if (pfound->has_arg)
642                         optarg = nameend + 1;
643                     else
644                     {
645                         if (opterr)
646                             fprintf(stderr, _("\
647 %s: option `-W %s' doesn't allow an argument\n"),
648                                 argv[0], pfound->name);
649
650                         nextchar += strlen(nextchar);
651                         return '?';
652                     }
653                 }
654                 else if (pfound->has_arg == 1)
655                 {
656                     if (optind < argc)
657                         optarg = argv[optind++];
658                     else
659                     {
660                         if (opterr)
661                             fprintf(stderr,
662                                 _("%s: option `%s' requires an argument\n"),
663                                 argv[0], argv[optind - 1]);
664                         nextchar += strlen(nextchar);
665                         return optstring[0] == ':' ? ':' : '?';
666                     }
667                 }
668                 nextchar += strlen(nextchar);
669                 if (longind != NULL)
670                     *longind = option_index;
671                 if (pfound->flag)
672                 {
673                     *(pfound->flag) = pfound->val;
674                     return 0;
675                 }
676                 return pfound->val;
677             }
678             nextchar = NULL;
679             return 'W';    /* Let the application handle it.   */
680         }
681         if (temp[1] == ':')
682         {
683             if (temp[2] == ':')
684             {
685                 /* This is an option that accepts an argument optionally.  */
686                 if (*nextchar != '\0')
687                 {
688                     optarg = nextchar;
689                     optind++;
690                 }
691                 else
692                     optarg = NULL;
693                 nextchar = NULL;
694             }
695             else
696             {
697                 /* This is an option that requires an argument.  */
698                 if (*nextchar != '\0')
699                 {
700                     optarg = nextchar;
701                     /* If we end this ARGV-element by taking the rest as an arg,
702                        we must advance to the next element now.  */
703                     optind++;
704                 }
705                 else if (optind == argc)
706                 {
707                     if (opterr)
708                     {
709                         /* 1003.2 specifies the format of this message.  */
710                         fprintf(stderr,
711                             _("%s: option requires an argument -- %c\n"),
712                             argv[0], c);
713                     }
714                     optopt = c;
715                     if (optstring[0] == ':')
716                         c = ':';
717                     else
718                         c = '?';
719                 }
720                 else
721                     /* We already incremented `optind' once;
722                        increment it again when taking next ARGV-elt as argument.  */
723                     optarg = argv[optind++];
724                 nextchar = NULL;
725             }
726         }
727         return c;
728     }
729 }