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:
Denys Vlasenko
2016-07-06 21:58:02 +02:00
parent 0844b5afe2
commit 237bedd499
58 changed files with 168 additions and 159 deletions

View File

@@ -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:+", &param);
"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:", &param);
"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;

View File

@@ -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;