From 9191d29c178f8293c45fd39c8aa479717d2e89a6 Mon Sep 17 00:00:00 2001 From: Jan 'Moskyt' Matejka Date: Thu, 20 Jun 2013 17:14:50 +0200 Subject: [PATCH] Opt: Config getopt and hooks Not tested yet, unfinished --- ucw/Makefile | 4 +-- ucw/conf-getopt.c | 8 +++--- ucw/conf-internal.h | 3 +++ ucw/ff-varint.c | 4 +-- ucw/opt.c | 63 +++++++++++++++++++++++++++++++++++++++++++++ ucw/opt.h | 32 +++++++++++++++++++++++ ucw/varint.c | 2 +- 7 files changed, 107 insertions(+), 9 deletions(-) diff --git a/ucw/Makefile b/ucw/Makefile index d1918273..11aabfa9 100644 --- a/ucw/Makefile +++ b/ucw/Makefile @@ -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 \ diff --git a/ucw/conf-getopt.c b/ucw/conf-getopt.c index 8e321cc0..bbb81e11 100644 --- a/ucw/conf-getopt.c +++ b/ucw/conf-getopt.c @@ -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); } diff --git a/ucw/conf-internal.h b/ucw/conf-internal.h index 67a96cf5..72ee7ca8 100644 --- a/ucw/conf-internal.h +++ b/ucw/conf-internal.h @@ -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 diff --git a/ucw/ff-varint.c b/ucw/ff-varint.c index 453a26f7..d446f243 100644 --- a/ucw/ff-varint.c +++ b/ucw/ff-varint.c @@ -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) { diff --git a/ucw/opt.c b/ucw/opt.c index 38688c8a..aa59a2ec 100644 --- a/ucw/opt.c +++ b/ucw/opt.c @@ -10,12 +10,17 @@ #include #include #include +#include +#include #include #include #include #include +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 diff --git a/ucw/opt.h b/ucw/opt.h index 122c5177..401f857e 100644 --- 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 **/ /*** diff --git a/ucw/varint.c b/ucw/varint.c index 18debb14..31c5ed6a 100644 --- a/ucw/varint.c +++ b/ucw/varint.c @@ -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; } -- 2.39.2