ReactOS 0.4.15-dev-7924-g5949c20
getopt.cpp
Go to the documentation of this file.
1
2// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3// All rights reserved
4// This file was released under the GPLv2 on June 2015.
6
7#include "getopt.h"
8
9
10#ifdef __cplusplus
11extern "C" {
12#endif
13
14/* Describe how to deal with options that follow non-option ARGV-elements.
15
16 If the caller did not specify anything,
17 the default is REQUIRE_ORDER if the environment variable
18 POSIXLY_CORRECT is defined, PERMUTE otherwise.
19
20 REQUIRE_ORDER means don't recognize them as options;
21 stop option processing when the first non-option is seen.
22 This is what Unix does.
23 This mode of operation is selected by either setting the environment
24 variable POSIXLY_CORRECT, or using `+' as the first character
25 of the list of option characters.
26
27 PERMUTE is the default. We permute the contents of ARGV as we scan,
28 so that eventually all the non-options are at the end. This allows options
29 to be given in any order, even with programs that were not written to
30 expect this.
31
32 RETURN_IN_ORDER is an option available to programs that were written
33 to expect options and other ARGV-elements in any order and that care about
34 the ordering of the two. We describe each non-option ARGV-element
35 as if it were the argument of an option with character code 1.
36 Using `-' as the first character of the list of option characters
37 selects this mode of operation.
38
39 The special argument `--' forces an end of option-scanning regardless
40 of the value of `ordering'. In the case of RETURN_IN_ORDER, only
41 `--' can cause `getopt' to return EOF with `optind' != ARGC. */
42
43static enum
44{
47
48#define my_index wcschr
49
50#define my_strtoul wcstoul
51#define my_strlen wcslen
52#define my_strncmp wcsncmp
53#define my_strcpy wcscpy
54#define my_strcat wcscat
55#define my_strcmp wcscmp
56
57/* Handle permutation of arguments. */
58
59
60void
62
63 o->optarg = NULL;
64 o->optind = 0;
65 o->optopt = BAD_OPTION;
66 o->opterr = 1;
67}
68
69static void
71 optarg_ctx* o,
72 WCHAR **argv
73 )
74{
75 WCHAR *temp, **first, **last;
76
77 /* Reverse all the elements [first_nonopt, optind) */
78 first = &argv[o->first_nonopt];
79 last = &argv[o->optind-1];
80 while (first < last) {
81 temp = *first; *first = *last; *last = temp; first++; last--;
82 }
83 /* Put back the options in order */
84 first = &argv[o->first_nonopt];
85 o->first_nonopt += (o->optind - o->last_nonopt);
86 last = &argv[o->first_nonopt - 1];
87 while (first < last) {
88 temp = *first; *first = *last; *last = temp; first++; last--;
89 }
90
91 /* Put back the non options in order */
92 first = &argv[o->first_nonopt];
93 o->last_nonopt = o->optind;
94 last = &argv[o->last_nonopt-1];
95 while (first < last) {
96 temp = *first; *first = *last; *last = temp; first++; last--;
97 }
98}
99
100/* Scan elements of ARGV (whose length is ARGC) for option characters
101 given in OPTSTRING.
102
103 If an element of ARGV starts with '-', and is not exactly "-" or "--",
104 then it is an option element. The characters of this element
105 (aside from the initial '-') are option characters. If `getopt'
106 is called repeatedly, it returns successively each of the option characters
107 from each of the option elements.
108
109 If `getopt' finds another option character, it returns that character,
110 updating `optind' and `nextchar' so that the next call to `getopt' can
111 resume the scan with the following option character or ARGV-element.
112
113 If there are no more option characters, `getopt' returns `EOF'.
114 Then `optind' is the index in ARGV of the first ARGV-element
115 that is not an option. (The ARGV-elements have been permuted
116 so that those that are not options now come last.)
117
118 OPTSTRING is a string containing the legitimate option characters.
119 If an option character is seen that is not listed in OPTSTRING,
120 return BAD_OPTION after printing an error message. If you set `opterr' to
121 zero, the error message is suppressed but we still return BAD_OPTION.
122
123 If a char in OPTSTRING is followed by a colon, that means it wants an arg,
124 so the following text in the same ARGV-element, or the text of the following
125 ARGV-element, is returned in `optarg'. Two colons mean an option that
126 wants an optional arg; if there is text in the current ARGV-element,
127 it is returned in `optarg', otherwise `optarg' is set to zero.
128
129 If OPTSTRING starts with `-' or `+', it requests different methods of
130 handling the non-option ARGV-elements.
131 See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
132
133 Long-named options begin with `--' instead of `-'.
134 Their names may be abbreviated as long as the abbreviation is unique
135 or is an exact match for some defined option. If they have an
136 argument, it follows the option name in the same ARGV-element, separated
137 from the option name by a `=', or else the in next ARGV-element.
138 When `getopt' finds a long-named option, it returns 0 if that option's
139 `flag' field is nonzero, the value of the option's `val' field
140 if the `flag' field is zero.
141
142 The elements of ARGV aren't really const, because we permute them.
143 But we pretend they're const in the prototype to be compatible
144 with other systems.
145
146 LONGOPTS is a vector of `struct option' terminated by an
147 element containing a name which is zero.
148
149 LONGIND returns the index in LONGOPT of the long-named option found.
150 It is only valid when a long-named option has been found by the most
151 recent call.
152
153 If LONG_ONLY is nonzero, '-' as well as '--' can introduce
154 long-named options. */
155
156int
158 optarg_ctx* o,
159 int argc,
160 WCHAR *const *argv,
161 const WCHAR *optstring,
162 const struct option *longopts,
163 int *longind,
164 int long_only)
165{
166 int option_index;
167
168 o->optarg = 0;
169
170 /* Initialize the internal data when the first call is made.
171 Start processing options with ARGV-element 1 (since ARGV-element 0
172 is the program name); the sequence of previously skipped
173 non-option ARGV-elements is empty. */
174
175 if (o->optind == 0)
176 {
177 o->first_nonopt = o->last_nonopt = o->optind = 1;
178
179 o->nextchar = NULL;
180
181 /* Determine how to handle the ordering of options and nonoptions. */
182
183 if (optstring[0] == '-') {
185 ++optstring;
186 } else if (optstring[0] == '+') {
188 ++optstring;
189/* } else if (getenv ("POSIXLY_CORRECT") != NULL) {
190 ordering = REQUIRE_ORDER;*/
191 } else {
193 }
194 }
195
196 if (o->nextchar == NULL || *(o->nextchar) == '\0')
197 {
198 if (ordering == PERMUTE)
199 {
200 /* If we have just processed some options following some non-options,
201 exchange them so that the options come first. */
202
203 if (o->first_nonopt != o->last_nonopt && o->last_nonopt != o->optind) {
204 exchange (o, (WCHAR **) argv);
205 } else if (o->last_nonopt != o->optind) {
206 o->first_nonopt = o->optind;
207 }
208
209 /* Now skip any additional non-options
210 and extend the range of non-options previously skipped. */
211
212 while (o->optind < argc
213 && (argv[o->optind][0] != '-' || argv[o->optind][1] == '\0')
214 ) {
215 o->optind++;
216 }
217 o->last_nonopt = o->optind;
218 }
219
220 /* Special ARGV-element `--' means premature end of options.
221 Skip it like a null option,
222 then exchange with previous non-options as if it were an option,
223 then skip everything else like a non-option. */
224
225 if (o->optind != argc && !my_strcmp (argv[o->optind], L"--"))
226 {
227 o->optind++;
228
229 if (o->first_nonopt != o->last_nonopt && o->last_nonopt != o->optind) {
230 exchange (o, (WCHAR **) argv);
231 } else if (o->first_nonopt == o->last_nonopt) {
232 o->first_nonopt = o->optind;
233 }
234 o->last_nonopt = argc;
235
236 o->optind = argc;
237 }
238
239 /* If we have done all the ARGV-elements, stop the scan
240 and back over any non-options that we skipped and permuted. */
241
242 if (o->optind == argc)
243 {
244 /* Set the next-arg-index to point at the non-options
245 that we previously skipped, so the caller will digest them. */
246 if (o->first_nonopt != o->last_nonopt)
247 o->optind = o->first_nonopt;
248 return EOF;
249 }
250
251 /* If we have come to a non-option and did not permute it,
252 either stop the scan or describe it to the caller and pass it by. */
253
254 if ((argv[o->optind][0] != '-' || argv[o->optind][1] == '\0'))
255 {
256 if (ordering == REQUIRE_ORDER)
257 return EOF;
258 o->optarg = argv[o->optind++];
259 return 1;
260 }
261
262 /* We have found another option-ARGV-element.
263 Start decoding its characters. */
264 o->nextchar = (argv[o->optind] + 1
265 + (longopts != NULL && argv[o->optind][1] == '-'));
266 }
267
268 if (longopts != NULL
269 && ((argv[o->optind][0] == '-'
270 && (argv[o->optind][1] == '-' || long_only))
271 ))
272 {
273 const struct option *p;
274 WCHAR *s = o->nextchar;
275 int exact = 0;
276 int ambig = 0;
277 const struct option *pfound = NULL;
278 int indfound = 0;
279
280 while (*s && *s != '=')
281 s++;
282
283 /* Test all options for either exact match or abbreviated matches. */
284 for (p = longopts, option_index = 0;
285 p->name;
286 p++, option_index++)
287 if ( (p->val) && (!my_strncmp (p->name, o->nextchar, s - o->nextchar)) )
288 {
289 if (s - o->nextchar == (int)my_strlen (p->name))
290 {
291 /* Exact match found. */
292 pfound = p;
293 indfound = option_index;
294 exact = 1;
295 break;
296 } else if (pfound == NULL) {
297 /* First nonexact match found. */
298 pfound = p;
299 indfound = option_index;
300 } else {
301 /* Second nonexact match found. */
302 ambig = 1;
303 }
304 }
305
306 if (ambig && !exact) {
307 if (o->opterr) {
308 UDFPrint(("%ws: option `%s' is ambiguous\n",
309 argv[0], argv[o->optind]));
310 }
311 o->nextchar += my_strlen (o->nextchar);
312 o->optind++;
313 return BAD_OPTION;
314 }
315
316 if (pfound != NULL)
317 {
318 option_index = indfound;
319 o->optind++;
320 if (*s) {
321 /* Don't test has_arg with >, because some C compilers don't
322 allow it to be used on enums. */
323 if (pfound->has_arg) {
324 o->optarg = s + 1;
325 } else {
326 if (o->opterr) {
327 if (argv[o->optind - 1][1] == '-') {
328 /* --option */
329 UDFPrint((
330 "%ws: option `--%ws' doesn't allow an argument\n",
331 argv[0], pfound->name));
332 } else {
333 /* +option or -option */
334 UDFPrint((
335 "%ws: option `%c%ws' doesn't allow an argument\n",
336 argv[0], argv[o->optind - 1][0], pfound->name));
337 }
338 }
339 o->nextchar += my_strlen (o->nextchar);
340 return BAD_OPTION;
341 }
342 }
343 else if (pfound->has_arg == 1)
344 {
345 if (o->optind < argc) {
346 o->optarg = argv[(o->optind)++];
347 } else {
348 if (o->opterr)
349 UDFPrint(("%ws: option `%ws' requires an argument\n",
350 argv[0], argv[o->optind - 1]));
351 o->nextchar += my_strlen (o->nextchar);
352 return optstring[0] == ':' ? ':' : BAD_OPTION;
353 }
354 }
355 o->nextchar += my_strlen (o->nextchar);
356 if (longind != NULL)
357 *longind = option_index;
358 if (pfound->flag) {
359 *(pfound->flag) = pfound->val;
360 return 0;
361 }
362 return pfound->val;
363 }
364 /* Can't find it as a long option. If this is not getopt_long_only,
365 or the option starts with '--' or is not a valid short
366 option, then it's an error.
367 Otherwise interpret it as a short option. */
368 if (!long_only || argv[o->optind][1] == '-'
369 || my_index (optstring, *(o->nextchar)) == NULL)
370 {
371 if (o->opterr)
372 {
373 if (argv[o->optind][1] == '-') {
374 /* --option */
375 UDFPrint(("%ws: unrecognized option `--%ws'\n",
376 argv[0], o->nextchar));
377 } else {
378 /* +option or -option */
379 UDFPrint(("%ws: unrecognized option `%c%ws'\n",
380 argv[0], argv[o->optind][0], o->nextchar));
381 }
382 }
383 o->nextchar = (WCHAR *) L"";
384 o->optind++;
385 return BAD_OPTION;
386 }
387 }
388
389 /* Look at and handle the next option-character. */
390
391 {
392 WCHAR c = *(o->nextchar)++;
393 WCHAR *temp = my_index (optstring, c);
394
395 /* Increment `optind' when we start to process its last character. */
396 if (*(o->nextchar) == '\0')
397 ++(o->optind);
398
399 if (temp == NULL || c == ':')
400 {
401 if (o->opterr)
402 {
403 UDFPrint(("%ws: illegal option -- %c\n", argv[0], c));
404 }
405 o->optopt = c;
406 return BAD_OPTION;
407 }
408 if (temp[1] == ':')
409 {
410 if (temp[2] == ':')
411 {
412 /* This is an option that accepts an argument optionally. */
413 if (*(o->nextchar) != '\0') {
414 o->optarg = o->nextchar;
415 o->optind++;
416 } else {
417 o->optarg = 0;
418 }
419 o->nextchar = NULL;
420 }
421 else
422 {
423 /* This is an option that requires an argument. */
424 if (*(o->nextchar) != '\0')
425 {
426 o->optarg = o->nextchar;
427 /* If we end this ARGV-element by taking the rest as an arg,
428 we must advance to the next element now. */
429 o->optind++;
430 }
431 else if (o->optind == argc)
432 {
433 if (o->opterr)
434 {
435 UDFPrint(("%ws: option requires an argument -- %c\n",
436 argv[0], c));
437 }
438 o->optopt = c;
439 if (optstring[0] == ':') {
440 c = ':';
441 } else {
442 c = BAD_OPTION;
443 }
444 }
445 else
446 {
447 /* We already incremented `optind' once;
448 increment it again when taking next ARGV-elt as argument. */
449 o->optarg = argv[o->optind++];
450 }
451 o->nextchar = NULL;
452 }
453 }
454 return c;
455 }
456}
457
458int
460 optarg_ctx* o,
461 int argc,
462 WCHAR *const *argv,
463 const WCHAR *optstring)
464{
465 return _getopt_internal (o, argc, argv, optstring,
466 (const struct option *) 0,
467 (int *) 0,
468 0);
469}
470
471int
473 optarg_ctx* o,
474 int argc,
475 WCHAR *const *argv,
476 const WCHAR *options,
477 const struct option *long_options,
478 int *opt_index)
479{
480 return _getopt_internal (o, argc, argv, options, long_options, opt_index, 0);
481}
482
483
484#ifdef __cplusplus
485}
486#endif
static int argc
Definition: ServiceArgs.c:12
#define NULL
Definition: types.h:112
#define BAD_OPTION
Definition: getopt.h:14
#define my_strcmp
Definition: getopt.cpp:55
int getopt_long(optarg_ctx *o, int argc, WCHAR *const *argv, const WCHAR *options, const struct option *long_options, int *opt_index)
Definition: getopt.cpp:472
#define my_strlen
Definition: getopt.cpp:51
void getopt_init(optarg_ctx *o)
Definition: getopt.cpp:61
static enum @954 ordering
static void exchange(optarg_ctx *o, WCHAR **argv)
Definition: getopt.cpp:70
#define my_index
Definition: getopt.cpp:48
@ REQUIRE_ORDER
Definition: getopt.cpp:45
@ RETURN_IN_ORDER
Definition: getopt.cpp:45
@ PERMUTE
Definition: getopt.cpp:45
int getopt(optarg_ctx *o, int argc, WCHAR *const *argv, const WCHAR *optstring)
Definition: getopt.cpp:459
int _getopt_internal(optarg_ctx *o, int argc, WCHAR *const *argv, const WCHAR *optstring, const struct option *longopts, int *longind, int long_only)
Definition: getopt.cpp:157
#define my_strncmp
Definition: getopt.cpp:52
GLdouble s
Definition: gl.h:2039
const GLubyte * c
Definition: glext.h:8905
const GLint * first
Definition: glext.h:5794
GLfloat GLfloat p
Definition: glext.h:8902
#define EOF
Definition: stdio.h:24
#define c
Definition: ke_i.h:80
static UINT UINT last
Definition: font.c:45
#define argv
Definition: mplay32.c:18
#define L(x)
Definition: ntvdm.h:50
static calc_node_t temp
Definition: rpn_ieee.c:38
static const char ambig[]
Definition: getopt.c:62
int optind
Definition: getopt.h:37
int opterr
Definition: getopt.h:51
WCHAR * optarg
Definition: getopt.h:23
WCHAR * nextchar
Definition: getopt.h:46
int last_nonopt
Definition: getopt.h:64
int first_nonopt
Definition: getopt.h:63
int optopt
Definition: getopt.h:57
Definition: getopt.h:109
int val
Definition: getopt.h:115
int * flag
Definition: getopt.h:114
int has_arg
Definition: getopt.h:113
WCHAR * name
Definition: getopt.h:110
#define UDFPrint(Args)
Definition: udffs.h:223
static const struct option long_options[]
Definition: widl.c:185
__wchar_t WCHAR
Definition: xmlstorage.h:180