]> git.sesse.net Git - vlc/blobdiff - src/config/getopt.c
Use var_Inherit* instead of var_CreateGet*.
[vlc] / src / config / getopt.c
index 4a32f558e779ffadb90567ccd6f106fbf248434a..9b1b1aa0fd68deafd4dc861dadc33db69b5e69b9 100644 (file)
 #include <stdio.h>
 #include <string.h>
 
-/* This version of `getopt' appears to the caller like standard Unix `getopt'
-   but it behaves differently for the user, since it allows the user
-   to intersperse the options with the other arguments.
-
-   As `getopt' works, it permutes the elements of ARGV so that,
-   when it is done, all the options precede everything else.  Thus
-   all application programs are extended to handle flexible argument order.
-
-   Setting the environment variable POSIXLY_CORRECT disables permutation.
-   Then the behavior is completely standard.
-
-   GNU application programs can use a third alternative mode in which
-   they can distinguish the relative order of options and other arguments.  */
-
 #include "vlc_getopt.h"
 
-/* For communication from `getopt' to the caller.
-   When `getopt' finds an option that takes an argument,
-   the argument value is returned here.
-   Also, when `ordering' is RETURN_IN_ORDER,
-   each non-option ARGV-element is returned here.  */
-
-char *optarg = NULL;
-
-/* Index in ARGV of the next element to be scanned.
-   This is used for communication to and from the caller
-   and for communication between successive calls to `getopt'.
-
-   On entry to `getopt', zero means this is the first call; initialize.
-
-   When `getopt' returns -1, this is the index of the first of the
-   non-option elements that the caller should itself scan.
-
-   Otherwise, `optind' communicates from one call to the next
-   how much of ARGV has been scanned so far.  */
-
-/* 1003.2 says this must be 1 before any call.  */
-int optind = 1;
-
-/* Formerly, initialization of getopt depended on optind==0, which
-   causes problems with re-calling getopt as programs generally don't
-   know that. */
-
-int __getopt_initialized = 0;
-
-/* The next char to be scanned in the option-element
-   in which the last option character we returned was found.
-   This allows us to pick up the scan where we left off.
-
-   If this is zero, or a null string, it means resume the scan
-   by advancing to the next ARGV-element.  */
-
-static char *nextchar;
-
-/* Callers store zero here to inhibit the error message
-   for unrecognized options.  */
-
-int opterr = 1;
-
-/* Set to an option character which was unrecognized.
-   This must be initialized on some systems to avoid linking in the
-   system's own getopt implementation.  */
-
-int optopt = '?';
-
-/* Describe how to deal with options that follow non-option ARGV-elements.
-
-   If the caller did not specify anything,
-   the default is REQUIRE_ORDER if the environment variable
-   POSIXLY_CORRECT is defined, PERMUTE otherwise.
-
-   REQUIRE_ORDER means don't recognize them as options;
-   stop option processing when the first non-option is seen.
-   This is what Unix does.
-   This mode of operation is selected by either setting the environment
-   variable POSIXLY_CORRECT, or using `+' as the first character
-   of the list of option characters.
-
-   PERMUTE is the default.  We permute the contents of ARGV as we scan,
-   so that eventually all the non-options are at the end.  This allows options
-   to be given in any order, even with programs that were not written to
-   expect this.
-
-   RETURN_IN_ORDER is an option available to programs that were written
-   to expect options and other ARGV-elements in any order and that care about
-   the ordering of the two.  We describe each non-option ARGV-element
-   as if it were the argument of an option with character code 1.
-   Using `-' as the first character of the list of option characters
-   selects this mode of operation.
-
-   The special argument `--' forces an end of option-scanning regardless
-   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
-   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
-
-static enum
-{
-    REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
-}
-ordering;
-
-/* Value of POSIXLY_CORRECT environment variable.  */
-static char *posixly_correct;
-
-/* Handle permutation of arguments.  */
-
-/* Describe the part of ARGV that contains non-options that have
-   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
-   `last_nonopt' is the index after the last of them.  */
-
-static int first_nonopt;
-static int last_nonopt;
-
 /* Exchange two adjacent subsequences of ARGV.
    One subsequence is elements [first_nonopt,last_nonopt)
    which contains all the non-options that have been skipped so far.
@@ -148,15 +38,11 @@ static int last_nonopt;
    `first_nonopt' and `last_nonopt' are relocated so that they describe
    the new indices of the non-options in ARGV after they are moved.  */
 
