Imported from ../bash-1.14.7.tar.gz.
[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 <stdio.h>
21 #include "../memalloc.h"
22 #include "../shell.h"
23 #include "getopt.h"
24
25 /* For communication from `sh_getopt' to the caller.
26    When `sh_getopt' finds an option that takes an argument,
27    the argument value is returned here. */
28 char *sh_optarg = 0;
29
30 /* Index in ARGV of the next element to be scanned.
31    This is used for communication to and from the caller
32    and for communication between successive calls to `sh_getopt'.
33
34    On entry to `sh_getopt', zero means this is the first call; initialize.
35
36    When `sh_getopt' returns EOF, this is the index of the first of the
37    non-option elements that the caller should itself scan.
38
39    Otherwise, `sh_optind' communicates from one call to the next
40    how much of ARGV has been scanned so far.  */
41
42 /* XXX 1003.2 says this must be 1 before any call.  */
43 int sh_optind = 0;
44
45 /* Index of the current argument. */
46 static int sh_curopt;
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 static int sh_charindex;
57
58 /* Callers store zero here to inhibit the error message
59    for unrecognized options.  */
60
61 int sh_opterr = 1;
62
63 /* Set to an option character which was unrecognized.
64    This must be initialized on some systems to avoid linking in the
65    system's own getopt implementation.  */
66
67 int sh_optopt = '?';
68
69 /* Scan elements of ARGV (whose length is ARGC) for option characters
70    given in OPTSTRING.
71
72    If an element of ARGV starts with '-', and is not exactly "-" or "--",
73    then it is an option element.  The characters of this element
74    (aside from the initial '-') are option characters.  If `sh_getopt'
75    is called repeatedly, it returns successively each of the option characters
76    from each of the option elements.
77
78    If `sh_getopt' finds another option character, it returns that character,
79    updating `sh_optind' and `nextchar' so that the next call to `sh_getopt' can
80    resume the scan with the following option character or ARGV-element.
81
82    If there are no more option characters, `sh_getopt' returns `EOF'.
83    Then `sh_optind' is the index in ARGV of the first ARGV-element
84    that is not an option.
85
86    OPTSTRING is a string containing the legitimate option characters.
87    If an option character is seen that is not listed in OPTSTRING,
88    return '?' after printing an error message.  If you set `sh_opterr' to
89    zero, the error message is suppressed but we still return '?'.
90
91    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
92    so the following text in the same ARGV-element, or the text of the following
93    ARGV-element, is returned in `sh_optarg'. */
94
95 /* 1003.2 specifies the format of this message.  */
96 #define BADOPT(x)  fprintf (stderr, "%s: illegal option -- %c\n", argv[0], x)
97 #define NEEDARG(x) fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], x)
98
99 int
100 sh_getopt (argc, argv, optstring)
101      int argc;
102      char *const *argv;
103      const char *optstring;
104 {
105   int option_index;
106   char c, *temp;
107
108   sh_optarg = 0;
109
110   if (sh_optind > argc || sh_optind < 0)
111     {
112       sh_optind = argc;
113       return (EOF);
114     }
115
116   /* Initialize the internal data when the first call is made.
117      Start processing options with ARGV-element 1 (since ARGV-element 0
118      is the program name); the sequence of previously skipped
119      non-option ARGV-elements is empty.  */
120
121   if (sh_optind == 0)
122     {
123       sh_optind = 1;
124       nextchar = (char *)NULL;
125     }
126
127   if (nextchar == 0 || *nextchar == '\0')
128     {
129       /* If we have done all the ARGV-elements, stop the scan
130          and back over any non-options that we skipped and permuted.  */
131       if (sh_optind == argc)
132         return EOF;
133
134       temp = argv[sh_optind];
135
136       /* Special ARGV-element `--' means premature end of options.
137          Skip it like a null option, and return EOF. */
138       if (temp[0] == '-' && temp[1] == '-' && temp[2] == '\0')
139         {
140           sh_optind++;
141           return EOF;
142         }
143
144       /* If we have come to a non-option, either stop the scan or describe
145          it to the caller and pass it by.  This makes the pseudo-option
146          `-' mean the end of options, but does not skip over it. */
147       if (temp[0] != '-' || temp[1] == '\0')
148         return EOF;
149
150       /* We have found another option-ARGV-element.
151          Start decoding its characters.  */
152       nextchar = argv[sh_curopt = sh_optind] + 1;
153       sh_charindex = 1;
154     }
155
156   /* Look at and handle the next option-character.  */
157
158   c = *nextchar++; sh_charindex++;
159   temp = strchr (optstring, c);
160
161   /* Increment `sh_optind' when we start to process its last character.  */
162   if (nextchar == 0 || *nextchar == '\0')
163     {
164       sh_optind++;
165       nextchar = (char *)NULL;
166     }
167
168   sh_optopt = c;
169
170   if (temp == NULL || c == ':')
171     {
172       if (sh_opterr)
173         BADOPT (c);
174
175       return '?';
176     }
177
178   if (temp[1] == ':')
179     {
180       if (nextchar && *nextchar)
181         {
182           /* This is an option that requires an argument.  */
183           sh_optarg = nextchar;
184           /* If we end this ARGV-element by taking the rest as an arg,
185              we must advance to the next element now.  */
186           sh_optind++;
187         }
188       else if (sh_optind == argc)
189         {
190           if (sh_opterr)
191             NEEDARG (c);
192
193           sh_optopt = c;
194           c = (optstring[0] == ':') ? ':' : '?';
195         }
196       else
197         /* We already incremented `sh_optind' once;
198            increment it again when taking next ARGV-elt as argument.  */
199         sh_optarg = argv[sh_optind++];
200       nextchar = (char *)NULL;
201     }
202   return c;
203 }
204
205 void
206 sh_getopt_restore_state (argv)
207      char **argv;
208 {
209   if (nextchar)
210     nextchar = argv[sh_curopt] + sh_charindex;
211 }
212
213 #ifdef TEST
214
215 /* Compile with -DTEST to make an executable for use in testing
216    the above definition of `sh_getopt'.  */
217
218 int
219 main (argc, argv)
220      int argc;
221      char **argv;
222 {
223   int c;
224   int digit_sh_optind = 0;
225
226   while (1)
227     {
228       int this_option_sh_optind = sh_optind ? sh_optind : 1;
229
230       c = sh_getopt (argc, argv, "abc:d:0123456789");
231       if (c == EOF)
232         break;
233
234       switch (c)
235         {
236         case '0':
237         case '1':
238         case '2':
239         case '3':
240         case '4':
241         case '5':
242         case '6':
243         case '7':
244         case '8':
245         case '9':
246           if (digit_sh_optind != 0 && digit_sh_optind != this_option_sh_optind)
247             printf ("digits occur in two different argv-elements.\n");
248           digit_sh_optind = this_option_sh_optind;
249           printf ("option %c\n", c);
250           break;
251
252         case 'a':
253           printf ("option a\n");
254           break;
255
256         case 'b':
257           printf ("option b\n");
258           break;
259
260         case 'c':
261           printf ("option c with value `%s'\n", sh_optarg);
262           break;
263
264         case '?':
265           break;
266
267         default:
268           printf ("?? sh_getopt returned character code 0%o ??\n", c);
269         }
270     }
271
272   if (sh_optind < argc)
273     {
274       printf ("non-option ARGV-elements: ");
275       while (sh_optind < argc)
276         printf ("%s ", argv[sh_optind++]);
277       printf ("\n");
278     }
279
280   exit (0);
281 }
282
283 #endif /* TEST */