]> sourceware.org Git - newlib-cygwin.git/blame - newlib/libc/stdlib/getopt.c
2008-03-07 Jeff Johnston <jjohnstn@redhat.com>
[newlib-cygwin.git] / newlib / libc / stdlib / getopt.c
CommitLineData
791c9bda 1/****************************************************************************
8a0efa53 2
791c9bda
JJ
3getopt.c - Read command line options
4
5AUTHOR: Gregory Pietsch
6CREATED Fri Jan 10 21:13:05 1997
7
8DESCRIPTION:
9
10The getopt() function parses the command line arguments. Its arguments argc
11and argv are the argument count and array as passed to the main() function
12on program invocation. The argument optstring is a list of available option
13characters. If such a character is followed by a colon (`:'), the option
14takes an argument, which is placed in optarg. If such a character is
15followed by two colons, the option takes an optional argument, which is
16placed in optarg. If the option does not take an argument, optarg is NULL.
17
18The external variable optind is the index of the next array element of argv
19to be processed; it communicates from one call to the next which element to
20process.
21
22The getopt_long() function works like getopt() except that it also accepts
23long options started by two dashes `--'. If these take values, it is either
24in the form
25
26--arg=value
27
28 or
29
30--arg value
31
32It takes the additional arguments longopts which is a pointer to the first
33element of an array of type struct option. The last element of the array
34has to be filled with NULL for the name field.
35
36The longind pointer points to the index of the current long option relative
37to longopts if it is non-NULL.
38
39The getopt() function returns the option character if the option was found
40successfully, `:' 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.
42
43The getopt_long() function's return value is described in the header file.
44
45The function getopt_long_only() is identical to getopt_long(), except that a
46plus sign `+' can introduce long options as well as `--'.
47
48The following describes how to deal with options that follow non-option
49argv-elements.
50
51If the caller did not specify anything, the default is REQUIRE_ORDER if the
52environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.
53
54REQUIRE_ORDER means don't recognize them as options; stop option processing
55when the first non-option is seen. This is what Unix does. This mode of
56operation is selected by either setting the environment variable
57POSIXLY_CORRECT, or using `+' as the first character of the optstring
58parameter.
59
60PERMUTE is the default. We permute the contents of ARGV as we scan, so that
61eventually all the non-options are at the end. This allows options to be
62given in any order, even with programs that were not written to expect this.
63
64RETURN_IN_ORDER is an option available to programs that were written to
65expect options and other argv-elements in any order and that care about the
66ordering of the two. We describe each non-option argv-element as if it were
67the argument of an option with character code 1. Using `-' as the first
68character of the optstring parameter selects this mode of operation.
69
70The special argument `--' forces an end of option-scanning regardless of the
71value of ordering. In the case of RETURN_IN_ORDER, only `--' can cause
72getopt() and friends to return EOF with optind != argc.
73
74COPYRIGHT NOTICE AND DISCLAIMER:
75
76Copyright (C) 1997 Gregory Pietsch
77
78This file and the accompanying getopt.h header file are hereby placed in the
79public domain without restrictions. Just give the author credit, don't
80claim you wrote it or prevent anyone else from using it.
81
82Gregory Pietsch's current e-mail address:
83gpietsch@comcast.net
84****************************************************************************/
85
c6228428 86#ifndef HAVE_GETOPT
76ff710c 87
791c9bda 88/* include files */
8a0efa53
CF
89#include <stdio.h>
90#include <stdlib.h>
91#include <string.h>
c6228428 92#define __need_getopt_newlib
791c9bda 93#include <getopt.h>
8a0efa53 94
791c9bda 95/* macros */
8a0efa53 96
791c9bda
JJ
97/* types */
98typedef enum GETOPT_ORDERING_T
99{
100 PERMUTE,
101 RETURN_IN_ORDER,
102 REQUIRE_ORDER
103} GETOPT_ORDERING_T;
104
105/* globally-defined variables */
76ff710c 106char *optarg = 0;
791c9bda
JJ
107int optind = 0;
108int opterr = 1;
109int optopt = '?';
110
76ff710c
JJ
111/* static variables */
112static int optwhere = 0;
113
791c9bda
JJ
114/* functions */
115
116/* reverse_argv_elements: reverses num elements starting at argv */
117static void
76ff710c 118reverse_argv_elements (char **argv, int num)
791c9bda
JJ
119{
120 int i;
121 char *tmp;
122
123 for (i = 0; i < (num >> 1); i++)
124 {
125 tmp = argv[i];
126 argv[i] = argv[num - i - 1];
127 argv[num - i - 1] = tmp;
128 }
129}
130
131/* permute: swap two blocks of argv-elements given their lengths */
132static void
133permute (char *const argv[], int len1, int len2)
134{
76ff710c
JJ
135 reverse_argv_elements ((char **) argv, len1);
136 reverse_argv_elements ((char **) argv, len1 + len2);
137 reverse_argv_elements ((char **) argv, len2);
791c9bda
JJ
138}
139
140/* is_option: is this argv-element an option or the end of the option list? */
141static int
142is_option (char *argv_element, int only)
143{
76ff710c
JJ
144 return ((argv_element == 0)
145 || (argv_element[0] == '-') || (only && argv_element[0] == '+'));
146}
147
148/* read_globals: read the values from the globals into a getopt_data
149 structure */
150static void
151read_globals (struct getopt_data *data)
152{
153 data->optarg = optarg;
154 data->optind = optind;
155 data->opterr = opterr;
156 data->optopt = optopt;
157 data->optwhere = optwhere;
158}
159
160/* write_globals: write the values into the globals from a getopt_data
161 structure */
162static void
163write_globals (struct getopt_data *data)
164{
165 optarg = data->optarg;
166 optind = data->optind;
167 opterr = data->opterr;
168 optopt = data->optopt;
169 optwhere = data->optwhere;
791c9bda
JJ
170}
171
172/* getopt_internal: the function that does all the dirty work */
173static int
174getopt_internal (int argc, char *const argv[], const char *shortopts,
76ff710c
JJ
175 const struct option *longopts, int *longind, int only,
176 struct getopt_data *data)
791c9bda
JJ
177{
178 GETOPT_ORDERING_T ordering = PERMUTE;
791c9bda
JJ
179 size_t permute_from = 0;
180 int num_nonopts = 0;
181 int optindex = 0;
182 size_t match_chars = 0;
76ff710c 183 char *possible_arg = 0;
791c9bda
JJ
184 int longopt_match = -1;
185 int has_arg = -1;
76ff710c 186 char *cp = 0;
791c9bda
JJ
187 int arg_next = 0;
188
189 /* first, deal with silly parameters and easy stuff */
76ff710c
JJ
190 if (argc == 0 || argv == 0 || (shortopts == 0 && longopts == 0)
191 || data->optind >= argc || argv[data->optind] == 0)
791c9bda 192 return EOF;
76ff710c 193 if (strcmp (argv[data->optind], "--") == 0)
791c9bda 194 {
76ff710c 195 data->optind++;
791c9bda
JJ
196 return EOF;
197 }
76ff710c 198
791c9bda 199 /* if this is our first time through */
76ff710c
JJ
200 if (data->optind == 0)
201 data->optind = data->optwhere = 1;
791c9bda
JJ
202
203 /* define ordering */
76ff710c 204 if (shortopts != 0 && (*shortopts == '-' || *shortopts == '+'))
791c9bda
JJ
205 {
206 ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
207 shortopts++;
208 }
209 else
76ff710c 210 ordering = (getenv ("POSIXLY_CORRECT") != 0) ? REQUIRE_ORDER : PERMUTE;
791c9bda
JJ
211
212 /*
213 * based on ordering, find our next option, if we're at the beginning of
214 * one
215 */
76ff710c 216 if (data->optwhere == 1)
791c9bda
JJ
217 {
218 switch (ordering)
76ff710c
JJ
219 {
220 default: /* shouldn't happen */
221 case PERMUTE:
222 permute_from = data->optind;
223 num_nonopts = 0;
224 while (!is_option (argv[data->optind], only))
225 {
226 data->optind++;
227 num_nonopts++;
228 }
229 if (argv[data->optind] == 0)
230 {
231 /* no more options */
232 data->optind = permute_from;
233 return EOF;
234 }
235 else if (strcmp (argv[data->optind], "--") == 0)
236 {
237 /* no more options, but have to get `--' out of the way */
238 permute (argv + permute_from, num_nonopts, 1);
239 data->optind = permute_from + 1;
240 return EOF;
241 }
242 break;
243 case RETURN_IN_ORDER:
244 if (!is_option (argv[data->optind], only))
245 {
246 data->optarg = argv[data->optind++];
247 return (data->optopt = 1);
248 }
249 break;
250 case REQUIRE_ORDER:
251 if (!is_option (argv[data->optind], only))
252 return EOF;
253 break;
254 }
791c9bda
JJ
255 }
256 /* we've got an option, so parse it */
257
258 /* first, is it a long option? */
76ff710c
JJ
259 if (longopts != 0
260 && (memcmp (argv[data->optind], "--", 2) == 0
261 || (only && argv[data->optind][0] == '+')) && data->optwhere == 1)
791c9bda
JJ
262 {
263 /* handle long options */
76ff710c
JJ
264 if (memcmp (argv[data->optind], "--", 2) == 0)
265 data->optwhere = 2;
791c9bda 266 longopt_match = -1;
76ff710c
JJ
267 possible_arg = strchr (argv[data->optind] + data->optwhere, '=');
268 if (possible_arg == 0)
269 {
270 /* no =, so next argv might be arg */
271 match_chars = strlen (argv[data->optind]);
272 possible_arg = argv[data->optind] + match_chars;
273 match_chars = match_chars - data->optwhere;
274 }
791c9bda 275 else
76ff710c
JJ
276 match_chars = (possible_arg - argv[data->optind]) - data->optwhere;
277 for (optindex = 0; longopts[optindex].name != 0; ++optindex)
278 {
279 if (memcmp
280 (argv[data->optind] + data->optwhere, longopts[optindex].name,
281 match_chars) == 0)
282 {
283 /* do we have an exact match? */
284 if (match_chars == (int) (strlen (longopts[optindex].name)))
285 {
286 longopt_match = optindex;
287 break;
288 }
289 /* do any characters match? */
290 else
291 {
292 if (longopt_match < 0)
293 longopt_match = optindex;
294 else
295 {
296 /* we have ambiguous options */
297 if (data->opterr)
298 fprintf (stderr, "%s: option `%s' is ambiguous "
299 "(could be `--%s' or `--%s')\n",
300 argv[0],
301 argv[data->optind],
302 longopts[longopt_match].name,
303 longopts[optindex].name);
304 return (data->optopt = '?');
305 }
306 }
307 }
308 }
791c9bda 309 if (longopt_match >= 0)
76ff710c 310 has_arg = longopts[longopt_match].has_arg;
791c9bda 311 }
76ff710c 312
791c9bda 313 /* if we didn't find a long option, is it a short option? */
76ff710c 314 if (longopt_match < 0 && shortopts != 0)
791c9bda 315 {
76ff710c
JJ
316 cp = strchr (shortopts, argv[data->optind][data->optwhere]);
317 if (cp == 0)
318 {
319 /* couldn't find option in shortopts */
320 if (data->opterr)
321 fprintf (stderr,
322 "%s: invalid option -- `-%c'\n",
323 argv[0], argv[data->optind][data->optwhere]);
324 data->optwhere++;
325 if (argv[data->optind][data->optwhere] == '\0')
326 {
327 data->optind++;
328 data->optwhere = 1;
329 }
330 return (data->optopt = '?');
331 }
791c9bda 332 has_arg = ((cp[1] == ':')
76ff710c
JJ
333 ? ((cp[2] == ':') ? OPTIONAL_ARG : REQUIRED_ARG) : NO_ARG);
334 possible_arg = argv[data->optind] + data->optwhere + 1;
335 data->optopt = *cp;
791c9bda 336 }
76ff710c
JJ
337
338 /* get argument and reset data->optwhere */
791c9bda
JJ
339 arg_next = 0;
340 switch (has_arg)
341 {
342 case OPTIONAL_ARG:
343 if (*possible_arg == '=')
76ff710c
JJ
344 possible_arg++;
345 data->optarg = (*possible_arg != '\0') ? possible_arg : 0;
346 data->optwhere = 1;
791c9bda
JJ
347 break;
348 case REQUIRED_ARG:
349 if (*possible_arg == '=')
76ff710c 350 possible_arg++;
791c9bda 351 if (*possible_arg != '\0')
76ff710c
JJ
352 {
353 data->optarg = possible_arg;
354 data->optwhere = 1;
355 }
356 else if (data->optind + 1 >= argc)
357 {
358 if (data->opterr)
359 {
360 fprintf (stderr, "%s: argument required for option `", argv[0]);
361 if (longopt_match >= 0)
362 fprintf (stderr, "--%s'\n", longopts[longopt_match].name);
363 else
364 fprintf (stderr, "-%c'\n", *cp);
365 }
366 data->optind++;
367 return (data->optopt = ':');
368 }
791c9bda 369 else
76ff710c
JJ
370 {
371 data->optarg = argv[data->optind + 1];
372 arg_next = 1;
373 data->optwhere = 1;
374 }
791c9bda 375 break;
76ff710c 376 default: /* shouldn't happen */
791c9bda
JJ
377 case NO_ARG:
378 if (longopt_match < 0)
76ff710c
JJ
379 {
380 data->optwhere++;
381 if (argv[data->optind][data->optwhere] == '\0')
382 data->optwhere = 1;
383 }
791c9bda 384 else
76ff710c
JJ
385 data->optwhere = 1;
386 data->optarg = 0;
791c9bda
JJ
387 break;
388 }
389
76ff710c
JJ
390 /* do we have to permute or otherwise modify data->optind? */
391 if (ordering == PERMUTE && data->optwhere == 1 && num_nonopts != 0)
791c9bda
JJ
392 {
393 permute (argv + permute_from, num_nonopts, 1 + arg_next);
76ff710c 394 data->optind = permute_from + 1 + arg_next;
791c9bda 395 }
76ff710c
JJ
396 else if (data->optwhere == 1)
397 data->optind = data->optind + 1 + arg_next;
791c9bda
JJ
398
399 /* finally return */
400 if (longopt_match >= 0)
401 {
76ff710c
JJ
402 if (longind != 0)
403 *longind = longopt_match;
404 if (longopts[longopt_match].flag != 0)
405 {
406 *(longopts[longopt_match].flag) = longopts[longopt_match].val;
407 return 0;
408 }
791c9bda 409 else
76ff710c 410 return longopts[longopt_match].val;
791c9bda
JJ
411 }
412 else
76ff710c 413 return data->optopt;
791c9bda 414}
8a0efa53 415
8a0efa53 416int
791c9bda 417getopt (int argc, char *const argv[], const char *optstring)
8a0efa53 418{
76ff710c
JJ
419 struct getopt_data data;
420 int r;
421
422 read_globals (&data);
423 r = getopt_internal (argc, argv, optstring, 0, 0, 0, &data);
424 write_globals (&data);
425 return r;
8a0efa53 426}
791c9bda
JJ
427
428int
429getopt_long (int argc, char *const argv[], const char *shortopts,
76ff710c 430 const struct option *longopts, int *longind)
791c9bda 431{
76ff710c
JJ
432 struct getopt_data data;
433 int r;
434
435 read_globals (&data);
436 r = getopt_internal (argc, argv, shortopts, longopts, longind, 0, &data);
437 write_globals (&data);
438 return r;
791c9bda
JJ
439}
440
441int
442getopt_long_only (int argc, char *const argv[], const char *shortopts,
76ff710c
JJ
443 const struct option *longopts, int *longind)
444{
445 struct getopt_data data;
446 int r;
447
448 read_globals (&data);
449 r = getopt_internal (argc, argv, shortopts, longopts, longind, 1, &data);
450 write_globals (&data);
451 return r;
452}
453
454int
455__getopt_r (int argc, char *const argv[], const char *optstring,
456 struct getopt_data *data)
457{
458 return getopt_internal (argc, argv, optstring, 0, 0, 0, data);
459}
460
461int
462__getopt_long_r (int argc, char *const argv[], const char *shortopts,
463 const struct option *longopts, int *longind,
464 struct getopt_data *data)
465{
466 return getopt_internal (argc, argv, shortopts, longopts, longind, 0, data);
467}
468
469int
470__getopt_long_only_r (int argc, char *const argv[], const char *shortopts,
471 const struct option *longopts, int *longind,
472 struct getopt_data *data)
791c9bda 473{
76ff710c 474 return getopt_internal (argc, argv, shortopts, longopts, longind, 1, data);
791c9bda
JJ
475}
476
c6228428
JJ
477#endif /* !HAVE_GETOPT */
478
791c9bda 479/* end of file GETOPT.C */
This page took 0.199863 seconds and 5 git commands to generate.