]> 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
76ff710c 86
791c9bda 87/* include files */
8a0efa53
CF
88#include <stdio.h>
89#include <stdlib.h>
90#include <string.h>
791c9bda 91#include <getopt.h>
8a0efa53 92
791c9bda 93/* macros */
8a0efa53 94
791c9bda
JJ
95/* types */
96typedef enum GETOPT_ORDERING_T
97{
98 PERMUTE,
99 RETURN_IN_ORDER,
100 REQUIRE_ORDER
101} GETOPT_ORDERING_T;
102
103/* globally-defined variables */
76ff710c 104char *optarg = 0;
791c9bda
JJ
105int optind = 0;
106int opterr = 1;
107int optopt = '?';
108
76ff710c
JJ
109/* static variables */
110static int optwhere = 0;
111
791c9bda
JJ
112/* functions */
113
114/* reverse_argv_elements: reverses num elements starting at argv */
115static void
76ff710c 116reverse_argv_elements (char **argv, int num)
791c9bda
JJ
117{
118 int i;
119 char *tmp;
120
121 for (i = 0; i < (num >> 1); i++)
122 {
123 tmp = argv[i];
124 argv[i] = argv[num - i - 1];
125 argv[num - i - 1] = tmp;
126 }
127}
128
129/* permute: swap two blocks of argv-elements given their lengths */
130static void
131permute (char *const argv[], int len1, int len2)
132{
76ff710c
JJ
133 reverse_argv_elements ((char **) argv, len1);
134 reverse_argv_elements ((char **) argv, len1 + len2);
135 reverse_argv_elements ((char **) argv, len2);
791c9bda
JJ
136}
137
138/* is_option: is this argv-element an option or the end of the option list? */
139static int
140is_option (char *argv_element, int only)
141{
76ff710c
JJ
142 return ((argv_element == 0)
143 || (argv_element[0] == '-') || (only && argv_element[0] == '+'));
144}
145
146/* read_globals: read the values from the globals into a getopt_data
147 structure */
148static void
149read_globals (struct getopt_data *data)
150{
151 data->optarg = optarg;
152 data->optind = optind;
153 data->opterr = opterr;
154 data->optopt = optopt;
155 data->optwhere = optwhere;
156}
157
158/* write_globals: write the values into the globals from a getopt_data
159 structure */
160static void
161write_globals (struct getopt_data *data)
162{
163 optarg = data->optarg;
164 optind = data->optind;
165 opterr = data->opterr;
166 optopt = data->optopt;
167 optwhere = data->optwhere;
791c9bda
JJ
168}
169
170/* getopt_internal: the function that does all the dirty work */
171static int
172getopt_internal (int argc, char *const argv[], const char *shortopts,
76ff710c
JJ
173 const struct option *longopts, int *longind, int only,
174 struct getopt_data *data)
791c9bda
JJ
175{
176 GETOPT_ORDERING_T ordering = PERMUTE;
791c9bda
JJ
177 size_t permute_from = 0;
178 int num_nonopts = 0;
179 int optindex = 0;
180 size_t match_chars = 0;
76ff710c 181 char *possible_arg = 0;
791c9bda
JJ
182 int longopt_match = -1;
183 int has_arg = -1;
76ff710c 184 char *cp = 0;
791c9bda
JJ
185 int arg_next = 0;
186
187 /* first, deal with silly parameters and easy stuff */
76ff710c
JJ
188 if (argc == 0 || argv == 0 || (shortopts == 0 && longopts == 0)
189 || data->optind >= argc || argv[data->optind] == 0)
791c9bda 190 return EOF;
76ff710c 191 if (strcmp (argv[data->optind], "--") == 0)
791c9bda 192 {
76ff710c 193 data->optind++;
791c9bda
JJ
194 return EOF;
195 }
76ff710c 196
791c9bda 197 /* if this is our first time through */
76ff710c
JJ
198 if (data->optind == 0)
199 data->optind = data->optwhere = 1;
791c9bda
JJ
200
201 /* define ordering */
76ff710c 202 if (shortopts != 0 && (*shortopts == '-' || *shortopts == '+'))
791c9bda
JJ
203 {
204 ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
205 shortopts++;
206 }
207 else
76ff710c 208 ordering = (getenv ("POSIXLY_CORRECT") != 0) ? REQUIRE_ORDER : PERMUTE;
791c9bda
JJ
209
210 /*
211 * based on ordering, find our next option, if we're at the beginning of
212 * one
213 */
76ff710c 214 if (data->optwhere == 1)
791c9bda
JJ
215 {
216 switch (ordering)
76ff710c
JJ
217 {
218 default: /* shouldn't happen */
219 case PERMUTE:
220 permute_from = data->optind;
221 num_nonopts = 0;
222 while (!is_option (argv[data->optind], only))
223 {
224 data->optind++;
225 num_nonopts++;
226 }
227 if (argv[data->optind] == 0)
228 {
229 /* no more options */
230 data->optind = permute_from;
231 return EOF;
232 }
233 else if (strcmp (argv[data->optind], "--") == 0)
234 {
235 /* no more options, but have to get `--' out of the way */
236 permute (argv + permute_from, num_nonopts, 1);
237 data->optind = permute_from + 1;
238 return EOF;
239 }
240 break;
241 case RETURN_IN_ORDER:
242 if (!is_option (argv[data->optind], only))
243 {
244 data->optarg = argv[data->optind++];
245 return (data->optopt = 1);
246 }
247 break;
248 case REQUIRE_ORDER:
249 if (!is_option (argv[data->optind], only))
250 return EOF;
251 break;
252 }
791c9bda
JJ
253 }
254 /* we've got an option, so parse it */
255
256 /* first, is it a long option? */
76ff710c
JJ
257 if (longopts != 0
258 && (memcmp (argv[data->optind], "--", 2) == 0
259 || (only && argv[data->optind][0] == '+')) && data->optwhere == 1)
791c9bda
JJ
260 {
261 /* handle long options */
76ff710c
JJ
262 if (memcmp (argv[data->optind], "--", 2) == 0)
263 data->optwhere = 2;
791c9bda 264 longopt_match = -1;
76ff710c
JJ
265 possible_arg = strchr (argv[data->optind] + data->optwhere, '=');
266 if (possible_arg == 0)
267 {
268 /* no =, so next argv might be arg */
269 match_chars = strlen (argv[data->optind]);
270 possible_arg = argv[data->optind] + match_chars;
271 match_chars = match_chars - data->optwhere;
272 }
791c9bda 273 else
76ff710c
JJ
274 match_chars = (possible_arg - argv[data->optind]) - data->optwhere;
275 for (optindex = 0; longopts[optindex].name != 0; ++optindex)
276 {
277 if (memcmp
278 (argv[data->optind] + data->optwhere, longopts[optindex].name,
279 match_chars) == 0)
280 {
281 /* do we have an exact match? */
282 if (match_chars == (int) (strlen (longopts[optindex].name)))
283 {
284 longopt_match = optindex;
285 break;
286 }
287 /* do any characters match? */
288 else
289 {
290 if (longopt_match < 0)
291 longopt_match = optindex;
292 else
293 {
294 /* we have ambiguous options */
295 if (data->opterr)
296 fprintf (stderr, "%s: option `%s' is ambiguous "
297 "(could be `--%s' or `--%s')\n",
298 argv[0],
299 argv[data->optind],
300 longopts[longopt_match].name,
301 longopts[optindex].name);
302 return (data->optopt = '?');
303 }
304 }
305 }
306 }
791c9bda 307 if (longopt_match >= 0)
76ff710c 308 has_arg = longopts[longopt_match].has_arg;
791c9bda 309 }
76ff710c 310
791c9bda 311 /* if we didn't find a long option, is it a short option? */
76ff710c 312 if (longopt_match < 0 && shortopts != 0)
791c9bda 313 {
76ff710c
JJ
314 cp = strchr (shortopts, argv[data->optind][data->optwhere]);
315 if (cp == 0)
316 {
317 /* couldn't find option in shortopts */
318 if (data->opterr)
319 fprintf (stderr,
320 "%s: invalid option -- `-%c'\n",
321 argv[0], argv[data->optind][data->optwhere]);
322 data->optwhere++;
323 if (argv[data->optind][data->optwhere] == '\0')
324 {
325 data->optind++;
326 data->optwhere = 1;
327 }
328 return (data->optopt = '?');
329 }
791c9bda 330 has_arg = ((cp[1] == ':')
76ff710c
JJ
331 ? ((cp[2] == ':') ? OPTIONAL_ARG : REQUIRED_ARG) : NO_ARG);
332 possible_arg = argv[data->optind] + data->optwhere + 1;
333 data->optopt = *cp;
791c9bda 334 }
76ff710c
JJ
335
336 /* get argument and reset data->optwhere */
791c9bda
JJ
337 arg_next = 0;
338 switch (has_arg)
339 {
340 case OPTIONAL_ARG:
341 if (*possible_arg == '=')
76ff710c
JJ
342 possible_arg++;
343 data->optarg = (*possible_arg != '\0') ? possible_arg : 0;
344 data->optwhere = 1;
791c9bda
JJ
345 break;
346 case REQUIRED_ARG:
347 if (*possible_arg == '=')
76ff710c 348 possible_arg++;
791c9bda 349 if (*possible_arg != '\0')
76ff710c
JJ
350 {
351 data->optarg = possible_arg;
352 data->optwhere = 1;
353 }
354 else if (data->optind + 1 >= argc)
355 {
356 if (data->opterr)
357 {
358 fprintf (stderr, "%s: argument required for option `", argv[0]);
359 if (longopt_match >= 0)
360 fprintf (stderr, "--%s'\n", longopts[longopt_match].name);
361 else
362 fprintf (stderr, "-%c'\n", *cp);
363 }
364 data->optind++;
365 return (data->optopt = ':');
366 }
791c9bda 367 else
76ff710c
JJ
368 {
369 data->optarg = argv[data->optind + 1];
370 arg_next = 1;
371 data->optwhere = 1;
372 }
791c9bda 373 break;
76ff710c 374 default: /* shouldn't happen */
791c9bda
JJ
375 case NO_ARG:
376 if (longopt_match < 0)
76ff710c
JJ
377 {
378 data->optwhere++;
379 if (argv[data->optind][data->optwhere] == '\0')
380 data->optwhere = 1;
381 }
791c9bda 382 else
76ff710c
JJ
383 data->optwhere = 1;
384 data->optarg = 0;
791c9bda
JJ
385 break;
386 }
387
76ff710c
JJ
388 /* do we have to permute or otherwise modify data->optind? */
389 if (ordering == PERMUTE && data->optwhere == 1 && num_nonopts != 0)
791c9bda
JJ
390 {
391 permute (argv + permute_from, num_nonopts, 1 + arg_next);
76ff710c 392 data->optind = permute_from + 1 + arg_next;
791c9bda 393 }
76ff710c
JJ
394 else if (data->optwhere == 1)
395 data->optind = data->optind + 1 + arg_next;
791c9bda
JJ
396
397 /* finally return */
398 if (longopt_match >= 0)
399 {
76ff710c
JJ
400 if (longind != 0)
401 *longind = longopt_match;
402 if (longopts[longopt_match].flag != 0)
403 {
404 *(longopts[longopt_match].flag) = longopts[longopt_match].val;
405 return 0;
406 }
791c9bda 407 else
76ff710c 408 return longopts[longopt_match].val;
791c9bda
JJ
409 }
410 else
76ff710c 411 return data->optopt;
791c9bda 412}
8a0efa53 413
8a0efa53 414int
791c9bda 415getopt (int argc, char *const argv[], const char *optstring)
8a0efa53 416{
76ff710c
JJ
417 struct getopt_data data;
418 int r;
419
420 read_globals (&data);
421 r = getopt_internal (argc, argv, optstring, 0, 0, 0, &data);
422 write_globals (&data);
423 return r;
8a0efa53 424}
791c9bda
JJ
425
426int
427getopt_long (int argc, char *const argv[], const char *shortopts,
76ff710c 428 const struct option *longopts, int *longind)
791c9bda 429{
76ff710c
JJ
430 struct getopt_data data;
431 int r;
432
433 read_globals (&data);
434 r = getopt_internal (argc, argv, shortopts, longopts, longind, 0, &data);
435 write_globals (&data);
436 return r;
791c9bda
JJ
437}
438
439int
440getopt_long_only (int argc, char *const argv[], const char *shortopts,
76ff710c
JJ
441 const struct option *longopts, int *longind)
442{
443 struct getopt_data data;
444 int r;
445
446 read_globals (&data);
447 r = getopt_internal (argc, argv, shortopts, longopts, longind, 1, &data);
448 write_globals (&data);
449 return r;
450}
451
452int
453__getopt_r (int argc, char *const argv[], const char *optstring,
454 struct getopt_data *data)
455{
456 return getopt_internal (argc, argv, optstring, 0, 0, 0, data);
457}
458
459int
460__getopt_long_r (int argc, char *const argv[], const char *shortopts,
461 const struct option *longopts, int *longind,
462 struct getopt_data *data)
463{
464 return getopt_internal (argc, argv, shortopts, longopts, longind, 0, data);
465}
466
467int
468__getopt_long_only_r (int argc, char *const argv[], const char *shortopts,
469 const struct option *longopts, int *longind,
470 struct getopt_data *data)
791c9bda 471{
76ff710c 472 return getopt_internal (argc, argv, shortopts, longopts, longind, 1, data);
791c9bda
JJ
473}
474
475/* end of file GETOPT.C */
This page took 0.183146 seconds and 5 git commands to generate.