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#if ENABLE_FEATURE_CLEAN_UP
160 static char *BUFFER = NULL;
161 free(BUFFER);
162#else
163 char *BUFFER;
164#endif
165
166 if (!quote) {
167 BUFFER = xstrdup(arg);
168 return BUFFER;
169 }
170
171
172
173
174
175 BUFFER = xmalloc(strlen(arg)*4 + 3);
176
177 bufptr = BUFFER;
178 *bufptr ++= '\'';
179
180 while (*arg) {
181 if (*arg == '\'') {
182
183 *bufptr ++= '\'';
184 *bufptr ++= '\\';
185 *bufptr ++= '\'';
186 *bufptr ++= '\'';
187 } else if (shell_TCSH && *arg == '!') {
188
189 *bufptr ++= '\'';
190 *bufptr ++= '\\';
191 *bufptr ++= '!';
192 *bufptr ++= '\'';
193 } else if (shell_TCSH && *arg == '\n') {
194
195 *bufptr ++= '\\';
196 *bufptr ++= 'n';
197 } else if (shell_TCSH && isspace(*arg)) {
198
199 *bufptr ++= '\'';
200 *bufptr ++= '\\';
201 *bufptr ++= *arg;
202 *bufptr ++= '\'';
203 } else
204
205 *bufptr ++= *arg;
206 arg++;
207 }
208 *bufptr ++= '\'';
209 *bufptr ++= '\0';
210 return BUFFER;
211}
212
213
214
215
216
217
218
219
220#if !ENABLE_FEATURE_GETOPT_LONG
221#define generate_output(argv,argc,optstr,longopts) \
222 generate_output(argv,argc,optstr)
223#endif
224static int generate_output(char **argv, int argc, const char *optstr, const struct option *longopts)
225{
226 int exit_code = 0;
227
228 if (quiet_errors)
229 opterr = 0;
230
231
232
233 GETOPT_RESET();
234
235 while (1) {
236#if ENABLE_FEATURE_GETOPT_LONG
237 int longindex;
238 int opt = alternative
239 ? getopt_long_only(argc, argv, optstr, longopts, &longindex)
240 : getopt_long(argc, argv, optstr, longopts, &longindex)
241 ;
242#else
243 int opt = getopt(argc, argv, optstr);
244#endif
245 if (opt == -1)
246 break;
247 if (opt == '?' || opt == ':' )
248 exit_code = 1;
249 else if (!quiet_output) {
250#if ENABLE_FEATURE_GETOPT_LONG
251 if (opt == LONG_OPT) {
252 printf(" --%s", longopts[longindex].name);
253 if (longopts[longindex].has_arg)
254 printf(" %s",
255 normalize(optarg ? optarg : ""));
256 } else
257#endif
258 if (opt == NON_OPT)
259 printf(" %s", normalize(optarg));
260 else {
261 const char *charptr;
262 printf(" -%c", opt);
263 charptr = strchr(optstr, opt);
264 if (charptr && *++charptr == ':')
265 printf(" %s",
266 normalize(optarg ? optarg : ""));
267 }
268 }
269 }
270
271 if (!quiet_output) {
272 unsigned idx;
273 printf(" --");
274 idx = optind;
275 while (argv[idx])
276 printf(" %s", normalize(argv[idx++]));
277 bb_putchar('\n');
278 }
279 return exit_code;
280}
281
282#if ENABLE_FEATURE_GETOPT_LONG
283
284
285
286
287
288static struct option *add_long_options(struct option *long_options, char *options)
289{
290 int long_nr = 0;
291 int arg_opt, tlen;
292 char *tokptr = strtok(options, ", \t\n");
293
294 if (long_options)
295 while (long_options[long_nr].name)
296 long_nr++;
297
298 while (tokptr) {
299 arg_opt = no_argument;
300 tlen = strlen(tokptr);
301 if (tlen) {
302 tlen--;
303 if (tokptr[tlen] == ':') {
304 arg_opt = required_argument;
305 if (tlen && tokptr[tlen-1] == ':') {
306 tlen--;
307 arg_opt = optional_argument;
308 }
309 tokptr[tlen] = '\0';
310 if (tlen == 0)
311 bb_error_msg_and_die("empty long option specified");
312 }
313 long_options = xrealloc_vector(long_options, 4, long_nr);
314 long_options[long_nr].has_arg = arg_opt;
315
316 long_options[long_nr].val = LONG_OPT;
317 long_options[long_nr].name = xstrdup(tokptr);
318 long_nr++;
319
320 }
321 tokptr = strtok(NULL, ", \t\n");
322 }
323 return long_options;
324}
325#endif
326
327static void set_shell(const char *new_shell)
328{
329 if (strcmp(new_shell, "bash") == 0 || strcmp(new_shell, "sh") == 0)
330 return;
331 if (strcmp(new_shell, "tcsh") == 0 || strcmp(new_shell, "csh") == 0)
332 option_mask32 |= SHELL_IS_TCSH;
333 else
334 bb_error_msg("unknown shell '%s', assuming bash", new_shell);
335}
336
337
338
339
340
341
342
343
344
345
346#if ENABLE_FEATURE_GETOPT_LONG
347static const char getopt_longopts[] ALIGN1 =
348 "options\0" Required_argument "o"
349 "longoptions\0" Required_argument "l"
350 "quiet\0" No_argument "q"
351 "quiet-output\0" No_argument "Q"
352 "shell\0" Required_argument "s"
353 "test\0" No_argument "T"
354 "unquoted\0" No_argument "u"
355 "alternative\0" No_argument "a"
356 "name\0" Required_argument "n"
357 ;
358#endif
359
360int getopt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
361int getopt_main(int argc, char **argv)
362{
363 int n;
364 char *optstr = NULL;
365 char *name = NULL;
366 unsigned opt;
367 const char *compatible;
368 char *s_arg;
369#if ENABLE_FEATURE_GETOPT_LONG
370 struct option *long_options = NULL;
371 llist_t *l_arg = NULL;
372#endif
373
374 compatible = getenv("GETOPT_COMPATIBLE");
375
376 if (!argv[1]) {
377 if (compatible) {
378
379
380 puts(" --");
381 return 0;
382 }
383 bb_error_msg_and_die("missing optstring argument");
384 }
385
386 if (argv[1][0] != '-' || compatible) {
387 char *s = argv[1];
388
389 option_mask32 |= OPT_u;
390 s = xstrdup(s + strspn(s, "-+"));
391 argv[1] = argv[0];
392 return generate_output(argv+1, argc-1, s, long_options);
393 }
394
395#if !ENABLE_FEATURE_GETOPT_LONG
396 opt = getopt32(argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg);
397#else
398 opt = getopt32long(argv, "+o:n:qQs:Tual:*", getopt_longopts,
399 &optstr, &name, &s_arg, &l_arg);
400
401 while (l_arg) {
402 long_options = add_long_options(long_options, llist_pop(&l_arg));
403 }
404#endif
405
406 if (opt & OPT_s) {
407 set_shell(s_arg);
408 }
409
410 if (opt & OPT_T) {
411 return 4;
412 }
413
414
415 n = optind - 1;
416 if (!optstr) {
417 optstr = argv[++n];
418 if (!optstr)
419 bb_error_msg_and_die("missing optstring argument");
420 }
421
422 argv[n] = name ? name : argv[0];
423 return generate_output(argv + n, argc - n, optstr, long_options);
424}
425