-static void exchange(char **);
-
-static void
-     exchange(argv)
-     char **argv;
+static void exchange(char **argv, vlc_getopt_t *restrict state)
 {
-    int bottom = first_nonopt;
-    int middle = last_nonopt;
-    int top = optind;
+    int bottom = state->first_nonopt;
+    int middle = state->last_nonopt;
+    int top = state->ind;
     char *tem;
 
     /* Exchange the shorter segment with the far end of the longer segment.
@@ -202,51 +88,10 @@ static void
 
     /* Update records for the slots the non-options now occupy.  */
 
-    first_nonopt += (optind - last_nonopt);
-    last_nonopt = optind;
+    state->first_nonopt += (state->ind - state->last_nonopt);
+    state->last_nonopt = state->ind;
 }
 
-/* Initialize the internal data when the first call is made.  */
-
-static const char *_getopt_initialize(int, char *const *, const char *);
-
-static const char *
-     _getopt_initialize(argc, argv, optstring)
-     int argc;
-     char *const *argv;
-     const char *optstring;
-{
-    (void)argc;
-    (void)argv;
-    /* Start processing options with ARGV-element 1 (since ARGV-element 0
-       is the program name); the sequence of previously skipped
-       non-option ARGV-elements is empty.  */
-
-    first_nonopt = last_nonopt = optind = 1;
-
-    nextchar = NULL;
-
-    posixly_correct = getenv("POSIXLY_CORRECT");
-
-    /* Determine how to handle the ordering of options and nonoptions.  */
-
-    if (optstring[0] == '-')
-    {
-        ordering = RETURN_IN_ORDER;
-        ++optstring;
-    }
-    else if (optstring[0] == '+')
-    {
-        ordering = REQUIRE_ORDER;
-        ++optstring;
-    }
-    else if (posixly_correct != NULL)
-        ordering = REQUIRE_ORDER;
-    else
-        ordering = PERMUTE;
-
-    return optstring;
-}
 \f
 /* Scan elements of ARGV (whose length is ARGC) for option characters
    given in OPTSTRING.
@@ -268,18 +113,15 @@ static const char *
 
    OPTSTRING is a string containing the legitimate option characters.
    If an option character is seen that is not listed in OPTSTRING,
-   return '?' after printing an error message.  If you set `opterr' to
-   zero, the error message is suppressed but we still return '?'.
+   return '?'.
 
    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
    so the following text in the same ARGV-element, or the text of the following
-   ARGV-element, is returned in `optarg'.  Two colons mean an option that
-   wants an optional arg; if there is text in the current ARGV-element,
-   it is returned in `optarg', otherwise `optarg' is set to zero.
+   ARGV-element, is returned in `optarg'.
 
    If OPTSTRING starts with `-' or `+', it requests different methods of
    handling the non-option ARGV-elements.
-   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+   See the comments about REQUIRE_ORDER, above.
 
    Long-named options begin with `--' instead of `-'.
    Their names may be abbreviated as long as the abbreviation is unique
@@ -301,81 +143,80 @@ static const char *
    It is only valid when a long-named option has been found by the most
    recent call.  */
 
