mescc: Support gcc-3.2: puts with newline.
[mes.git] / lib / getopt.c
1 /* Getopt for GNU.
2    Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
3    Copyright (C) 2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
18 \f
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <getopt.h>
23
24 #if __MESC__
25 #define static
26 #endif
27
28 /* For communication from `getopt' to the caller.
29    When `getopt' finds an option that takes an argument,
30    the argument value is returned here. */
31
32 char *optarg = 0;
33
34 /* Index in ARGV of the next element to be scanned.
35    This is used for communication to and from the caller
36    and for communication between successive calls to `getopt'.
37
38    On entry to `getopt', zero means this is the first call; initialize.
39
40    When `getopt' returns EOF, this is the index of the first of the
41    non-option elements that the caller should itself scan.
42
43    Otherwise, `optind' communicates from one call to the next
44    how much of ARGV has been scanned so far.  */
45
46 int optind = 0;
47
48 /* The next char to be scanned in the option-element
49    in which the last option character we returned was found.
50    This allows us to pick up the scan where we left off.
51
52    If this is zero, or a null string, it means resume the scan
53    by advancing to the next ARGV-element.  */
54
55 static char *nextchar;
56
57 /* Callers store zero here to inhibit the error message
58    for unrecognized options.  */
59
60 int opterr = 1;
61
62 \f
63 /* Handle permutation of arguments.  */
64
65 /* Describe the part of ARGV that contains non-options that have
66    been skipped.  `first_nonopt' is the index in ARGV of the first of them;
67    `last_nonopt' is the index after the last of them.  */
68
69 static int first_nonopt;
70 static int last_nonopt;
71
72 \f
73 /* Scan elements of ARGV (whose length is ARGC) for option characters
74    given in OPTSTRING.
75
76    If an element of ARGV starts with '-', and is not exactly "-" or "--",
77    then it is an option element.  The characters of this element
78    (aside from the initial '-') are option characters.  If `getopt'
79    is called repeatedly, it returns successively each of the option characters
80    from each of the option elements.
81
82    If `getopt' finds another option character, it returns that character,
83    updating `optind' and `nextchar' so that the next call to `getopt' can
84    resume the scan with the following option character or ARGV-element.
85
86    If there are no more option characters, `getopt' returns `EOF'.
87    Then `optind' is the index in ARGV of the first ARGV-element
88    that is not an option.  (The ARGV-elements have been permuted
89    so that those that are not options now come last.)
90
91    OPTSTRING is a string containing the legitimate option characters.
92    If an option character is seen that is not listed in OPTSTRING,
93    return '?' after printing an error message.  If you set `opterr' to
94    zero, the error message is suppressed but we still return '?'.
95
96    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
97    so the following text in the same ARGV-element, or the text of the following
98    ARGV-element, is returned in `optarg'.  Two colons mean an option that
99    wants an optional arg; if there is text in the current ARGV-element,
100    it is returned in `optarg', otherwise `optarg' is set to zero.
101
102    If OPTSTRING starts with `-' or `+', it requests different methods of
103    handling the non-option ARGV-elements.
104
105    Long-named options begin with `--' instead of `-'.
106    Their names may be abbreviated as long as the abbreviation is unique
107    or is an exact match for some defined option.  If they have an
108    argument, it follows the option name in the same ARGV-element, separated
109    from the option name by a `=', or else the in next ARGV-element.
110    When `getopt' finds a long-named option, it returns 0 if that option's
111    `flag' field is nonzero, the value of the option's `val' field
112    if the `flag' field is zero.
113
114    The elements of ARGV aren't really const, because we permute them.
115    But we pretend they're const in the prototype to be compatible
116    with other systems.
117
118    LONGOPTS is a vector of `struct option' terminated by an
119    element containing a name which is zero.
120
121    LONGIND returns the index in LONGOPT of the long-named option found.
122    It is only valid when a long-named option has been found by the most
123    recent call.
124
125    If LONG_ONLY is nonzero, '-' as well as '--' can introduce
126    long-named options.  */
127
128 int
129 _getopt_internal (int argc, char *const
130                   *argv, char const *optstring, struct option const *longopts, int *longind, int long_only)
131 {
132   int option_index;
133
134   optarg = 0;
135
136   /* Initialize the internal data when the first call is made.
137      Start processing options with ARGV-element 1 (since ARGV-element 0
138      is the program name); the sequence of previously skipped
139      non-option ARGV-elements is empty.  */
140
141   if (optind == 0)
142     {
143       first_nonopt = last_nonopt = optind = 1;
144
145       nextchar = NULL;
146     }
147
148   if (nextchar == NULL || *nextchar == '\0')
149     {
150       /* If we have done all the ARGV-elements, stop the scan
151          and back over any non-options that we skipped and permuted.  */
152
153       if (optind == argc)
154         {
155           /* Set the next-arg-index to point at the non-options
156              that we previously skipped, so the caller will digest them.  */
157           if (first_nonopt != last_nonopt)
158             optind = first_nonopt;
159           return EOF;
160         }
161
162       /* If we have come to a non-option and did not permute it,
163          either stop the scan or describe it to the caller and pass it by.  */
164
165       if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
166         return EOF;
167
168       /* We have found another option-ARGV-element.
169          Start decoding its characters.  */
170
171       nextchar = (argv[optind] + 1
172                   + (longopts != NULL && argv[optind][1] == '-'));
173     }
174
175   if (longopts != NULL
176       && ((argv[optind][0] == '-'
177            && (argv[optind][1] == '-' || long_only))))
178     {
179       const struct option *p;
180       char *s = nextchar;
181       int exact = 0;
182       int ambig = 0;
183       const struct option *pfound = NULL;
184       int indfound;
185
186       while (*s && *s != '=')
187         s++;
188
189       /* Test all options for either exact match or abbreviated matches.  */
190       for (p = longopts, option_index = 0; p->name;
191            p++, option_index++)
192         if (!strncmp (p->name, nextchar, s - nextchar))
193           {
194             if (s - nextchar == strlen (p->name))
195               {
196                 /* Exact match found.  */
197                 pfound = p;
198                 indfound = option_index;
199                 exact = 1;
200                 break;
201               }
202             else if (pfound == NULL)
203               {
204                 /* First nonexact match found.  */
205                 pfound = p;
206                 indfound = option_index;
207               }
208             else
209               /* Second nonexact match found.  */
210               ambig = 1;
211           }
212
213       if (ambig && !exact)
214         {
215           if (opterr)
216             fprintf (stderr, "%s: option `%s' is ambiguous\n",
217                      argv[0], argv[optind]);
218           nextchar += strlen (nextchar);
219           optind++;
220           return '?';
221         }
222
223       if (pfound != NULL)
224         {
225           option_index = indfound;
226           optind++;
227           if (*s)
228             {
229               /* Don't test has_arg with >, because some C compilers don't
230                  allow it to be used on enums. */
231               if (pfound->has_arg)
232                 optarg = s + 1;
233               else
234                 {
235                   if (opterr)
236                     {
237                       if (argv[optind - 1][1] == '-')
238                         /* --option */
239                         fprintf (stderr,
240                                  "%s: option `--%s' doesn't allow an argument\n",
241                                  argv[0], pfound->name);
242                       else
243                         /* +option or -option */
244                         fprintf (stderr,
245                              "%s: option `%c%s' doesn't allow an argument\n",
246                              argv[0], argv[optind - 1][0], pfound->name);
247                     }
248                   nextchar += strlen (nextchar);
249                   return '?';
250                 }
251             }
252           else if (pfound->has_arg == 1)
253             {
254               if (optind < argc)
255                 optarg = argv[optind++];
256               else
257                 {
258                   if (opterr)
259                     fprintf (stderr, "%s: option `%s' requires an argument\n",
260                              argv[0], argv[optind - 1]);
261                   nextchar += strlen (nextchar);
262                   return '?';
263                 }
264             }
265           nextchar += strlen (nextchar);
266           if (longind != NULL)
267             *longind = option_index;
268           if (pfound->flag)
269             {
270               *(pfound->flag) = pfound->val;
271               return 0;
272             }
273           return pfound->val;
274         }
275       /* Can't find it as a long option.  If this is not getopt_long_only,
276          or the option starts with '--' or is not a valid short
277          option, then it's an error.
278          Otherwise interpret it as a short option. */
279       if (!long_only || argv[optind][1] == '-'
280           || strchr (optstring, *nextchar) == NULL)
281         {
282           if (opterr)
283             {
284               if (argv[optind][1] == '-')
285                 /* --option */
286                 fprintf (stderr, "%s: unrecognized option `--%s'\n",
287                          argv[0], nextchar);
288               else
289                 /* +option or -option */
290                 fprintf (stderr, "%s: unrecognized option `%c%s'\n",
291                          argv[0], argv[optind][0], nextchar);
292             }
293           nextchar += strlen (nextchar);
294           optind++;
295           return '?';
296         }
297     }
298
299   /* Look at and handle the next option-character.  */
300
301   {
302     char c = *nextchar++;
303     char *temp = strchr (optstring, c);
304
305     /* Increment `optind' when we start to process its last character.  */
306     if (*nextchar == '\0')
307       optind++;
308
309     if (temp == NULL || c == ':')
310       {
311         if (opterr)
312           {
313             if (c < 040 || c >= 0177)
314               fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
315                        argv[0], c);
316             else
317               fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
318           }
319         return '?';
320       }
321     if (temp[1] == ':')
322       {
323         if (temp[2] == ':')
324           {
325             /* This is an option that accepts an argument optionally.  */
326             if (*nextchar != '\0')
327               {
328                 optarg = nextchar;
329                 optind++;
330               }
331             else
332               optarg = 0;
333             nextchar = NULL;
334           }
335         else
336           {
337             /* This is an option that requires an argument.  */
338             if (*nextchar != 0)
339               {
340                 optarg = nextchar;
341                 /* If we end this ARGV-element by taking the rest as an arg,
342                    we must advance to the next element now.  */
343                 optind++;
344               }
345             else if (optind == argc)
346               {
347                 if (opterr)
348                   fprintf (stderr, "%s: option `-%c' requires an argument\n",
349                            argv[0], c);
350                 c = '?';
351               }
352             else
353               /* We already incremented `optind' once;
354                  increment it again when taking next ARGV-elt as argument.  */
355               optarg = argv[optind++];
356             nextchar = NULL;
357           }
358       }
359     return c;
360   }
361 }
362
363 int
364 getopt (int argc, char *const *argv, char const *options)
365 {
366   return _getopt_internal (argc, argv, options,
367                            (const struct option *) 0, (int *) 0, 0);
368 }
369
370 int
371 getopt_long (int argc, char *const *argv, char const *options,
372              struct option const *long_options, int *opt_index)
373 {
374   return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
375 }
376
377 int
378 getopt_long_only (int argc, char *const *argv, char const *options,
379                   struct option const *long_options, int *opt_index)
380 {
381   return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
382 }