1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 1987-1997 Free Software Foundation, Inc.
5 * Copyright (C) 2005-2010 the VideoLAN team
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.
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.
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 *****************************************************************************/
25 #include <vlc_common.h>
30 #include "vlc_getopt.h"
32 /* For communication from `getopt' to the caller.
33 When `getopt' finds an option that takes an argument,
34 the argument value is returned here. */
36 char *vlc_optarg = NULL;
38 /* Index in ARGV of the next element to be scanned.
39 This is used for communication to and from the caller
40 and for communication between successive calls to `getopt'.
42 On entry to `getopt', zero means this is the first call; initialize.
44 When `getopt' returns -1, this is the index of the first of the
45 non-option elements that the caller should itself scan.
47 Otherwise, `optind' communicates from one call to the next
48 how much of ARGV has been scanned so far. */
50 /* 1003.2 says this must be 1 before any call. */
53 /* The next char to be scanned in the option-element
54 in which the last option character we returned was found.
55 This allows us to pick up the scan where we left off.
57 If this is zero, or a null string, it means resume the scan
58 by advancing to the next ARGV-element. */
60 static char *nextchar;
62 /* Set to an option character which was unrecognized.
63 This must be initialized on some systems to avoid linking in the
64 system's own getopt implementation. */
68 /* Handle permutation of arguments. */
70 /* Describe the part of ARGV that contains non-options that have
71 been skipped. `first_nonopt' is the index in ARGV of the first of them;
72 `last_nonopt' is the index after the last of them. */
74 static int first_nonopt;
75 static int last_nonopt;
77 /* Exchange two adjacent subsequences of ARGV.
78 One subsequence is elements [first_nonopt,last_nonopt)
79 which contains all the non-options that have been skipped so far.
80 The other is elements [last_nonopt,optind), which contains all
81 the options processed since those non-options were skipped.
83 `first_nonopt' and `last_nonopt' are relocated so that they describe
84 the new indices of the non-options in ARGV after they are moved. */
86 static void exchange(char **argv)
88 int bottom = first_nonopt;
89 int middle = last_nonopt;
93 /* Exchange the shorter segment with the far end of the longer segment.
94 That puts the shorter segment into the right place.
95 It leaves the longer segment in the right place overall,
96 but it consists of two parts that need to be swapped next. */
98 while (top > middle && middle > bottom)
100 if (top - middle > middle - bottom)
102 /* Bottom segment is the short one. */
103 int len = middle - bottom;
106 /* Swap it with the top part of the top segment. */
107 for (i = 0; i < len; i++)
109 tem = argv[bottom + i];
110 argv[bottom + i] = argv[top - (middle - bottom) + i];
111 argv[top - (middle - bottom) + i] = tem;
113 /* Exclude the moved bottom segment from further swapping. */
118 /* Top segment is the short one. */
119 int len = top - middle;
122 /* Swap it with the bottom part of the bottom segment. */
123 for (i = 0; i < len; i++)
125 tem = argv[bottom + i];
126 argv[bottom + i] = argv[middle + i];
127 argv[middle + i] = tem;
129 /* Exclude the moved top segment from further swapping. */
134 /* Update records for the slots the non-options now occupy. */
136 first_nonopt += (vlc_optind - last_nonopt);
137 last_nonopt = vlc_optind;
141 /* Scan elements of ARGV (whose length is ARGC) for option characters
144 If an element of ARGV starts with '-', and is not exactly "-" or "--",
145 then it is an option element. The characters of this element
146 (aside from the initial '-') are option characters. If `getopt'
147 is called repeatedly, it returns successively each of the option characters
148 from each of the option elements.
150 If `getopt' finds another option character, it returns that character,
151 updating `optind' and `nextchar' so that the next call to `getopt' can
152 resume the scan with the following option character or ARGV-element.
154 If there are no more option characters, `getopt' returns -1.
155 Then `optind' is the index in ARGV of the first ARGV-element
156 that is not an option. (The ARGV-elements have been permuted
157 so that those that are not options now come last.)
159 OPTSTRING is a string containing the legitimate option characters.
160 If an option character is seen that is not listed in OPTSTRING,
163 If a char in OPTSTRING is followed by a colon, that means it wants an arg,
164 so the following text in the same ARGV-element, or the text of the following
165 ARGV-element, is returned in `optarg'.
167 If OPTSTRING starts with `-' or `+', it requests different methods of
168 handling the non-option ARGV-elements.
169 See the comments about REQUIRE_ORDER, above.
171 Long-named options begin with `--' instead of `-'.
172 Their names may be abbreviated as long as the abbreviation is unique
173 or is an exact match for some defined option. If they have an
174 argument, it follows the option name in the same ARGV-element, separated
175 from the option name by a `=', or else the in next ARGV-element.
176 When `getopt' finds a long-named option, it returns 0 if that option's
177 `flag' field is nonzero, the value of the option's `val' field
178 if the `flag' field is zero.
180 The elements of ARGV aren't really const, because we permute them.
181 But we pretend they're const in the prototype to be compatible
184 LONGOPTS is a vector of `struct option' terminated by an
185 element containing a name which is zero.
187 LONGIND returns the index in LONGOPT of the long-named option found.
188 It is only valid when a long-named option has been found by the most
191 int vlc_getopt_long(int argc, char *const *argv,
192 const char *optstring,
193 const struct vlc_option *restrict longopts, int *longind)
199 /* Initialize the internal data when the first call is made. */
200 /* Start processing options with ARGV-element 1 (since ARGV-element 0
201 is the program name); the sequence of previously skipped
202 non-option ARGV-elements is empty. */
203 first_nonopt = last_nonopt = vlc_optind = 1;
207 #define NONOPTION_P (argv[vlc_optind][0] != '-' || argv[vlc_optind][1] == '\0')
209 if (nextchar == NULL || *nextchar == '\0')
211 /* Advance to the next ARGV-element. */
213 /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
214 moved back by the user (who may also have changed the arguments). */
215 if (last_nonopt > vlc_optind)
216 last_nonopt = vlc_optind;
217 if (first_nonopt > vlc_optind)
218 first_nonopt = vlc_optind;
220 /* If we have just processed some options following some non-options,
221 exchange them so that the options come first. */
223 if (first_nonopt != last_nonopt && last_nonopt != vlc_optind)
224 exchange((char **) argv);
225 else if (last_nonopt != vlc_optind)
226 first_nonopt = vlc_optind;
228 /* Skip any additional non-options
229 and extend the range of non-options previously skipped. */
231 while (vlc_optind < argc && NONOPTION_P)
233 last_nonopt = vlc_optind;
235 /* The special ARGV-element `--' means premature end of options.
236 Skip it like a null option,
237 then exchange with previous non-options as if it were an option,
238 then skip everything else like a non-option. */
240 if (vlc_optind != argc && !strcmp(argv[vlc_optind], "--"))
244 if (first_nonopt != last_nonopt && last_nonopt != vlc_optind)
245 exchange((char **) argv);
246 else if (first_nonopt == last_nonopt)
247 first_nonopt = vlc_optind;
253 /* If we have done all the ARGV-elements, stop the scan
254 and back over any non-options that we skipped and permuted. */
256 if (vlc_optind == argc)
258 /* Set the next-arg-index to point at the non-options
259 that we previously skipped, so the caller will digest them. */
260 if (first_nonopt != last_nonopt)
261 vlc_optind = first_nonopt;
265 /* If we have come to a non-option and did not permute it,
266 either stop the scan or describe it to the caller and pass it by. */
270 vlc_optarg = argv[vlc_optind++];
274 /* We have found another option-ARGV-element.
275 Skip the initial punctuation. */
277 nextchar = (argv[vlc_optind] + 1
278 + (argv[vlc_optind][1] == '-'));
281 /* Decode the current option-ARGV-element. */
283 /* Check whether the ARGV-element is a long option. */
285 if (argv[vlc_optind][1] == '-')
288 const struct vlc_option *p;
289 const struct vlc_option *pfound = NULL;
295 for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
298 /* Test all long options for either exact match
299 or abbreviated matches. */
300 for (p = longopts, option_index = 0; p->name; p++, option_index++)
301 if (!strncmp(p->name, nextchar, nameend - nextchar))
303 if ((unsigned int) (nameend - nextchar)
304 == (unsigned int) strlen(p->name))
306 /* Exact match found. */
308 indfound = option_index;
312 else if (pfound == NULL)
314 /* First nonexact match found. */
316 indfound = option_index;
319 /* Second or later nonexact match found. */
325 nextchar += strlen(nextchar);
333 option_index = indfound;
338 vlc_optarg = nameend + 1;
341 nextchar += strlen(nextchar);
343 vlc_optopt = pfound->val;
347 else if (pfound->has_arg)
349 if (vlc_optind < argc)
350 vlc_optarg = argv[vlc_optind++];
353 nextchar += strlen(nextchar);
354 vlc_optopt = pfound->val;
355 return optstring[0] == ':' ? ':' : '?';
358 nextchar += strlen(nextchar);
360 *longind = option_index;
363 *(pfound->flag) = pfound->val;
369 nextchar = (char *) "";
375 /* Look at and handle the next short option-character. */
378 char c = *nextchar++;
379 char *temp = strchr(optstring, c);
381 /* Increment `optind' when we start to process its last character. */
382 if (*nextchar == '\0')
385 if (temp == NULL || c == ':')
390 /* Convenience. Treat POSIX -W foo same as long option --foo */
391 if (temp[0] == 'W' && temp[1] == ';')
394 const struct vlc_option *p;
395 const struct vlc_option *pfound = NULL;
401 /* This is an option that requires an argument. */
402 if (*nextchar != '\0')
404 vlc_optarg = nextchar;
405 /* If we end this ARGV-element by taking the rest as an arg,
406 we must advance to the next element now. */
409 else if (vlc_optind == argc)
412 if (optstring[0] == ':')
419 /* We already incremented `optind' once;
420 increment it again when taking next ARGV-elt as argument. */
421 vlc_optarg = argv[vlc_optind++];
423 /* optarg is now the argument, see if it's in the
424 table of longopts. */
426 for (nextchar = nameend = vlc_optarg; *nameend && *nameend != '='; nameend++)
429 /* Test all long options for either exact match
430 or abbreviated matches. */
431 for (p = longopts, option_index = 0; p->name; p++, option_index++)
432 if (!strncmp(p->name, nextchar, nameend - nextchar))
434 if ((unsigned int) (nameend - nextchar) == strlen(p->name))
436 /* Exact match found. */
438 indfound = option_index;
442 else if (pfound == NULL)
444 /* First nonexact match found. */
446 indfound = option_index;
449 /* Second or later nonexact match found. */
454 nextchar += strlen(nextchar);
460 option_index = indfound;
464 vlc_optarg = nameend + 1;
467 nextchar += strlen(nextchar);
471 else if (pfound->has_arg)
473 if (vlc_optind < argc)
474 vlc_optarg = argv[vlc_optind++];
477 nextchar += strlen(nextchar);
478 return optstring[0] == ':' ? ':' : '?';
481 nextchar += strlen(nextchar);
483 *longind = option_index;
486 *(pfound->flag) = pfound->val;
492 return 'W'; /* Let the application handle it. */
496 /* This is an option that requires an argument. */
497 if (*nextchar != '\0')
499 vlc_optarg = nextchar;
500 /* If we end this ARGV-element by taking the rest as an arg,
501 we must advance to the next element now. */
504 else if (vlc_optind == argc)
507 if (optstring[0] == ':')
513 /* We already incremented `optind' once;
514 increment it again when taking next ARGV-elt as argument. */
515 vlc_optarg = argv[vlc_optind++];