1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108#if ENABLE_FEATURE_GETOPT_LONG
109# include <getopt.h>
110#endif
111#include "libbb.h"
112
113
114
115enum {
116 NON_OPT = 1,
117#if ENABLE_FEATURE_GETOPT_LONG
118
119 LONG_OPT = 2
120#endif
121};
122
123
124enum {
125 OPT_o = 0x1,
126 OPT_n = 0x2,
127 OPT_q = 0x4,
128 OPT_Q = 0x8,
129 OPT_s = 0x10,
130 OPT_T = 0x20,
131 OPT_u = 0x40,
132#if ENABLE_FEATURE_GETOPT_LONG
133 OPT_a = 0x80,
134 OPT_l = 0x100,
135#endif
136 SHELL_IS_TCSH = 0x8000,
137};
138
139
140#define alternative (option_mask32 & OPT_a)
141
142#define quiet_errors (option_mask32 & OPT_q)
143#define quiet_output (option_mask32 & OPT_Q)
144#define quote (!(option_mask32 & OPT_u))
145#define shell_TCSH (option_mask32 & SHELL_IS_TCSH)
146
147
148
149
150
151
152
153
154
155
156static const char *normalize(const char *arg)
157{
158 char *bufptr;
159 char *BUFFER;
160
161 if (!quote) {
162 return arg;
163 }
164
165
166
167
168
169 BUFFER = auto_string(xmalloc(strlen(arg)*4 + 3));
170
171 bufptr = BUFFER;
172 *bufptr ++= '\'';
173
174 while (*arg) {
175 if (shell_TCSH && *arg == '\n') {
176
177 *bufptr++ = '\\';
178 *bufptr++ = 'n';
179 } else
180 if ((shell_TCSH && (*arg == '!' || isspace(*arg)))
181 || *arg == '\''
182 ) {
183
184 *bufptr++ = '\'';
185 *bufptr++ = '\\';
186 *bufptr++ = *arg;
187 *bufptr++ = '\'';
188 } else {
189
190 *bufptr ++= *arg;
191 }
192 arg++;
193 }
194 *bufptr++ = '\'';
195 *bufptr++ = '\0';
196 return BUFFER;
197}
198
199
200
201
202
203
204
205
206#if !ENABLE_FEATURE_GETOPT_LONG
207#define generate_output(argv,argc,optstr,longopts) \
208 generate_output(argv,argc,optstr)
209#endif
210static int generate_output(char **argv, int argc, const char *optstr, const struct option *longopts)
211{
212 int exit_code = 0;
213
214 if (quiet_errors)
215 opterr = 0;
216
217
218
219 GETOPT_RESET();
220
221 while (1) {
222#if ENABLE_FEATURE_GETOPT_LONG
223 int longindex;
224 int opt = alternative
225 ? getopt_long_only(argc, argv, optstr, longopts, &longindex)
226 : getopt_long(argc, argv, optstr, longopts, &longindex)
227 ;
228#else
229 int opt = getopt(argc, argv, optstr);
230#endif
231 if (opt == -1)
232 break;
233 if (opt == '?' || opt == ':' )
234 exit_code = 1;
235 else if (!quiet_output) {
236#if ENABLE_FEATURE_GETOPT_LONG
237 if (opt == LONG_OPT) {
238 printf(" --%s", longopts[longindex].name);
239 if (longopts[longindex].has_arg)
240 printf(" %s",
241 normalize(optarg ? optarg : ""));
242 } else
243#endif
244 if (opt == NON_OPT)
245 printf(" %s", normalize(optarg));
246 else {
247 const char *charptr;
248 printf(" -%c", opt);
249 charptr = strchr(optstr, opt);
250 if (charptr && *++charptr == ':')
251 printf(" %s",
252 normalize(optarg ? optarg : ""));
253 }
254 }
255 }
256
257 if (!quiet_output) {
258 unsigned idx;
259 printf(" --");
260 idx = optind;
261 while (argv[idx])
262 printf(" %s", normalize(argv[idx++]));
263 bb_putchar('\n');
264 }
265 return exit_code;
266}
267
268#if ENABLE_FEATURE_GETOPT_LONG
269
270
271
272
273
274static struct option *add_long_options(struct option *long_options, char *options)
275{
276 int long_nr = 0;
277 int arg_opt, tlen;
278 char *tokptr;
279
280 if (long_options)
281 while (long_options[long_nr].name)
282 long_nr++;
283
284 tokptr = strtok_r(options, ", \t\n", &options);
285 while (tokptr) {
286 arg_opt = no_argument;
287 tlen = strlen(tokptr);
288 if (tlen) {
289 tlen--;
290 if (tokptr[tlen] == ':') {
291 arg_opt = required_argument;
292 if (tlen && tokptr[tlen-1] == ':') {
293 tlen--;
294 arg_opt = optional_argument;
295 }
296 tokptr[tlen] = '\0';
297 if (tlen == 0)
298 bb_simple_error_msg_and_die("empty long option specified");
299 }
300 long_options = xrealloc_vector(long_options, 4, long_nr);
301 long_options[long_nr].has_arg = arg_opt;
302
303 long_options[long_nr].val = LONG_OPT;
304 long_options[long_nr].name = xstrdup(tokptr);
305 long_nr++;
306
307 }
308 tokptr = strtok_r(NULL, ", \t\n", &options);
309 }
310 return long_options;
311}
312#endif
313
314static void set_shell(const char *new_shell)
315{
316 switch (index_in_strings("bash\0sh\0tcsh\0csh\0", new_shell)) {
317 case 0:
318 case 1:
319 break;
320 case 2:
321 case 3:
322 option_mask32 |= SHELL_IS_TCSH;
323 break;
324 default:
325 bb_error_msg("unknown shell '%s', assuming bash", new_shell);
326 break;
327 }
328}
329
330
331
332
333
334
335
336
337
338
339#if ENABLE_FEATURE_GETOPT_LONG
340static const char getopt_longopts[] ALIGN1 =
341 "options\0" Required_argument "o"
342 "longoptions\0" Required_argument "l"
343 "quiet\0" No_argument "q"
344 "quiet-output\0" No_argument "Q"
345 "shell\0" Required_argument "s"
346 "test\0" No_argument "T"
347 "unquoted\0" No_argument "u"
348 "alternative\0" No_argument "a"
349 "name\0" Required_argument "n"
350 ;
351#endif
352
353int getopt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
354int getopt_main(int argc, char **argv)
355{
356 int n;
357 char *optstr = NULL;
358 char *name = NULL;
359 unsigned opt;
360 const char *compatible;
361 char *s_arg;
362#if ENABLE_FEATURE_GETOPT_LONG
363 struct option *long_options = NULL;
364 llist_t *l_arg = NULL;
365#endif
366
367 compatible = getenv("GETOPT_COMPATIBLE");
368
369 if (!argv[1]) {
370 if (compatible) {
371
372
373 puts(" --");
374 return 0;
375 }
376 bb_simple_error_msg_and_die("missing optstring argument");
377 }
378
379 if (argv[1][0] != '-' || compatible) {
380 char *s = argv[1];
381
382 option_mask32 |= OPT_u;
383 s = xstrdup(s + strspn(s, "-+"));
384 argv[1] = argv[0];
385 return generate_output(argv+1, argc-1, s, long_options);
386 }
387
388#if !ENABLE_FEATURE_GETOPT_LONG
389 opt = getopt32(argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg);
390#else
391 opt = getopt32long(argv, "+o:n:qQs:Tual:*", getopt_longopts,
392 &optstr, &name, &s_arg, &l_arg);
393
394 while (l_arg) {
395 long_options = add_long_options(long_options, llist_pop(&l_arg));
396 }
397#endif
398
399 if (opt & OPT_s) {
400 set_shell(s_arg);
401 }
402
403 if (opt & OPT_T) {
404 return 4;
405 }
406
407
408 n = optind - 1;
409 if (!optstr) {
410 optstr = argv[++n];
411 if (!optstr)
412 bb_simple_error_msg_and_die("missing optstring argument");
413 }
414
415 argv[n] = name ? name : argv[0];
416 return generate_output(argv + n, argc - n, optstr, long_options);
417}
418