blob: 0404dced41dbbd978db1a4bc2b178f064e47b165 [file] [log] [blame]
Dan Pasanenc6e37862014-10-02 14:08:59 -05001/* getopts.c, created from getopts.def. */
2#line 22 "./getopts.def"
3
4#line 64 "./getopts.def"
5
6#include <config.h>
7
8#include <stdio.h>
9
10#if defined (HAVE_UNISTD_H)
11# ifdef _MINIX
12# include <sys/types.h>
13# endif
14# include <unistd.h>
15#endif
16
17#include "../bashansi.h"
18
19#include "../shell.h"
20#include "common.h"
21#include "bashgetopt.h"
22#include "getopt.h"
23
24#define G_EOF -1
25#define G_INVALID_OPT -2
26#define G_ARG_MISSING -3
27
28extern char *this_command_name;
29
30static int getopts_bind_variable __P((char *, char *));
31static int dogetopts __P((int, char **));
32
33/* getopts_reset is magic code for when OPTIND is reset. N is the
34 value that has just been assigned to OPTIND. */
35void
36getopts_reset (newind)
37 int newind;
38{
39 sh_optind = newind;
40 sh_badopt = 0;
41}
42
43static int
44getopts_bind_variable (name, value)
45 char *name, *value;
46{
47 SHELL_VAR *v;
48
49 if (legal_identifier (name))
50 {
51 v = bind_variable (name, value, 0);
52 if (v && (readonly_p (v) || noassign_p (v)))
53 return (EX_MISCERROR);
54 return (v ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
55 }
56 else
57 {
58 sh_invalidid (name);
59 return (EXECUTION_FAILURE);
60 }
61}
62
63/* Error handling is now performed as specified by Posix.2, draft 11
64 (identical to that of ksh-88). The special handling is enabled if
65 the first character of the option string is a colon; this handling
66 disables diagnostic messages concerning missing option arguments
67 and invalid option characters. The handling is as follows.
68
69 INVALID OPTIONS:
70 name -> "?"
71 if (special_error) then
72 OPTARG = option character found
73 no error output
74 else
75 OPTARG unset
76 diagnostic message
77 fi
78
79 MISSING OPTION ARGUMENT;
80 if (special_error) then
81 name -> ":"
82 OPTARG = option character found
83 else
84 name -> "?"
85 OPTARG unset
86 diagnostic message
87 fi
88 */
89
90static int
91dogetopts (argc, argv)
92 int argc;
93 char **argv;
94{
95 int ret, special_error, old_opterr, i, n;
96 char strval[2], numval[16];
97 char *optstr; /* list of options */
98 char *name; /* variable to get flag val */
99 char *t;
100
101 if (argc < 3)
102 {
103 builtin_usage ();
104 return (EX_USAGE);
105 }
106
107 /* argv[0] is "getopts". */
108
109 optstr = argv[1];
110 name = argv[2];
111 argc -= 2;
112 argv += 2;
113
114 special_error = optstr[0] == ':';
115
116 if (special_error)
117 {
118 old_opterr = sh_opterr;
119 optstr++;
120 sh_opterr = 0; /* suppress diagnostic messages */
121 }
122
123 if (argc > 1)
124 {
125 sh_getopt_restore_state (argv);
126 t = argv[0];
127 argv[0] = dollar_vars[0];
128 ret = sh_getopt (argc, argv, optstr);
129 argv[0] = t;
130 }
131 else if (rest_of_args == (WORD_LIST *)NULL)
132 {
133 for (i = 0; i < 10 && dollar_vars[i]; i++)
134 ;
135
136 sh_getopt_restore_state (dollar_vars);
137 ret = sh_getopt (i, dollar_vars, optstr);
138 }
139 else
140 {
141 register WORD_LIST *words;
142 char **v;
143
144 for (i = 0; i < 10 && dollar_vars[i]; i++)
145 ;
146 for (words = rest_of_args; words; words = words->next, i++)
147 ;
148 v = strvec_create (i + 1);
149 for (i = 0; i < 10 && dollar_vars[i]; i++)
150 v[i] = dollar_vars[i];
151 for (words = rest_of_args; words; words = words->next, i++)
152 v[i] = words->word->word;
153 v[i] = (char *)NULL;
154 sh_getopt_restore_state (v);
155 ret = sh_getopt (i, v, optstr);
156 free (v);
157 }
158
159 if (special_error)
160 sh_opterr = old_opterr;
161
162 /* Set the OPTIND variable in any case, to handle "--" skipping. It's
163 highly unlikely that 14 digits will be too few. */
164 if (sh_optind < 10)
165 {
166 numval[14] = sh_optind + '0';
167 numval[15] = '\0';
168 i = 14;
169 }
170 else
171 {
172 numval[i = 15] = '\0';
173 n = sh_optind;
174 do
175 {
176 numval[--i] = (n % 10) + '0';
177 }
178 while (n /= 10);
179 }
180 bind_variable ("OPTIND", numval + i, 0);
181
182 /* If an error occurred, decide which one it is and set the return
183 code appropriately. In all cases, the option character in error
184 is in OPTOPT. If an invalid option was encountered, OPTARG is
185 NULL. If a required option argument was missing, OPTARG points
186 to a NULL string (that is, sh_optarg[0] == 0). */
187 if (ret == '?')
188 {
189 if (sh_optarg == NULL)
190 ret = G_INVALID_OPT;
191 else if (sh_optarg[0] == '\0')
192 ret = G_ARG_MISSING;
193 }
194
195 if (ret == G_EOF)
196 {
197 unbind_variable ("OPTARG");
198 getopts_bind_variable (name, "?");
199 return (EXECUTION_FAILURE);
200 }
201
202 if (ret == G_INVALID_OPT)
203 {
204 /* Invalid option encountered. */
205 ret = getopts_bind_variable (name, "?");
206
207 if (special_error)
208 {
209 strval[0] = (char)sh_optopt;
210 strval[1] = '\0';
211 bind_variable ("OPTARG", strval, 0);
212 }
213 else
214 unbind_variable ("OPTARG");
215
216 return (ret);
217 }
218
219 if (ret == G_ARG_MISSING)
220 {
221 /* Required argument missing. */
222 if (special_error)
223 {
224 ret = getopts_bind_variable (name, ":");
225
226 strval[0] = (char)sh_optopt;
227 strval[1] = '\0';
228 bind_variable ("OPTARG", strval, 0);
229 }
230 else
231 {
232 ret = getopts_bind_variable (name, "?");
233 unbind_variable ("OPTARG");
234 }
235 return (ret);
236 }
237
238 bind_variable ("OPTARG", sh_optarg, 0);
239
240 strval[0] = (char) ret;
241 strval[1] = '\0';
242 return (getopts_bind_variable (name, strval));
243}
244
245/* The getopts builtin. Build an argv, and call dogetopts with it. */
246int
247getopts_builtin (list)
248 WORD_LIST *list;
249{
250 char **av;
251 int ac, ret;
252
253 if (list == 0)
254 {
255 builtin_usage ();
256 return EX_USAGE;
257 }
258
259 reset_internal_getopt ();
260 if (internal_getopt (list, "") != -1)
261 {
262 builtin_usage ();
263 return (EX_USAGE);
264 }
265 list = loptend;
266
267 av = make_builtin_argv (list, &ac);
268 ret = dogetopts (ac, av);
269 free ((char *)av);
270
271 return (ret);
272}