ReactOS  0.4.14-dev-41-g31d7680
getopt.cpp
Go to the documentation of this file.
1 // 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
11 extern "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 
43 static enum
44 {
46 } ordering;
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 
60 void
62 
63  o->optarg = NULL;
64  o->optind = 0;
65  o->optopt = BAD_OPTION;
66  o->opterr = 1;
67 }
68 
69 static 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 
156 int
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 {
192  ordering = PERMUTE;
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 
458 int
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 
471 int
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 void exchange(optarg_ctx *o, WCHAR **argv)
Definition: getopt.cpp:70
static int argc
Definition: ServiceArgs.c:12
#define UDFPrint(Args)
Definition: udffs.h:225
int opterr
Definition: getopt.h:51
int val
Definition: getopt.h:115
#define BAD_OPTION
Definition: getopt.h:14
POINT last
Definition: font.c:46
#define my_strlen
Definition: getopt.cpp:51
const GLint * first
Definition: glext.h:5794
int * flag
Definition: getopt.h:114
#define argv
Definition: mplay32.c:18
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
int last_nonopt
Definition: getopt.h:64
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
static const struct option long_options[]
Definition: widl.c:185
WCHAR * name
Definition: getopt.h:110
smooth NULL
Definition: ftsmooth.c:416
Definition: getopt.h:108
int getopt(optarg_ctx *o, int argc, WCHAR *const *argv, const WCHAR *optstring)
Definition: getopt.cpp:459
int optind
Definition: getopt.h:37
void getopt_init(optarg_ctx *o)
Definition: getopt.cpp:61
__wchar_t WCHAR
Definition: xmlstorage.h:180
static enum @949 ordering
const GLubyte * c
Definition: glext.h:8905
#define my_index
Definition: getopt.cpp:48
static const WCHAR L[]
Definition: oid.c:1250
GLdouble s
Definition: gl.h:2039
#define my_strcmp
Definition: getopt.cpp:55
WCHAR * nextchar
Definition: getopt.h:46
static calc_node_t temp
Definition: rpn_ieee.c:38
int first_nonopt
Definition: getopt.h:63
WCHAR * optarg
Definition: getopt.h:23
#define EOF
Definition: stdio.h:24
#define c
Definition: ke_i.h:80
int has_arg
Definition: getopt.h:113
static const char ambig[]
Definition: getopt.c:62
#define my_strncmp
Definition: getopt.cpp:52
GLfloat GLfloat p
Definition: glext.h:8902
int optopt
Definition: getopt.h:57