]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/doc/conf.txt
Released as 6.5.16.
[libucw.git] / ucw / doc / conf.txt
index a1f2aaf24735a156270f3f315235b171573a0476..813a18358365c893b3885fc3fc611b4a0e0d3e3d 100644 (file)
@@ -1,53 +1,53 @@
-Configuration and command line parser
-=====================================
+Configuration parser
+====================
 
 
-Libucw contains a parser for configuration files described in
-<<config:>>.
+Libucw contains a parser for configuration files. The syntax of the
+configuration files is described in <<config:>>, 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 command line parser has the same interface as unix getopt_long(),
-but handles setting of configuration files and configuration values
-from command line.
+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.
 
 - <<example,Example>>
   * <<ex_structure,The structure>>
 
 - <<example,Example>>
   * <<ex_structure,The structure>>
-  * <<ex_load,Loading>>
+  * <<ex_load,Loading configuration>>
 - <<deep,Getting deeper>>
 - <<deep,Getting deeper>>
+  * <<conf_multi,Arrays and lists>>
   * <<reload,Reloading configuration>>
   * <<custom_parser,Creating custom parsers>>
   * <<hooks,Hooks>>
 - <<conf_h,ucw/conf.h>>
   * <<reload,Reloading configuration>>
   * <<custom_parser,Creating custom parsers>>
   * <<hooks,Hooks>>
 - <<conf_h,ucw/conf.h>>
+  * <<conf_ctxt,Configuration contexts>>
+  * <<conf_load,Safe configuration loading>>
   * <<conf_types,Data types>>
   * <<conf_macros,Convenience macros>>
   * <<alloc,Memory allocation>>
   * <<journal,Undo journal>>
   * <<conf_types,Data types>>
   * <<conf_macros,Convenience macros>>
   * <<alloc,Memory allocation>>
   * <<journal,Undo journal>>
+  * <<declare,Section declaration>>
   * <<bparser,Parsers for basic types>>
   * <<bparser,Parsers for basic types>>
-- <<getopt_h,ucw/getopt.h>>
-  * <<conf_load,Safe configuration loading>>
   * <<conf_direct,Direct access>>
   * <<conf_dump,Debug dumping>>
   * <<conf_direct,Direct access>>
   * <<conf_dump,Debug dumping>>
-  * <<conf_journal,Journaling control>>
-  * <<conf_getopt,Loading by cf_getopt()>>
+- <<getopt_h,ucw/getopt.h>>
+  * <<conf_getopt,Loading configuration by cf_getopt()>> (obsolete)
+  * <<getopt_example,Example>> (obsolete)
 
 [[example]]
 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
 
 [[example]]
 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 <<conf_macros,convenience macros>> section to see list of
+at the <<conf_macros,convenience macros>> section to see list of
 supported data types, sections, etc.
 
 [[ex_cfile]]
 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"
 
   HelloWorld {
     Text       "Hello planet"
@@ -81,49 +81,44 @@ it exists.
   }
 
 The variables are used to store the loaded values. Their initial
   }
 
 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()
 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.
+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
 various places across your code.
 
 [[ex_load]]
 
 You can plug in as many configuration sections as you like, from
 various places across your code.
 
 [[ex_load]]
-Loading of the values
+Loading configuration
 ~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~
-You need to parse the command line arguments and load the
-configuration. You can do it in a similar way to this example.
+You can load the configuration explicitly by calling @cf_load().
+That can be convenient when writing a library, but in normal programs,
+you can ask the <<opt:,option parser>> to handle it for you.
 
 
-  #include <ucw/lib.h>
-  #include <ucw/conf.h>
-  #include <ucw/getopt.h>
+A typical example follows, please see the <<opt:conf,interface between
+conf and opt>> for details.
 
 
-  static byte short_opts[] = CF_SHORT_OPTS "v";
-  static struct option long_opts[] = {
-    CF_LONG_OPTS
-    { "verbose", 0, 0, 'v' },
-    { NULL, 0, 0, 0 }
+  #include <ucw/lib.h>
+  #include <ucw/opt.h>
+  
+  static struct opt_section options = {
+    OPT_ITEMS {
+      // More options can be specified here
+      OPT_HELP("Configuration options:"),
+      OPT_CONF_OPTIONS,
+      OPT_END
+    }
   };
   };
