Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / stdlib / getopt.c
blobd4f225a7a735dc741d2874eb6c131b6fce2967c5
1 /****************************************************************************
3 getopt.c - Read command line options
5 AUTHOR: Gregory Pietsch
6 CREATED Fri Jan 10 21:13:05 1997
8 DESCRIPTION:
10 The getopt() function parses the command line arguments. Its arguments argc
11 and argv are the argument count and array as passed to the main() function
12 on program invocation. The argument optstring is a list of available option
13 characters. If such a character is followed by a colon (`:'), the option
14 takes an argument, which is placed in optarg. If such a character is
15 followed by two colons, the option takes an optional argument, which is
16 placed in optarg. If the option does not take an argument, optarg is NULL.
18 The external variable optind is the index of the next array element of argv
19 to be processed; it communicates from one call to the next which element to
20 process.
22 The getopt_long() function works like getopt() except that it also accepts
23 long options started by two dashes `--'. If these take values, it is either
24 in the form
26 --arg=value
30 --arg value
32 It takes the additional arguments longopts which is a pointer to the first
33 element of an array of type struct option. The last element of the array
34 has to be filled with NULL for the name field.
36 The longind pointer points to the index of the current long option relative
37 to longopts if it is non-NULL.
39 The getopt() function returns the option character if the option was found
40 successfully, `:' if there was a missing parameter for one of the options,
41 `?' for an unknown option character, and EOF for the end of the option list.
43 The getopt_long() function's return value is described in the header file.
45 The function getopt_long_only() is identical to getopt_long(), except that a
46 plus sign `+' can introduce long options as well as `--'.
48 The following describes how to deal with options that follow non-option
49 argv-elements.
51 If the caller did not specify anything, the default is REQUIRE_ORDER if the
52 environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.
54 REQUIRE_ORDER means don't recognize them as options; stop option processing
55 when the first non-option is seen. This is what Unix does. This mode of
56 operation is selected by either setting the environment variable
57 POSIXLY_CORRECT, or using `+' as the first character of the optstring
58 parameter.
60 PERMUTE is the default. We permute the contents of ARGV as we scan, so that
61 eventually all the non-options are at the end. This allows options to be
62 given in any order, even with programs that were not written to expect this.
64 RETURN_IN_ORDER is an option available to programs that were written to
65 expect options and other argv-elements in any order and that care about the
66 ordering of the two. We describe each non-option argv-element as if it were
67 the argument of an option with character code 1. Using `-' as the first
68 character of the optstring parameter selects this mode of operation.
70 The special argument `--' forces an end of option-scanning regardless of the
71 value of ordering. In the case of RETURN_IN_ORDER, only `--' can cause
72 getopt() and friends to return EOF with optind != argc.
74 2012-08-26: Tried to make the error handling more sus4-like. The functions
75 return a colon if getopt() and friends detect a missing argument and the
76 first character of shortopts/optstring starts with a colon (`:'). If getopt()
77 and friends detect a missing argument and shortopts/optstring does not start
78 with a colon, the function returns a question mark (`?'). If it was a missing
79 argument to a short option, optopt is set to the character in question. The
80 colon goes after the ordering character (`+' or `-').
82 COPYRIGHT NOTICE AND DISCLAIMER:
84 Copyright (C) 1997 Gregory Pietsch
86 This file and the accompanying getopt.h header file are hereby placed in the
87 public domain without restrictions. Just give the author credit, don't
88 claim you wrote it or prevent anyone else from using it.
90 Gregory Pietsch's current e-mail address:
91 gpietsch@comcast.net
92 ****************************************************************************/
94 #ifndef HAVE_GETOPT
96 /* include files */
97 #include <stdio.h>
98 #include <stdlib.h>
99 #include <string.h>
100 #define __need_getopt_newlib
101 #include <getopt.h>
103 /* macros */
105 /* types */
106 typedef enum GETOPT_ORDERING_T
108 PERMUTE,
109 RETURN_IN_ORDER,
110 REQUIRE_ORDER
111 } GETOPT_ORDERING_T;
113 /* globally-defined variables */
114 char *optarg = 0;
115 int optind = 0;
116 int opterr = 1;
117 int optopt = '?';
119 /* static variables */
120 static int optwhere = 0;
121 static int permute_from = 0;
122 static int num_nonopts = 0;
124 /* functions */
126 /* reverse_argv_elements: reverses num elements starting at argv */
127 static void
128 reverse_argv_elements (char **argv, int num)
130 int i;
131 char *tmp;
133 for (i = 0; i < (num >> 1); i++)
135 tmp = argv[i];
136 argv[i] = argv[num - i - 1];
137 argv[num - i - 1] = tmp;
141 /* permute: swap two blocks of argv-elements given their lengths */
142 static void
143 permute (char *const argv[], int len1, int len2)
145 reverse_argv_elements ((char **) argv, len1);
146 reverse_argv_elements ((char **) argv, len1 + len2);
147 reverse_argv_elements ((char **) argv, len2);
150 /* is_option: is this argv-element an option or the end of the option list? */
151 static int
152 is_option (char *argv_element, int only)
154 return ((argv_element == 0)
155 || (argv_element[0] == '-') || (only && argv_element[0] == '+'));
158 /* read_globals: read the values from the globals into a getopt_data
159 structure */
160 static void
161 read_globals (struct getopt_data *data)
163 data->optarg = optarg;
164 data->optind = optind;
165 data->opterr = opterr;
166 data->optopt = optopt;
167 data->optwhere = optwhere;
168 data->permute_from = permute_from;
169 data->num_nonopts = num_nonopts;
172 /* write_globals: write the values into the globals from a getopt_data
173 structure */
174 static void
175 write_globals (struct getopt_data *data)
177 optarg = data->optarg;
178 optind = data->optind;
179 opterr = data->opterr;
180 optopt = data->optopt;
181 optwhere = data->optwhere;
182 permute_from = data->permute_from;
183 num_nonopts = data->num_nonopts;
186 /* getopt_internal: the function that does all the dirty work
187 NOTE: to reduce the code and RAM footprint this function uses
188 fputs()/fputc() to do output to stderr instead of fprintf(). */
189 static int
190 getopt_internal (int argc, char *const argv[], const char *shortopts,
191 const struct option *longopts, int *longind, int only,
192 struct getopt_data *data)
194 GETOPT_ORDERING_T ordering = PERMUTE;
195 int optindex = 0;
196 size_t match_chars = 0;
197 char *possible_arg = 0;
198 int longopt_match = -1;
199 int has_arg = -1;
200 char *cp = 0;
201 int arg_next = 0;
202 int initial_colon = 0;
204 /* first, deal with silly parameters and easy stuff */
205 if (argc == 0 || argv == 0 || (shortopts == 0 && longopts == 0)
206 || data->optind >= argc || argv[data->optind] == 0)
207 return EOF;
208 if (strcmp (argv[data->optind], "--") == 0)
210 data->optind++;
211 return EOF;
214 /* if this is our first time through */
215 if (data->optind == 0)
217 data->optind = 1;
218 data->optwhere = 1;
219 data->permute_from = 0;
220 data->num_nonopts = 0;
223 /* define ordering */
224 if (shortopts != 0 && (*shortopts == '-' || *shortopts == '+'))
226 ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
227 shortopts++;
229 else
230 ordering = (getenv ("POSIXLY_CORRECT") != 0) ? REQUIRE_ORDER : PERMUTE;
232 /* check for initial colon in shortopts */
233 if (shortopts != 0 && *shortopts == ':')
235 ++shortopts;
236 initial_colon = 1;
240 * based on ordering, find our next option, if we're at the beginning of
241 * one
243 if (data->optwhere == 1)
245 switch (ordering)
247 default: /* shouldn't happen */
248 case PERMUTE:
249 data->permute_from = data->optind;
250 data->num_nonopts = 0;
251 while (!is_option (argv[data->optind], only))
253 data->optind++;
254 data->num_nonopts++;
256 if (argv[data->optind] == 0)
258 /* no more options */
259 data->optind = data->permute_from;
260 return EOF;
262 else if (strcmp (argv[data->optind], "--") == 0)
264 /* no more options, but have to get `--' out of the way */
265 permute (argv + data->permute_from, data->num_nonopts, 1);
266 data->optind = data->permute_from + 1;
267 return EOF;
269 break;
270 case RETURN_IN_ORDER:
271 if (!is_option (argv[data->optind], only))
273 data->optarg = argv[data->optind++];
274 return (data->optopt = 1);
276 break;
277 case REQUIRE_ORDER:
278 if (!is_option (argv[data->optind], only))
279 return EOF;
280 break;
283 /* End of option list? */
284 if (argv[data->optind] == 0)
285 return EOF;
287 /* we've got an option, so parse it */
289 /* first, is it a long option? */
290 if (longopts != 0
291 && (memcmp (argv[data->optind], "--", 2) == 0
292 || (only && argv[data->optind][0] == '+')) && data->optwhere == 1)
294 /* handle long options */
295 if (memcmp (argv[data->optind], "--", 2) == 0)
296 data->optwhere = 2;
297 longopt_match = -1;
298 possible_arg = strchr (argv[data->optind] + data->optwhere, '=');
299 if (possible_arg == 0)
301 /* no =, so next argv might be arg */
302 match_chars = strlen (argv[data->optind]);
303 possible_arg = argv[data->optind] + match_chars;
304 match_chars = match_chars - data->optwhere;
306 else
307 match_chars = (possible_arg - argv[data->optind]) - data->optwhere;
308 for (optindex = 0; longopts[optindex].name != 0; ++optindex)
310 if (memcmp
311 (argv[data->optind] + data->optwhere, longopts[optindex].name,
312 match_chars) == 0)
314 /* do we have an exact match? */
315 if (match_chars == strlen (longopts[optindex].name))
317 longopt_match = optindex;
318 break;
320 /* do any characters match? */
321 else
323 if (longopt_match < 0)
324 longopt_match = optindex;
325 else
327 /* we have ambiguous options */
328 if (data->opterr)
330 fputs (argv[0], stderr);
331 fputs (": option `", stderr);
332 fputs (argv[data->optind], stderr);
333 fputs ("' is ambiguous (could be `--", stderr);
334 fputs (longopts[longopt_match].name, stderr);
335 fputs ("' or `--", stderr);
336 fputs (longopts[optindex].name, stderr);
337 fputs ("')\n", stderr);
339 return (data->optopt = '?');
344 if (longopt_match >= 0)
345 has_arg = longopts[longopt_match].has_arg;
348 /* if we didn't find a long option, is it a short option? */
349 if (longopt_match < 0 && shortopts != 0)
351 cp = strchr (shortopts, argv[data->optind][data->optwhere]);
352 if (cp == 0)
354 /* couldn't find option in shortopts */
355 if (data->opterr)
357 fputs (argv[0], stderr);
358 fputs (": invalid option -- `-", stderr);
359 fputc (argv[data->optind][data->optwhere], stderr);
360 fputs ("'\n", stderr);
362 data->optwhere++;
363 if (argv[data->optind][data->optwhere] == '\0')
365 data->optind++;
366 data->optwhere = 1;
368 return (data->optopt = '?');
370 has_arg = ((cp[1] == ':')
371 ? ((cp[2] == ':') ? OPTIONAL_ARG : REQUIRED_ARG) : NO_ARG);
372 possible_arg = argv[data->optind] + data->optwhere + 1;
373 data->optopt = *cp;
376 /* get argument and reset data->optwhere */
377 arg_next = 0;
378 switch (has_arg)
380 case OPTIONAL_ARG:
381 if (*possible_arg == '=')
382 possible_arg++;
383 data->optarg = (*possible_arg != '\0') ? possible_arg : 0;
384 data->optwhere = 1;
385 break;
386 case REQUIRED_ARG:
387 if (*possible_arg == '=')
388 possible_arg++;
389 if (*possible_arg != '\0')
391 data->optarg = possible_arg;
392 data->optwhere = 1;
394 else if (data->optind + 1 >= argc)
396 if (data->opterr)
398 fputs (argv[0], stderr);
399 fputs (": argument required for option `-", stderr);
400 if (longopt_match >= 0)
402 fputc ('-', stderr);
403 fputs (longopts[longopt_match].name, stderr);
404 data->optopt = initial_colon ? ':' : '\?';
406 else
408 fputc (*cp, stderr);
409 data->optopt = *cp;
411 fputs ("'\n", stderr);
413 data->optind++;
414 return initial_colon ? ':' : '\?';
416 else
418 data->optarg = argv[data->optind + 1];
419 arg_next = 1;
420 data->optwhere = 1;
422 break;
423 default: /* shouldn't happen */
424 case NO_ARG:
425 if (longopt_match < 0)
427 data->optwhere++;
428 if (argv[data->optind][data->optwhere] == '\0')
429 data->optwhere = 1;
431 else
432 data->optwhere = 1;
433 data->optarg = 0;
434 break;
437 /* do we have to permute or otherwise modify data->optind? */
438 if (ordering == PERMUTE && data->optwhere == 1 && data->num_nonopts != 0)
440 permute (argv + data->permute_from, data->num_nonopts, 1 + arg_next);
441 data->optind = data->permute_from + 1 + arg_next;
443 else if (data->optwhere == 1)
444 data->optind = data->optind + 1 + arg_next;
446 /* finally return */
447 if (longopt_match >= 0)
449 if (longind != 0)
450 *longind = longopt_match;
451 if (longopts[longopt_match].flag != 0)
453 *(longopts[longopt_match].flag) = longopts[longopt_match].val;
454 return 0;
456 else
457 return longopts[longopt_match].val;
459 else
460 return data->optopt;
464 getopt (int argc, char *const argv[], const char *optstring)
466 struct getopt_data data;
467 int r;
469 read_globals (&data);
470 r = getopt_internal (argc, argv, optstring, 0, 0, 0, &data);
471 write_globals (&data);
472 return r;
476 getopt_long (int argc, char *const argv[], const char *shortopts,
477 const struct option *longopts, int *longind)
479 struct getopt_data data;
480 int r;
482 read_globals (&data);
483 r = getopt_internal (argc, argv, shortopts, longopts, longind, 0, &data);
484 write_globals (&data);
485 return r;
489 getopt_long_only (int argc, char *const argv[], const char *shortopts,
490 const struct option *longopts, int *longind)
492 struct getopt_data data;
493 int r;
495 read_globals (&data);
496 r = getopt_internal (argc, argv, shortopts, longopts, longind, 1, &data);
497 write_globals (&data);
498 return r;
502 __getopt_r (int argc, char *const argv[], const char *optstring,
503 struct getopt_data *data)
505 return getopt_internal (argc, argv, optstring, 0, 0, 0, data);
509 __getopt_long_r (int argc, char *const argv[], const char *shortopts,
510 const struct option *longopts, int *longind,
511 struct getopt_data *data)
513 return getopt_internal (argc, argv, shortopts, longopts, longind, 0, data);
517 __getopt_long_only_r (int argc, char *const argv[], const char *shortopts,
518 const struct option *longopts, int *longind,
519 struct getopt_data *data)
521 return getopt_internal (argc, argv, shortopts, longopts, longind, 1, data);
524 #endif /* !HAVE_GETOPT */
526 /* end of file GETOPT.C */