]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/getopt.c
Imported from ../bash-2.05b.tar.gz.
[thirdparty/bash.git] / builtins / getopt.c
CommitLineData
726f6388
JA
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
bb70624e 18 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
726f6388 19
ccc6cda3
JA
20#include <config.h>
21
22#if defined (HAVE_UNISTD_H)
cce855bc
JA
23# ifdef _MINIX
24# include <sys/types.h>
25# endif
ccc6cda3
JA
26# include <unistd.h>
27#endif
28
726f6388 29#include <stdio.h>
bb70624e 30#include "memalloc.h"
726f6388
JA
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. */
37char *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. */
52int sh_optind = 0;
53
54/* Index of the current argument. */
55static 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
64static char *nextchar;
65static int sh_charindex;
66
67/* Callers store zero here to inhibit the error message
68 for unrecognized options. */
69
70int 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
76int sh_optopt = '?';
77
7117c2d2 78/* Set to 1 when we see an invalid option; public so getopts can reset it. */
ccc6cda3
JA
79int sh_badopt = 0;
80
726f6388
JA
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
111int
112sh_getopt (argc, argv, optstring)
113 int argc;
114 char *const *argv;
115 const char *optstring;
116{
726f6388
JA
117 char c, *temp;
118
119 sh_optarg = 0;
120
d166f048 121 if (sh_optind >= argc || sh_optind < 0) /* XXX was sh_optind > argc */
726f6388
JA
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 if (nextchar == 0 || *nextchar == '\0')
139 {
ccc6cda3 140 /* If we have done all the ARGV-elements, stop the scan. */
d166f048 141 if (sh_optind >= argc)
726f6388
JA
142 return EOF;
143
144 temp = argv[sh_optind];
145
146 /* Special ARGV-element `--' means premature end of options.
147 Skip it like a null option, and return EOF. */
148 if (temp[0] == '-' && temp[1] == '-' && temp[2] == '\0')
149 {
150 sh_optind++;
151 return EOF;
152 }
153
154 /* If we have come to a non-option, either stop the scan or describe
155 it to the caller and pass it by. This makes the pseudo-option
156 `-' mean the end of options, but does not skip over it. */
157 if (temp[0] != '-' || temp[1] == '\0')
158 return EOF;
159
160 /* We have found another option-ARGV-element.
161 Start decoding its characters. */
162 nextchar = argv[sh_curopt = sh_optind] + 1;
163 sh_charindex = 1;
164 }
165
166 /* Look at and handle the next option-character. */
167
168 c = *nextchar++; sh_charindex++;
169 temp = strchr (optstring, c);
170
726f6388
JA
171 sh_optopt = c;
172
7117c2d2
JA
173 /* Increment `sh_optind' when we start to process its last character. */
174 if (nextchar == 0 || *nextchar == '\0')
175 {
176 sh_optind++;
177 nextchar = (char *)NULL;
178 }
179
ccc6cda3 180 if (sh_badopt = (temp == NULL || c == ':'))
726f6388
JA
181 {
182 if (sh_opterr)
183 BADOPT (c);
184
185 return '?';
186 }
187
188 if (temp[1] == ':')
189 {
190 if (nextchar && *nextchar)
191 {
192 /* This is an option that requires an argument. */
193 sh_optarg = nextchar;
194 /* If we end this ARGV-element by taking the rest as an arg,
195 we must advance to the next element now. */
196 sh_optind++;
197 }
198 else if (sh_optind == argc)
199 {
200 if (sh_opterr)
201 NEEDARG (c);
202
203 sh_optopt = c;
ccc6cda3 204 sh_optarg = ""; /* Needed by getopts. */
726f6388
JA
205 c = (optstring[0] == ':') ? ':' : '?';
206 }
207 else
208 /* We already incremented `sh_optind' once;
209 increment it again when taking next ARGV-elt as argument. */
210 sh_optarg = argv[sh_optind++];
211 nextchar = (char *)NULL;
212 }
213 return c;
214}
215
216void
217sh_getopt_restore_state (argv)
218 char **argv;
219{
220 if (nextchar)
221 nextchar = argv[sh_curopt] + sh_charindex;
222}
223
b72432fd
JA
224#if 0
225void
226sh_getopt_debug_restore_state (argv)
227 char **argv;
228{
229 if (nextchar && nextchar != argv[sh_curopt] + sh_charindex)
230 {
231 itrace("sh_getopt_debug_restore_state: resetting nextchar");
232 nextchar = argv[sh_curopt] + sh_charindex;
233 }
234}
235#endif
236
726f6388
JA
237#ifdef TEST
238
239/* Compile with -DTEST to make an executable for use in testing
240 the above definition of `sh_getopt'. */
241
242int
243main (argc, argv)
244 int argc;
245 char **argv;
246{
247 int c;
248 int digit_sh_optind = 0;
249
250 while (1)
251 {
252 int this_option_sh_optind = sh_optind ? sh_optind : 1;
253
254 c = sh_getopt (argc, argv, "abc:d:0123456789");
255 if (c == EOF)
256 break;
257
258 switch (c)
259 {
260 case '0':
261 case '1':
262 case '2':
263 case '3':
264 case '4':
265 case '5':
266 case '6':
267 case '7':
268 case '8':
269 case '9':
270 if (digit_sh_optind != 0 && digit_sh_optind != this_option_sh_optind)
271 printf ("digits occur in two different argv-elements.\n");
272 digit_sh_optind = this_option_sh_optind;
273 printf ("option %c\n", c);
274 break;
275
276 case 'a':
277 printf ("option a\n");
278 break;
279
280 case 'b':
281 printf ("option b\n");
282 break;
283
284 case 'c':
285 printf ("option c with value `%s'\n", sh_optarg);
286 break;
287
288 case '?':
289 break;
290
291 default:
292 printf ("?? sh_getopt returned character code 0%o ??\n", c);
293 }
294 }
295
296 if (sh_optind < argc)
297 {
298 printf ("non-option ARGV-elements: ");
299 while (sh_optind < argc)
300 printf ("%s ", argv[sh_optind++]);
301 printf ("\n");
302 }
303
304 exit (0);
305}
306
307#endif /* TEST */