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