Imported Upstream version 1.7.1
[platform/upstream/ninja.git] / src / getopt.c
1 /****************************************************************************
2
3 getopt.c - Read command line options
4
5 AUTHOR: Gregory Pietsch
6 CREATED Fri Jan 10 21:13:05 1997
7
8 DESCRIPTION:
9
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.
17
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.
21
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
25
26 --arg=value
27
28  or
29
30 --arg value
31
32 It takes the additional arguments longopts which is a pointer to the first
33 element of an array of type GETOPT_LONG_OPTION_T.  The last element of the
34 array has to be filled with NULL for the name field.
35
36 The longind pointer points to the index of the current long option relative
37 to longopts if it is non-NULL.
38
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.
42
43 The getopt_long() function's return value is described in the header file.
44
45 The function getopt_long_only() is identical to getopt_long(), except that a
46 plus sign `+' can introduce long options as well as `--'.
47
48 The following describes how to deal with options that follow non-option
49 argv-elements.
50
51 If the caller did not specify anything, the default is REQUIRE_ORDER if the
52 environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.
53
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.
59
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.
63
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.
69
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.
73
74 COPYRIGHT NOTICE AND DISCLAIMER:
75
76 Copyright (C) 1997 Gregory Pietsch
77
78 This file and the accompanying getopt.h header file are hereby placed in the 
79 public domain without restrictions.  Just give the author credit, don't
80 claim you wrote it or prevent anyone else from using it.
81
82 Gregory Pietsch's current e-mail address:
83 gpietsch@comcast.net
84 ****************************************************************************/
85
86 /* include files */
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #ifndef GETOPT_H
91 #include "getopt.h"
92 #endif
93
94 /* macros */
95
96 /* types */
97 typedef enum GETOPT_ORDERING_T
98 {
99   PERMUTE,
100   RETURN_IN_ORDER,
101   REQUIRE_ORDER
102 } GETOPT_ORDERING_T;
103
104 /* globally-defined variables */
105 char *optarg = NULL;
106 int optind = 0;
107 int opterr = 1;
108 int optopt = '?';
109
110 /* functions */
111
112 /* reverse_argv_elements:  reverses num elements starting at argv */
113 static void
114 reverse_argv_elements (char **argv, int num)
115 {
116   int i;
117   char *tmp;
118
119   for (i = 0; i < (num >> 1); i++)
120     {
121       tmp = argv[i];
122       argv[i] = argv[num - i - 1];
123       argv[num - i - 1] = tmp;
124     }
125 }
126
127 /* permute: swap two blocks of argv-elements given their lengths */
128 static void
129 permute (char **argv, int len1, int len2)
130 {
131   reverse_argv_elements (argv, len1);
132   reverse_argv_elements (argv, len1 + len2);
133   reverse_argv_elements (argv, len2);
134 }
135
136 /* is_option: is this argv-element an option or the end of the option list? */
137 static int
138 is_option (char *argv_element, int only)
139 {
140   return ((argv_element == NULL)
141           || (argv_element[0] == '-') || (only && argv_element[0] == '+'));
142 }
143
144 /* getopt_internal:  the function that does all the dirty work */
145 static int
146 getopt_internal (int argc, char **argv, char *shortopts,
147                  GETOPT_LONG_OPTION_T * longopts, int *longind, int only)
148 {
149   GETOPT_ORDERING_T ordering = PERMUTE;
150   static size_t optwhere = 0;
151   size_t permute_from = 0;
152   int num_nonopts = 0;
153   int optindex = 0;
154   size_t match_chars = 0;
155   char *possible_arg = NULL;
156   int longopt_match = -1;
157   int has_arg = -1;
158   char *cp = NULL;
159   int arg_next = 0;
160
161   /* first, deal with silly parameters and easy stuff */
162   if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL))
163     return (optopt = '?');
164   if (optind >= argc || argv[optind] == NULL)
165     return EOF;
166   if (strcmp (argv[optind], "--") == 0)
167     {
168       optind++;
169       return EOF;
170     }
171   /* if this is our first time through */
172   if (optind == 0)
173     optind = optwhere = 1;
174
175   /* define ordering */
176   if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+'))
177     {
178       ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
179       shortopts++;
180     }
181   else
182     ordering = (getenv ("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE;
183
184   /*
185    * based on ordering, find our next option, if we're at the beginning of
186    * one
187    */
188   if (optwhere == 1)
189     {
190       switch (ordering)
191         {
192         case PERMUTE:
193           permute_from = optind;
194           num_nonopts = 0;
195           while (!is_option (argv[optind], only))
196             {
197               optind++;
198               num_nonopts++;
199             }
200           if (argv[optind] == NULL)
201             {
202               /* no more options */
203               optind = permute_from;
204               return EOF;
205             }
206           else if (strcmp (argv[optind], "--") == 0)
207             {
208               /* no more options, but have to get `--' out of the way */
209               permute (argv + permute_from, num_nonopts, 1);
210               optind = permute_from + 1;
211               return EOF;
212             }
213           break;
214         case RETURN_IN_ORDER:
215           if (!is_option (argv[optind], only))
216             {
217               optarg = argv[optind++];
218               return (optopt = 1);
219             }
220           break;
221         case REQUIRE_ORDER:
222           if (!is_option (argv[optind], only))
223             return EOF;
224           break;
225         }
226     }
227   /* we've got an option, so parse it */
228
229   /* first, is it a long option? */
230   if (longopts != NULL
231       && (memcmp (argv[optind], "--", 2) == 0
232           || (only && argv[optind][0] == '+')) && optwhere == 1)
233     {
234       /* handle long options */
235       if (memcmp (argv[optind], "--", 2) == 0)
236         optwhere = 2;
237       longopt_match = -1;
238       possible_arg = strchr (argv[optind] + optwhere, '=');
239       if (possible_arg == NULL)
240         {
241           /* no =, so next argv might be arg */
242           match_chars = strlen (argv[optind]);
243           possible_arg = argv[optind] + match_chars;
244           match_chars = match_chars - optwhere;
245         }
246       else
247         match_chars = (possible_arg - argv[optind]) - optwhere;
248       for (optindex = 0; longopts[optindex].name != NULL; optindex++)
249         {
250           if (memcmp (argv[optind] + optwhere,
251                       longopts[optindex].name, match_chars) == 0)
252             {
253               /* do we have an exact match? */
254               if (match_chars == strlen (longopts[optindex].name))
255                 {
256                   longopt_match = optindex;
257                   break;
258                 }
259               /* do any characters match? */
260               else
261                 {
262                   if (longopt_match < 0)
263                     longopt_match = optindex;
264                   else
265                     {
266                       /* we have ambiguous options */
267                       if (opterr)
268                         fprintf (stderr, "%s: option `%s' is ambiguous "
269                                  "(could be `--%s' or `--%s')\n",
270                                  argv[0],
271                                  argv[optind],
272                                  longopts[longopt_match].name,
273                                  longopts[optindex].name);
274                       return (optopt = '?');
275                     }
276                 }
277             }
278         }
279       if (longopt_match >= 0)
280         has_arg = longopts[longopt_match].has_arg;
281     }
282   /* if we didn't find a long option, is it a short option? */
283   if (longopt_match < 0 && shortopts != NULL)
284     {
285       cp = strchr (shortopts, argv[optind][optwhere]);
286       if (cp == NULL)
287         {
288           /* couldn't find option in shortopts */
289           if (opterr)
290             fprintf (stderr,
291                      "%s: invalid option -- `-%c'\n",
292                      argv[0], argv[optind][optwhere]);
293           optwhere++;
294           if (argv[optind][optwhere] == '\0')
295             {
296               optind++;
297               optwhere = 1;
298             }
299           return (optopt = '?');
300         }
301       has_arg = ((cp[1] == ':')
302                  ? ((cp[2] == ':') ? OPTIONAL_ARG : required_argument) : no_argument);
303       possible_arg = argv[optind] + optwhere + 1;
304       optopt = *cp;
305     }
306   /* get argument and reset optwhere */
307   arg_next = 0;
308   switch (has_arg)
309     {
310     case OPTIONAL_ARG:
311       if (*possible_arg == '=')
312         possible_arg++;
313       if (*possible_arg != '\0')
314         {
315           optarg = possible_arg;
316           optwhere = 1;
317         }
318       else
319         optarg = NULL;
320       break;
321     case required_argument:
322       if (*possible_arg == '=')
323         possible_arg++;
324       if (*possible_arg != '\0')
325         {
326           optarg = possible_arg;
327           optwhere = 1;
328         }
329       else if (optind + 1 >= argc)
330         {
331           if (opterr)
332             {
333               fprintf (stderr, "%s: argument required for option `", argv[0]);
334               if (longopt_match >= 0)
335                 fprintf (stderr, "--%s'\n", longopts[longopt_match].name);
336               else
337                 fprintf (stderr, "-%c'\n", *cp);
338             }
339           optind++;
340           return (optopt = ':');
341         }
342       else
343         {
344           optarg = argv[optind + 1];
345           arg_next = 1;
346           optwhere = 1;
347         }
348       break;
349     case no_argument:
350       if (longopt_match < 0)
351         {
352           optwhere++;
353           if (argv[optind][optwhere] == '\0')
354             optwhere = 1;
355         }
356       else
357         optwhere = 1;
358       optarg = NULL;
359       break;
360     }
361
362   /* do we have to permute or otherwise modify optind? */
363   if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0)
364     {
365       permute (argv + permute_from, num_nonopts, 1 + arg_next);
366       optind = permute_from + 1 + arg_next;
367     }
368   else if (optwhere == 1)
369     optind = optind + 1 + arg_next;
370
371   /* finally return */
372   if (longopt_match >= 0)
373     {
374       if (longind != NULL)
375         *longind = longopt_match;
376       if (longopts[longopt_match].flag != NULL)
377         {
378           *(longopts[longopt_match].flag) = longopts[longopt_match].val;
379           return 0;
380         }
381       else
382         return longopts[longopt_match].val;
383     }
384   else
385     return optopt;
386 }
387
388 #ifndef _AIX
389 int
390 getopt (int argc, char **argv, char *optstring)
391 {
392   return getopt_internal (argc, argv, optstring, NULL, NULL, 0);
393 }
394 #endif
395
396 int
397 getopt_long (int argc, char **argv, const char *shortopts,
398              const GETOPT_LONG_OPTION_T * longopts, int *longind)
399 {
400   return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 0);
401 }
402
403 int
404 getopt_long_only (int argc, char **argv, const char *shortopts,
405                   const GETOPT_LONG_OPTION_T * longopts, int *longind)
406 {
407   return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 1);
408 }
409
410 /* end of file GETOPT.C */