opt_failure("Invalid option %s.", str);
}
+#define OPT_PTR(type) ({ \
+ type * ptr; \
+ if (item->flags & OPT_MULTIPLE) { \
+ struct { \
+ cnode n; \
+ type v; \
+ } * n = xmalloc(sizeof(*n)); \
+ clist_add_tail(item->ptr, &(n->n)); \
+ ptr = &(n->v); \
+ } else \
+ ptr = item->ptr; \
+ ptr; })
+
#define OPT_NAME (longopt == 2 ? stk_printf("positional arg #%d", opt_positional_count) : (longopt == 1 ? stk_printf("--%s", opt->name) : stk_printf("-%c", item->letter)))
static void opt_parse_value(struct opt_precomputed_option * opt, char * value, int longopt) {
struct opt_item * item = opt->item;
+
switch (item->cls) {
case OPT_CL_BOOL:
if (!value || !strcasecmp(value, "y") || !strcasecmp(value, "yes") || !strcasecmp(value, "true") || !strcasecmp(value, "1"))
switch (item->type) {
case CT_INT:
if (!value)
- *((int*)item->ptr) = 0;
+ *OPT_PTR(int) = 0;
else
- e = cf_parse_int(value, item->ptr);
+ e = cf_parse_int(value, OPT_PTR(int));
if (e)
opt_failure("Integer value parsing failed for %s: %s", OPT_NAME, e);
break;
case CT_U64:
if (!value)
- *((u64*)item->ptr) = 0;
+ *OPT_PTR(u64) = 0;
else
- e = cf_parse_u64(value, item->ptr);
+ e = cf_parse_u64(value, OPT_PTR(u64));
if (e)
opt_failure("Unsigned 64-bit value parsing failed for %s: %s", OPT_NAME, e);
break;
case CT_DOUBLE:
if (!value)
- *((double*)item->ptr) = NAN;
+ *OPT_PTR(double) = NAN;
else
- e = cf_parse_double(value, item->ptr);
+ e = cf_parse_double(value, OPT_PTR(double));
if (e)
opt_failure("Double value parsing failed for %s: %s", OPT_NAME, e);
break;
case CT_IP:
if (!value)
- e = cf_parse_ip("0.0.0.0", item->ptr);
+ e = cf_parse_ip("0.0.0.0", OPT_PTR(u32));
else
- e = cf_parse_ip(value, item->ptr);
+ e = cf_parse_ip(value, OPT_PTR(u32));
if (e)
opt_failure("IP parsing failed for %s: %s", OPT_NAME, e);
break;
case CT_STRING:
if (!value)
- item->ptr = NULL;
+ *OPT_PTR(const char *) = NULL;
else
- *((const char **) (item->ptr)) = xstrdup(value);
+ *OPT_PTR(const char *) = xstrdup(value);
break;
default:
ASSERT(0);
case OPT_CL_USER:
{
char * e = NULL;
- e = item->u.utype->parser(value, item->ptr);
+ e = item->u.utype->parser(value, OPT_PTR(void*));
if (e)
opt_failure("User defined type value parsing failed for %s: %s", OPT_NAME, e);
break;
static int sugar = 0;
static int verbose = 1;
static int with_gas = 0;
-static int black_magic = 0;
+static clist black_magic;
static int pray = 0;
static int water_amount = 0;
static char * first_tea = NULL;
"\t\tOnly integer values allowed."),
OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
OPT_INC('q', "quiet", verbose, OPT_NEGATIVE, "\tQuiet (the more -q, the more quiet)"),
- OPT_INT('b', "black-magic", black_magic, 0, "<strength>\tUse black magic to make the tea extraordinary delicious"),
+ OPT_INT('b', "black-magic", black_magic, OPT_MULTIPLE, "<strength>\tUse black magic to make the tea extraordinary delicious.\n\t\tMay be specified more than once to describe the amounts of black magic to be invoked in each step of tea boiling."),
OPT_BOOL('p', "pray", pray, OPT_SINGLE, "\tPray before boiling"),
OPT_STRING(OPT_POSITIONAL(1), NULL, first_tea, OPT_REQUIRED | OPT_NO_HELP, ""),
OPT_CALL(OPT_POSITIONAL_TAIL, NULL, add_tea, &tea_list, OPT_NO_HELP, ""),
}
};
+struct intnode {
+ cnode n;
+ int x;
+};
+
int main(int argc UNUSED, char ** argv)
{
+ clist_init(&black_magic);
opt_parse(&help, argv+1);
printf("English style: %s|", english ? "yes" : "no");
printf("Chosen teapot: %s|", teapot_type_str[set]);
printf("Temperature: %d%s|", temperature.value, temp_scale_str[temperature.scale]);
printf("Verbosity: %d|", verbose);
- if (black_magic)
- printf("Black magic: %d|", black_magic);
+ CLIST_FOR_EACH(struct intnode *, n, black_magic)
+ printf("Black magic: %d|", n->x);
printf("Prayer: %s|", pray ? "yes" : "no");
printf("Water amount: %d|", water_amount);
printf("Gas: %s|", with_gas ? "yes" : "no");
#define OPT_HELP_OPTION OPT_CALL(0, "help", opt_show_help_internal, NULL, OPT_NO_VALUE, "Show this help")
#define OPT_HELP(line) { .help = line, .cls = OPT_CL_HELP }
#define OPT_BOOL(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_BOOL, .type = CT_INT }
-#define OPT_STRING(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, char **), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_STRING }
-#define OPT_U64(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, u64 *), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_U64 }
-#define OPT_INT(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, int *), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_INT }
-#define OPT_DOUBLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, double *), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_DOUBLE }
-#define OPT_IP(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, u32 *), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_IP }
-#define OPT_SWITCH(shortopt, longopt, target, val, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, int *), .help = desc, .flags = fl, .cls = OPT_CL_SWITCH, .type = CT_LOOKUP, .u.value = val }
+#define OPT_STRING(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_STRING }
+#define OPT_U64(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_U64 }
+#define OPT_INT(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_INT }
+#define OPT_DOUBLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_DOUBLE }
+#define OPT_IP(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_IP }
+#define OPT_SWITCH(shortopt, longopt, target, val, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_SWITCH, .type = CT_LOOKUP, .u.value = val }
#define OPT_CALL(shortopt, longopt, fn, data, fl, desc) { .letter = shortopt, .name = longopt, .ptr = data, .help = desc, .u.call = fn, .flags = fl, .cls = OPT_CL_CALL, .type = CT_USER }
#define OPT_USER(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.utype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_USER, .type = CT_USER }
#define OPT_INC(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .flags = fl, .help = desc, .cls = OPT_CL_INC, .type = CT_INT }
#define OPT_MAYBE_VALUE 0x8 /** Argument may have a value **/
#define OPT_VALUE_FLAGS (OPT_REQUIRED_VALUE | OPT_NO_VALUE | OPT_MAYBE_VALUE)
#define OPT_NEGATIVE 0x10 /** Reversing the effect of OPT_INC or saving @false into OPT_BOOL **/
-#define OPT_SINGLE 0x20 /** Argument must appear at most once **/
-#define OPT_NO_HELP 0x40 /** Omit this line from help **/
-#define OPT_LAST_ARG 0x80 /** Stop processing argv after this line **/
+#define OPT_NO_HELP 0x20 /** Omit this line from help **/
+#define OPT_LAST_ARG 0x40 /** Stop processing argv after this line **/
+#define OPT_SINGLE 0x100 /** Argument must appear at most once **/
+#define OPT_MULTIPLE 0x200 /** Argument may appear any time; will save all the values into a simple list **/
+
/***
* Value flags defaults