]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/doc/conf.txt
hashtable: Documented HASH_TABLE_VARS.
[libucw.git] / ucw / doc / conf.txt
index 3044f5c489d158263a6e3279de1267a43883adea..31698a62b9d6f4fafb8ad78a6c6b1c535844356d 100644 (file)
@@ -13,7 +13,7 @@ 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 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,
+The command line parser has the same interface as unix getopt_long(),
 but handles setting of configuration files and configuration values
 from command line.
 
 but handles setting of configuration files and configuration values
 from command line.
 
@@ -21,6 +21,7 @@ from command line.
   * <<ex_structure,The structure>>
   * <<ex_load,Loading>>
 - <<deep,Getting deeper>>
   * <<ex_structure,The structure>>
   * <<ex_load,Loading>>
 - <<deep,Getting deeper>>
+  * <<conf_multi,Arrays and lists>>
   * <<reload,Reloading configuration>>
   * <<custom_parser,Creating custom parsers>>
   * <<hooks,Hooks>>
   * <<reload,Reloading configuration>>
   * <<custom_parser,Creating custom parsers>>
   * <<hooks,Hooks>>
@@ -29,6 +30,7 @@ from command line.
   * <<conf_macros,Convenience macros>>
   * <<alloc,Memory allocation>>
   * <<journal,Undo journal>>
   * <<conf_macros,Convenience macros>>
   * <<alloc,Memory allocation>>
   * <<journal,Undo journal>>
+  * <<declare,Section declaration>>
   * <<bparser,Parsers for basic types>>
 - <<getopt_h,ucw/getopt.h>>
   * <<conf_load,Safe configuration loading>>
   * <<bparser,Parsers for basic types>>
 - <<getopt_h,ucw/getopt.h>>
   * <<conf_load,Safe configuration loading>>
@@ -84,7 +86,8 @@ The variables are used to store the loaded values. Their initial
 values work as default, 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()
 values work as default, 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.
+is called and it plugs in the whole section to the parser (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.
 
 You can plug in as many configuration sections as you like, from
 various places across your code.
@@ -92,21 +95,23 @@ various places across your code.
 [[ex_load]]
 Loading of the values
 ~~~~~~~~~~~~~~~~~~~~~
 [[ex_load]]
 Loading of the values
 ~~~~~~~~~~~~~~~~~~~~~
-You need to parse the command line arguments and load the
-configuration. You can do it in a similar way to this example.
+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
+configuration files.
 
   #include <ucw/lib.h>
   #include <ucw/conf.h>
   #include <ucw/getopt.h>
 
 
   #include <ucw/lib.h>
   #include <ucw/conf.h>
   #include <ucw/getopt.h>
 
-  static byte short_opts[] = CF_SHORT_OPTS "v";
+  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 struct option long_opts[] = {
     CF_LONG_OPTS
     { "verbose", 0, 0, 'v' },
     { NULL, 0, 0, 0 }
   };
 
-  int verbose;
+  static int verbose;
 
   int main(int argc, char *argv[]) {
     cf_def_file = "default.cf";
 
   int main(int argc, char *argv[]) {
     cf_def_file = "default.cf";
@@ -116,14 +121,15 @@ configuration. You can do it in a similar way to this example.
        case 'v': verbose = 1; break;
        default: fprintf("Unknown option %c\n", opt); return 1;
       }
        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
 
 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.
+add the `-S` and `-C` options for the configuration parser as described
+in <<config:>>. These options are handled internally by @cf_getopt().
 
 
-See documentation of unix getopt_long() function.
+You can rely on the configuration files having been loaded before the
+first of your program's options is parsed.
 
 [[deep]]
 Getting deeper
 
 [[deep]]
 Getting deeper
@@ -132,6 +138,70 @@ 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 uns array[] = { 1, 2, 3, 4, 5 };
++
+  static struct cf_section section = {
+    CF_ITEMS {
+      CF_UNS_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 an array of needed
+  size. You can use the <<def_DARY_LEN,`DARY_LEN`>> macro to find out
+  the number of elements actually loaded.
++
+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 <<clist:>>. You provide description
+  of single node and pointer to the
+  <<clist:struct_clist,`struct clist`>> variable. All the nodes will
+  be created dynamically and put there.
++
+First element of your structure must be <<clist:type_cnode,`cnode`>>.
++
+The first example is list of strings and uses <<clist:simple,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
 ~~~~~~~~~~~~~~~~~~~~~~~
@@ -162,33 +232,30 @@ 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
 
 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 few thinks.
+should know a few things.
 
 The parser needs to support <<journal,journaling>>. To accomplish that,
 you have to use the <<alloc,configuration mempool>> for memory allocation.
 
 The parser needs to support <<journal,journaling>>. To accomplish that,
 you have to use the <<alloc,configuration mempool>> for memory allocation.
-Furthermore, you need to call @cf_journal_block() before you change
-the configuration (eg. before you save the parsed value to the destination
-variable). You can use <<def_CF_JOURNAL_VAR,`CF_JOURNAL_VAR`>> macro
-instead if it is simple variable.
 
 Now, you need a function with the same signature as
 <<type_cf_parser1,`cf_parser1`>>. Parse the first parameter (the
 
 Now, you need a function with the same signature as
 <<type_cf_parser1,`cf_parser1`>>. Parse the first parameter (the
-string), call @cf_journal_block() on the second parameter and store
-the data there. You may want to write a dumper function, with
-signature of <<type_cf_dumper1,`cf_dumper1`>> (needed for debug
-dumps).
-
-// TODO Does the config system support storing of configuration?
+string) and store the data in the second parameter. You may want to
+write a dumper function, with signature of
+<<type_cf_dumper1,`cf_dumper1`>> (needed for debug dumps).
 
 
-Fill in a <<struct_cf_user_type,structure cf_user_type>> and use the
+Fill in a structure <<struct_cf_user_type,cf_user_type>> and use the
 new data type in your configuration description with
 new data type in your configuration description with
-<<def_CF_USER,`CF_USER` macro>>.
+<<def_CF_USER,`CF_USER`>> macro as its @t parameter.
+
+You do not need to call @cf_journal_block() on the variable you store
+the result. It is true you change it, but it was stored to journal
+before your parser function was called.
 
 [[hooks]]
 Hooks
 ~~~~~
 
 
 [[hooks]]
 Hooks
 ~~~~~
 
-The configuration system supports hooks. They are used to initiate the
+The configuration system supports hooks. They are used to initialize the
 configuration (if simple default value of variable is not enough) and
 to check the sanity of loaded data.
 
 configuration (if simple default value of variable is not enough) and
 to check the sanity of loaded data.
 
@@ -201,7 +268,14 @@ 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.
 
 journaling. If you change nothing in the commit hook, you do not need
 to care about the journaling either.
 
-// TODO maybe copier here too? What good is it?
+You may use the return value to inform about errors. Just return the
+error message, or NULL if everything went well.
+
+Another similar function is a copy function. It is very similar to a
+hook and is used when the item is copied and is too complicated to use
+simple memcpy(). Its type is <<type_cf_copier,`cf_copier`>> and is
+specified by the <<def_CF_COPY,`CF_COPY`>> macro. It's return value is
+the same as the one of a hook.
 
 [[conf_h]]
 ucw/conf.h
 
 [[conf_h]]
 ucw/conf.h