]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
1 | This file is getopts.def, from which is created getopts.c. |
2 | It implements the builtin "getopts" in Bash. | |
3 | ||
95732b49 | 4 | Copyright (C) 1987-2004 Free Software Foundation, Inc. |
726f6388 JA |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
8 | Bash is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
bb70624e | 10 | Software Foundation; either version 2, or (at your option) any later |
726f6388 JA |
11 | version. |
12 | ||
13 | Bash is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License along | |
19 | with Bash; see the file COPYING. If not, write to the Free Software | |
bb70624e | 20 | Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. |
726f6388 JA |
21 | |
22 | $PRODUCES getopts.c | |
23 | ||
24 | $BUILTIN getopts | |
726f6388 JA |
25 | $FUNCTION getopts_builtin |
26 | $SHORT_DOC getopts optstring name [arg] | |
27 | Getopts is used by shell procedures to parse positional parameters. | |
28 | ||
29 | OPTSTRING contains the option letters to be recognized; if a letter | |
30 | is followed by a colon, the option is expected to have an argument, | |
31 | which should be separated from it by white space. | |
32 | ||
33 | Each time it is invoked, getopts will place the next option in the | |
34 | shell variable $name, initializing name if it does not exist, and | |
35 | the index of the next argument to be processed into the shell | |
36 | variable OPTIND. OPTIND is initialized to 1 each time the shell or | |
37 | a shell script is invoked. When an option requires an argument, | |
38 | getopts places that argument into the shell variable OPTARG. | |
39 | ||
40 | getopts reports errors in one of two ways. If the first character | |
41 | of OPTSTRING is a colon, getopts uses silent error reporting. In | |
7117c2d2 | 42 | this mode, no error messages are printed. If an invalid option is |
726f6388 JA |
43 | seen, getopts places the option character found into OPTARG. If a |
44 | required argument is not found, getopts places a ':' into NAME and | |
45 | sets OPTARG to the option character found. If getopts is not in | |
7117c2d2 | 46 | silent mode, and an invalid option is seen, getopts places '?' into |
b80f6443 | 47 | NAME and unsets OPTARG. If a required argument is not found, a '?' |
726f6388 JA |
48 | is placed in NAME, OPTARG is unset, and a diagnostic message is |
49 | printed. | |
50 | ||
51 | If the shell variable OPTERR has the value 0, getopts disables the | |
52 | printing of error messages, even if the first character of | |
53 | OPTSTRING is not a colon. OPTERR has the value 1 by default. | |
54 | ||
55 | Getopts normally parses the positional parameters ($0 - $9), but if | |
56 | more arguments are given, they are parsed instead. | |
57 | $END | |
58 | ||
ccc6cda3 JA |
59 | #include <config.h> |
60 | ||
726f6388 JA |
61 | #include <stdio.h> |
62 | ||
ccc6cda3 | 63 | #if defined (HAVE_UNISTD_H) |
cce855bc JA |
64 | # ifdef _MINIX |
65 | # include <sys/types.h> | |
66 | # endif | |
ccc6cda3 JA |
67 | # include <unistd.h> |
68 | #endif | |
726f6388 | 69 | |
ccc6cda3 | 70 | #include "../bashansi.h" |
726f6388 | 71 | |
ccc6cda3 JA |
72 | #include "../shell.h" |
73 | #include "common.h" | |
74 | #include "bashgetopt.h" | |
726f6388 JA |
75 | #include "getopt.h" |
76 | ||
ccc6cda3 | 77 | #define G_EOF -1 |
7117c2d2 | 78 | #define G_INVALID_OPT -2 |
ccc6cda3 | 79 | #define G_ARG_MISSING -3 |
726f6388 JA |
80 | |
81 | extern char *this_command_name; | |
726f6388 | 82 | |
7117c2d2 JA |
83 | static int getopts_bind_variable __P((char *, char *)); |
84 | static int dogetopts __P((int, char **)); | |
85 | ||
726f6388 JA |
86 | /* getopts_reset is magic code for when OPTIND is reset. N is the |
87 | value that has just been assigned to OPTIND. */ | |
88 | void | |
89 | getopts_reset (newind) | |
90 | int newind; | |
91 | { | |
92 | sh_optind = newind; | |
ccc6cda3 JA |
93 | sh_badopt = 0; |
94 | } | |
95 | ||
96 | static int | |
97 | getopts_bind_variable (name, value) | |
98 | char *name, *value; | |
99 | { | |
100 | SHELL_VAR *v; | |
101 | ||
102 | if (legal_identifier (name)) | |
103 | { | |
95732b49 | 104 | v = bind_variable (name, value, 0); |
ccc6cda3 JA |
105 | return (v && (readonly_p (v) == 0)) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; |
106 | } | |
107 | else | |
108 | { | |
7117c2d2 | 109 | sh_invalidid (name); |
ccc6cda3 JA |
110 | return (EXECUTION_FAILURE); |
111 | } | |
726f6388 JA |
112 | } |
113 | ||
114 | /* Error handling is now performed as specified by Posix.2, draft 11 | |
115 | (identical to that of ksh-88). The special handling is enabled if | |
116 | the first character of the option string is a colon; this handling | |
117 | disables diagnostic messages concerning missing option arguments | |
7117c2d2 | 118 | and invalid option characters. The handling is as follows. |
726f6388 | 119 | |
7117c2d2 | 120 | INVALID OPTIONS: |
726f6388 JA |
121 | name -> "?" |
122 | if (special_error) then | |
123 | OPTARG = option character found | |
124 | no error output | |
125 | else | |
126 | OPTARG unset | |
127 | diagnostic message | |
128 | fi | |
129 | ||
130 | MISSING OPTION ARGUMENT; | |
131 | if (special_error) then | |
132 | name -> ":" | |
133 | OPTARG = option character found | |
134 | else | |
135 | name -> "?" | |
136 | OPTARG unset | |
137 | diagnostic message | |
138 | fi | |
139 | */ | |
140 | ||
141 | static int | |
142 | dogetopts (argc, argv) | |
143 | int argc; | |
144 | char **argv; | |
145 | { | |
ccc6cda3 | 146 | int ret, special_error, old_opterr, i, n; |
726f6388 JA |
147 | char strval[2], numval[16]; |
148 | char *optstr; /* list of options */ | |
149 | char *name; /* variable to get flag val */ | |
150 | char *t; | |
151 | ||
152 | if (argc < 3) | |
153 | { | |
ccc6cda3 | 154 | builtin_usage (); |
726f6388 JA |
155 | return (EX_USAGE); |
156 | } | |
157 | ||
158 | /* argv[0] is "getopts". */ | |
159 | ||
160 | optstr = argv[1]; | |
161 | name = argv[2]; | |
162 | argc -= 2; | |
163 | argv += 2; | |
164 | ||
165 | special_error = optstr[0] == ':'; | |
166 | ||
167 | if (special_error) | |
168 | { | |
169 | old_opterr = sh_opterr; | |
170 | optstr++; | |
171 | sh_opterr = 0; /* suppress diagnostic messages */ | |
172 | } | |
173 | ||
174 | if (argc > 1) | |
175 | { | |
176 | sh_getopt_restore_state (argv); | |
177 | t = argv[0]; | |
178 | argv[0] = dollar_vars[0]; | |
179 | ret = sh_getopt (argc, argv, optstr); | |
180 | argv[0] = t; | |
181 | } | |
182 | else if (rest_of_args == (WORD_LIST *)NULL) | |
183 | { | |
ccc6cda3 JA |
184 | for (i = 0; i < 10 && dollar_vars[i]; i++) |
185 | ; | |
b72432fd JA |
186 | |
187 | sh_getopt_restore_state (dollar_vars); | |
726f6388 JA |
188 | ret = sh_getopt (i, dollar_vars, optstr); |
189 | } | |
190 | else | |
191 | { | |
726f6388 JA |
192 | register WORD_LIST *words; |
193 | char **v; | |
194 | ||
ccc6cda3 JA |
195 | for (i = 0; i < 10 && dollar_vars[i]; i++) |
196 | ; | |
197 | for (words = rest_of_args; words; words = words->next, i++) | |
198 | ; | |
7117c2d2 | 199 | v = strvec_create (i + 1); |
726f6388 | 200 | for (i = 0; i < 10 && dollar_vars[i]; i++) |
28ef6c31 | 201 | v[i] = dollar_vars[i]; |
726f6388 | 202 | for (words = rest_of_args; words; words = words->next, i++) |
28ef6c31 | 203 | v[i] = words->word->word; |
726f6388 | 204 | v[i] = (char *)NULL; |
b72432fd | 205 | sh_getopt_restore_state (v); |
726f6388 JA |
206 | ret = sh_getopt (i, v, optstr); |
207 | free (v); | |
208 | } | |
209 | ||
210 | if (special_error) | |
211 | sh_opterr = old_opterr; | |
212 | ||
7117c2d2 JA |
213 | /* Set the OPTIND variable in any case, to handle "--" skipping. It's |
214 | highly unlikely that 14 digits will be too few. */ | |
726f6388 JA |
215 | if (sh_optind < 10) |
216 | { | |
217 | numval[14] = sh_optind + '0'; | |
218 | numval[15] = '\0'; | |
219 | i = 14; | |
220 | } | |
221 | else | |
222 | { | |
223 | numval[i = 15] = '\0'; | |
224 | n = sh_optind; | |
225 | do | |
226 | { | |
227 | numval[--i] = (n % 10) + '0'; | |
228 | } | |
229 | while (n /= 10); | |
230 | } | |
95732b49 | 231 | bind_variable ("OPTIND", numval + i, 0); |
726f6388 JA |
232 | |
233 | /* If an error occurred, decide which one it is and set the return | |
234 | code appropriately. In all cases, the option character in error | |
7117c2d2 | 235 | is in OPTOPT. If an invalid option was encountered, OPTARG is |
726f6388 | 236 | NULL. If a required option argument was missing, OPTARG points |
ccc6cda3 | 237 | to a NULL string (that is, sh_optarg[0] == 0). */ |
726f6388 JA |
238 | if (ret == '?') |
239 | { | |
240 | if (sh_optarg == NULL) | |
7117c2d2 | 241 | ret = G_INVALID_OPT; |
726f6388 JA |
242 | else if (sh_optarg[0] == '\0') |
243 | ret = G_ARG_MISSING; | |
244 | } | |
245 | ||
246 | if (ret == G_EOF) | |
247 | { | |
b80f6443 | 248 | unbind_variable ("OPTARG"); |
ccc6cda3 | 249 | getopts_bind_variable (name, "?"); |
726f6388 JA |
250 | return (EXECUTION_FAILURE); |
251 | } | |
252 | ||
7117c2d2 | 253 | if (ret == G_INVALID_OPT) |
726f6388 | 254 | { |
7117c2d2 | 255 | /* Invalid option encountered. */ |
ccc6cda3 | 256 | ret = getopts_bind_variable (name, "?"); |
726f6388 JA |
257 | |
258 | if (special_error) | |
259 | { | |
ccc6cda3 | 260 | strval[0] = (char)sh_optopt; |
726f6388 | 261 | strval[1] = '\0'; |
95732b49 | 262 | bind_variable ("OPTARG", strval, 0); |
726f6388 JA |
263 | } |
264 | else | |
7117c2d2 | 265 | unbind_variable ("OPTARG"); |
ccc6cda3 JA |
266 | |
267 | return (ret); | |
726f6388 JA |
268 | } |
269 | ||
270 | if (ret == G_ARG_MISSING) | |
271 | { | |
272 | /* Required argument missing. */ | |
273 | if (special_error) | |
274 | { | |
ccc6cda3 | 275 | ret = getopts_bind_variable (name, ":"); |
726f6388 | 276 | |
ccc6cda3 | 277 | strval[0] = (char)sh_optopt; |
726f6388 | 278 | strval[1] = '\0'; |
95732b49 | 279 | bind_variable ("OPTARG", strval, 0); |
726f6388 JA |
280 | } |
281 | else | |
282 | { | |
ccc6cda3 | 283 | ret = getopts_bind_variable (name, "?"); |
7117c2d2 | 284 | unbind_variable ("OPTARG"); |
726f6388 | 285 | } |
ccc6cda3 | 286 | return (ret); |
726f6388 JA |
287 | } |
288 | ||
95732b49 | 289 | bind_variable ("OPTARG", sh_optarg, 0); |
726f6388 JA |
290 | |
291 | strval[0] = (char) ret; | |
292 | strval[1] = '\0'; | |
ccc6cda3 | 293 | return (getopts_bind_variable (name, strval)); |
726f6388 JA |
294 | } |
295 | ||
296 | /* The getopts builtin. Build an argv, and call dogetopts with it. */ | |
297 | int | |
298 | getopts_builtin (list) | |
299 | WORD_LIST *list; | |
300 | { | |
726f6388 JA |
301 | char **av; |
302 | int ac, ret; | |
726f6388 JA |
303 | |
304 | if (list == 0) | |
d166f048 JA |
305 | { |
306 | builtin_usage (); | |
307 | return EX_USAGE; | |
308 | } | |
726f6388 | 309 | |
ccc6cda3 | 310 | reset_internal_getopt (); |
f73dda09 | 311 | if (internal_getopt (list, "") != -1) |
ccc6cda3 | 312 | { |
f73dda09 JA |
313 | builtin_usage (); |
314 | return (EX_USAGE); | |
ccc6cda3 JA |
315 | } |
316 | list = loptend; | |
726f6388 | 317 | |
ccc6cda3 | 318 | av = make_builtin_argv (list, &ac); |
726f6388 JA |
319 | ret = dogetopts (ac, av); |
320 | free ((char *)av); | |
ccc6cda3 | 321 | |
726f6388 JA |
322 | return (ret); |
323 | } |