From 237bedd499c58034a1355484d6d4d906f0180308 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 6 Jul 2016 21:58:02 +0200 Subject: 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 --- libbb/getopt32.c | 82 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 23 deletions(-) (limited to 'libbb/getopt32.c') diff --git a/libbb/getopt32.c b/libbb/getopt32.c index d0e83d88e..15b6efc09 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -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; -- cgit v1.2.3