getopt32: add new syntax of 'o:+' and 'o:*' for -o NUM and -o LIST
In many cases, this aqllows to drop use of opt_complementary. Approximately -400 bytes: function old new delta getopt32 1423 1502 +79 opt_string 17 18 +1 OPT_STR 24 25 +1 uniq_main 416 406 -10 timeout_main 279 269 -10 sulogin_main 270 260 -10 readprofile_main 1825 1815 -10 ps_main 543 533 -10 pidof_main 245 235 -10 pgrep_main 611 601 -10 od_main 2600 2590 -10 mkfs_minix_main 2684 2674 -10 mkfs_ext2_main 2603 2593 -10 microcom_main 712 702 -10 makemime_main 315 305 -10 ionice_main 282 272 -10 inetd_main 2074 2064 -10 ifplugd_main 1144 1134 -10 halt_main 353 343 -10 getopt_main 636 626 -10 fdisk_main 2854 2844 -10 env_main 206 196 -10 dmesg_main 319 309 -10 conspy_main 1214 1204 -10 awk_main 981 971 -10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/22 up/down: 81/-220) Total: -139 bytes text data bss dec hex filename 919373 906 14060 934339 e41c3 busybox_old 918969 906 14060 933935 e402f busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
@@ -17,23 +17,20 @@
|
||||
uint32_t
|
||||
getopt32(char **argv, const char *applet_opts, ...)
|
||||
|
||||
The command line options must be declared in const char
|
||||
*applet_opts as a string of chars, for example:
|
||||
|
||||
flags = getopt32(argv, "rnug");
|
||||
The command line options are passed as the applet_opts string.
|
||||
|
||||
If one of the given options is found, a flag value is added to
|
||||
the return value (an unsigned long).
|
||||
the return value.
|
||||
|
||||
The flag value is determined by the position of the char in
|
||||
applet_opts string. For example, in the above case:
|
||||
applet_opts string. For example:
|
||||
|
||||
flags = getopt32(argv, "rnug");
|
||||
|
||||
"r" will add 1 (bit 0)
|
||||
"n" will add 2 (bit 1)
|
||||
"u" will add 4 (bit 2)
|
||||
"g" will add 8 (bit 3)
|
||||
"r" will set 1 (bit 0)
|
||||
"n" will set 2 (bit 1)
|
||||
"u" will set 4 (bit 2)
|
||||
"g" will set 8 (bit 3)
|
||||
|
||||
and so on. You can also look at the return value as a bit
|
||||
field and each option sets one bit.
|
||||
@@ -45,7 +42,7 @@ getopt32(char **argv, const char *applet_opts, ...)
|
||||
(options and their parameters will be moved into argv[]
|
||||
positions prior to argv[optind]).
|
||||
|
||||
":" If one of the options requires an argument, then add a ":"
|
||||
"o:" If one of the options requires an argument, then add a ":"
|
||||
after the char in applet_opts and provide a pointer to store
|
||||
the argument. For example:
|
||||
|
||||
@@ -58,15 +55,39 @@ getopt32(char **argv, const char *applet_opts, ...)
|
||||
&pointer_to_arg_for_a, &pointer_to_arg_for_b,
|
||||
&pointer_to_arg_for_c, &pointer_to_arg_for_d);
|
||||
|
||||
The type of the pointer (char* or llist_t*) may be controlled
|
||||
by the "::" special separator that is set in the external string
|
||||
opt_complementary (see below for more info).
|
||||
The type of the pointer may be controlled by "o::" or "o+" in
|
||||
the external string opt_complementary (see below for more info).
|
||||
|
||||
"::" If option can have an *optional* argument, then add a "::"
|
||||
"o::" If option can have an *optional* argument, then add a "::"
|
||||
after its char in applet_opts and provide a pointer to store
|
||||
the argument. Note that optional arguments _must_
|
||||
immediately follow the option: -oparam, not -o param.
|
||||
|
||||
"o:+" This means that the parameter for this option is a nonnegative integer.
|
||||
It will be processed with xatoi_positive() - allowed range
|
||||
is 0..INT_MAX.
|
||||
|
||||
int param; // "unsigned param;" will also work
|
||||
getopt32(argv, "p:+", ¶m);
|
||||
|
||||
"o:*" This means that the option can occur multiple times. Each occurrence
|
||||
will be saved as a llist_t element instead of char*.
|
||||
|
||||
For example:
|
||||
The grep applet can have one or more "-e pattern" arguments.
|
||||
In this case you should use getopt32() as follows:
|
||||
|
||||
llist_t *patterns = NULL;
|
||||
|
||||
(this pointer must be initializated to NULL if the list is empty
|
||||
as required by llist_add_to_end(llist_t **old_head, char *new_item).)
|
||||
|
||||
getopt32(argv, "e:*", &patterns);
|
||||
|
||||
$ grep -e user -e root /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
user:x:500:500::/home/user:/bin/bash
|
||||
|
||||
"+" If the first character in the applet_opts string is a plus,
|
||||
then option processing will stop as soon as a non-option is
|
||||
encountered in the argv array. Useful for applets like env
|
||||
@@ -82,7 +103,7 @@ const char *applet_long_options
|
||||
This struct allows you to define long options:
|
||||
|
||||
static const char applet_longopts[] ALIGN1 =
|
||||
//"name\0" has_arg val
|
||||
//"name\0" has_arg val
|
||||
"verbose\0" No_argument "v"
|
||||
;
|
||||
applet_long_options = applet_longopts;
|
||||
@@ -90,7 +111,7 @@ const char *applet_long_options
|
||||
The last member of struct option (val) typically is set to
|
||||
matching short option from applet_opts. If there is no matching
|
||||
char in applet_opts, then:
|
||||
- return bit have next position after short options
|
||||
- return bit has next position after short options
|
||||
- if has_arg is not "No_argument", use ptr for arg also
|
||||
- opt_complementary affects it too
|
||||
|
||||
@@ -139,8 +160,8 @@ const char *opt_complementary
|
||||
|
||||
llist_t *my_b = NULL;
|
||||
int verbose_level = 0;
|
||||
opt_complementary = "vv:b::b-c:c-b";
|
||||
f = getopt32(argv, "vb:c", &my_b, &verbose_level);
|
||||
opt_complementary = "vv:b-c:c-b";
|
||||
f = getopt32(argv, "vb:*c", &my_b, &verbose_level);
|
||||
if (f & 2) // -c after -b unsets -b flag
|
||||
while (my_b) dosomething_with(llist_pop(&my_b));
|
||||
if (my_b) // but llist is stored if -b is specified
|
||||
@@ -233,7 +254,7 @@ Special characters:
|
||||
"x--x" Variation of the above, it means that -x option should occur
|
||||
at most once.
|
||||
|
||||
"a+" A plus after a char in opt_complementary means that the parameter
|
||||
"o+" A plus after a char in opt_complementary means that the parameter
|
||||
for this option is a nonnegative integer. It will be processed
|
||||
with xatoi_positive() - allowed range is 0..INT_MAX.
|
||||
|
||||
@@ -241,7 +262,7 @@ Special characters:
|
||||
opt_complementary = "p+";
|
||||
getopt32(argv, "p:", ¶m);
|
||||
|
||||
"a::" A double colon after a char in opt_complementary means that the
|
||||
"o::" A double colon after a char in opt_complementary means that the
|
||||
option can occur multiple times. Each occurrence will be saved as
|
||||
a llist_t element instead of char*.
|
||||
|
||||
@@ -255,12 +276,17 @@ Special characters:
|
||||
as required by llist_add_to_end(llist_t **old_head, char *new_item).)
|
||||
|
||||
opt_complementary = "e::";
|
||||
|
||||
getopt32(argv, "e:", &patterns);
|
||||
|
||||
$ grep -e user -e root /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
user:x:500:500::/home/user:/bin/bash
|
||||
|
||||
"o+" and "o::" can be handled by "o:+" and "o:*" specifiers
|
||||
in option string (and it is preferred), but this does not work
|
||||
for "long options only" cases, such as tar --exclude=PATTERN,
|
||||
wget --header=HDR cases.
|
||||
|
||||
"a?b" A "?" between an option and a group of options means that
|
||||
at least one of them is required to occur if the first option
|
||||
occurs in preceding command line arguments.
|
||||
@@ -359,10 +385,11 @@ getopt32(char **argv, const char *applet_opts, ...)
|
||||
|
||||
va_start(p, applet_opts);
|
||||
|
||||
c = 0;
|
||||
on_off = complementary;
|
||||
memset(on_off, 0, sizeof(complementary));
|
||||
|
||||
applet_opts = strcpy(alloca(strlen(applet_opts) + 1), applet_opts);
|
||||
|
||||
/* skip bbox extension */
|
||||
first_char = applet_opts[0];
|
||||
if (first_char == '!')
|
||||
@@ -372,6 +399,7 @@ getopt32(char **argv, const char *applet_opts, ...)
|
||||
s = (const unsigned char *)applet_opts;
|
||||
if (*s == '+' || *s == '-')
|
||||
s++;
|
||||
c = 0;
|
||||
while (*s) {
|
||||
if (c >= 32)
|
||||
break;
|
||||
@@ -379,6 +407,13 @@ getopt32(char **argv, const char *applet_opts, ...)
|
||||
on_off->switch_on = (1 << c);
|
||||
if (*++s == ':') {
|
||||
on_off->optarg = va_arg(p, void **);
|
||||
if (s[1] == '+' || s[1] == '*') {
|
||||
/* 'o:+' or 'o:*' */
|
||||
on_off->param_type = (s[1] == '+') ?
|
||||
PARAM_INT : PARAM_LIST;
|
||||
overlapping_strcpy((char*)s + 1, (char*)s + 2);
|
||||
}
|
||||
/* skip possible 'o::' (or 'o:+:' !) */
|
||||
while (*++s == ':')
|
||||
continue;
|
||||
}
|
||||
@@ -431,6 +466,7 @@ getopt32(char **argv, const char *applet_opts, ...)
|
||||
applet_long_options = NULL;
|
||||
}
|
||||
#endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG */
|
||||
|
||||
for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
|
||||
t_complementary *pair;
|
||||
unsigned *pair_switch;
|
||||
|
@@ -42,8 +42,8 @@ int parse_main(int argc UNUSED_PARAM, char **argv)
|
||||
int mintokens = 0, ntokens = 128;
|
||||
unsigned noout;
|
||||
|
||||
opt_complementary = "-1:n+:m+:f+";
|
||||
noout = 1 & getopt32(argv, "xn:m:d:f:", &ntokens, &mintokens, &delims, &flags);
|
||||
opt_complementary = "-1";
|
||||
noout = 1 & getopt32(argv, "xn:+m:+d:f:+", &ntokens, &mintokens, &delims, &flags);
|
||||
//argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
|
Reference in New Issue
Block a user