getpot: add support for "a+" specifier for nonnegative int parameters.
By Vladimir Dronnikov <dronnikov at gmail.com>.
fdisk and top are converted as an example.
function old new delta
getopt32 1340 1370 +30
top_main 1137 1120 -17
fdisk_main 3033 2949 -84
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/2 up/down: 30/-101) Total: -71 bytes
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index 80d5d28..46807a3 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -220,6 +220,14 @@
"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
+ for this option is a nonnegative integer. It will be processed
+ with xatoi_u() - allowed range is 0..INT_MAX.
+
+ int param; // "unsigned param;" will also work
+ opt_complementary = "p+";
+ getopt32(argv, "p:", ¶m);
+
"a::" 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*.
@@ -275,14 +283,20 @@
const char *opt_complementary;
+enum {
+ PARAM_STRING,
+ PARAM_LIST,
+ PARAM_INT,
+};
+
typedef struct {
- int opt;
- int list_flg;
+ unsigned char opt_char;
+ smallint param_type;
unsigned switch_on;
unsigned switch_off;
unsigned incongruously;
unsigned requires;
- void **optarg; /* char **optarg or llist_t **optarg */
+ void **optarg; /* char**, llist_t** or int *. */
int *counter;
} t_complementary;
@@ -337,12 +351,14 @@
if (*s == '+' || *s == '-')
s++;
while (*s) {
- if (c >= 32) break;
- on_off->opt = *s;
+ if (c >= 32)
+ break;
+ on_off->opt_char = *s;
on_off->switch_on = (1 << c);
if (*++s == ':') {
on_off->optarg = va_arg(p, void **);
- while (*++s == ':') /* skip */;
+ while (*++s == ':')
+ continue;
}
on_off++;
c++;
@@ -375,11 +391,12 @@
for (l_o = long_options; l_o->name; l_o++) {
if (l_o->flag)
continue;
- for (on_off = complementary; on_off->opt != 0; on_off++)
- if (on_off->opt == l_o->val)
+ for (on_off = complementary; on_off->opt_char; on_off++)
+ if (on_off->opt_char == l_o->val)
goto next_long;
- if (c >= 32) break;
- on_off->opt = l_o->val;
+ if (c >= 32)
+ break;
+ on_off->opt_char = l_o->val;
on_off->switch_on = (1 << c);
if (l_o->has_arg != no_argument)
on_off->optarg = va_arg(p, void **);
@@ -422,11 +439,15 @@
s++;
continue;
}
- for (on_off = complementary; on_off->opt; on_off++)
- if (on_off->opt == *s)
+ for (on_off = complementary; on_off->opt_char; on_off++)
+ if (on_off->opt_char == *s)
break;
if (c == ':' && s[2] == ':') {
- on_off->list_flg++;
+ on_off->param_type = PARAM_LIST;
+ continue;
+ }
+ if (c == '+' && (s[2] == ':' || s[2] == '\0')) {
+ on_off->param_type = PARAM_INT;
continue;
}
if (c == ':' || c == '\0') {
@@ -454,8 +475,8 @@
else
pair_switch = &(pair->switch_off);
} else {
- for (on_off = complementary; on_off->opt; on_off++)
- if (on_off->opt == *s) {
+ for (on_off = complementary; on_off->opt_char; on_off++)
+ if (on_off->opt_char == *s) {
*pair_switch |= on_off->switch_on;
break;
}
@@ -508,9 +529,9 @@
#endif
c &= 0xff; /* fight libc's sign extension */
loop_arg_is_opt:
- for (on_off = complementary; on_off->opt != c; on_off++) {
+ for (on_off = complementary; on_off->opt_char != c; on_off++) {
/* c==0 if long opt have non NULL flag */
- if (on_off->opt == 0 && c != 0)
+ if (on_off->opt_char == '\0' && c != '\0')
bb_show_usage();
}
if (flags & on_off->incongruously)
@@ -521,8 +542,10 @@
flags ^= trigger;
if (on_off->counter)
(*(on_off->counter))++;
- if (on_off->list_flg) {
+ if (on_off->param_type == PARAM_LIST) {
llist_add_to_end((llist_t **)(on_off->optarg), optarg);
+ } else if (on_off->param_type == PARAM_INT) {
+ *(unsigned*)(on_off->optarg) = xatoi_u(optarg);
} else if (on_off->optarg) {
*(char **)(on_off->optarg) = optarg;
}
@@ -550,7 +573,7 @@
free(argv[1]);
#endif
/* check depending requires for given options */
- for (on_off = complementary; on_off->opt; on_off++) {
+ for (on_off = complementary; on_off->opt_char; on_off++) {
if (on_off->requires && (flags & on_off->switch_on) &&
(flags & on_off->requires) == 0)
bb_show_usage();