]> mj.ucw.cz Git - libucw.git/blob - ucw/doc/conf.txt
ucw docs: multiple configuration items
[libucw.git] / ucw / doc / conf.txt
1 Configuration and command line parser
2 =====================================
3
4 Libucw contains a parser for configuration files described in
5 <<config:>>.
6
7 The principle is you specify the structure of the configuration file,
8 the section names, variable names and types and your C variables that
9 are assigned to them. Then you run the parser and it fills your
10 variables with the values from the configuration file.
11
12 It is modular. It means you do not have to write all configuration at
13 the same place, you just declare the parts you need locally and do not
14 care about the other parts.
15
16 The command line parser has the same interface as unix getopt_long(),
17 but handles setting of configuration files and configuration values
18 from command line.
19
20 - <<example,Example>>
21   * <<ex_structure,The structure>>
22   * <<ex_load,Loading>>
23 - <<deep,Getting deeper>>
24   * <<conf_multi,Arrays and lists>>
25   * <<reload,Reloading configuration>>
26   * <<custom_parser,Creating custom parsers>>
27   * <<hooks,Hooks>>
28 - <<conf_h,ucw/conf.h>>
29   * <<conf_types,Data types>>
30   * <<conf_macros,Convenience macros>>
31   * <<alloc,Memory allocation>>
32   * <<journal,Undo journal>>
33   * <<bparser,Parsers for basic types>>
34 - <<getopt_h,ucw/getopt.h>>
35   * <<conf_load,Safe configuration loading>>
36   * <<conf_direct,Direct access>>
37   * <<conf_dump,Debug dumping>>
38   * <<conf_journal,Journaling control>>
39   * <<conf_getopt,Loading by cf_getopt()>>
40
41 [[example]]
42 Example
43 -------
44 If you want to just load simple configuration, this is the part you
45 want to read. This simple example should give you the overview. Look
46 into the <<conf_macros,convenience macros>> section to see list of
47 supported data types, sections, etc.
48
49 [[ex_cfile]]
50 Let's say you have configuration file with this content and want to
51 load it:
52
53   HelloWorld {
54     Text        "Hello planet"
55     Count       3
56   }
57
58 [[ex_structure]]
59 The structure
60 ~~~~~~~~~~~~~
61 First, you declare the structure and let the configuration parser know
62 it exists.
63
64   #include <ucw/lib.h>
65   #include <ucw/conf.h>
66
67   static char *hw_text = "Hello world";
68   static int hw_count = 1;
69   static int hw_wait_answer = 0;
70
71   static struct cf_section hw_config = {
72     CF_ITEMS {
73       CF_STRING("Text", &hw_text),
74       CF_INT("Count", &hw_count),
75       CF_INT("WaitAnswer", &hw_wait_answer),
76       CF_END
77     }
78   };
79
80   static void CONSTRUCTOR hw_init(void) {
81     cf_declare_section("HelloWorld", &hw_config, 0);
82   }
83
84 The variables are used to store the loaded values. Their initial
85 values work as default, if nothing else is loaded. The hw_config()
86 structure assigns the variables to configuration names. The hw_init()
87 function (because of the `CONSTRUCTOR` macro) is run before main()
88 is called and it plugs in the whole section to the parser (alternatively,
89 you can call @cf_declare_section() at the start of your main()).
90
91 You can plug in as many configuration sections as you like, from
92 various places across your code.
93
94 [[ex_load]]
95 Loading of the values
96 ~~~~~~~~~~~~~~~~~~~~~
97 Suppose you need to parse the command line arguments and load the
98 configuration. Then @cf_getopt() is there for you: it works like
99 the the traditional @getopt() from the C library, but it also handles
100 configuration files.
101
102   #include <ucw/lib.h>
103   #include <ucw/conf.h>
104   #include <ucw/getopt.h>
105
106   static byte short_opts[] = CF_SHORT_OPTS "v";
107   static struct option long_opts[] = {
108     CF_LONG_OPTS
109     { "verbose", 0, 0, 'v' },
110     { NULL, 0, 0, 0 }
111   };
112
113   int verbose;
114
115   int main(int argc, char *argv[]) {
116     cf_def_file = "default.cf";
117     int opt;
118     while((opt = cf_getopt(argc, argv, short_opts, long_opts, NULL)) >= 0)
119       switch(opt) {
120         case 'v': verbose = 1; break;
121         default: fprintf("Unknown option %c\n", opt); return 1;
122       }
123   }
124
125 The `short_opts` and `long_opts` variables describe the command line
126 arguments. Notice the `CF_SHORT_OPTS` and `CF_LONG_OPTS` macros. They
127 add the `-S` and `-C` options for the configuration parser as described
128 in <<config:>>. These options are handled internally by @cf_getopt().
129
130 You can rely on the configuration files having been loaded before the
131 first of your program's options is parsed.
132
133 [[deep]]
134 Getting deeper
135 --------------
136
137 Since the configuration system is somehow complicated, this part gives
138 you a little overview of what you can find and where.
139
140 [[conf_multi]]
141 Arrays and lists
142 ~~~~~~~~~~~~~~~~
143
144 It is sometime needed to have multiple items of the same type. There
145 are three ways to do that:
146
147 *Static arrays*::
148   An array with fixed maximum length. You provide
149   the length and already allocated array which is filled with items.
150   The configuration may contain less than the maximum length items.
151 +
152 For example, you can have an static array of five unsigned integers:
153 +
154   static uns array = { 1, 2, 3, 4, 5 };
155 +
156   static struct cf_section section = {
157     CF_ITEMS {
158       CF_UNS_ARY("array", array, 5),
159       CF_END
160     }
161   };
162
163 *Dynamic arrays*::
164   Similar to static array, but you provide pointer
165   to pointer to the given item (eg. if you want dynamic array of
166   `int` s, you give `**int`). The parser allocates an array of needed
167   size. You can use the <<def_DARY_LEN,`DARY_LEN`>> macro to find out
168   the number of elements actually loaded.
169 +
170 If you want dynamic array of strings, you would use:
171 +
172   static char *array[];
173 +
174   static struct cf_section section = {
175     CF_ITEMS {
176       CF_STRING_DYN("array", &array, CF_ANY_NUM),
177       CF_END
178     }
179   };
180
181 *Lists*::
182   Linked lists based on <<clist:>>. You provide description
183   of single node and pointer to the
184   <<clist:struct_clist,`struct clist`>> variable. All the nodes will
185   be created dynamically and put there.
186 +
187 First element of your structure must be <<clist:type_cnode,`cnode`>>.
188 +
189 The first example is list of strings and uses <<clist:simple,simple
190 lists>>:
191   struct clist list;
192 +
193   static struct cf_section section = {
194     CF_ITEMS {
195       CF_LIST("list", &list, &cf_string_list_cofnig),
196       CF_END
197     }
198   };
199 +
200 Another example, describing how to create more complicated list node
201 than just a string can be found at the <<def_CF_TYPE,`CF_TYPE`>> macro.
202
203 [[reload]]
204 Reloading configuration
205 ~~~~~~~~~~~~~~~~~~~~~~~
206
207 The configuration system allows you to reload configuration at
208 runtime. The new config changes the values against the default values.
209 It means, if the default value for variable `A` is `10`, the currently
210 loaded config sets it to `42` and the new config does not talk about
211 this variable, `A` will have a value of `10` after a successful load.
212
213 Furthermore, if the loading of a new configuration fails, the current
214 configuration is preserved.
215
216 All this is done with <<journal,config journaling>>. The load of the
217 first config creates a journal entry. If you try to load some new
218 configuration, it is partially rolled back to defaults (the rollback
219 happens, but instead of removing the journal entry, another journal
220 entry is added for the rollback). If the loading succeeds, the two
221 journal entries are removed and a new one, for the new configuration,
222 is added. If it fails, the first one is replayed and the rollback
223 entry is removed.
224
225 See <<cf_reload()>>.
226
227 [[custom_parser]]
228 Creating custom parsers
229 ~~~~~~~~~~~~~~~~~~~~~~~
230
231 If you need to parse some data type the configuration system can't
232 handle, you can write your own parser. But before you start, you
233 should know a few things.
234
235 The parser needs to support <<journal,journaling>>. To accomplish that,
236 you have to use the <<alloc,configuration mempool>> for memory allocation.
237
238 Now, you need a function with the same signature as
239 <<type_cf_parser1,`cf_parser1`>>. Parse the first parameter (the
240 string) and store the data in the second parameter. You may want to
241 write a dumper function, with signature of
242 <<type_cf_dumper1,`cf_dumper1`>> (needed for debug dumps).
243
244 Fill in a structure <<struct_cf_user_type,cf_user_type>> and use the
245 new data type in your configuration description with
246 <<def_CF_USER,`CF_USER`>> macro as its @t parameter.
247
248 You do not need to call @cf_journal_block() on the variable you store
249 the result. It is true you change it, but it was stored to journal
250 before your parser function was called.
251
252 [[hooks]]
253 Hooks
254 ~~~~~
255
256 The configuration system supports hooks. They are used to initialize the
257 configuration (if simple default value of variable is not enough) and
258 to check the sanity of loaded data.
259
260 Each hook is of type <<type_cf_hook,`cf_hook`>> and you can include
261 them in configuration description using <<def_CF_INIT,`CF_INIT`>> and
262 <<def_CF_COMMIT,`CF_COMMIT`>> macros.
263
264 The hooks should follow similar guidelines as custom parsers (well,
265 init hooks do not need to call @cf_journal_block()) to support
266 journaling. If you change nothing in the commit hook, you do not need
267 to care about the journaling either.
268
269 You may use the return value to inform about errors. Just return the
270 error message, or NULL if everything went well.
271
272 Another similar function is a copy function. It is very similar to a
273 hook and is used when the item is copied and is too complicated to use
274 simple memcpy(). Its type is <<type_cf_copier,`cf_copier`>> and is
275 specified by the <<def_CF_COPY,`CF_COPY`>> macro. It's return value is
276 the same as the one of a hook.
277
278 [[conf_h]]
279 ucw/conf.h
280 ----------
281
282 Use this file if you want define a configuration section, request
283 loading of some variables or create new item type.
284
285 !!ucw/conf.h
286
287 [[getopt_h]]
288 ucw/getopt.h
289 ------------
290
291 This header contains routines for parsing command line arguments and
292 loading the configuration.
293
294 !!ucw/getopt.h