struct opt_precomputed {
struct opt_precomputed_option {
+ struct opt_precomputed *pre;
struct opt_item * item;
const char * name;
short flags;
struct opt_precomputed_option * candidate = NULL;
for (int i=0; i<pre->opt_count; i++) {
+ if (!pre->opts[i]->name)
+ continue;
if (!strncmp(pre->opts[i]->name, str, len)) {
if (strlen(pre->opts[i]->name) == len) {
if (pre->opts[i]->count++ && (pre->opts[i]->flags & OPT_SINGLE))
#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;
+ struct opt_precomputed * pre = opt->pre;
+ for (int i=0;i<pre->hooks_before_value_count;i++)
+ pre->hooks_before_value[i]->u.call(item, value, pre->hooks_before_value[i]->ptr);
switch (item->cls) {
case OPT_CL_BOOL:
ASSERT(0);
}
opt_parsed_count++;
+
+ for (int i=0;i<pre->hooks_after_value_count;i++)
+ pre->hooks_after_value[i]->u.call(item, value, pre->hooks_after_value[i]->ptr);
}
#undef OPT_NAME
OPT_TRAVERSE_SECTIONS;
if (item->letter || item->name) {
struct opt_precomputed_option * opt = xmalloc(sizeof(*opt));
+ opt->pre = pre;
opt->item = item;
opt->flags = item->flags;
opt->count = 0;
int force_positional = 0;
for (int i=0;argv[i];i++) {
+ for (int j=0;j<pre->hooks_before_arg_count;j++)
+ pre->hooks_before_arg[j]->u.call(NULL, NULL, pre->hooks_before_arg[j]->ptr);
if (argv[i][0] != '-' || force_positional) {
opt_positional(argv[i], pre);
}
}
}
-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.");
+static void opt_conf_end_of_options(struct cf_context *cc) {
+ cf_load_default(cc);
+ if (cc->postpone_commit && cf_close_group())
+ opt_failure("Loading of configuration failed");
+}
+void opt_conf_internal(struct opt_item * opt, const char * value, void * data UNUSED) {
struct cf_context *cc = cf_get_context();
- switch(opt->letter) {
+ switch (opt->letter) {
case 'S':
cf_load_default(cc);
if (cf_set(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");
+ opt_conf_end_of_options(cc);
struct fastbuf *b = bfdopen(1, 4096);
cf_dump_sections(b);
bclose(b);
opt_conf_parsed_count++;
}
+void opt_conf_hook_internal(struct opt_item * opt, const char * value UNUSED, void * data UNUSED) {
+ static enum {
+ OPT_CONF_HOOK_BEGIN,
+ OPT_CONF_HOOK_CONFIG,
+ OPT_CONF_HOOK_OTHERS
+ } state = OPT_CONF_HOOK_BEGIN;
+
+ int confopt = 0;
+
+ if (opt->letter == 'S' || opt->letter == 'C' || (opt->name && !strcmp(opt->name, "dumpconfig")))
+ confopt = 1;
+
+ switch (state) {
+ case OPT_CONF_HOOK_BEGIN:
+ if (confopt)
+ state = OPT_CONF_HOOK_CONFIG;
+ else {
+ opt_conf_end_of_options(cf_get_context());
+ state = OPT_CONF_HOOK_OTHERS;
+ }
+ break;
+ case OPT_CONF_HOOK_CONFIG:
+ if (!confopt) {
+ opt_conf_end_of_options(cf_get_context());
+ state = OPT_CONF_HOOK_OTHERS;
+ }
+ break;
+ case OPT_CONF_HOOK_OTHERS:
+ if (confopt)
+ opt_failure("Config options (-C, -S) must stand before other options.");
+ break;
+ default:
+ ASSERT(0);
+ }
+}
+
#ifdef TEST
#include <ucw/fastbuf.h>
static char * teapot_type_str[] = { "standard", "exclusive", "glass", "hands" };
+static int show_hooks = 0;
static int english = 0;
static int sugar = 0;
static int verbose = 1;
.dumper = (cf_dumper1*) teapot_temperature_dumper
};
+static void opt_test_hook(struct opt_item * opt, const char * value, void * data) {
+ if (!show_hooks)
+ return;
+ if (opt)
+ printf("[HOOK-%s:%c/%s=%s] ", (char *) data, opt->letter, opt->name, value);
+ else
+ printf("[HOOK-%s] ", (char *) data);
+}
+
static struct opt_section water_options = {
OPT_ITEMS {
OPT_INT('w', "water", water_amount, OPT_REQUIRED | OPT_REQUIRED_VALUE, "<volume>\tAmount of water (in mls; required)"),
OPT_HELP(""),
OPT_HELP("Water options:"),
OPT_SECTION(water_options),
+ OPT_HOOK(opt_test_hook, "prearg", OPT_HOOK_BEFORE_ARG),
+ OPT_HOOK(opt_test_hook, "preval", OPT_HOOK_BEFORE_VALUE),
+ OPT_HOOK(opt_test_hook, "postval", OPT_HOOK_AFTER_VALUE),
+ OPT_BOOL('H', "show-hooks", show_hooks, 0, "Demonstrate the hooks."),
+ OPT_CONF_OPTIONS,
OPT_END
}
};
* 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_BEFORE_VALUE gets both @opt and @value set.
* 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
#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);
+void opt_conf_hook_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;