#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 *vlc_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 vlc_optind = 1;
-
-/* 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;
-
-/* 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 vlc_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.
`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 = vlc_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.
/* Update records for the slots the non-options now occupy. */
- first_nonopt += (vlc_optind - last_nonopt);
- last_nonopt = vlc_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 *vlc_getopt_initialize(int, char *const *, const char *);
-
-static const char *
- vlc_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 = vlc_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.
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
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 vlc_option *restrict 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)
{
- vlc_optarg = NULL;
+ state->arg = NULL;
- if (vlc_optind == 0)
+ if (state->ind == 0)
{
- optstring = vlc_getopt_initialize(argc, argv, optstring);
- vlc_optind = 1; /* Don't scan ARGV[0], the program name. */
+ /* 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[vlc_optind][0] != '-' || argv[vlc_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 > vlc_optind)
- last_nonopt = vlc_optind;
- if (first_nonopt > vlc_optind)
- first_nonopt = vlc_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 != vlc_optind)
- exchange((char **) argv);
- else if (last_nonopt != vlc_optind)
- first_nonopt = vlc_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 (vlc_optind < argc && NONOPTION_P)
- vlc_optind++;
- last_nonopt = vlc_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 (vlc_optind != argc && !strcmp(argv[vlc_optind], "--"))
+ if (state->ind != argc && !strcmp(argv[state->ind], "--"))
{
- vlc_optind++;
+ state->ind++;
- if (first_nonopt != last_nonopt && last_nonopt != vlc_optind)
- exchange((char **) argv);
- else if (first_nonopt == last_nonopt)
- first_nonopt = vlc_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;
- vlc_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 (vlc_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)
- vlc_optind = first_nonopt;
+ if (state->first_nonopt != state->last_nonopt)
+ state->ind = state->first_nonopt;
return -1;
}
if (NONOPTION_P)
{
- if (ordering == REQUIRE_ORDER)
- return -1;
- vlc_optarg = argv[vlc_optind++];
+ state->arg = argv[state->ind++];
return 1;
}
/* We have found another option-ARGV-element.
Skip the initial punctuation. */
- nextchar = (argv[vlc_optind] + 1
- + (argv[vlc_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[vlc_optind][1] == '-')
+ if (argv[state->ind][1] == '-')
{
char *nameend;
const struct vlc_option *p;
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. */
if (ambig && !exact)
{
- nextchar += strlen(nextchar);
- vlc_optind++;
- vlc_optopt = 0;
+ state->nextchar += strlen(state->nextchar);
+ state->ind++;
+ state->opt = 0;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
- vlc_optind++;
+ state->ind++;
if (*nameend)
{
if (pfound->has_arg)
- vlc_optarg = nameend + 1;
+ state->arg = nameend + 1;
else
{
- nextchar += strlen(nextchar);
+ state->nextchar += strlen(state->nextchar);
- vlc_optopt = pfound->val;
+ state->opt = pfound->val;
return '?';
}
}
else if (pfound->has_arg)
{
- if (vlc_optind < argc)
- vlc_optarg = argv[vlc_optind++];
+ if (state->ind < argc)
+ state->arg = argv[state->ind++];
else
{
- nextchar += strlen(nextchar);
- vlc_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)
return pfound->val;
}
- nextchar = (char *) "";
- vlc_optind++;
- vlc_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')
- ++vlc_optind;
+ if (*state->nextchar == '\0')
+ ++state->ind;
if (temp == NULL || c == ':')
{
- vlc_optopt = c;
+ state->opt = c;
return '?';
}
/* Convenience. Treat POSIX -W foo same as long option --foo */
int option_index;
/* This is an option that requires an argument. */
- if (*nextchar != '\0')
+ if (*state->nextchar != '\0')
{
- vlc_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. */
- vlc_optind++;
+ state->ind++;
}
- else if (vlc_optind == argc)
+ else if (state->ind == argc)
{
- vlc_optopt = c;
+ state->opt = c;
if (optstring[0] == ':')
c = ':';
else
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
- vlc_optarg = argv[vlc_optind++];
+ state->arg = argv[state->ind++];
/* optarg is now the argument, see if it's in the
table of longopts. */
- for (nextchar = nameend = vlc_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;
}
if (ambig && !exact)
{
- nextchar += strlen(nextchar);
- vlc_optind++;
+ state->nextchar += strlen(state->nextchar);
+ state->ind++;
return '?';
}
if (pfound != NULL)
if (*nameend)
{
if (pfound->has_arg)
- vlc_optarg = nameend + 1;
+ state->arg = nameend + 1;
else
{
- nextchar += strlen(nextchar);
+ state->nextchar += strlen(state->nextchar);
return '?';
}
}
else if (pfound->has_arg)
{
- if (vlc_optind < argc)
- vlc_optarg = argv[vlc_optind++];
+ if (state->ind < argc)
+ state->arg = argv[state->ind++];
else
{
- 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)
}
return pfound->val;
}
- nextchar = NULL;
+ state->nextchar = NULL;
return 'W'; /* Let the application handle it. */
}
if (temp[1] == ':')
{
/* This is an option that requires an argument. */
- if (*nextchar != '\0')
+ if (*state->nextchar != '\0')
{
- vlc_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. */
- vlc_optind++;
+ state->ind++;
}
- else if (vlc_optind == argc)
+ else if (state->ind == argc)
{
- vlc_optopt = c;
+ state->opt = c;
if (optstring[0] == ':')
c = ':';
else
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
- vlc_optarg = argv[vlc_optind++];
- nextchar = NULL;
+ state->arg = argv[state->ind++];
+ state->nextchar = NULL;
}
return c;
}