meta_engine: support id3v2.4 tag for id3 chapter markers
[vlc.git] / src / config / getopt.c
blobc48838c8f9be4b71288cc533ea5ac957b8ef50cf
1 /*****************************************************************************
2 * getopt_long()
3 *****************************************************************************
4 * Copyright (C) 1987-1997 Free Software Foundation, Inc.
5 * Copyright (C) 2005-2010 VLC authors and VideoLAN
7 * This program is free software; you can redistribute it and/or modify it
8 * 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 Lesser 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 *****************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <vlc_common.h>
27 #include <stdio.h>
28 #include <string.h>
30 #include "vlc_getopt.h"
32 /* Exchange two adjacent subsequences of ARGV.
33 One subsequence is elements [first_nonopt,last_nonopt)
34 which contains all the non-options that have been skipped so far.
35 The other is elements [last_nonopt,optind), which contains all
36 the options processed since those non-options were skipped.
38 `first_nonopt' and `last_nonopt' are relocated so that they describe
39 the new indices of the non-options in ARGV after they are moved. */
41 static void exchange(char **argv, vlc_getopt_t *restrict state)
43 int bottom = state->first_nonopt;
44 int middle = state->last_nonopt;
45 int top = state->ind;
46 char *tem;
48 /* Exchange the shorter segment with the far end of the longer segment.
49 That puts the shorter segment into the right place.
50 It leaves the longer segment in the right place overall,
51 but it consists of two parts that need to be swapped next. */
53 while (top > middle && middle > bottom)
55 if (top - middle > middle - bottom)
57 /* Bottom segment is the short one. */
58 int len = middle - bottom;
59 register int i;
61 /* Swap it with the top part of the top segment. */
62 for (i = 0; i < len; i++)
64 tem = argv[bottom + i];
65 argv[bottom + i] = argv[top - (middle - bottom) + i];
66 argv[top - (middle - bottom) + i] = tem;
68 /* Exclude the moved bottom segment from further swapping. */
69 top -= len;
71 else
73 /* Top segment is the short one. */
74 int len = top - middle;
75 register int i;
77 /* Swap it with the bottom part of the bottom segment. */
78 for (i = 0; i < len; i++)
80 tem = argv[bottom + i];
81 argv[bottom + i] = argv[middle + i];
82 argv[middle + i] = tem;
84 /* Exclude the moved top segment from further swapping. */
85 bottom += len;
89 /* Update records for the slots the non-options now occupy. */
91 state->first_nonopt += (state->ind - state->last_nonopt);
92 state->last_nonopt = state->ind;
96 /* Scan elements of ARGV (whose length is ARGC) for option characters
97 given in OPTSTRING.
99 If an element of ARGV starts with '-', and is not exactly "-" or "--",
100 then it is an option element. The characters of this element
101 (aside from the initial '-') are option characters. If `getopt'
102 is called repeatedly, it returns successively each of the option characters
103 from each of the option elements.
105 If `getopt' finds another option character, it returns that character,
106 updating `optind' and `nextchar' so that the next call to `getopt' can
107 resume the scan with the following option character or ARGV-element.
109 If there are no more option characters, `getopt' returns -1.
110 Then `optind' is the index in ARGV of the first ARGV-element
111 that is not an option. (The ARGV-elements have been permuted
112 so that those that are not options now come last.)
114 OPTSTRING is a string containing the legitimate option characters.
115 If an option character is seen that is not listed in OPTSTRING,
116 return '?'.
118 If a char in OPTSTRING is followed by a colon, that means it wants an arg,
119 so the following text in the same ARGV-element, or the text of the following
120 ARGV-element, is returned in `optarg'.
122 If OPTSTRING starts with `-' or `+', it requests different methods of
123 handling the non-option ARGV-elements.
124 See the comments about REQUIRE_ORDER, above.
126 Long-named options begin with `--' instead of `-'.
127 Their names may be abbreviated as long as the abbreviation is unique
128 or is an exact match for some defined option. If they have an
129 argument, it follows the option name in the same ARGV-element, separated
130 from the option name by a `=', or else the in next ARGV-element.
131 When `getopt' finds a long-named option, it returns 0 if that option's
132 `flag' field is nonzero, the value of the option's `val' field
133 if the `flag' field is zero.
135 The elements of ARGV aren't really const, because we permute them.
136 But we pretend they're const in the prototype to be compatible
137 with other systems.
139 LONGOPTS is a vector of `struct option' terminated by an
140 element containing a name which is zero.
142 LONGIND returns the index in LONGOPT of the long-named option found.
143 It is only valid when a long-named option has been found by the most
144 recent call. */
146 int vlc_getopt_long(int argc, char *const *argv,
147 const char *optstring,
148 const struct vlc_option *restrict longopts, int *longind,
149 vlc_getopt_t *restrict state)
151 state->arg = NULL;
153 if (state->ind == 0)
155 /* Initialize the internal data when the first call is made. */
156 /* Start processing options with ARGV-element 1 (since ARGV-element 0
157 is the program name); the sequence of previously skipped
158 non-option ARGV-elements is empty. */
159 state->first_nonopt = state->last_nonopt = state->ind = 1;
160 state->nextchar = NULL;
163 #define NONOPTION_P (argv[state->ind][0] != '-' || argv[state->ind][1] == '\0')
165 if (state->nextchar == NULL || *state->nextchar == '\0')
167 /* Advance to the next ARGV-element. */
169 /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
170 moved back by the user (who may also have changed the arguments). */
171 if (state->last_nonopt > state->ind)
172 state->last_nonopt = state->ind;
173 if (state->first_nonopt > state->ind)
174 state->first_nonopt = state->ind;
176 /* If we have just processed some options following some non-options,
177 exchange them so that the options come first. */
179 if (state->first_nonopt != state->last_nonopt
180 && state->last_nonopt != state->ind)
181 exchange((char **) argv, state);
182 else if (state->last_nonopt != state->ind)
183 state->first_nonopt = state->ind;
185 /* Skip any additional non-options
186 and extend the range of non-options previously skipped. */
188 while (state->ind < argc && NONOPTION_P)
189 state->ind++;
190 state->last_nonopt = state->ind;
192 /* The special ARGV-element `--' means premature end of options.
193 Skip it like a null option,
194 then exchange with previous non-options as if it were an option,
195 then skip everything else like a non-option. */
197 if (state->ind != argc && !strcmp(argv[state->ind], "--"))
199 state->ind++;
201 if (state->first_nonopt != state->last_nonopt
202 && state->last_nonopt != state->ind)
203 exchange((char **) argv, state);
204 else if (state->first_nonopt == state->last_nonopt)
205 state->first_nonopt = state->ind;
206 state->last_nonopt = argc;
208 state->ind = argc;
211 /* If we have done all the ARGV-elements, stop the scan
212 and back over any non-options that we skipped and permuted. */
214 if (state->ind == argc)
216 /* Set the next-arg-index to point at the non-options
217 that we previously skipped, so the caller will digest them. */
218 if (state->first_nonopt != state->last_nonopt)
219 state->ind = state->first_nonopt;
220 return -1;
223 /* If we have come to a non-option and did not permute it,
224 either stop the scan or describe it to the caller and pass it by. */
226 if (NONOPTION_P)
228 state->arg = argv[state->ind++];
229 return 1;
232 /* We have found another option-ARGV-element.
233 Skip the initial punctuation. */
235 state->nextchar = (argv[state->ind] + 1
236 + (argv[state->ind][1] == '-'));
239 /* Decode the current option-ARGV-element. */
241 /* Check whether the ARGV-element is a long option. */
243 if (argv[state->ind][1] == '-')
245 char *nameend;
246 const struct vlc_option *p;
247 const struct vlc_option *pfound = NULL;
248 int exact = 0;
249 int ambig = 0;
250 int indfound = -1;
251 int option_index;
253 for (nameend = state->nextchar; *nameend && *nameend != '='; nameend++)
254 /* Do nothing. */ ;
256 /* Test all long options for either exact match
257 or abbreviated matches. */
258 for (p = longopts, option_index = 0; p->name; p++, option_index++)
259 if (!strncmp(p->name, state->nextchar, nameend - state->nextchar))
261 if ((unsigned int) (nameend - state->nextchar)
262 == (unsigned int) strlen(p->name))
264 /* Exact match found. */
265 pfound = p;
266 indfound = option_index;
267 exact = 1;
268 break;
270 else if (pfound == NULL)
272 /* First nonexact match found. */
273 pfound = p;
274 indfound = option_index;
276 else
277 /* Second or later nonexact match found. */
278 ambig = 1;
281 if (ambig && !exact)
283 state->nextchar += strlen(state->nextchar);
284 state->ind++;
285 state->opt = 0;
286 return '?';
289 if (pfound != NULL)
291 option_index = indfound;
292 state->ind++;
293 if (*nameend)
295 if (pfound->has_arg)
296 state->arg = nameend + 1;
297 else
299 state->nextchar += strlen(state->nextchar);
301 state->opt = pfound->val;
302 return '?';
305 else if (pfound->has_arg)
307 if (state->ind < argc)
308 state->arg = argv[state->ind++];
309 else
311 state->nextchar += strlen(state->nextchar);
312 state->opt = pfound->val;
313 return optstring[0] == ':' ? ':' : '?';
316 state->nextchar += strlen(state->nextchar);
317 if (longind != NULL)
318 *longind = option_index;
319 if (pfound->flag)
321 *(pfound->flag) = pfound->val;
322 return 0;
324 return pfound->val;
327 state->nextchar = (char *) "";
328 state->ind++;
329 state->opt = 0;
330 return '?';
333 /* Look at and handle the next short option-character. */
336 char c = *(state->nextchar)++;
337 char *temp = strchr(optstring, c);
339 /* Increment `optind' when we start to process its last character. */
340 if (*state->nextchar == '\0')
341 ++state->ind;
343 if (temp == NULL || c == ':')
345 state->opt = c;
346 return '?';
348 /* Convenience. Treat POSIX -W foo same as long option --foo */
349 if (temp[0] == 'W' && temp[1] == ';')
351 char *nameend;
352 const struct vlc_option *p;
353 const struct vlc_option *pfound = NULL;
354 int exact = 0;
355 int ambig = 0;
356 int indfound = 0;
357 int option_index;
359 /* This is an option that requires an argument. */
360 if (*state->nextchar != '\0')
362 state->arg = state->nextchar;
363 /* If we end this ARGV-element by taking the rest as an arg,
364 we must advance to the next element now. */
365 state->ind++;
367 else if (state->ind == argc)
369 state->opt = c;
370 if (optstring[0] == ':')
371 c = ':';
372 else
373 c = '?';
374 return c;
376 else
377 /* We already incremented `optind' once;
378 increment it again when taking next ARGV-elt as argument. */
379 state->arg = argv[state->ind++];
381 /* optarg is now the argument, see if it's in the
382 table of longopts. */
384 for (state->nextchar = nameend = state->arg; *nameend && *nameend != '='; nameend++)
385 /* Do nothing. */ ;
387 /* Test all long options for either exact match
388 or abbreviated matches. */
389 for (p = longopts, option_index = 0; p->name; p++, option_index++)
390 if (!strncmp(p->name, state->nextchar, nameend - state->nextchar))
392 if ((unsigned int) (nameend - state->nextchar)
393 == strlen(p->name))
395 /* Exact match found. */
396 pfound = p;
397 indfound = option_index;
398 exact = 1;
399 break;
401 else if (pfound == NULL)
403 /* First nonexact match found. */
404 pfound = p;
405 indfound = option_index;
407 else
408 /* Second or later nonexact match found. */
409 ambig = 1;
411 if (ambig && !exact)
413 state->nextchar += strlen(state->nextchar);
414 state->ind++;
415 return '?';
417 if (pfound != NULL)
419 option_index = indfound;
420 if (*nameend)
422 if (pfound->has_arg)
423 state->arg = nameend + 1;
424 else
426 state->nextchar += strlen(state->nextchar);
427 return '?';
430 else if (pfound->has_arg)
432 if (state->ind < argc)
433 state->arg = argv[state->ind++];
434 else
436 state->nextchar += strlen(state->nextchar);
437 return optstring[0] == ':' ? ':' : '?';
440 state->nextchar += strlen(state->nextchar);
441 if (longind != NULL)
442 *longind = option_index;
443 if (pfound->flag)
445 *(pfound->flag) = pfound->val;
446 return 0;
448 return pfound->val;
450 state->nextchar = NULL;
451 return 'W'; /* Let the application handle it. */
453 if (temp[1] == ':')
455 /* This is an option that requires an argument. */
456 if (*state->nextchar != '\0')
458 state->arg = state->nextchar;
459 /* If we end this ARGV-element by taking the rest as an arg,
460 we must advance to the next element now. */
461 state->ind++;
463 else if (state->ind == argc)
465 state->opt = c;
466 if (optstring[0] == ':')
467 c = ':';
468 else
469 c = '?';
471 else
472 /* We already incremented `optind' once;
473 increment it again when taking next ARGV-elt as argument. */
474 state->arg = argv[state->ind++];
475 state->nextchar = NULL;
477 return c;