7 |
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
8 |
*/ |
*/ |
9 |
|
|
|
#include "libbb.h" |
|
10 |
#include <getopt.h> |
#include <getopt.h> |
11 |
|
#include "libbb.h" |
12 |
|
|
13 |
/* Documentation |
/* Documentation |
14 |
|
|
15 |
uint32_t |
uint32_t |
16 |
getopt32(int argc, char **argv, const char *applet_opts, ...) |
getopt32(char **argv, const char *applet_opts, ...) |
17 |
|
|
18 |
The command line options must be declared in const char |
The command line options must be declared in const char |
19 |
*applet_opts as a string of chars, for example: |
*applet_opts as a string of chars, for example: |
20 |
|
|
21 |
flags = getopt32(argc, argv, "rnug"); |
flags = getopt32(argv, "rnug"); |
22 |
|
|
23 |
If one of the given options is found, a flag value is added to |
If one of the given options is found, a flag value is added to |
24 |
the return value (an unsigned long). |
the return value (an unsigned long). |
26 |
The flag value is determined by the position of the char in |
The flag value is determined by the position of the char in |
27 |
applet_opts string. For example, in the above case: |
applet_opts string. For example, in the above case: |
28 |
|
|
29 |
flags = getopt32(argc, argv, "rnug"); |
flags = getopt32(argv, "rnug"); |
30 |
|
|
31 |
"r" will add 1 (bit 0) |
"r" will add 1 (bit 0) |
32 |
"n" will add 2 (bit 1) |
"n" will add 2 (bit 1) |
33 |
"u will add 4 (bit 2) |
"u" will add 4 (bit 2) |
34 |
"g" will add 8 (bit 3) |
"g" will add 8 (bit 3) |
35 |
|
|
36 |
and so on. You can also look at the return value as a bit |
and so on. You can also look at the return value as a bit |
52 |
char *pointer_to_arg_for_c; |
char *pointer_to_arg_for_c; |
53 |
char *pointer_to_arg_for_d; |
char *pointer_to_arg_for_d; |
54 |
|
|
55 |
flags = getopt32(argc, argv, "a:b:c:d:", |
flags = getopt32(argv, "a:b:c:d:", |
56 |
&pointer_to_arg_for_a, &pointer_to_arg_for_b, |
&pointer_to_arg_for_a, &pointer_to_arg_for_b, |
57 |
&pointer_to_arg_for_c, &pointer_to_arg_for_d); |
&pointer_to_arg_for_c, &pointer_to_arg_for_d); |
58 |
|
|
59 |
The type of the pointer (char* or llist_t*) may be controlled |
The type of the pointer (char* or llist_t*) may be controlled |
60 |
by the "::" special separator that is set in the external string |
by the "::" special separator that is set in the external string |
72 |
env -i ls -d / |
env -i ls -d / |
73 |
Here we want env to process just the '-i', not the '-d'. |
Here we want env to process just the '-i', not the '-d'. |
74 |
|
|
75 |
const struct option *applet_long_options |
const char *applet_long_options |
76 |
|
|
77 |
|
This struct allows you to define long options: |
78 |
|
|
79 |
This struct allows you to define long options. The syntax for |
static const char applet_longopts[] ALIGN1 = |
80 |
declaring the array is just like that of getopt's longopts. |
//"name\0" has_arg val |
81 |
(see getopt(3)) |
"verbose\0" No_argument "v" |
82 |
|
; |
83 |
static const struct option applet_long_options[] = { |
applet_long_options = applet_longopts; |
|
//name,has_arg,flag,val |
|
|
{ "verbose", 0, 0, 'v' }, |
|
|
{ 0, 0, 0, 0 } |
|
|
}; |
|
|
applet_long_options = applet_long_options; |
|
84 |
|
|
85 |
The last member of struct option (val) typically is set to |
The last member of struct option (val) typically is set to |
86 |
matching short option from applet_opts. If there is no matching |
matching short option from applet_opts. If there is no matching |
87 |
char in applet_opts, then: |
char in applet_opts, then: |
88 |
- return bit have next position after short options |
- return bit have next position after short options |
89 |
- if has_arg is not "no_argument", use ptr for arg also |
- if has_arg is not "No_argument", use ptr for arg also |
90 |
- opt_complementary affects it too |
- opt_complementary affects it too |
91 |
|
|
92 |
Note: a good applet will make long options configurable via the |
Note: a good applet will make long options configurable via the |
105 |
if they are not specifed on the command line. For example: |
if they are not specifed on the command line. For example: |
106 |
|
|
107 |
opt_complementary = "abc"; |
opt_complementary = "abc"; |
108 |
flags = getopt32(argc, argv, "abcd") |
flags = getopt32(argv, "abcd") |
109 |
|
|
110 |
If getopt() finds "-a" on the command line, then |
If getopt() finds "-a" on the command line, then |
111 |
getopt32's return value will be as if "-a -b -c" were |
getopt32's return value will be as if "-a -b -c" were |
117 |
if w is given once, GNU ps sets the width to 132, |
if w is given once, GNU ps sets the width to 132, |
118 |
if w is given more than once, it is "unlimited" |
if w is given more than once, it is "unlimited" |
119 |
|
|
120 |
int w_counter = 0; |
int w_counter = 0; // must be initialized! |
121 |
opt_complementary = "ww"; |
opt_complementary = "ww"; |
122 |
getopt32(argc, argv, "w", &w_counter); |
getopt32(argv, "w", &w_counter); |
123 |
if (w_counter) |
if (w_counter) |
124 |
width = (w_counter == 1) ? 132 : INT_MAX; |
width = (w_counter == 1) ? 132 : INT_MAX; |
125 |
else |
else |
126 |
get_terminal_width(...&width...); |
get_terminal_width(...&width...); |
127 |
|
|
128 |
w_counter is a pointer to an integer. It has to be passed to |
w_counter is a pointer to an integer. It has to be passed to |
129 |
getopt32() after all other option argument sinks. |
getopt32() after all other option argument sinks. |
135 |
llist_t *my_b = NULL; |
llist_t *my_b = NULL; |
136 |
int verbose_level = 0; |
int verbose_level = 0; |
137 |
opt_complementary = "vv:b::b-c:c-b"; |
opt_complementary = "vv:b::b-c:c-b"; |
138 |
f = getopt32(argc, argv, "vb:c", &my_b, &verbose_level); |
f = getopt32(argv, "vb:c", &my_b, &verbose_level); |
139 |
if (f & 2) // -c after -b unsets -b flag |
if (f & 2) // -c after -b unsets -b flag |
140 |
while (my_b) { dosomething_with(my_b->data); my_b = my_b->link; } |
while (my_b) dosomething_with(llist_pop(&my_b)); |
141 |
if (my_b) // but llist is stored if -b is specified |
if (my_b) // but llist is stored if -b is specified |
142 |
free_llist(my_b); |
free_llist(my_b); |
143 |
if (verbose_level) printf("verbose level is %d\n", verbose_level); |
if (verbose_level) printf("verbose level is %d\n", verbose_level); |
144 |
|
|
145 |
Special characters: |
Special characters: |
150 |
use ':' or end of line. For example: |
use ':' or end of line. For example: |
151 |
|
|
152 |
opt_complementary = "-:w-x:x-w"; |
opt_complementary = "-:w-x:x-w"; |
153 |
getopt32(argc, argv, "wx"); |
getopt32(argv, "wx"); |
154 |
|
|
155 |
Allows any arguments to be given without a dash (./program w x) |
Allows any arguments to be given without a dash (./program w x) |
156 |
as well as with a dash (./program -x). |
as well as with a dash (./program -x). |
157 |
|
|
158 |
|
NB: getopt32() will leak a small amount of memory if you use |
159 |
|
this option! Do not use it if there is a possibility of recursive |
160 |
|
getopt32() calls. |
161 |
|
|
162 |
"--" A double dash at the beginning of opt_complementary means the |
"--" A double dash at the beginning of opt_complementary means the |
163 |
argv[1] string should always be treated as options, even if it isn't |
argv[1] string should always be treated as options, even if it isn't |
164 |
prefixed with a "-". This is useful for special syntax in applets |
prefixed with a "-". This is useful for special syntax in applets |
165 |
such as "ar" and "tar": |
such as "ar" and "tar": |
166 |
tar xvf foo.tar |
tar xvf foo.tar |
167 |
|
|
168 |
|
NB: getopt32() will leak a small amount of memory if you use |
169 |
|
this option! Do not use it if there is a possibility of recursive |
170 |
|
getopt32() calls. |
171 |
|
|
172 |
"-N" A dash as the first char in a opt_complementary group followed |
"-N" A dash as the first char in a opt_complementary group followed |
173 |
by a single digit (0-9) means that at least N non-option |
by a single digit (0-9) means that at least N non-option |
174 |
arguments must be present on the command line |
arguments must be present on the command line |
182 |
on the command line. |
on the command line. |
183 |
|
|
184 |
"V-" An option with dash before colon or end-of-line results in |
"V-" An option with dash before colon or end-of-line results in |
185 |
bb_show_usage being called if this option is encountered. |
bb_show_usage() being called if this option is encountered. |
186 |
This is typically used to implement "print verbose usage message |
This is typically used to implement "print verbose usage message |
187 |
and exit" option. |
and exit" option. |
188 |
|
|
189 |
"-" A dash between two options causes the second of the two |
"a-b" A dash between two options causes the second of the two |
190 |
to be unset (and ignored) if it is given on the command line. |
to be unset (and ignored) if it is given on the command line. |
191 |
|
|
192 |
[FIXME: what if they are the same? like "x-x"? Is it ever useful?] |
[FIXME: what if they are the same? like "x-x"? Is it ever useful?] |
205 |
char *smax_print_depth; |
char *smax_print_depth; |
206 |
|
|
207 |
opt_complementary = "s-d:d-s:x-x"; |
opt_complementary = "s-d:d-s:x-x"; |
208 |
opt = getopt32(argc, argv, "sd:x", &smax_print_depth); |
opt = getopt32(argv, "sd:x", &smax_print_depth); |
209 |
|
|
210 |
if (opt & 2) |
if (opt & 2) |
211 |
max_print_depth = atoi(smax_print_depth); |
max_print_depth = atoi(smax_print_depth); |
212 |
if (opt & 4) |
if (opt & 4) |
213 |
printf("Detected odd -x usage\n"); |
printf("Detected odd -x usage\n"); |
214 |
|
|
215 |
"--" A double dash between two options, or between an option and a group |
"a--b" A double dash between two options, or between an option and a group |
216 |
of options, means that they are mutually exclusive. Unlike |
of options, means that they are mutually exclusive. Unlike |
217 |
the "-" case above, an error will be forced if the options |
the "-" case above, an error will be forced if the options |
218 |
are used together. |
are used together. |
219 |
|
|
220 |
For example: |
For example: |
221 |
The cut applet must have only one type of list specified, so |
The cut applet must have only one type of list specified, so |
222 |
-b, -c and -f are mutally exclusive and should raise an error |
-b, -c and -f are mutually exclusive and should raise an error |
223 |
if specified together. In this case you must set |
if specified together. In this case you must set |
224 |
opt_complementary = "b--cf:c--bf:f--bc". If two of the |
opt_complementary = "b--cf:c--bf:f--bc". If two of the |
225 |
mutually exclusive options are found, getopt32's |
mutually exclusive options are found, getopt32 will call |
226 |
return value will have the error flag set (BB_GETOPT_ERROR) so |
bb_show_usage() and die. |
|
that we can check for it: |
|
|
|
|
|
if (flags & BB_GETOPT_ERROR) |
|
|
bb_show_usage(); |
|
227 |
|
|
228 |
"x--x" Variation of the above, it means that -x option should occur |
"x--x" Variation of the above, it means that -x option should occur |
229 |
at most once. |
at most once. |
230 |
|
|
231 |
"?" A "?" as the first char in a opt_complementary group means: |
"a+" A plus after a char in opt_complementary means that the parameter |
232 |
if BB_GETOPT_ERROR is detected, don't return, call bb_show_usage |
for this option is a nonnegative integer. It will be processed |
233 |
and exit instead. Next char after '?' can't be a digit. |
with xatoi_u() - allowed range is 0..INT_MAX. |
234 |
|
|
235 |
|
int param; // "unsigned param;" will also work |
236 |
|
opt_complementary = "p+"; |
237 |
|
getopt32(argv, "p:", ¶m); |
238 |
|
|
239 |
"::" A double colon after a char in opt_complementary means that the |
"a::" A double colon after a char in opt_complementary means that the |
240 |
option can occur multiple times. Each occurrence will be saved as |
option can occur multiple times. Each occurrence will be saved as |
241 |
a llist_t element instead of char*. |
a llist_t element instead of char*. |
242 |
|
|
247 |
llist_t *patterns = NULL; |
llist_t *patterns = NULL; |
248 |
|
|
249 |
(this pointer must be initializated to NULL if the list is empty |
(this pointer must be initializated to NULL if the list is empty |
250 |
as required by *llist_add_to(llist_t *old_head, char *new_item).) |
as required by llist_add_to_end(llist_t **old_head, char *new_item).) |
251 |
|
|
252 |
opt_complementary = "e::"; |
opt_complementary = "e::"; |
253 |
|
|
254 |
getopt32(argc, argv, "e:", &patterns); |
getopt32(argv, "e:", &patterns); |
255 |
$ grep -e user -e root /etc/passwd |
$ grep -e user -e root /etc/passwd |
256 |
root:x:0:0:root:/root:/bin/bash |
root:x:0:0:root:/root:/bin/bash |
257 |
user:x:500:500::/home/user:/bin/bash |
user:x:500:500::/home/user:/bin/bash |
258 |
|
|
259 |
"?" An "?" between an option and a group of options means that |
"a?b" A "?" between an option and a group of options means that |
260 |
at least one of them is required to occur if the first option |
at least one of them is required to occur if the first option |
261 |
occurs in preceding command line arguments. |
occurs in preceding command line arguments. |
262 |
|
|
263 |
For example from "id" applet: |
For example from "id" applet: |
264 |
|
|
265 |
// Don't allow -n -r -rn -ug -rug -nug -rnug |
// Don't allow -n -r -rn -ug -rug -nug -rnug |
266 |
opt_complementary = "r?ug:n?ug:?u--g:g--u"; |
opt_complementary = "r?ug:n?ug:u--g:g--u"; |
267 |
flags = getopt32(argc, argv, "rnug"); |
flags = getopt32(argv, "rnug"); |
268 |
|
|
269 |
This example allowed only: |
This example allowed only: |
270 |
$ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng |
$ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng |
275 |
For example from "start-stop-daemon" applet: |
For example from "start-stop-daemon" applet: |
276 |
|
|
277 |
// Don't allow -KS -SK, but -S or -K is required |
// Don't allow -KS -SK, but -S or -K is required |
278 |
opt_complementary = "K:S:?K--S:S--K"; |
opt_complementary = "K:S:K--S:S--K"; |
279 |
flags = getopt32(argc, argv, "KS...); |
flags = getopt32(argv, "KS...); |
280 |
|
|
281 |
|
|
282 |
Don't forget to use ':'. For example, "?322-22-23X-x-a" |
Don't forget to use ':'. For example, "?322-22-23X-x-a" |
284 |
max 3 args; count uses of '-2'; min 2 args; if there is |
max 3 args; count uses of '-2'; min 2 args; if there is |
285 |
a '-2' option then unset '-3', '-X' and '-a'; if there is |
a '-2' option then unset '-3', '-X' and '-a'; if there is |
286 |
a '-2' and after it a '-x' then error out. |
a '-2' and after it a '-x' then error out. |
287 |
|
But it's far too obfuscated. Use ':' to separate groups. |
288 |
*/ |
*/ |
289 |
|
|
290 |
/* Code here assumes that 'unsigned' is at least 32 bits wide */ |
/* Code here assumes that 'unsigned' is at least 32 bits wide */ |
291 |
|
|
292 |
|
const char *const bb_argv_dash[] = { "-", NULL }; |
293 |
|
|
294 |
const char *opt_complementary; |
const char *opt_complementary; |
295 |
|
|
296 |
|
enum { |
297 |
|
PARAM_STRING, |
298 |
|
PARAM_LIST, |
299 |
|
PARAM_INT, |
300 |
|
}; |
301 |
|
|
302 |
typedef struct { |
typedef struct { |
303 |
int opt; |
unsigned char opt_char; |
304 |
int list_flg; |
smallint param_type; |
305 |
unsigned switch_on; |
unsigned switch_on; |
306 |
unsigned switch_off; |
unsigned switch_off; |
307 |
unsigned incongruously; |
unsigned incongruously; |
308 |
unsigned requires; |
unsigned requires; |
309 |
void **optarg; /* char **optarg or llist_t **optarg */ |
void **optarg; /* char**, llist_t** or int *. */ |
310 |
int *counter; |
int *counter; |
311 |
} t_complementary; |
} t_complementary; |
312 |
|
|
313 |
/* You can set applet_long_options for parse called long options */ |
/* You can set applet_long_options for parse called long options */ |
314 |
#if ENABLE_GETOPT_LONG |
#if ENABLE_GETOPT_LONG |
315 |
static const struct option bb_default_long_options[] = { |
static const struct option bb_null_long_options[1] = { |
|
/* { "help", 0, NULL, '?' }, */ |
|
316 |
{ 0, 0, 0, 0 } |
{ 0, 0, 0, 0 } |
317 |
}; |
}; |
318 |
|
const char *applet_long_options; |
|
const struct option *applet_long_options = bb_default_long_options; |
|
319 |
#endif |
#endif |
320 |
|
|
321 |
uint32_t option_mask32; |
uint32_t option_mask32; |
322 |
|
|
323 |
uint32_t |
uint32_t FAST_FUNC |
324 |
getopt32(int argc, char **argv, const char *applet_opts, ...) |
getopt32(char **argv, const char *applet_opts, ...) |
325 |
{ |
{ |
326 |
|
int argc; |
327 |
unsigned flags = 0; |
unsigned flags = 0; |
328 |
unsigned requires = 0; |
unsigned requires = 0; |
329 |
t_complementary complementary[33]; |
t_complementary complementary[33]; /* last stays zero-filled */ |
330 |
int c; |
int c; |
331 |
const unsigned char *s; |
const unsigned char *s; |
332 |
t_complementary *on_off; |
t_complementary *on_off; |
333 |
va_list p; |
va_list p; |
334 |
#if ENABLE_GETOPT_LONG |
#if ENABLE_GETOPT_LONG |
335 |
const struct option *l_o; |
const struct option *l_o; |
336 |
|
struct option *long_options = (struct option *) &bb_null_long_options; |
337 |
#endif |
#endif |
338 |
unsigned trigger; |
unsigned trigger; |
339 |
char **pargv = NULL; |
char **pargv; |
340 |
int min_arg = 0; |
int min_arg = 0; |
341 |
int max_arg = -1; |
int max_arg = -1; |
342 |
|
|
343 |
#define SHOW_USAGE_IF_ERROR 1 |
#define SHOW_USAGE_IF_ERROR 1 |
344 |
#define ALL_ARGV_IS_OPTS 2 |
#define ALL_ARGV_IS_OPTS 2 |
345 |
#define FIRST_ARGV_IS_OPT 4 |
#define FIRST_ARGV_IS_OPT 4 |
346 |
#define FREE_FIRST_ARGV_IS_OPT 8 |
|
347 |
int spec_flgs = 0; |
int spec_flgs = 0; |
348 |
|
|
349 |
|
/* skip 0: some applets cheat: they do not actually HAVE argv[0] */ |
350 |
|
argc = 1; |
351 |
|
while (argv[argc]) |
352 |
|
argc++; |
353 |
|
|
354 |
va_start(p, applet_opts); |
va_start(p, applet_opts); |
355 |
|
|
356 |
c = 0; |
c = 0; |
362 |
if (*s == '+' || *s == '-') |
if (*s == '+' || *s == '-') |
363 |
s++; |
s++; |
364 |
while (*s) { |
while (*s) { |
365 |
if (c >= 32) break; |
if (c >= 32) |
366 |
on_off->opt = *s; |
break; |
367 |
|
on_off->opt_char = *s; |
368 |
on_off->switch_on = (1 << c); |
on_off->switch_on = (1 << c); |
369 |
if (*++s == ':') { |
if (*++s == ':') { |
370 |
on_off->optarg = va_arg(p, void **); |
on_off->optarg = va_arg(p, void **); |
371 |
while (*++s == ':') /* skip */; |
while (*++s == ':') |
372 |
|
continue; |
373 |
} |
} |
374 |
on_off++; |
on_off++; |
375 |
c++; |
c++; |
376 |
} |
} |
377 |
|
|
378 |
#if ENABLE_GETOPT_LONG |
#if ENABLE_GETOPT_LONG |
379 |
for (l_o = applet_long_options; l_o->name; l_o++) { |
if (applet_long_options) { |
380 |
if (l_o->flag) |
const char *optstr; |
381 |
continue; |
unsigned i, count; |
382 |
for (on_off = complementary; on_off->opt != 0; on_off++) |
|
383 |
if (on_off->opt == l_o->val) |
count = 1; |
384 |
goto next_long; |
optstr = applet_long_options; |
385 |
if (c >= 32) break; |
while (optstr[0]) { |
386 |
on_off->opt = l_o->val; |
optstr += strlen(optstr) + 3; /* skip NUL, has_arg, val */ |
387 |
on_off->switch_on = (1 << c); |
count++; |
388 |
if (l_o->has_arg != no_argument) |
} |
389 |
on_off->optarg = va_arg(p, void **); |
/* count == no. of longopts + 1 */ |
390 |
c++; |
long_options = alloca(count * sizeof(*long_options)); |
391 |
|
memset(long_options, 0, count * sizeof(*long_options)); |
392 |
|
i = 0; |
393 |
|
optstr = applet_long_options; |
394 |
|
while (--count) { |
395 |
|
long_options[i].name = optstr; |
396 |
|
optstr += strlen(optstr) + 1; |
397 |
|
long_options[i].has_arg = (unsigned char)(*optstr++); |
398 |
|
/* long_options[i].flag = NULL; */ |
399 |
|
long_options[i].val = (unsigned char)(*optstr++); |
400 |
|
i++; |
401 |
|
} |
402 |
|
for (l_o = long_options; l_o->name; l_o++) { |
403 |
|
if (l_o->flag) |
404 |
|
continue; |
405 |
|
for (on_off = complementary; on_off->opt_char; on_off++) |
406 |
|
if (on_off->opt_char == l_o->val) |
407 |
|
goto next_long; |
408 |
|
if (c >= 32) |
409 |
|
break; |
410 |
|
on_off->opt_char = l_o->val; |
411 |
|
on_off->switch_on = (1 << c); |
412 |
|
if (l_o->has_arg != no_argument) |
413 |
|
on_off->optarg = va_arg(p, void **); |
414 |
|
c++; |
415 |
next_long: ; |
next_long: ; |
416 |
|
} |
417 |
} |
} |
418 |
#endif /* ENABLE_GETOPT_LONG */ |
#endif /* ENABLE_GETOPT_LONG */ |
419 |
for (s = (const unsigned char *)opt_complementary; s && *s; s++) { |
for (s = (const unsigned char *)opt_complementary; s && *s; s++) { |
450 |
s++; |
s++; |
451 |
continue; |
continue; |
452 |
} |
} |
453 |
for (on_off = complementary; on_off->opt; on_off++) |
for (on_off = complementary; on_off->opt_char; on_off++) |
454 |
if (on_off->opt == *s) |
if (on_off->opt_char == *s) |
455 |
break; |
break; |
456 |
if (c == ':' && s[2] == ':') { |
if (c == ':' && s[2] == ':') { |
457 |
on_off->list_flg++; |
on_off->param_type = PARAM_LIST; |
458 |
|
continue; |
459 |
|
} |
460 |
|
if (c == '+' && (s[2] == ':' || s[2] == '\0')) { |
461 |
|
on_off->param_type = PARAM_INT; |
462 |
continue; |
continue; |
463 |
} |
} |
464 |
if (c == ':' || c == '\0') { |
if (c == ':' || c == '\0') { |
486 |
else |
else |
487 |
pair_switch = &(pair->switch_off); |
pair_switch = &(pair->switch_off); |
488 |
} else { |
} else { |
489 |
for (on_off = complementary; on_off->opt; on_off++) |
for (on_off = complementary; on_off->opt_char; on_off++) |
490 |
if (on_off->opt == *s) { |
if (on_off->opt_char == *s) { |
491 |
*pair_switch |= on_off->switch_on; |
*pair_switch |= on_off->switch_on; |
492 |
break; |
break; |
493 |
} |
} |
495 |
} |
} |
496 |
s--; |
s--; |
497 |
} |
} |
498 |
va_end (p); |
va_end(p); |
499 |
|
|
500 |
if (spec_flgs & FIRST_ARGV_IS_OPT) { |
if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) { |
501 |
if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') { |
pargv = argv + 1; |
502 |
argv[1] = xasprintf("-%s", argv[1]); |
while (*pargv) { |
503 |
if (ENABLE_FEATURE_CLEAN_UP) |
if (pargv[0][0] != '-' && pargv[0][0] != '\0') { |
504 |
spec_flgs |= FREE_FIRST_ARGV_IS_OPT; |
/* Can't use alloca: opts with params will |
505 |
|
* return pointers to stack! |
506 |
|
* NB: we leak these allocations... */ |
507 |
|
char *pp = xmalloc(strlen(*pargv) + 2); |
508 |
|
*pp = '-'; |
509 |
|
strcpy(pp + 1, *pargv); |
510 |
|
*pargv = pp; |
511 |
|
} |
512 |
|
if (!(spec_flgs & ALL_ARGV_IS_OPTS)) |
513 |
|
break; |
514 |
|
pargv++; |
515 |
} |
} |
516 |
} |
} |
517 |
/* Note: just "getopt() <= 0" will not work good for |
|
518 |
|
/* In case getopt32 was already called: |
519 |
|
* reset the libc getopt() function, which keeps internal state. |
520 |
|
* run_nofork_applet_prime() does this, but we might end up here |
521 |
|
* also via gunzip_main() -> gzip_main(). Play safe. |
522 |
|
*/ |
523 |
|
#ifdef __GLIBC__ |
524 |
|
optind = 0; |
525 |
|
#else /* BSD style */ |
526 |
|
optind = 1; |
527 |
|
/* optreset = 1; */ |
528 |
|
#endif |
529 |
|
/* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ |
530 |
|
|
531 |
|
pargv = NULL; |
532 |
|
|
533 |
|
/* Note: just "getopt() <= 0" will not work well for |
534 |
* "fake" short options, like this one: |
* "fake" short options, like this one: |
535 |
* wget $'-\203' "Test: test" http://kernel.org/ |
* wget $'-\203' "Test: test" http://kernel.org/ |
536 |
* (supposed to act as --header, but doesn't) */ |
* (supposed to act as --header, but doesn't) */ |
537 |
#if ENABLE_GETOPT_LONG |
#if ENABLE_GETOPT_LONG |
538 |
while ((c = getopt_long(argc, argv, applet_opts, |
while ((c = getopt_long(argc, argv, applet_opts, |
539 |
applet_long_options, NULL)) != -1) { |
long_options, NULL)) != -1) { |
540 |
#else |
#else |
541 |
while ((c = getopt(argc, argv, applet_opts)) != -1) { |
while ((c = getopt(argc, argv, applet_opts)) != -1) { |
542 |
#endif /* ENABLE_GETOPT_LONG */ |
#endif |
543 |
c &= 0xff; /* fight libc's sign extends */ |
/* getopt prints "option requires an argument -- X" |
544 |
loop_arg_is_opt: |
* and returns '?' if an option has no arg, but one is reqd */ |
545 |
for (on_off = complementary; on_off->opt != c; on_off++) { |
c &= 0xff; /* fight libc's sign extension */ |
546 |
/* c==0 if long opt have non NULL flag */ |
for (on_off = complementary; on_off->opt_char != c; on_off++) { |
547 |
if (on_off->opt == 0 && c != 0) |
/* c can be NUL if long opt has non-NULL ->flag, |
548 |
bb_show_usage(); |
* but we construct long opts so that flag |
549 |
} |
* is always NULL (see above) */ |
550 |
if (flags & on_off->incongruously) { |
if (on_off->opt_char == '\0' /* && c != '\0' */) { |
551 |
if ((spec_flgs & SHOW_USAGE_IF_ERROR)) |
/* c is probably '?' - "bad option" */ |
552 |
bb_show_usage(); |
bb_show_usage(); |
553 |
flags |= BB_GETOPT_ERROR; |
} |
554 |
} |
} |
555 |
|
if (flags & on_off->incongruously) |
556 |
|
bb_show_usage(); |
557 |
trigger = on_off->switch_on & on_off->switch_off; |
trigger = on_off->switch_on & on_off->switch_off; |
558 |
flags &= ~(on_off->switch_off ^ trigger); |
flags &= ~(on_off->switch_off ^ trigger); |
559 |
flags |= on_off->switch_on ^ trigger; |
flags |= on_off->switch_on ^ trigger; |
560 |
flags ^= trigger; |
flags ^= trigger; |
561 |
if (on_off->counter) |
if (on_off->counter) |
562 |
(*(on_off->counter))++; |
(*(on_off->counter))++; |
563 |
if (on_off->list_flg) { |
if (on_off->param_type == PARAM_LIST) { |
564 |
llist_add_to((llist_t **)(on_off->optarg), optarg); |
if (optarg) |
565 |
|
llist_add_to_end((llist_t **)(on_off->optarg), optarg); |
566 |
|
} else if (on_off->param_type == PARAM_INT) { |
567 |
|
if (optarg) |
568 |
|
//TODO: xatoi_u indirectly pulls in printf machinery |
569 |
|
*(unsigned*)(on_off->optarg) = xatoi_u(optarg); |
570 |
} else if (on_off->optarg) { |
} else if (on_off->optarg) { |
571 |
*(char **)(on_off->optarg) = optarg; |
if (optarg) |
572 |
|
*(char **)(on_off->optarg) = optarg; |
573 |
} |
} |
574 |
if (pargv != NULL) |
if (pargv != NULL) |
575 |
break; |
break; |
576 |
} |
} |
577 |
|
|
|
if (spec_flgs & ALL_ARGV_IS_OPTS) { |
|
|
/* process argv is option, for example "ps" applet */ |
|
|
if (pargv == NULL) |
|
|
pargv = argv + optind; |
|
|
while (*pargv) { |
|
|
c = **pargv; |
|
|
if (c == '\0') { |
|
|
pargv++; |
|
|
} else { |
|
|
(*pargv)++; |
|
|
goto loop_arg_is_opt; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
#if (ENABLE_AR || ENABLE_TAR) && ENABLE_FEATURE_CLEAN_UP |
|
|
if (spec_flgs & FREE_FIRST_ARGV_IS_OPT) |
|
|
free(argv[1]); |
|
|
#endif |
|
578 |
/* check depending requires for given options */ |
/* check depending requires for given options */ |
579 |
for (on_off = complementary; on_off->opt; on_off++) { |
for (on_off = complementary; on_off->opt_char; on_off++) { |
580 |
if (on_off->requires && (flags & on_off->switch_on) && |
if (on_off->requires && (flags & on_off->switch_on) && |
581 |
(flags & on_off->requires) == 0) |
(flags & on_off->requires) == 0) |
582 |
bb_show_usage(); |
bb_show_usage(); |