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