]> mj.ucw.cz Git - libucw.git/commitdiff
Opt: Config getopt and hooks
authorJan 'Moskyt' Matejka <mq@ucw.cz>
Thu, 20 Jun 2013 15:14:50 +0000 (17:14 +0200)
committerJan 'Moskyt' Matejka <mq@ucw.cz>
Thu, 20 Jun 2013 15:14:50 +0000 (17:14 +0200)
Not tested yet, unfinished

ucw/Makefile
ucw/conf-getopt.c
ucw/conf-internal.h
ucw/ff-varint.c
ucw/opt.c
ucw/opt.h
ucw/varint.c

index d19182736404f3e564b1f051b99cef24d203ae16..11aabfa9a2eb1b3a7257571984cce5407f843c3c 100644 (file)
@@ -116,8 +116,8 @@ endif
 $(o)/ucw/ipaccess-test: $(o)/ucw/ipaccess-test.o $(LIBUCW)
 $(o)/ucw/trie-test: $(o)/ucw/trie-test.o $(LIBUCW)
 
-TESTS+=$(addprefix $(o)/ucw/,varint.test regex.test unicode.test hash-test.test mempool.test stkstring.test \
-    slists.test bbuf.test kmp-test.test getopt.test ff-unicode.test ff-varint.test eltpool.test \
+TESTS+=$(addprefix $(o)/ucw/,regex.test unicode.test hash-test.test mempool.test stkstring.test \
+    slists.test bbuf.test kmp-test.test getopt.test ff-unicode.test eltpool.test \
     fb-socket.test trie-test.test string.test sha1.test asort-test.test binheap-test.test \
     redblack-test.test fb-file.test fb-grow.test fb-pool.test fb-atomic.test \
     fb-limfd.test fb-temp.test fb-mem.test fb-buffer.test fb-mmap.test fb-multi.test url.test strtonum-test.test \
index 8e321cc00fdf55f661a54b703b436b837ab2d531..bbb81e1119e9cfe66c646897e355400d36247ccf 100644 (file)
@@ -26,8 +26,8 @@ char *cf_def_file = CONFIG_UCW_DEFAULT_CONFIG;
 #endif
 char *cf_env_file = CONFIG_UCW_ENV_VAR_CONFIG;
 
-static void
-load_default(struct cf_context *cc)
+void
+cf_load_default(struct cf_context *cc)
 {
   if (cc->config_loaded++)
     return;
@@ -55,7 +55,7 @@ load_default(struct cf_context *cc)
 static void
 end_of_options(struct cf_context *cc)
 {
-  load_default(cc);
+  cf_load_default(cc);
   if (cc->postpone_commit && cf_close_group())
     die("Loading of configuration failed");
 }
@@ -76,7 +76,7 @@ cf_getopt(int argc, char *const argv[], const char *short_opts, const struct opt
            die("The -S and -C options must precede all other arguments");
          if (res == 'S')
            {
-             load_default(cc);
+             cf_load_default(cc);
              if (cf_set(optarg))
                die("Cannot set %s", optarg);
            }
index 67a96cf5baece5563bf866c68a57d265fcd33467..72ee7ca8b4a9e2e439c303ba33272eff345c4ecd 100644 (file)
@@ -103,4 +103,7 @@ struct cf_item *cf_find_subitem(struct cf_section *sec, const char *name);
 int cf_commit_all(enum cf_commit_mode cm);
 void cf_add_dirty(struct cf_section *sec, void *ptr);
 
+/* conf-getopt.c */
+void cf_load_default(struct cf_context *cc);
+
 #endif
index 453a26f788c8a0a1bed6d59610dfa13c68a8b025..d446f2431845dbd3e48ba4466595f31b6c2c1c45 100644 (file)
@@ -78,14 +78,14 @@ int main(int argc, char **argv)
                                if (btell(b))
                                        putchar(' ');
                                r = bget_varint_slow(b, ~0LLU);
-                               printf("%lx", r);
+                               printf("%llx", r);
                        }
                        putchar('\n');
                        break;
 
                case FUNC_BPUT_VARINT:
                        i = 0;
-                       while (scanf("%lx", &r) == 1)
+                       while (scanf("%llx", &r) == 1)
                                bput_varint_slow(b, r);
                        fbgrow_rewind(b);
                        while (bpeekc(b) >= 0) {
index 38688c8a19e49381f3b8e76fe7cb765540d72dea..aa59a2eca012fc7b278816fe9ebb130668bfe3f6 100644 (file)
--- a/ucw/opt.c
+++ b/ucw/opt.c
 #include <ucw/lib.h>
 #include <ucw/opt.h>
 #include <ucw/conf.h>
+#include <ucw/conf-internal.h>
+#include <ucw/fastbuf.h>
 #include <ucw/stkstring.h>
 #include <ucw/strtonum.h>
 
 #include <alloca.h>
 #include <math.h>
 
+int opt_parsed_count = 0;
+int opt_conf_parsed_count = 0;
+
 static void opt_failure(const char * mesg, ...) FORMAT_CHECK(printf,1,2) NONRET;
 static void opt_failure(const char * mesg, ...) {
   va_list args;
@@ -174,7 +179,13 @@ struct opt_precomputed {
     short count;
   } ** opts;
   struct opt_precomputed_option ** shortopt;
+  struct opt_item ** hooks_before_arg;
+  struct opt_item ** hooks_before_value;
+  struct opt_item ** hooks_after_value;
   short opt_count;
+  short hooks_before_arg_count;
+  short hooks_before_value_count;
+  short hooks_after_value_count;
 };
 
 static struct opt_precomputed_option * opt_find_item_shortopt(int chr, struct opt_precomputed * pre) {
@@ -322,6 +333,7 @@ static void opt_parse_value(struct opt_precomputed_option * opt, char * value, i
     default:
       ASSERT(0);
   }
+  opt_parsed_count++;
 }
 #undef OPT_NAME
 
@@ -443,6 +455,7 @@ void opt_parse(const struct opt_section * options, char ** argv) {
   memset(pre, 0, sizeof (*pre));
 
   int count = 0;
+  int hooks = 0;
 
   for (struct opt_item * item = options->opt; ; item++) {
     OPT_TRAVERSE_SECTIONS;
@@ -452,11 +465,20 @@ void opt_parse(const struct opt_section * options, char ** argv) {
       count++;
     if (item->letter > 256)
       opt_positional_max++;
+    if (item->cls == OPT_CL_HOOK)
+      hooks++;
   }
   
   pre->opts = alloca(sizeof(*pre->opts) * count);
   pre->shortopt = alloca(sizeof(*pre->shortopt) * (opt_positional_max + 257));
   memset(pre->shortopt, 0, sizeof(*pre->shortopt) * (opt_positional_max + 257));
+  pre->hooks_before_arg = alloca(sizeof (*pre->hooks_before_arg) * hooks);
+  pre->hooks_before_value = alloca(sizeof (*pre->hooks_before_value) * hooks);
+  pre->hooks_after_value = alloca(sizeof (*pre->hooks_after_value) * hooks);
+  
+  pre->hooks_before_arg_count = 0;
+  pre->hooks_before_value_count = 0;
+  pre->hooks_after_value_count = 0;
   
   pre->opt_count = 0;
 
@@ -473,6 +495,16 @@ void opt_parse(const struct opt_section * options, char ** argv) {
        pre->shortopt[(int) item->letter] = opt;
       OPT_ADD_DEFAULT_ITEM_FLAGS(item, opt->flags);
     }
+    if (item->cls == OPT_CL_HOOK) {
+      if (item->flags & OPT_HOOK_BEFORE_ARG)
+       pre->hooks_before_arg[pre->hooks_before_arg_count++] = item;
+      else if (item->flags & OPT_HOOK_BEFORE_VALUE)
+       pre->hooks_before_value[pre->hooks_before_value_count++] = item;
+      else if (item->flags & OPT_HOOK_AFTER_VALUE)
+       pre->hooks_after_value[pre->hooks_after_value_count++] = item;
+      else
+       ASSERT(0);
+    }
   }
 
   int force_positional = 0;
@@ -512,6 +544,37 @@ void opt_parse(const struct opt_section * options, char ** argv) {
   }
 }
 
+void opt_conf_internal(struct opt_item * opt, const char * value, void * data UNUSED) {
+  if (opt_parsed_count > opt_conf_parsed_count)
+    opt_failure("Config options (-C, -S) must stand before other options.");
+
+  struct cf_context *cc = cf_get_context();
+  switch(opt->letter) {
+    case 'S':
+      cf_load_default(cc);
+      if (cf_set(value))
+       opt_failure("Cannot set %s", value);
+      break;
+    case 'C':
+      if (cf_load(value))
+       opt_failure("Cannot load config file %s", value);
+      break;
+#ifdef CONFIG_UCW_DEBUG
+    case '0':
+      cf_load_default(cc);
+      if (cc->postpone_commit && cf_close_group())
+       opt_failure("Loading of configuration failed");
+      struct fastbuf *b = bfdopen(1, 4096);
+      cf_dump_sections(b);
+      bclose(b);
+      exit(0);
+      break;
+#endif
+  }
+
+  opt_conf_parsed_count++;
+}
+
 #ifdef TEST
 #include <ucw/fastbuf.h>
 
index 122c5177a0f4694c1b5b3346d421d57423ff1b38..401f857ee5767bfd0fdb84c629970ed330943848 100644 (file)
--- a/ucw/opt.h
+++ b/ucw/opt.h
@@ -32,6 +32,7 @@ enum opt_class {
   OPT_CL_USER,   // user defined value
   OPT_CL_SECTION, // subsection
   OPT_CL_HELP,   // help line
+  OPT_CL_HOOK,   // hook
 };
 
 struct opt_section;
@@ -70,6 +71,10 @@ struct opt_section {
  *            parser fails if it matches an OPT_SWITCH with OPT_SINGLE set and also target set.
  *            Target must be of signed integer type; it is set to -1 if no switch appears at the command-line.
  *  OPT_CALL calls the given function with an argument, giving also the opt_item structure and some custom data.
+ *  OPT_HOOK is called at the specified place: before option parsing, before value parsing and after value parsing as specified in @flags;
+ *            OPT_HOOK_BEFORE_ARG gets @opt and @value set to NULL;
+ *            OPT_HOOK_BEFORE_VALUE gets @opt set and @value NULL;
+ *            OPT_HOOK_AFTER_VALUE gets both @opt and @value set.
  *  OPT_USER declares a custom type of value defined by the given @cf_user_type in @ttype
  *  OPT_INC declares an incremental value like -v/--verbose
  *  OPT_SECTION declares a subsection
@@ -89,8 +94,32 @@ struct opt_section {
 #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_SECTION(sec) { .cls = OPT_CL_SECTION, .u.section = &sec }
+#define OPT_HOOK(fn, data, fl) { .cls = OPT_CL_HOOK, .u.call = fn, .flags = OPT_NO_HELP | fl, .ptr = data }
 #define OPT_END { .cls = OPT_CL_END }
 
+/***
+ * UCW Conf options
+ * ~~~~~~~~~~~~~~~~
+ * 
+ * OPT_CONF_OPTIONS declares -C and -S as described in @getopt.h
+ ***/
+
+#ifdef CONFIG_UCW_DEBUG
+#define OPT_CONF_OPTIONS    OPT_CONF_CONFIG, OPT_CONF_SET, OPT_CONF_DUMPCONFIG, OPT_CONF_HOOK
+#else
+#define OPT_CONF_OPTIONS    OPT_CONF_CONFIG, OPT_CONF_SET, OPT_CONF_HOOK
+#endif
+
+#define OPT_CONF_CONFIG            OPT_CALL('C', "config", opt_conf_internal, NULL, OPT_REQUIRED_VALUE, "Override the default configuration file")
+#define OPT_CONF_SET       OPT_CALL('S', "set", opt_conf_internal, NULL, OPT_REQUIRED_VALUE, "Manual setting of a configuration item")
+#define OPT_CONF_DUMPCONFIG OPT_CALL(0, "dumpconfig", opt_conf_internal, NULL, OPT_NO_VALUE, "Dump program configuration")
+#define OPT_CONF_HOOK      OPT_HOOK(opt_conf_hook_internal, NULL, OPT_HOOK_BEFORE_VALUE)
+
+void opt_conf_internal(struct opt_item * opt, const char * value, void * data);
+
+extern int opt_parsed_count;       /** How many opts have been already parsed. **/
+extern int opt_conf_parsed_count;
+
 /***
  * Predefined shortopt arguments
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -122,6 +151,9 @@ struct opt_section {
 #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 **/
+#define OPT_HOOK_BEFORE_ARG    0x1000  /** Call before option parsing **/
+#define OPT_HOOK_BEFORE_VALUE  0x2000  /** Call before value parsing **/
+#define OPT_HOOK_AFTER_VALUE   0x4000  /** Call after value parsing **/
 
 
 /***
index 18debb14867811c6b7c90631f3db08ce906b0716..31c5ed6aea49053d9d660e64b7990a503036c120 100644 (file)
@@ -92,7 +92,7 @@ int main(int argc, char **argv UNUSED)
        byte buf[16] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa };
        u64 u;
 
-       if (scanf("%lx", &u) != 1) {
+       if (scanf("%llx", &u) != 1) {
                fprintf(stderr, "Invalid usage!\n");
                return 1;
        }