2fbcac73ea13ce183a5394caf6e3cd45fd667dc3
[platform/upstream/bash.git] / builtins / getopt.c
1 /* getopt for BASH.
2
3    Copyright (C) 1993, 1994
4         Free Software Foundation, Inc.
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <config.h>
21
22 #if defined (HAVE_UNISTD_H)
23 #  ifdef _MINIX
24 #    include <sys/types.h>
25 #  endif
26 #  include <unistd.h>
27 #endif
28
29 #include <stdio.h>
30 #include "../memalloc.h"
31 #include "../shell.h"
32 #include "getopt.h"
33
34 /* For communication from `sh_getopt' to the caller.
35    When `sh_getopt' finds an option that takes an argument,
36    the argument value is returned here. */
37 char *sh_optarg = 0;
38
39 /* Index in ARGV of the next element to be scanned.
40    This is used for communication to and from the caller
41    and for communication between successive calls to `sh_getopt'.
42
43    On entry to `sh_getopt', zero means this is the first call; initialize.
44
45    When `sh_getopt' returns EOF, this is the index of the first of the
46    non-option elements that the caller should itself scan.
47
48    Otherwise, `sh_optind' communicates from one call to the next
49    how much of ARGV has been scanned so far.  */
50
51 /* XXX 1003.2 says this must be 1 before any call.  */
52 int sh_optind = 0;
53
54 /* Index of the current argument. */
55 static int sh_curopt;
56
57 /* The next char to be scanned in the option-element
58    in which the last option character we returned was found.
59    This allows us to pick up the scan where we left off.
60
61    If this is zero, or a null string, it means resume the scan
62    by advancing to the next ARGV-element.  */
63
64 static char *nextchar;
65 static int sh_charindex;
66
67 /* Callers store zero here to inhibit the error message
68    for unrecognized options.  */
69
70 int sh_opterr = 1;
71
72 /* Set to an option character which was unrecognized.
73    This must be initialized on some systems to avoid linking in the
74    system's own getopt implementation.  */
75
76 int sh_optopt = '?';
77
78 /* Set to 1 when we see an illegal option; public so getopts can reset it. */
79 int sh_badopt = 0;
80
81 /* Scan elements of ARGV (whose length is ARGC) for option characters
82    given in OPTSTRING.
83
84    If an element of ARGV starts with '-', and is not exactly "-" or "--",
85    then it is an option element.  The characters of this element
86    (aside from the initial '-') are option characters.  If `sh_getopt'
87    is called repeatedly, it returns successively each of the option characters
88    from each of the option elements.
89
90    If `sh_getopt' finds another option character, it returns that character,
91    updating `sh_optind' and `nextchar' so that the next call to `sh_getopt' can
92    resume the scan with the following option character or ARGV-element.
93
94    If there are no more option characters, `sh_getopt' returns `EOF'.
95    Then `sh_optind' is the index in ARGV of the first ARGV-element
96    that is not an option.
97
98    OPTSTRING is a string containing the legitimate option characters.
99    If an option character is seen that is not listed in OPTSTRING,
100    return '?' after printing an error message.  If you set `sh_opterr' to
101    zero, the error message is suppressed but we still return '?'.
102
103    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
104    so the following text in the same ARGV-element, or the text of the following
105    ARGV-element, is returned in `sh_optarg'. */
106
107 /* 1003.2 specifies the format of this message.  */
108 #define BADOPT(x)  fprintf (stderr, "%s: illegal option -- %c\n", argv[0], x)
109 #define NEEDARG(x) fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], x)
110
111 int
112 sh_getopt (argc, argv, optstring)
113      int argc;
114      char *const *argv;
115      const char *optstring;
116 {
117   char c, *temp;
118
119   sh_optarg = 0;
120
121   if (sh_optind >= argc || sh_optind < 0)       /* XXX was sh_optind > argc */
122     {
123       sh_optind = argc;
124       return (EOF);
125     }
126
127   /* Initialize the internal data when the first call is made.
128      Start processing options with ARGV-element 1 (since ARGV-element 0
129      is the program name); the sequence of previously skipped
130      non-option ARGV-elements is empty.  */
131
132   if (sh_optind == 0)
133     {
134       sh_optind = 1;
135       nextchar = (char *)NULL;
136     }
137
138   /* Do the increment of `sh_optind' we deferred because the last option
139      was illegal.  */
140   if (sh_badopt && (nextchar == 0 || *nextchar == '\0'))
141     {
142       sh_badopt = 0;
143       sh_optind++;
144       nextchar = (char *)NULL;
145     }
146
147   if (nextchar == 0 || *nextchar == '\0')
148     {
149       /* If we have done all the ARGV-elements, stop the scan. */
150       if (sh_optind >= argc)
151         return EOF;
152
153       temp = argv[sh_optind];
154
155       /* Special ARGV-element `--' means premature end of options.
156          Skip it like a null option, and return EOF. */
157       if (temp[0] == '-' && temp[1] == '-' && temp[2] == '\0')
158         {
159           sh_optind++;
160           return EOF;
161         }
162
163       /* If we have come to a non-option, either stop the scan or describe
164          it to the caller and pass it by.  This makes the pseudo-option
165          `-' mean the end of options, but does not skip over it. */
166       if (temp[0] != '-' || temp[1] == '\0')
167         return EOF;
168
169       /* We have found another option-ARGV-element.
170          Start decoding its characters.  */
171       nextchar = argv[sh_curopt = sh_optind] + 1;
172       sh_charindex = 1;
173     }
174
175   /* Look at and handle the next option-character.  */
176
177   c = *nextchar++; sh_charindex++;
178   temp = strchr (optstring, c);
179
180   sh_optopt = c;
181
182   /* If the option is illegal, return an error, but defer updating sh_optind
183      until the next call so $OPTIND is correct. */
184   if (sh_badopt = (temp == NULL || c == ':'))
185     {
186       if (sh_opterr)
187         BADOPT (c);
188
189       return '?';
190     }
191
192   /* Increment `sh_optind' when we start to process its last character.  */
193   if (nextchar == 0 || *nextchar == '\0')
194     {
195       sh_optind++;
196       nextchar = (char *)NULL;
197     }
198
199   if (temp[1] == ':')
200     {
201       if (nextchar && *nextchar)
202         {
203           /* This is an option that requires an argument.  */
204           sh_optarg = nextchar;
205           /* If we end this ARGV-element by taking the rest as an arg,
206              we must advance to the next element now.  */
207           sh_optind++;
208         }
209       else if (sh_optind == argc)
210         {
211           if (sh_opterr)
212             NEEDARG (c);
213
214           sh_optopt = c;
215           sh_optarg = "";       /* Needed by getopts. */
216           c = (optstring[0] == ':') ? ':' : '?';
217         }
218       else
219         /* We already incremented `sh_optind' once;
220            increment it again when taking next ARGV-elt as argument.  */
221         sh_optarg = argv[sh_optind++];
222       nextchar = (char *)NULL;
223     }
224   return c;
225 }
226
227 void
228 sh_getopt_restore_state (argv)
229      char **argv;
230 {
231   if (nextchar)
232     nextchar = argv[sh_curopt] + sh_charindex;
233 }
234
235 #ifdef TEST
236
237 /* Compile with -DTEST to make an executable for use in testing
238    the above definition of `sh_getopt'.  */
239
240 int
241 main (argc, argv)
242      int argc;
243      char **argv;
244 {
245   int c;
246   int digit_sh_optind = 0;
247
248   while (1)
249     {
250       int this_option_sh_optind = sh_optind ? sh_optind : 1;
251
252       c = sh_getopt (argc, argv, "abc:d:0123456789");
253       if (c == EOF)
254         break;
255
256       switch (c)
257         {
258         case '0':
259         case '1':
260         case '2':
261         case '3':
262         case '4':
263         case '5':
264         case '6':
265         case '7':
266         case '8':
267         case '9':
268           if (digit_sh_optind != 0 && digit_sh_optind != this_option_sh_optind)
269             printf ("digits occur in two different argv-elements.\n");
270           digit_sh_optind = this_option_sh_optind;
271           printf ("option %c\n", c);
272           break;
273
274         case 'a':
275           printf ("option a\n");
276           break;
277
278         case 'b':
279           printf ("option b\n");
280           break;
281
282         case 'c':
283           printf ("option c with value `%s'\n", sh_optarg);
284           break;
285
286         case '?':
287           break;
288
289         default:
290           printf ("?? sh_getopt returned character code 0%o ??\n", c);
291         }
292     }
293
294   if (sh_optind < argc)
295     {
296       printf ("non-option ARGV-elements: ");
297       while (sh_optind < argc)
298         printf ("%s ", argv[sh_optind++]);
299       printf ("\n");
300     }
301
302   exit (0);
303 }
304
305 #endif /* TEST */