-
-  int verbose;
-
-  int main(int argc, char *argv[]) {
+  
+  int main(int argc, char **argv)
+  {
     cf_def_file = "default.cf";
     cf_def_file = "default.cf";
-    int opt;
-    while((opt = cf_getopt(argc, argv, short_opts, long_opts, NULL)) >= 0)
-      switch(opt) {
-       case 'v': verbose = 1; break;
-       default: fprintf("Unknown option %c\n", opt); return 1;
-      }
-
-The `short_opts` and `long_opts` variables describe the command line
-arguments. Notice the `CF_SHORT_OPTS` and `CF_LONG_OPTS` macros. They
-add options for the configuration parser. These options are handled
-internally by @cf_getopt(). It loads the configuration before it starts
-giving you your program's options.
-
-See documentation of unix getopt_long() function.
+    opt_parse(&options, argv+1);
+    // Configuration file is already loaded here
+    return 0;
+  }
 
 [[deep]]
 Getting deeper
 
 [[deep]]
 Getting deeper
@@ -132,6 +127,69 @@ Getting deeper
 Since the configuration system is somehow complicated, this part gives
 you a little overview of what you can find and where.
 
 Since the configuration system is somehow complicated, this part gives
 you a little overview of what you can find and where.
 
+[[conf_multi]]
+Arrays and lists
+~~~~~~~~~~~~~~~~
+
+It is sometime needed to have multiple items of the same type. There
+are three ways to do that:
+
+*Static arrays*::
+  An array with fixed maximum length. You provide
+  the length and already allocated array which is filled with items.
+  The configuration may contain less than the maximum length items.
++
+For example, you can have an static array of five unsigned integers:
++
+  static uint array[] = { 1, 2, 3, 4, 5 };
++
+  static struct cf_section section = {
+    CF_ITEMS {
+      CF_UINT_ARY("array", array, 5),
+      CF_END
+    }
+  };
+
+*Dynamic arrays*::
+  Similar to static array, but you provide pointer
+  to pointer to the given item (eg. if you want dynamic array of
+  integers, you give `**int`). The parser allocates a <<gary:,growing array>>
+  of the required size.
++
+If you want dynamic array of strings, you would use:
++
+  static char *array[];
++
+  static struct cf_section section = {
+    CF_ITEMS {
+      CF_STRING_DYN("array", &array, CF_ANY_NUM),
+      CF_END
+    }
+  };
+
+*Lists*::
+  Linked lists based on <<lists:clists,clists>>. You provide description
+  of single node and pointer to the
+  <<lists:struct_clist,`struct clist`>> variable. All the nodes will
+  be created dynamically and put there.
++
+First element of your structure must be <<lists:struct_cnode,`cnode`>>.
++
+The first example is list of strings and uses <<lists:simple_lists,simple
+lists>>:
++
+  static struct clist list;
++
+  static struct cf_section section = {
+    CF_ITEMS {
+      CF_LIST("list", &list, &cf_string_list_config),
+      CF_END
+    }
+  };
++
+Another example, describing how to create more complicated list node
+than just a string can be found at the <<def_CF_TYPE,`CF_TYPE`>> macro.
+
 [[reload]]
 Reloading configuration
 ~~~~~~~~~~~~~~~~~~~~~~~
 [[reload]]
 Reloading configuration
 ~~~~~~~~~~~~~~~~~~~~~~~
@@ -145,7 +203,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.
 
 Furthermore, if the loading of a new configuration fails, the current
 configuration is preserved.
 
-All this is done with <<journal,config journaling>>. The load of the
+All this is done with <<journal,config journalling>>. 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
 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
@@ -154,17 +212,20 @@ journal entries are removed and a new one, for the new configuration,
 is added. If it fails, the first one is replayed and the rollback
 entry is removed.
 
 is added. If it fails, the first one is replayed and the rollback
 entry is removed.
 
-See <<cf_reload()>>.
+See @cf_reload().
 
 [[custom_parser]]
 Creating custom parsers
 ~~~~~~~~~~~~~~~~~~~~~~~
 
 If you need to parse some data type the configuration system can't
 
 [[custom_parser]]
 Creating custom parsers
 ~~~~~~~~~~~~~~~~~~~~~~~
 
 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.
+handle, you can write your own <<xtypes:,extended type>>
+and use <<def_CF_XTYPE,`CF_XTYPE`>> macro to declare a new option.
 
 
-The parser needs to support <<journal,journaling>>. To accomplish that,
+There is also an obsolete way to write a custom parser.
+Before you start, you should know a few things.
+
+The parser needs to support <<journal,journalling>>. To accomplish that,
 you have to use the <<alloc,configuration mempool>> for memory allocation.
 
 Now, you need a function with the same signature as
 you have to use the <<alloc,configuration mempool>> for memory allocation.
 
 Now, you need a function with the same signature as
@@ -195,8 +256,8 @@ them in configuration description using <<def_CF_INIT,`CF_INIT`>> and
 
 The hooks should follow similar guidelines as custom parsers (well,
 init hooks do not need to call @cf_journal_block()) to support
 
 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.
 
 You may use the return value to inform about errors. Just return the
 error message, or NULL if everything went well.
@@ -211,8 +272,7 @@ the same as the one of a hook.
 ucw/conf.h
 ----------
 
 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
 
 
 !!ucw/conf.h
 
@@ -221,6 +281,47 @@ ucw/getopt.h
 ------------
 
 This header contains routines for parsing command line arguments and
 ------------
 
 This header contains routines for parsing command line arguments and
-loading the configuration.
+loading the default configuration.
+
+In new programs, please consider using the new <<opt:,option parser>>
+instead. The getopt interface is already considered obsolete and may
+be removed in the future.
 
 !!ucw/getopt.h
 
 !!ucw/getopt.h
+
+Example
+~~~~~~~
+Typically, @cf_getopt() is used as follows: it works like
+the traditional @getopt_long() from the C library, but it also handles
+configuration files.
+
+  #include <ucw/lib.h>
+  #include <ucw/conf.h>
+  #include <ucw/getopt.h>
+
+  static char short_opts[] = CF_SHORT_OPTS "v";
+  static struct option long_opts[] = {
+    CF_LONG_OPTS
+    { "verbose", 0, 0, 'v' },
+    { NULL, 0, 0, 0 }
+  };
+
+  static int verbose;
+
+  int main(int argc, char *argv[]) {
+    cf_def_file = "default.cf";
+    int opt;
+    while((opt = cf_getopt(argc, argv, short_opts, long_opts, NULL)) >= 0)
+      switch(opt) {
+       case 'v': verbose = 1; break;
+       default: fprintf("Unknown option %c\n", opt); return 1;
+      }
+  }
+
+The `short_opts` and `long_opts` variables describe the command line
+arguments. Notice the `CF_SHORT_OPTS` and `CF_LONG_OPTS` macros. They
+add the `-S` and `-C` options for the configuration parser as described
+in <<config:>>. These options are handled internally by @cf_getopt().
+
+You can rely on the configuration files having been loaded before the
+first of your program's options is parsed.