1 /*****************************************************************************
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 *****************************************************************************/
25 #include <vlc_common.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
;
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
;
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. */
73 /* Top segment is the short one. */
74 int len
= top
- middle
;
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. */
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
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,
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
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
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
)
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
)
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
], "--"))
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
;
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
;
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. */
228 state
->arg
= argv
[state
->ind
++];
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] == '-')
246 const struct vlc_option
*p
;
247 const struct vlc_option
*pfound
= NULL
;
253 for (nameend
= state
->nextchar
; *nameend
&& *nameend
!= '='; nameend
++)
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. */
266 indfound
= option_index
;
270 else if (pfound
== NULL
)
272 /* First nonexact match found. */
274 indfound
= option_index
;
277 /* Second or later nonexact match found. */
283 state
->nextchar
+= strlen(state
->nextchar
);
291 option_index
= indfound
;
296 state
->arg
= nameend
+ 1;
299 state
->nextchar
+= strlen(state
->nextchar
);
301 state
->opt
= pfound
->val
;
305 else if (pfound
->has_arg
)
307 if (state
->ind
< argc
)
308 state
->arg
= argv
[state
->ind
++];
311 state
->nextchar
+= strlen(state
->nextchar
);
312 state
->opt
= pfound
->val
;
313 return optstring
[0] == ':' ? ':' : '?';
316 state
->nextchar
+= strlen(state
->nextchar
);
318 *longind
= option_index
;
321 *(pfound
->flag
) = pfound
->val
;
327 state
->nextchar
= (char *) "";
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')
343 if (temp
== NULL
|| c
== ':')
348 /* Convenience. Treat POSIX -W foo same as long option --foo */
349 if (temp
[0] == 'W' && temp
[1] == ';')
352 const struct vlc_option
*p
;
353 const struct vlc_option
*pfound
= NULL
;
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. */
367 else if (state
->ind
== argc
)
370 if (optstring
[0] == ':')
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
++)
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
)
395 /* Exact match found. */
397 indfound
= option_index
;
401 else if (pfound
== NULL
)
403 /* First nonexact match found. */
405 indfound
= option_index
;
408 /* Second or later nonexact match found. */
413 state
->nextchar
+= strlen(state
->nextchar
);
419 option_index
= indfound
;
423 state
->arg
= nameend
+ 1;
426 state
->nextchar
+= strlen(state
->nextchar
);
430 else if (pfound
->has_arg
)
432 if (state
->ind
< argc
)
433 state
->arg
= argv
[state
->ind
++];
436 state
->nextchar
+= strlen(state
->nextchar
);
437 return optstring
[0] == ':' ? ':' : '?';
440 state
->nextchar
+= strlen(state
->nextchar
);
442 *longind
= option_index
;
445 *(pfound
->flag
) = pfound
->val
;
450 state
->nextchar
= NULL
;
451 return 'W'; /* Let the application handle it. */
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. */
463 else if (state
->ind
== argc
)
466 if (optstring
[0] == ':')
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
;