From 5423d3ec7aa3ff3fec105c49f7ec1a122e82561d Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 29 Apr 2012 00:00:00 +0200 Subject: [PATCH] Conf: Split off everything related to cf_getopt() now contains only cf_getopt() and related settings. All high-level configuration functions have been moved to . --- ucw/Makefile | 2 +- ucw/conf-getopt.c | 114 ++++++++++++++++++++++++++++++++++++++++++ ucw/conf-input.c | 111 ++--------------------------------------- ucw/conf-internal.h | 4 +- ucw/conf-intr.c | 6 ++- ucw/conf.h | 98 +++++++++++++++++++++++++++++++++++- ucw/getopt.h | 119 +++----------------------------------------- 7 files changed, 230 insertions(+), 224 deletions(-) create mode 100644 ucw/conf-getopt.c diff --git a/ucw/Makefile b/ucw/Makefile index 62373ade..af6219bf 100644 --- a/ucw/Makefile +++ b/ucw/Makefile @@ -13,7 +13,7 @@ LIBUCW_MODS= \ partmap hashfunc \ slists simple-lists bitsig \ log log-stream log-file log-syslog log-conf tbf \ - conf-context conf-alloc conf-dump conf-input conf-intr conf-journal conf-parse conf-section \ + conf-context conf-alloc conf-dump conf-input conf-intr conf-journal conf-parse conf-section conf-getopt \ ipaccess \ fastbuf ff-binary ff-string ff-printf ff-unicode ff-stkstring \ fb-file fb-mem fb-temp tempfile fb-mmap fb-limfd fb-buffer fb-grow fb-pool fb-atomic fb-param fb-socket \ diff --git a/ucw/conf-getopt.c b/ucw/conf-getopt.c new file mode 100644 index 00000000..507c5102 --- /dev/null +++ b/ucw/conf-getopt.c @@ -0,0 +1,114 @@ +/* + * UCW Library -- Configuration files: getopt wrapper + * + * (c) 2001--2006 Robert Spalek + * (c) 2003--2012 Martin Mares + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. + */ + +#include +#include +#include +#include +#include + +#include + +#ifndef CONFIG_UCW_DEFAULT_CONFIG +#define CONFIG_UCW_DEFAULT_CONFIG NULL +#endif +char *cf_def_file = CONFIG_UCW_DEFAULT_CONFIG; + +#ifndef CONFIG_UCW_ENV_VAR_CONFIG +#define CONFIG_UCW_ENV_VAR_CONFIG NULL +#endif +char *cf_env_file = CONFIG_UCW_ENV_VAR_CONFIG; + +static void +load_default(struct cf_context *cc) +{ + if (cc->config_loaded++) + return; + if (cf_def_file) + { + char *env; + if (cf_env_file && (env = getenv(cf_env_file))) + { + if (cf_load(env)) + die("Cannot load config file %s", env); + } + else if (cf_load(cf_def_file)) + die("Cannot load default config %s", cf_def_file); + } + else + { + // We need to create an empty pool and initialize all configuration items + struct cf_journal_item *oldj = cf_journal_new_transaction(1); + cf_init_stack(cc); + cf_done_stack(cc); + cf_journal_commit_transaction(1, oldj); + } +} + +static void +final_commit(struct cf_context *cc) +{ + if (cc->postpone_commit) + { + cc->postpone_commit = 0; + if (cf_done_stack(cc)) + die("Cannot commit after the initialization"); + } +} + +int +cf_getopt(int argc, char *const argv[], const char *short_opts, const struct option *long_opts, int *long_index) +{ + struct cf_context *cc = cf_get_context(); + cc->postpone_commit = 1; + + while (1) + { + int res = getopt_long(argc, argv, short_opts, long_opts, long_index); + if (res == 'S' || res == 'C' || res == 0x64436667) + { + if (cc->other_options) + die("The -S and -C options must precede all other arguments"); + if (res == 'S') + { + load_default(cc); + if (cf_set(optarg)) + die("Cannot set %s", optarg); + } + else if (res == 'C') + { + if (cf_load(optarg)) + die("Cannot load config file %s", optarg); + } +#ifdef CONFIG_UCW_DEBUG + else + { /* --dumpconfig */ + load_default(cc); + final_commit(cc); + struct fastbuf *b = bfdopen(1, 4096); + cf_dump_sections(b); + bclose(b); + exit(0); + } +#endif + } + else + { + /* unhandled option or end of options */ + if (res != ':' && res != '?') + { + load_default(cc); + final_commit(cc); + } + cc->other_options++; + return res; + } + } +} diff --git a/ucw/conf-input.c b/ucw/conf-input.c index f8ed1ff0..5a782bf0 100644 --- a/ucw/conf-input.c +++ b/ucw/conf-input.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -292,18 +291,6 @@ error: return "included from here"; } -static int -done_stack(struct cf_context *cc) -{ - if (cf_check_stack(cc)) - return 1; - if (cf_commit_all(cc->postpone_commit ? CF_NO_COMMIT : cc->everything_committed ? CF_COMMIT : CF_COMMIT_ALL)) - return 1; - if (!cc->postpone_commit) - cc->everything_committed = 1; - return 0; -} - static int load_file(struct cf_context *cc, const char *file) { @@ -315,7 +302,7 @@ load_file(struct cf_context *cc, const char *file) } char *err_msg = parse_fastbuf(cc, file, fb, 0); bclose(fb); - return !!err_msg || done_stack(cc); + return !!err_msg || cf_done_stack(cc); } static int @@ -325,7 +312,7 @@ load_string(struct cf_context *cc, const char *string) struct fastbuf fb; fbbuf_init_read(&fb, (byte *)string, strlen(string), 0); char *msg = parse_fastbuf(cc, NULL, &fb, 0); - return !!msg || done_stack(cc); + return !!msg || cf_done_stack(cc); } /* Safe loading and reloading */ @@ -381,7 +368,7 @@ cf_reload(const char *file) cc->postpone_commit = 0; if (!err) - err |= done_stack(cc); + err |= cf_done_stack(cc); if (!err) { cf_journal_delete(); @@ -404,7 +391,7 @@ cf_load(const char *file) if (!err) { cf_journal_commit_transaction(1, oldj); cf_remember_entry(cc, CE_FILE, file); - cc->def_loaded = 1; + cc->config_loaded = 1; } else cf_journal_rollback_transaction(1, oldj); return err; @@ -423,93 +410,3 @@ cf_set(const char *string) cf_journal_rollback_transaction(0, oldj); return err; } - -/* Command-line parser */ - -#ifndef CONFIG_UCW_DEFAULT_CONFIG -#define CONFIG_UCW_DEFAULT_CONFIG NULL -#endif -char *cf_def_file = CONFIG_UCW_DEFAULT_CONFIG; - -#ifndef CONFIG_UCW_ENV_VAR_CONFIG -#define CONFIG_UCW_ENV_VAR_CONFIG NULL -#endif -char *cf_env_file = CONFIG_UCW_ENV_VAR_CONFIG; - -static void -load_default(struct cf_context *cc) -{ - if (cc->def_loaded++) - return; - if (cf_def_file) - { - char *env; - if (cf_env_file && (env = getenv(cf_env_file))) - { - if (cf_load(env)) - die("Cannot load config file %s", env); - } - else if (cf_load(cf_def_file)) - die("Cannot load default config %s", cf_def_file); - } - else - { - // We need to create an empty pool and initialize all configuration items - struct cf_journal_item *oldj = cf_journal_new_transaction(1); - cf_init_stack(cc); - done_stack(cc); - cf_journal_commit_transaction(1, oldj); - } -} - -static void -final_commit(struct cf_context *cc) -{ - if (cc->postpone_commit) { - cc->postpone_commit = 0; - if (done_stack(cc)) - die("Cannot commit after the initialization"); - } -} - -int -cf_getopt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index) -{ - struct cf_context *cc = cf_get_context(); - cc->postpone_commit = 1; - - while (1) { - int res = getopt_long (argc, argv, short_opts, long_opts, long_index); - if (res == 'S' || res == 'C' || res == 0x64436667) - { - if (cc->other_options) - die("The -S and -C options must precede all other arguments"); - if (res == 'S') { - load_default(cc); - if (cf_set(optarg)) - die("Cannot set %s", optarg); - } else if (res == 'C') { - if (cf_load(optarg)) - die("Cannot load config file %s", optarg); - } -#ifdef CONFIG_UCW_DEBUG - else { /* --dumpconfig */ - load_default(cc); - final_commit(cc); - struct fastbuf *b = bfdopen(1, 4096); - cf_dump_sections(b); - bclose(b); - exit(0); - } -#endif - } else { - /* unhandled option or end of options */ - if (res != ':' && res != '?') { - load_default(cc); - final_commit(cc); - } - cc->other_options++; - return res; - } - } -} diff --git a/ucw/conf-internal.h b/ucw/conf-internal.h index bab53837..ee6d08d4 100644 --- a/ucw/conf-internal.h +++ b/ucw/conf-internal.h @@ -42,7 +42,7 @@ struct dirty_section { struct cf_context { struct mempool *pool; int is_active; - int def_loaded; + int config_loaded; // at least one config file was loaded struct cf_parser_state *parser; uns everything_committed; // after the 1st load, this flag is set on uns postpone_commit; // used internally by cf_getopt() @@ -85,7 +85,7 @@ extern char *cf_type_names[]; uns cf_type_size(enum cf_type type, struct cf_user_type *utype); char *cf_interpret_line(struct cf_context *cc, char *name, enum cf_operation op, int number, char **pars); void cf_init_stack(struct cf_context *cc); -int cf_check_stack(struct cf_context *cc); +int cf_done_stack(struct cf_context *cc); /* conf-journal.c */ void cf_journal_swap(void); diff --git a/ucw/conf-intr.c b/ucw/conf-intr.c index f4226510..0b5d5407 100644 --- a/ucw/conf-intr.c +++ b/ucw/conf-intr.c @@ -652,11 +652,15 @@ cf_init_stack(struct cf_context *cc) } int -cf_check_stack(struct cf_context *cc) +cf_done_stack(struct cf_context *cc) { if (cc->stack_level > 0) { msg(L_ERROR, "Unterminated block"); return 1; } + if (cf_commit_all(cc->postpone_commit ? CF_NO_COMMIT : cc->everything_committed ? CF_COMMIT : CF_COMMIT_ALL)) + return 1; + if (!cc->postpone_commit) + cc->everything_committed = 1; return 0; } diff --git a/ucw/conf.h b/ucw/conf.h index 07d83e7b..bef4553e 100644 --- a/ucw/conf.h +++ b/ucw/conf.h @@ -49,6 +49,22 @@ void cf_free_context(struct cf_context *cc); **/ struct cf_context *cf_switch_context(struct cf_context *cc); +/*** + * [[conf_load]] + * Safe configuration loading + * ~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * These functions can be used to to safely load or reload configuration. + */ + +int cf_reload(const char *file); /** Reload configuration from @file, replace the old one. **/ +int cf_load(const char *file); /** Load configuration from @file. If @file is NULL, reload all loaded configuration files. **/ +/** + * Parse some part of configuration passed in @string. + * The syntax is the same as in the <>. + **/ +int cf_set(const char *string); + /*** === Data types [[conf_types]] ***/ enum cf_class { /** Class of the configuration item. **/ @@ -364,7 +380,11 @@ char *cf_printf(const char *fmt, ...) FORMAT_CHECK(printf,1,2); /** printf() int * Undo journal * ~~~~~~~~~~~~ * - * For error recovery when <>. + * The configuration system uses journaling to safely reload + * configuration. It begins a transaction and tries to load the + * configuration. If it fails, it restores the original state. + * + * The behaviour of journal is described in <>. ***/ /** * By default, the configuration mechanism remembers all changes in a journal, @@ -382,6 +402,31 @@ void cf_set_journalling(int enable); void cf_journal_block(void *ptr, uns len); #define CF_JOURNAL_VAR(var) cf_journal_block(&(var), sizeof(var)) // Store single value into journal. +struct cf_journal_item; /** Opaque identifier of the journal state. **/ +/** + * Starts a new transaction. It returns the current state so you can + * get back to it. The @new_pool parameter tells if a new memory pool + * should be created and used from now. + **/ +struct cf_journal_item *cf_journal_new_transaction(uns new_pool); +/** + * Marks current state as a complete transaction. The @new_pool + * parameter tells if the transaction was created with new memory pool + * (the parameter must be the same as the one with + * @cf_journal_new_transaction() was called with). The @oldj parameter + * is the journal state returned from last + * @cf_journal_new_transaction() call. + **/ +void cf_journal_commit_transaction(uns new_pool, struct cf_journal_item *oldj); +/** + * Returns to an old journal state, reverting anything the current + * transaction did. The @new_pool parameter must be the same as the + * one you used when you created the transaction. The @oldj parameter + * is the journal state you got from @cf_journal_new_transaction() -- + * it is the state to return to. + **/ +void cf_journal_rollback_transaction(uns new_pool, struct cf_journal_item *oldj); + /*** * [[declare]] * Section declaration @@ -421,4 +466,55 @@ char *cf_parse_u64(const char *str, u64 *ptr); /** Parser for 64 unsigned integ char *cf_parse_double(const char *str, double *ptr); /** Parser for doubles. **/ char *cf_parse_ip(const char *p, u32 *varp); /** Parser for IP addresses. **/ +/*** + * [[conf_direct]] + * Direct access + * ~~~~~~~~~~~~~ + * + * Direct access to configuration items. + * You probably should not need this. + ***/ + +/** + * List of operations used on items. + * This macro is used to generate internal source code, + * but you may be interested in the list of operations it creates. + * + * Each operation corresponds to the same-named operation + * described in <>. + **/ +#define CF_OPERATIONS T(CLOSE) T(SET) T(CLEAR) T(ALL) \ + T(APPEND) T(PREPEND) T(REMOVE) T(EDIT) T(AFTER) T(BEFORE) T(COPY) T(RESET) + /* Closing brace finishes previous block. + * Basic attributes (static, dynamic, parsed) can be used with SET. + * Dynamic arrays can be used with SET, APPEND, PREPEND. + * Sections can be used with SET. + * Lists can be used with everything. */ +#define T(x) OP_##x, +enum cf_operation { CF_OPERATIONS }; /** Allowed operations on items. See <> for list (they have an `OP_` prefix -- it means you use `OP_SET` instead of just `SET`). **/ +#undef T + +/** + * Searches for a configuration item called @name. + * If it is found, it is copied into @item and NULL is returned. + * Otherwise, an error is returned and @item is zeroed. + **/ +char *cf_find_item(const char *name, struct cf_item *item); +/** + * Performs a single operation on a given item. + **/ +char *cf_modify_item(struct cf_item *item, enum cf_operation op, int number, char **pars); + +/*** + * [[conf_dump]] + * Debug dumping + * ~~~~~~~~~~~~~ + ***/ + +struct fastbuf; +/** + * Take everything and write it into @fb. + **/ +void cf_dump_sections(struct fastbuf *fb); + #endif diff --git a/ucw/getopt.h b/ucw/getopt.h index 6263d47f..68d10633 100644 --- a/ucw/getopt.h +++ b/ucw/getopt.h @@ -2,7 +2,7 @@ * UCW Library -- Parsing of configuration and command-line options * * (c) 2001--2006 Robert Spalek - * (c) 2003--2006 Martin Mares + * (c) 2003--2012 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -17,15 +17,11 @@ #include #endif -void reset_getopt(void); /** If you want to start parsing of the arguments from the first one again. **/ - /*** - * [[conf_load]] - * Safe configuration loading - * ~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * These functions can be used to to safely load or reload configuration. - */ + * [[conf_getopt]] + * Loading by @cf_getopt() + * ~~~~~~~~~~~~~~~~~~~~~~~ + ***/ /** * The default config (as set by `CONFIG_UCW_DEFAULT_CONFIG`) or NULL if already loaded. @@ -37,109 +33,6 @@ extern char *cf_def_file; * Defaults to `CONFIG_UCW_ENV_VAR_CONFIG`. **/ extern char *cf_env_file; -int cf_reload(const char *file); /** Reload configuration from @file, replace the old one. **/ -int cf_load(const char *file); /** Load configuration from @file. If @file is NULL, reload all loaded configuration files. **/ -/** - * Parse some part of configuration passed in @string. - * The syntax is the same as in the <>. - **/ -int cf_set(const char *string); - -/*** - * [[conf_direct]] - * Direct access - * ~~~~~~~~~~~~~ - * - * Direct access to configuration items. - * You probably should not need this. - ***/ - -/** - * List of operations used on items. - * This macro is used to generate internal source code, - * but you may be interested in the list of operations it creates. - * - * Each operation corresponds to the same-named operation - * described in <>. - **/ -#define CF_OPERATIONS T(CLOSE) T(SET) T(CLEAR) T(ALL) \ - T(APPEND) T(PREPEND) T(REMOVE) T(EDIT) T(AFTER) T(BEFORE) T(COPY) T(RESET) - /* Closing brace finishes previous block. - * Basic attributes (static, dynamic, parsed) can be used with SET. - * Dynamic arrays can be used with SET, APPEND, PREPEND. - * Sections can be used with SET. - * Lists can be used with everything. */ -#define T(x) OP_##x, -enum cf_operation { CF_OPERATIONS }; /** Allowed operations on items. See <> for list (they have an `OP_` prefix -- it means you use `OP_SET` instead of just `SET`). **/ -#undef T - -struct cf_item; -/** - * Searches for a configuration item called @name. - * If it is found, it is copied into @item and NULL is returned. - * Otherwise, an error is returned and @item is zeroed. - **/ -char *cf_find_item(const char *name, struct cf_item *item); -/** - * Performs a single operation on a given item. - **/ -char *cf_modify_item(struct cf_item *item, enum cf_operation op, int number, char **pars); - -/*** - * [[conf_dump]] - * Debug dumping - * ~~~~~~~~~~~~~ - ***/ - -struct fastbuf; -/** - * Take everything and write it into @fb. - **/ -void cf_dump_sections(struct fastbuf *fb); - -/*** - * [[conf_journal]] - * Journaling control - * ~~~~~~~~~~~~~~~~~~ - * - * The configuration system uses journaling to safely reload - * configuration. It begins a transaction and tries to load the - * configuration. If it fails, it restores the original state. - * - * The behaviour of journal is described in <>. - ***/ - -struct cf_journal_item; /** Opaque identifier of the journal state. **/ -/** - * Starts a new transaction. It returns the current state so you can - * get back to it. The @new_pool parameter tells if a new memory pool - * should be created and used from now. - **/ -struct cf_journal_item *cf_journal_new_transaction(uns new_pool); -/** - * Marks current state as a complete transaction. The @new_pool - * parameter tells if the transaction was created with new memory pool - * (the parameter must be the same as the one with - * @cf_journal_new_transaction() was called with). The @oldj parameter - * is the journal state returned from last - * @cf_journal_new_transaction() call. - **/ -void cf_journal_commit_transaction(uns new_pool, struct cf_journal_item *oldj); -/** - * Returns to an old journal state, reverting anything the current - * transaction did. The @new_pool parameter must be the same as the - * one you used when you created the transaction. The @oldj parameter - * is the journal state you got from @cf_journal_new_transaction() -- - * it is the state to return to. - **/ -void cf_journal_rollback_transaction(uns new_pool, struct cf_journal_item *oldj); - -/*** - * [[conf_getopt]] - * Loading by @cf_getopt() - * ~~~~~~~~~~~~~~~~~~~~~~~ - ***/ - /** * Short options for loading configuration by @cf_getopt(). * Prepend to your own options. @@ -189,4 +82,6 @@ void cf_journal_rollback_transaction(uns new_pool, struct cf_journal_item *oldj) **/ int cf_getopt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index); +void reset_getopt(void); /** If you want to start parsing of the arguments from the first one again. **/ + #endif -- 2.39.2