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 **);
92 int bottom = first_nonopt;
93 int middle = last_nonopt;
97 /* Exchange the shorter segment with the far end of the longer segment.
98 That puts the shorter segment into the right place.
99 It leaves the longer segment in the right place overall,
100 but it consists of two parts that need to be swapped next. */
102 while (top > middle && middle > bottom)
104 if (top - middle > middle - bottom)
106 /* Bottom segment is the short one. */
107 int len = middle - bottom;
110 /* Swap it with the top part of the top segment. */
111 for (i = 0; i < len; i++)
113 tem = argv[bottom + i];
114 argv[bottom + i] = argv[top - (middle - bottom) + i];
115 argv[top - (middle - bottom) + i] = tem;
117 /* Exclude the moved bottom segment from further swapping. */
122 /* Top segment is the short one. */
123 int len = top - middle;
126 /* Swap it with the bottom part of the bottom segment. */
127 for (i = 0; i < len; i++)
129 tem = argv[bottom + i];
130 argv[bottom + i] = argv[middle + i];
131 argv[middle + i] = tem;
133 /* Exclude the moved top segment from further swapping. */
138 /* Update records for the slots the non-options now occupy. */
140 first_nonopt += (vlc_optind - last_nonopt);
141 last_nonopt = vlc_optind;
145 /* Scan elements of ARGV (whose length is ARGC) for option characters
148 If an element of ARGV starts with '-', and is not exactly "-" or "--",
149 then it is an option element. The characters of this element
150 (aside from the initial '-') are option characters. If `getopt'
151 is called repeatedly, it returns successively each of the option characters
152 from each of the option elements.
154 If `getopt' finds another option character, it returns that character,
155 updating `optind' and `nextchar' so that the next call to `getopt' can
156 resume the scan with the following option character or ARGV-element.
158 If there are no more option characters, `getopt' returns -1.
159 Then `optind' is the index in ARGV of the first ARGV-element
160 that is not an option. (The ARGV-elements have been permuted
161 so that those that are not options now come last.)
163 OPTSTRING is a string containing the legitimate option characters.
164 If an option character is seen that is not listed in OPTSTRING,
167 If a char in OPTSTRING is followed by a colon, that means it wants an arg,
168 so the following text in the same ARGV-element, or the text of the following
169 ARGV-element, is returned in `optarg'.
171 If OPTSTRING starts with `-' or `+', it requests different methods of
172 handling the non-option ARGV-elements.
173 See the comments about REQUIRE_ORDER, above.
175 Long-named options begin with `--' instead of `-'.
176 Their names may be abbreviated as long as the abbreviation is unique
177 or is an exact match for some defined option. If they have an
178 argument, it follows the option name in the same ARGV-element, separated
179 from the option name by a `=', or else the in next ARGV-element.
180 When `getopt' finds a long-named option, it returns 0 if that option's
181 `flag' field is nonzero, the value of the option's `val' field
182 if the `flag' field is zero.
184 The elements of ARGV aren't really const, because we permute them.
185 But we pretend they're const in the prototype to be compatible
188 LONGOPTS is a vector of `struct option' terminated by an
189 element containing a name which is zero.
191 LONGIND returns the index in LONGOPT of the long-named option found.
192 It is only valid when a long-named option has been found by the most
196 vlc_getopt_long(argc, argv, optstring, longopts, longind)
199 const char *optstring;
200 const struct vlc_option *restrict longopts;
207 /* Initialize the internal data when the first call is made. */
208 /* Start processing options with ARGV-element 1 (since ARGV-element 0
209 is the program name); the sequence of previously skipped
210 non-option ARGV-elements is empty. */
211 first_nonopt = last_nonopt = vlc_optind = 1;
215 #define NONOPTION_P (argv[vlc_optind][0] != '-' || argv[vlc_optind][1] == '\0')
217 if (nextchar == NULL || *nextchar == '\0')
219 /* Advance to the next ARGV-element. */
221 /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
222 moved back by the user (who may also have changed the arguments). */
223 if (last_nonopt > vlc_optind)
224 last_nonopt = vlc_optind;
225 if (first_nonopt > vlc_optind)
226 first_nonopt = vlc_optind;
228 /* If we have just processed some options following some non-options,
229 exchange them so that the options come first. */
231 if (first_nonopt != last_nonopt && last_nonopt != vlc_optind)
232 exchange((char **) argv);
233 else if (last_nonopt != vlc_optind)
234 first_nonopt = vlc_optind;
236 /* Skip any additional non-options
237 and extend the range of non-options previously skipped. */
239 while (vlc_optind < argc && NONOPTION_P)
241 last_nonopt = vlc_optind;
243 /* The special ARGV-element `--' means premature end of options.
244 Skip it like a null option,
245 then exchange with previous non-options as if it were an option,
246 then skip everything else like a non-option. */
248 if (vlc_optind != argc && !strcmp(argv[vlc_optind], "--"))
252 if (first_nonopt != last_nonopt && last_nonopt != vlc_optind)
253 exchange((char **) argv);
254 else if (first_nonopt == last_nonopt)
255 first_nonopt = vlc_optind;
261 /* If we have done all the ARGV-elements, stop the scan
262 and back over any non-options that we skipped and permuted. */
264 if (vlc_optind == argc)
266 /* Set the next-arg-index to point at the non-options
267 that we previously skipped, so the caller will digest them. */
268 if (first_nonopt != last_nonopt)
269 vlc_optind = first_nonopt;
273 /* If we have come to a non-option and did not permute it,
274 either stop the scan or describe it to the caller and pass it by. */
278 vlc_optarg = argv[vlc_optind++];
282 /* We have found another option-ARGV-element.
283 Skip the initial punctuation. */
285 nextchar = (argv[vlc_optind] + 1
286 + (argv[vlc_optind][1] == '-'));
289 /* Decode the current option-ARGV-element. */
291 /* Check whether the ARGV-element is a long option. */
293 if (argv[vlc_optind][1] == '-')
296 const struct vlc_option *p;
297 const struct vlc_option *pfound = NULL;
303 for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
306 /* Test all long options for either exact match
307 or abbreviated matches. */
308 for (p = longopts, option_index = 0; p->name; p++, option_index++)
309 if (!strncmp(p->name, nextchar, nameend - nextchar))
311 if ((unsigned int) (nameend - nextchar)
312 == (unsigned int) strlen(p->name))
314 /* Exact match found. */
316 indfound = option_index;
320 else if (pfound == NULL)
322 /* First nonexact match found. */
324 indfound = option_index;
327 /* Second or later nonexact match found. */
333 nextchar += strlen(nextchar);
341 option_index = indfound;
346 vlc_optarg = nameend + 1;
349 nextchar += strlen(nextchar);
351 vlc_optopt = pfound->val;
355 else if (pfound->has_arg)
357 if (vlc_optind < argc)
358 vlc_optarg = argv[vlc_optind++];
361 nextchar += strlen(nextchar);
362 vlc_optopt = pfound->val;
363 return optstring[0] == ':' ? ':' : '?';
366 nextchar += strlen(nextchar);
368 *longind = option_index;
371 *(pfound->flag) = pfound->val;
377 nextchar = (char *) "";
383 /* Look at and handle the next short option-character. */
386 char c = *nextchar++;
387 char *temp = strchr(optstring, c);
389 /* Increment `optind' when we start to process its last character. */
390 if (*nextchar == '\0')
393 if (temp == NULL || c == ':')
398 /* Convenience. Treat POSIX -W foo same as long option --foo */
399 if (temp[0] == 'W' && temp[1] == ';')
402 const struct vlc_option *p;
403 const struct vlc_option *pfound = NULL;
409 /* This is an option that requires an argument. */
410 if (*nextchar != '\0')
412 vlc_optarg = nextchar;
413 /* If we end this ARGV-element by taking the rest as an arg,
414 we must advance to the next element now. */
417 else if (vlc_optind == argc)
420 if (optstring[0] == ':')
427 /* We already incremented `optind' once;
428 increment it again when taking next ARGV-elt as argument. */
429 vlc_optarg = argv[vlc_optind++];
431 /* optarg is now the argument, see if it's in the
432 table of longopts. */
434 for (nextchar = nameend = vlc_optarg; *nameend && *nameend != '='; nameend++)
437 /* Test all long options for either exact match
438 or abbreviated matches. */
439 for (p = longopts, option_index = 0; p->name; p++, option_index++)
440 if (!strncmp(p->name, nextchar, nameend - nextchar))
442 if ((unsigned int) (nameend - nextchar) == strlen(p->name))
444 /* Exact match found. */
446 indfound = option_index;
450 else if (pfound == NULL)
452 /* First nonexact match found. */
454 indfound = option_index;
457 /* Second or later nonexact match found. */
462 nextchar += strlen(nextchar);
468 option_index = indfound;
472 vlc_optarg = nameend + 1;
475 nextchar += strlen(nextchar);
479 else if (pfound->has_arg)
481 if (vlc_optind < argc)
482 vlc_optarg = argv[vlc_optind++];
485 nextchar += strlen(nextchar);
486 return optstring[0] == ':' ? ':' : '?';
489 nextchar += strlen(nextchar);
491 *longind = option_index;
494 *(pfound->flag) = pfound->val;
500 return 'W'; /* Let the application handle it. */
504 /* This is an option that requires an argument. */
505 if (*nextchar != '\0')
507 vlc_optarg = nextchar;
508 /* If we end this ARGV-element by taking the rest as an arg,
509 we must advance to the next element now. */
512 else if (vlc_optind == argc)
515 if (optstring[0] == ':')
521 /* We already incremented `optind' once;
522 increment it again when taking next ARGV-elt as argument. */
523 vlc_optarg = argv[vlc_optind++];