-int
-    vlc_getopt_long(argc, argv, optstring, longopts, longind)
-     int argc;
-     char *const *argv;
-     const char *optstring;
-     const struct option *longopts;
-     int *longind;
+int vlc_getopt_long(int argc, char *const *argv,
+                    const char *optstring,
+                    const struct vlc_option *restrict longopts, int *longind,
+                    vlc_getopt_t *restrict state)
 {
-    optarg = NULL;
+    state->arg = NULL;
 
-    if (!__getopt_initialized || optind == 0)
+    if (state->ind == 0)
     {
-        optstring = _getopt_initialize(argc, argv, optstring);
-        optind = 1;    /* Don't scan ARGV[0], the program name.  */
-        __getopt_initialized = 1;
+        /* Initialize the internal data when the first call is made.  */
+        /* Start processing options with ARGV-element 1 (since ARGV-element 0
+           is the program name); the sequence of previously skipped
+           non-option ARGV-elements is empty.  */
+        state->first_nonopt = state->last_nonopt = state->ind = 1;
+        state->nextchar = NULL;
     }
 
-#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#define NONOPTION_P (argv[state->ind][0] != '-' || argv[state->ind][1] == '\0')
 
-    if (nextchar == NULL || *nextchar == '\0')
+    if (state->nextchar == NULL || *state->nextchar == '\0')
     {
         /* Advance to the next ARGV-element.  */
 
         /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
            moved back by the user (who may also have changed the arguments).  */
-        if (last_nonopt > optind)
-            last_nonopt = optind;
-        if (first_nonopt > optind)
-            first_nonopt = optind;
+        if (state->last_nonopt > state->ind)
+            state->last_nonopt = state->ind;
+        if (state->first_nonopt > state->ind)
+            state->first_nonopt = state->ind;
 
-        if (ordering == PERMUTE)
-        {
-            /* If we have just processed some options following some non-options,
-               exchange them so that the options come first.  */
+        /* If we have just processed some options following some non-options,
+           exchange them so that the options come first.  */
 
-            if (first_nonopt != last_nonopt && last_nonopt != optind)
-                exchange((char **) argv);
-            else if (last_nonopt != optind)
-                first_nonopt = optind;
+        if (state->first_nonopt != state->last_nonopt
+            && state->last_nonopt != state->ind)
+            exchange((char **) argv, state);
+        else if (state->last_nonopt != state->ind)
+            state->first_nonopt = state->ind;
 
-            /* Skip any additional non-options
-               and extend the range of non-options previously skipped.  */
+        /* Skip any additional non-options
+           and extend the range of non-options previously skipped.  */
 
-            while (optind < argc && NONOPTION_P)
-                optind++;
-            last_nonopt = optind;
-        }
+        while (state->ind < argc && NONOPTION_P)
+            state->ind++;
+        state->last_nonopt = state->ind;
 
         /* The special ARGV-element `--' means premature end of options.
            Skip it like a null option,
            then exchange with previous non-options as if it were an option,
            then skip everything else like a non-option.  */
 
-        if (optind != argc && !strcmp(argv[optind], "--"))
+        if (state->ind != argc && !strcmp(argv[state->ind], "--"))
         {
-            optind++;
+            state->ind++;
 
-            if (first_nonopt != last_nonopt && last_nonopt != optind)
-                exchange((char **) argv);
-            else if (first_nonopt == last_nonopt)
-                first_nonopt = optind;
-            last_nonopt = argc;
+            if (state->first_nonopt != state->last_nonopt
+                && state->last_nonopt != state->ind)
+                exchange((char **) argv, state);
+            else if (state->first_nonopt == state->last_nonopt)
+                state->first_nonopt = state->ind;
+            state->last_nonopt = argc;
 
-            optind = argc;
+            state->ind = argc;
         }
 
         /* If we have done all the ARGV-elements, stop the scan
            and back over any non-options that we skipped and permuted.  */
 
-        if (optind == argc)
+        if (state->ind == argc)
         {
             /* Set the next-arg-index to point at the non-options
                that we previously skipped, so the caller will digest them.  */
-            if (first_nonopt != last_nonopt)
-                optind = first_nonopt;
+            if (state->first_nonopt != state->last_nonopt)
+                state->ind = state->first_nonopt;
             return -1;
         }
 
@@ -384,42 +225,40 @@ int
 
         if (NONOPTION_P)
         {
-            if (ordering == REQUIRE_ORDER)
-                return -1;
-            optarg = argv[optind++];
+            state->arg = argv[state->ind++];
             return 1;
         }
 
         /* We have found another option-ARGV-element.
            Skip the initial punctuation.  */
 
-        nextchar = (argv[optind] + 1
-                + (argv[optind][1] == '-'));
+        state->nextchar = (argv[state->ind] + 1
+                        + (argv[state->ind][1] == '-'));
     }
 
     /* Decode the current option-ARGV-element.  */
 
     /* Check whether the ARGV-element is a long option.  */
 
-    if (argv[optind][1] == '-')
+    if (argv[state->ind][1] == '-')
     {
         char *nameend;
-        const struct option *p;
-        const struct option *pfound = NULL;
+        const struct vlc_option *p;
+        const struct vlc_option *pfound = NULL;
         int exact = 0;
         int ambig = 0;
         int indfound = -1;
         int option_index;
 
-        for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+        for (nameend = state->nextchar; *nameend && *nameend != '='; nameend++)
             /* Do nothing.  */ ;
 
         /* Test all long options for either exact match
            or abbreviated matches.  */
         for (p = longopts, option_index = 0; p->name; p++, option_index++)
-            if (!strncmp(p->name, nextchar, nameend - nextchar))
+            if (!strncmp(p->name, state->nextchar, nameend - state->nextchar))
             {
-                if ((unsigned int) (nameend - nextchar)
+                if ((unsigned int) (nameend - state->nextchar)
                     == (unsigned int) strlen(p->name))
                 {
                     /* Exact match found.  */
@@ -441,63 +280,40 @@ int
 
         if (ambig && !exact)
         {
-            if (opterr)
-                fprintf(stderr, _("%s: option `%s' is ambiguous\n"),
-                    argv[0], argv[optind]);
-            nextchar += strlen(nextchar);
-            optind++;
-            optopt = 0;
+            state->nextchar += strlen(state->nextchar);
+            state->ind++;
+            state->opt = 0;
             return '?';
         }
 
         if (pfound != NULL)
         {
             option_index = indfound;
-            optind++;
+            state->ind++;
             if (*nameend)
             {
-                /* Don't test has_arg with >, because some C compilers don't
-                   allow it to be used on enums.  */
                 if (pfound->has_arg)
-                    optarg = nameend + 1;
+                    state->arg = nameend + 1;
                 else
                 {
-                    if (opterr)
-                    {
-                        if (argv[optind - 1][1] == '-')
-                            /* --option */
-                            fprintf(stderr,
-                                _("%s: option `--%s' doesn't allow an argument\n"),
-                                argv[0], pfound->name);
-                        else
-                            /* +option or -option */
-                            fprintf(stderr,
-                                _("%s: option `%c%s' doesn't allow an argument\n"),
-                                argv[0], argv[optind - 1][0], pfound->name);
-                    }
-
-                    nextchar += strlen(nextchar);
+                    state->nextchar += strlen(state->nextchar);
 
-                    optopt = pfound->val;
+                    state->opt = pfound->val;
                     return '?';
                 }
             }
-            else if (pfound->has_arg == 1)
+            else if (pfound->has_arg)
             {
-                if (optind < argc)
-                    optarg = argv[optind++];
+                if (state->ind < argc)
+                    state->arg = argv[state->ind++];
                 else
                 {
-                    if (opterr)
-                        fprintf(stderr,
-                            _("%s: option `%s' requires an argument\n"),
-                         argv[0], argv[optind - 1]);
-                    nextchar += strlen(nextchar);
-                    optopt = pfound->val;
+                    state->nextchar += strlen(state->nextchar);
+                    state->opt = pfound->val;
                     return optstring[0] == ':' ? ':' : '?';
                 }
             }
-            nextchar += strlen(nextchar);
+            state->nextchar += strlen(state->nextchar);
             if (longind != NULL)
                 *longind = option_index;
             if (pfound->flag)
@@ -508,80 +324,49 @@ int
             return pfound->val;
         }
 
-        /* Can't find it as a long option.  It's an error.   */
-        if (opterr)
-        {
-            if (argv[optind][1] == '-')
-                /* --option */
-                fprintf(stderr, _("%s: unrecognized option `%s%s'\n"),
-                        "--", argv[0], nextchar);
-            else
-            {
-                char t[2] = { argv[optind][0], '\0' };
-                /* +option or -option */
-                fprintf(stderr, _("%s: unrecognized option `%s%s'\n"),
-                        argv[0], t, nextchar);
-            }
-        }
-        nextchar = (char *) "";
-        optind++;
-        optopt = 0;
+        state->nextchar = (char *) "";
+        state->ind++;
+        state->opt = 0;
         return '?';
     }
 
     /* Look at and handle the next short option-character.  */
 
     {
-        char c = *nextchar++;
+        char c = *(state->nextchar)++;
         char *temp = strchr(optstring, c);
 
         /* Increment `optind' when we start to process its last character.  */
-        if (*nextchar == '\0')
-            ++optind;
+        if (*state->nextchar == '\0')
+            ++state->ind;
 
         if (temp == NULL || c == ':')
         {
-            if (opterr)
-            {
-                if (posixly_correct)
-                    /* 1003.2 specifies the format of this message.  */
-                    fprintf(stderr, _("%s: illegal option -- %c\n"),
-                        argv[0], c);
-                else
-                    fprintf(stderr, _("%s: invalid option -- %c\n"),
-                        argv[0], c);
-            }
-            optopt = c;
+            state->opt = c;
             return '?';
         }
         /* Convenience. Treat POSIX -W foo same as long option --foo */
         if (temp[0] == 'W' && temp[1] == ';')
         {
             char *nameend;
-            const struct option *p;
-            const struct option *pfound = NULL;
+            const struct vlc_option *p;
+            const struct vlc_option *pfound = NULL;
             int exact = 0;
             int ambig = 0;
             int indfound = 0;
             int option_index;
 
             /* This is an option that requires an argument.  */
-            if (*nextchar != '\0')
+            if (*state->nextchar != '\0')
             {
-                optarg = nextchar;
+                state->arg = state->nextchar;
                 /* If we end this ARGV-element by taking the rest as an arg,
                    we must advance to the next element now.  */
-                optind++;
+                state->ind++;
             }
-            else if (optind == argc)
+            else if (state->ind == argc)
             {
-                if (opterr)
-                {
-                    /* 1003.2 specifies the format of this message.  */
-                    fprintf(stderr, _("%s: option requires an argument -- %c\n"),
-                        argv[0], c);
-                }
-                optopt = c;
+                state->opt = c;
                 if (optstring[0] == ':')
                     c = ':';
                 else
@@ -591,20 +376,21 @@ int
             else
                 /* We already incremented `optind' once;
                    increment it again when taking next ARGV-elt as argument.  */
-                optarg = argv[optind++];
+                state->arg = argv[state->ind++];
 
             /* optarg is now the argument, see if it's in the
                table of longopts.  */
 
-            for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+            for (state->nextchar = nameend = state->arg; *nameend && *nameend != '='; nameend++)
                 /* Do nothing.  */ ;
 
             /* Test all long options for either exact match
                or abbreviated matches.  */
             for (p = longopts, option_index = 0; p->name; p++, option_index++)
-                if (!strncmp(p->name, nextchar, nameend - nextchar))
+                if (!strncmp(p->name, state->nextchar, nameend - state->nextchar))
                 {
-                    if ((unsigned int) (nameend - nextchar) == strlen(p->name))
+                    if ((unsigned int) (nameend - state->nextchar)
+                        == strlen(p->name))
                     {
                         /* Exact match found.  */
                         pfound = p;
@@ -624,11 +410,8 @@ int
                 }
             if (ambig && !exact)
             {
-                if (opterr)
-                    fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"),
-                        argv[0], argv[optind]);
-                nextchar += strlen(nextchar);
-                optind++;
+                state->nextchar += strlen(state->nextchar);
+                state->ind++;
                 return '?';
             }
             if (pfound != NULL)
@@ -636,36 +419,25 @@ int
                 option_index = indfound;
                 if (*nameend)
                 {
-                    /* Don't test has_arg with >, because some C compilers don't
-                       allow it to be used on enums.  */
                     if (pfound->has_arg)
-                        optarg = nameend + 1;
+                        state->arg = nameend + 1;
                     else
                     {
-                        if (opterr)
-                            fprintf(stderr, _("\
-%s: option `-W %s' doesn't allow an argument\n"),
-                                argv[0], pfound->name);
-
-                        nextchar += strlen(nextchar);
+                        state->nextchar += strlen(state->nextchar);
                         return '?';
                     }
                 }
-                else if (pfound->has_arg == 1)
+                else if (pfound->has_arg)
                 {
-                    if (optind < argc)
-                        optarg = argv[optind++];
+                    if (state->ind < argc)
+                        state->arg = argv[state->ind++];
                     else
                     {
-                        if (opterr)
-                            fprintf(stderr,
-                                _("%s: option `%s' requires an argument\n"),
-                                argv[0], argv[optind - 1]);
-                        nextchar += strlen(nextchar);
+                        state->nextchar += strlen(state->nextchar);
                         return optstring[0] == ':' ? ':' : '?';
                     }
                 }
-                nextchar += strlen(nextchar);
+                state->nextchar += strlen(state->nextchar);
                 if (longind != NULL)
                     *longind = option_index;
                 if (pfound->flag)
@@ -675,54 +447,32 @@ int
                 }
                 return pfound->val;
             }
-            nextchar = NULL;
+            state->nextchar = NULL;
             return 'W';    /* Let the application handle it.   */
         }
         if (temp[1] == ':')
         {
-            if (temp[2] == ':')
+            /* This is an option that requires an argument.  */
+            if (*state->nextchar != '\0')
             {
-                /* This is an option that accepts an argument optionally.  */
-                if (*nextchar != '\0')
-                {
-                    optarg = nextchar;
-                    optind++;
-                }
-                else
-                    optarg = NULL;
-                nextchar = NULL;
+                state->arg = state->nextchar;
+                /* If we end this ARGV-element by taking the rest as an arg,
+                   we must advance to the next element now.  */
+                state->ind++;
             }
-            else
+            else if (state->ind == argc)
             {
-                /* This is an option that requires an argument.  */
-                if (*nextchar != '\0')
-                {
-                    optarg = nextchar;
-                    /* If we end this ARGV-element by taking the rest as an arg,
-                       we must advance to the next element now.  */
-                    optind++;
-                }
-                else if (optind == argc)
-                {
-                    if (opterr)
-                    {
-                        /* 1003.2 specifies the format of this message.  */
-                        fprintf(stderr,
-                            _("%s: option requires an argument -- %c\n"),
-                            argv[0], c);
-                    }
-                    optopt = c;
-                    if (optstring[0] == ':')
-                        c = ':';
-                    else
-                        c = '?';
-                }
+                state->opt = c;
+                if (optstring[0] == ':')
+                    c = ':';
                 else
-                    /* We already incremented `optind' once;
-                       increment it again when taking next ARGV-elt as argument.  */
-                    optarg = argv[optind++];
-                nextchar = NULL;
+                    c = '?';
             }
+            else
+                /* We already incremented `optind' once;
+                   increment it again when taking next ARGV-elt as argument.  */
+                state->arg = argv[state->ind++];
+            state->nextchar = NULL;
         }
         return c;
     }