$(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 \
#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;
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");
}
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);
}
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
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) {
#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;
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) {
default:
ASSERT(0);
}
+ opt_parsed_count++;
}
#undef OPT_NAME
memset(pre, 0, sizeof (*pre));
int count = 0;
+ int hooks = 0;
for (struct opt_item * item = options->opt; ; item++) {
OPT_TRAVERSE_SECTIONS;
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;
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;
}
}
+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>
OPT_CL_USER, // user defined value
OPT_CL_SECTION, // subsection
OPT_CL_HELP, // help line
+ OPT_CL_HOOK, // hook
};
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
#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
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#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 **/
/***
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;
}