X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fconfig%2Fgetopt.c;h=c48838c8f9be4b71288cc533ea5ac957b8ef50cf;hb=5ebd61f421602d9df5ab47d0044c0d0f32b0156a;hp=08753f71ba6059f88b8ad42e37024006e9190af0;hpb=6edb2da8f463a74490a6a16ddaef86ea6ddb4417;p=vlc diff --git a/src/config/getopt.c b/src/config/getopt.c index 08753f71ba..c48838c8f9 100644 --- a/src/config/getopt.c +++ b/src/config/getopt.c @@ -2,17 +2,17 @@ * getopt_long() ***************************************************************************** * Copyright (C) 1987-1997 Free Software Foundation, Inc. - * Copyright (C) 2005-2010 the VideoLAN team + * Copyright (C) 2005-2010 VLC authors and VideoLAN * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, @@ -27,113 +27,8 @@ #include #include -/* 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; - -/* 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. @@ -143,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. @@ -197,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; -} /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. @@ -267,13 +117,11 @@ static const char * 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 @@ -295,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; } @@ -378,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. */ @@ -435,42 +280,40 @@ int if (ambig && !exact) { - 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 { - 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 { - 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) @@ -481,49 +324,49 @@ int return pfound->val; } - 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 == ':') { - 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) { - optopt = c; + state->opt = c; if (optstring[0] == ':') c = ':'; else @@ -533,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; @@ -566,8 +410,8 @@ int } if (ambig && !exact) { - nextchar += strlen(nextchar); - optind++; + state->nextchar += strlen(state->nextchar); + state->ind++; return '?'; } if (pfound != NULL) @@ -575,27 +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 { - 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 { - 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) @@ -605,47 +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) - { - 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; }