From 61dec66f0e14df50777adab21cd7d03488452a1e Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 29 Apr 2012 01:32:37 +0200 Subject: [PATCH] Conf: Config documentation --- ucw/conf-context.c | 1 + ucw/conf.h | 31 ++++++++++++++++--------- ucw/doc/conf.txt | 56 +++++++++++++++++++++++----------------------- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/ucw/conf-context.c b/ucw/conf-context.c index 8a7b4a6b..f4929644 100644 --- a/ucw/conf-context.c +++ b/ucw/conf-context.c @@ -32,6 +32,7 @@ cf_new_context(void) void cf_free_context(struct cf_context *cc) { + // FIXME: Roll back all transactions ASSERT(!cc->is_active); ASSERT(cc != &cf_default_context); xfree(cc->parser); diff --git a/ucw/conf.h b/ucw/conf.h index a387f274..fc228eb8 100644 --- a/ucw/conf.h +++ b/ucw/conf.h @@ -24,7 +24,7 @@ struct mempool; * One such context is automatically created during initialization of the library * and you need not care about more, as long as you use a single configuration file. * - * In full generality, you can define as many context as you wish and switch + * In full generality, you can define as many contexts as you wish and switch * between them. Each thread has its own pointer to the current context, which * must not be shared with other threads. ***/ @@ -400,6 +400,9 @@ struct cf_section { /** A section. **/ * reloaded or rolled back, or the context is deleted, it gets lost). * * Memory allocated from within custom parsers should be allocated from the pools. + * + * Please note that the pool is not guaranteed to exist before you call cf_load(), + * cf_set(), or cf_getopt() on the particular context. ***/ struct mempool *cf_get_pool(void); /** Return a pointer to the current configuration pool. **/ void *cf_malloc(uns size); /** Returns @size bytes of memory allocated from the current configuration pool. **/ @@ -412,16 +415,21 @@ char *cf_printf(const char *fmt, ...) FORMAT_CHECK(printf,1,2); /** printf() int * Undo journal * ~~~~~~~~~~~~ * - * 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 configuration system uses a simple journaling mechanism, which makes + * it possible to undo changes to configuration. A typical example is loading + * of configuration by cf_load(): internally, it creates a transaction, applies + * all changes specified by the configuration and if one of them fails, the whole + * journal is replayed to restore the whole original state. Similarly, cf_reload() + * uses the journal to switch between configurations. * - * The behaviour of journal is described in <>. + * In most cases, you need not care about the journal, except when you need + * to change some data from a <>, or if you want to call cf_modify_item() and then + * undo the changes. ***/ /** - * By default, the configuration mechanism remembers all changes in a journal, - * so that the configuration can be rolled back or reloaded. This function - * can be used to disable journalling, which saves some memory. + * This function can be used to disable the whole journalling mechanism. + * It saves some memory, but it makes undoing of configuration changes impossible, + * which breaks for example cf_reload(). **/ void cf_set_journalling(int enable); /** @@ -432,7 +440,7 @@ void cf_set_journalling(int enable); * before them. **/ void cf_journal_block(void *ptr, uns len); -#define CF_JOURNAL_VAR(var) cf_journal_block(&(var), sizeof(var)) // Store single value into journal. +#define CF_JOURNAL_VAR(var) cf_journal_block(&(var), sizeof(var)) // Store a single value into the journal struct cf_journal_item; /** Opaque identifier of the journal state. **/ /** @@ -504,7 +512,8 @@ char *cf_parse_ip(const char *p, u32 *varp); /** Parser for IP addresses. **/ * ~~~~~~~~~~~~~ * * Direct access to configuration items. - * You probably should not need this. + * You probably should not need this, but in your do, you have to handle + * <> yourself. ***/ /** @@ -545,7 +554,7 @@ char *cf_modify_item(struct cf_item *item, enum cf_operation op, int number, cha struct fastbuf; /** - * Take everything and write it into @fb. + * Write the current state of all configuration items into @fb. **/ void cf_dump_sections(struct fastbuf *fb); diff --git a/ucw/doc/conf.txt b/ucw/doc/conf.txt index 31698a62..257447c0 100644 --- a/ucw/doc/conf.txt +++ b/ucw/doc/conf.txt @@ -1,21 +1,22 @@ Configuration and command line parser ===================================== -Libucw contains a parser for configuration files described in -<>. +Libucw contains a parser for configuration files. The syntax of the +configuration files is described in <>, here we explain the +interface of the parser. -The principle is you specify the structure of the configuration file, -the section names, variable names and types and your C variables that -are assigned to them. Then you run the parser and it fills your -variables with the values from the configuration file. +Basically, you write a description of the configuration file syntax, +which maps configuration items to variables of your program. Then +Then you run the parser and it fills your variables with the values +from the configuration file. -It is modular. It means you do not have to write all configuration at -the same place, you just declare the parts you need locally and do not -care about the other parts. +The descriptions are modular. The configuration can be split to sections, +each section declared at a separate place. You can also define your own +data types. -The command line parser has the same interface as unix getopt_long(), -but handles setting of configuration files and configuration values -from command line. +There is also a simple wrapper around getopt_long(), which processes +options related to selection of a configuration file, overriding of +configuration variables and loading of the default configuration. - <> * <> @@ -26,17 +27,17 @@ from command line. * <> * <> - <> + * <> + * <> * <> * <> * <> * <> * <> * <> -- <> - * <> * <> * <> - * <> +- <> * <> [[example]] @@ -44,12 +45,12 @@ Example ------- If you want to just load simple configuration, this is the part you want to read. This simple example should give you the overview. Look -into the <> section to see list of +at the <> section to see list of supported data types, sections, etc. [[ex_cfile]] -Let's say you have configuration file with this content and want to -load it: +Suppose you have configuration file with the following content and you +want to load it: HelloWorld { Text "Hello planet" @@ -83,10 +84,10 @@ it exists. } The variables are used to store the loaded values. Their initial -values work as default, if nothing else is loaded. The hw_config() +values work as defaults, if nothing else is loaded. The hw_config() structure assigns the variables to configuration names. The hw_init() function (because of the `CONSTRUCTOR` macro) is run before main() -is called and it plugs in the whole section to the parser (alternatively, +is called and it tells the parser that the section exists (alternatively, you can call @cf_declare_section() at the start of your main()). You can plug in as many configuration sections as you like, from @@ -97,7 +98,7 @@ Loading of the values ~~~~~~~~~~~~~~~~~~~~~ Suppose you need to parse the command line arguments and load the configuration. Then @cf_getopt() is there for you: it works like -the the traditional @getopt() from the C library, but it also handles +the traditional @getopt_long() from the C library, but it also handles configuration files. #include @@ -215,7 +216,7 @@ this variable, `A` will have a value of `10` after a successful load. Furthermore, if the loading of a new configuration fails, the current configuration is preserved. -All this is done with <>. The load of the +All this is done with <>. The load of the first config creates a journal entry. If you try to load some new configuration, it is partially rolled back to defaults (the rollback happens, but instead of removing the journal entry, another journal @@ -234,7 +235,7 @@ If you need to parse some data type the configuration system can't handle, you can write your own parser. But before you start, you should know a few things. -The parser needs to support <>. To accomplish that, +The parser needs to support <>. To accomplish that, you have to use the <> for memory allocation. Now, you need a function with the same signature as @@ -265,8 +266,8 @@ them in configuration description using <> and The hooks should follow similar guidelines as custom parsers (well, init hooks do not need to call @cf_journal_block()) to support -journaling. If you change nothing in the commit hook, you do not need -to care about the journaling either. +journalling. If you change nothing in the commit hook, you do not need +to care about the journalling either. You may use the return value to inform about errors. Just return the error message, or NULL if everything went well. @@ -281,8 +282,7 @@ the same as the one of a hook. ucw/conf.h ---------- -Use this file if you want define a configuration section, request -loading of some variables or create new item type. +This header file contains the public interface of the configuration module. !!ucw/conf.h @@ -291,6 +291,6 @@ ucw/getopt.h ------------ This header contains routines for parsing command line arguments and -loading the configuration. +loading the default configuration. !!ucw/getopt.h -- 2.39.5