]> mj.ucw.cz Git - libucw.git/commitdiff
Opt: OPT_MULTIPLE implemented, no tests yet but seems working
authorJan 'Moskyt' Matejka <mq@ucw.cz>
Mon, 13 May 2013 16:01:46 +0000 (18:01 +0200)
committerJan 'Moskyt' Matejka <mq@ucw.cz>
Mon, 13 May 2013 16:01:46 +0000 (18:01 +0200)
ucw/opt.c
ucw/opt.h

index e311c441e8d2ca0e1a69285c278ab048e688fec9..38688c8a19e49381f3b8e76fe7cb765540d72dea 100644 (file)
--- a/ucw/opt.c
+++ b/ucw/opt.c
@@ -223,9 +223,23 @@ static struct opt_precomputed_option * opt_find_item_longopt(char * str, struct
   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"))
@@ -241,41 +255,41 @@ static void opt_parse_value(struct opt_precomputed_option * opt, char * value, i
        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);
@@ -300,7 +314,7 @@ static void opt_parse_value(struct opt_precomputed_option * opt, char * value, i
     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;
@@ -533,7 +547,7 @@ static int english = 0;
 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;
@@ -618,7 +632,7 @@ static struct opt_section help = {
              "\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, ""),
@@ -629,8 +643,14 @@ static struct opt_section 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");
@@ -640,8 +660,8 @@ int main(int argc UNUSED, char ** argv)
     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");
index 07d546d96821f387bef2eee62927fb68db0a22b5..122c5177a0f4694c1b5b3346d421d57423ff1b38 100644 (file)
--- a/ucw/opt.h
+++ b/ucw/opt.h
@@ -79,12 +79,12 @@ struct opt_section {
 #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 }
@@ -118,9 +118,11 @@ struct opt_section {
 #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