improve of cmpl.
[bush.git] / builtins / getopts.def
blob2f99c9de97fd1c51cf0c46a51a7856aa9341f747
1 This file is getopts.def, from which is created getopts.c.
2 It implements the builtin "getopts" in Bush.
4 Copyright (C) 1987-2019 Free Software Foundation, Inc.
6 This file is part of GNU Bush, the Bourne Again SHell.
8 Bush 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.
13 Bush 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.
18 You should have received a copy of the GNU General Public License
19 along with Bush. If not, see <http://www.gnu.org/licenses/>.
21 $PRODUCES getopts.c
23 $BUILTIN getopts
24 $FUNCTION getopts_builtin
25 $SHORT_DOC getopts optstring name [arg ...]
26 Parse option arguments.
28 Getopts is used by shell procedures to parse positional parameters
29 as options.
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.
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.
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
44 this mode, no error messages are printed. If an invalid option is
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
48 silent mode, and an invalid option is seen, getopts places '?' into
49 NAME and unsets OPTARG. If a required argument is not found, a '?'
50 is placed in NAME, OPTARG is unset, and a diagnostic message is
51 printed.
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.
57 Getopts normally parses the positional parameters, but if arguments
58 are supplied as ARG values, they are parsed instead.
60 Exit Status:
61 Returns success if an option is found; fails if the end of options is
62 encountered or an error occurs.
63 $END
65 #include <config.h>
67 #include <stdio.h>
69 #if defined (HAVE_UNISTD_H)
70 # ifdef _MINIX
71 # include <sys/types.h>
72 # endif
73 # include <unistd.h>
74 #endif
76 #include "../src/bushansi.h"
77 #include "../src/bushintl.h"
79 #include "../src/shell.h"
80 #include "../src/runner/execute_cmd.h"
81 #include "common.h"
82 #include "bushgetopt.h"
83 #include "getopt.h"
85 #define G_EOF -1
86 #define G_INVALID_OPT -2
87 #define G_ARG_MISSING -3
89 static int getopts_unbind_variable PARAMS((char *));
90 static int getopts_bind_variable PARAMS((char *, char *));
91 static int dogetopts PARAMS((int, char **));
93 /* getopts_reset is magic code for when OPTIND is reset. N is the
94 value that has just been assigned to OPTIND. */
95 void
96 getopts_reset (newind)
97 int newind;
99 sh_optind = newind;
100 sh_badopt = 0;
103 static int
104 getopts_unbind_variable (name)
105 char *name;
107 #if 0
108 return (unbind_variable (name));
109 #else
110 return (unbind_variable_noref (name));
111 #endif
114 static int
115 getopts_bind_variable (name, value)
116 char *name, *value;
118 SHELL_VAR *v;
120 if (legal_identifier (name))
122 v = bind_variable (name, value, 0);
123 if (v && (readonly_p (v) || noassign_p (v)))
124 return (EX_MISCERROR);
125 return (v ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
127 else
129 sh_invalidid (name);
130 return (EXECUTION_FAILURE);
134 /* Error handling is now performed as specified by Posix.2, draft 11
135 (identical to that of ksh-88). The special handling is enabled if
136 the first character of the option string is a colon; this handling
137 disables diagnostic messages concerning missing option arguments
138 and invalid option characters. The handling is as follows.
140 INVALID OPTIONS:
141 name -> "?"
142 if (special_error) then
143 OPTARG = option character found
144 no error output
145 else
146 OPTARG unset
147 diagnostic message
150 MISSING OPTION ARGUMENT;
151 if (special_error) then
152 name -> ":"
153 OPTARG = option character found
154 else
155 name -> "?"
156 OPTARG unset
157 diagnostic message
161 static int
162 dogetopts (argc, argv)
163 int argc;
164 char **argv;
166 int ret, special_error, old_opterr, i, n;
167 char strval[2], numval[16];
168 char *optstr; /* list of options */
169 char *name; /* variable to get flag val */
170 char *t;
172 if (argc < 3)
174 builtin_usage ();
175 return (EX_USAGE);
178 /* argv[0] is "getopts". */
180 optstr = argv[1];
181 name = argv[2];
182 argc -= 2;
183 argv += 2;
185 special_error = optstr[0] == ':';
187 if (special_error)
189 old_opterr = sh_opterr;
190 optstr++;
191 sh_opterr = 0; /* suppress diagnostic messages */
194 if (argc > 1)
196 sh_getopt_restore_state (argv);
197 t = argv[0];
198 argv[0] = dollar_vars[0];
199 ret = sh_getopt (argc, argv, optstr);
200 argv[0] = t;
202 else if (rest_of_args == (WORD_LIST *)NULL)
204 for (i = 0; i < 10 && dollar_vars[i]; i++)
207 sh_getopt_restore_state (dollar_vars);
208 ret = sh_getopt (i, dollar_vars, optstr);
210 else
212 register WORD_LIST *words;
213 char **v;
215 i = number_of_args () + 1; /* +1 for $0 */
216 v = strvec_create (i + 1);
217 for (i = 0; i < 10 && dollar_vars[i]; i++)
218 v[i] = dollar_vars[i];
219 for (words = rest_of_args; words; words = words->next, i++)
220 v[i] = words->word->word;
221 v[i] = (char *)NULL;
222 sh_getopt_restore_state (v);
223 ret = sh_getopt (i, v, optstr);
224 free (v);
227 if (special_error)
228 sh_opterr = old_opterr;
230 /* Set the OPTIND variable in any case, to handle "--" skipping. It's
231 highly unlikely that 14 digits will be too few. */
232 if (sh_optind < 10)
234 numval[14] = sh_optind + '0';
235 numval[15] = '\0';
236 i = 14;
238 else
240 numval[i = 15] = '\0';
241 n = sh_optind;
244 numval[--i] = (n % 10) + '0';
246 while (n /= 10);
248 bind_variable ("OPTIND", numval + i, 0);
250 /* If an error occurred, decide which one it is and set the return
251 code appropriately. In all cases, the option character in error
252 is in OPTOPT. If an invalid option was encountered, OPTARG is
253 NULL. If a required option argument was missing, OPTARG points
254 to a NULL string (that is, sh_optarg[0] == 0). */
255 if (ret == '?')
257 if (sh_optarg == NULL)
258 ret = G_INVALID_OPT;
259 else if (sh_optarg[0] == '\0')
260 ret = G_ARG_MISSING;
263 if (ret == G_EOF)
265 getopts_unbind_variable ("OPTARG");
266 getopts_bind_variable (name, "?");
267 return (EXECUTION_FAILURE);
270 if (ret == G_INVALID_OPT)
272 /* Invalid option encountered. */
273 ret = getopts_bind_variable (name, "?");
275 if (special_error)
277 strval[0] = (char)sh_optopt;
278 strval[1] = '\0';
279 bind_variable ("OPTARG", strval, 0);
281 else
282 getopts_unbind_variable ("OPTARG");
284 return (ret);
287 if (ret == G_ARG_MISSING)
289 /* Required argument missing. */
290 if (special_error)
292 ret = getopts_bind_variable (name, ":");
294 strval[0] = (char)sh_optopt;
295 strval[1] = '\0';
296 bind_variable ("OPTARG", strval, 0);
298 else
300 ret = getopts_bind_variable (name, "?");
301 getopts_unbind_variable ("OPTARG");
303 return (ret);
306 bind_variable ("OPTARG", sh_optarg, 0);
308 strval[0] = (char) ret;
309 strval[1] = '\0';
310 return (getopts_bind_variable (name, strval));
313 /* The getopts builtin. Build an argv, and call dogetopts with it. */
315 getopts_builtin (list)
316 WORD_LIST *list;
318 char **av;
319 int ac, ret;
321 if (list == 0)
323 builtin_usage ();
324 return EX_USAGE;
327 reset_internal_getopt ();
328 if ((ret = internal_getopt (list, "")) != -1)
330 if (ret == GETOPT_HELP)
331 builtin_help ();
332 else
333 builtin_usage ();
334 return (EX_USAGE);
336 list = loptend;
338 av = make_builtin_argv (list, &ac);
339 ret = dogetopts (ac, av);
340 free ((char *)av);
342 return (ret);