So far, we have only use a flat configuration file. libConfuse can also handle sections to build a hierarchy of options. Sections can be used to group options in logical blocks, and those blocks can (optionally) be specified multiple times.
Sections are initialized with the CFG_SEC()
macro. It also takes three
parameters: the name of the option, an array of options allowed in the section
and flags.
We'll extend the, now rather complex, hello program so we can do other kinds of greetings, not just "Hello". Each greeting will have its own settings for targets and repeat.
1 #include <stdio.h> 2 #include <confuse.h> 3 4 int main(void) 5 { 6 cfg_opt_t greet_opts[] = 7 { 8 CFG_STR_LIST("targets", "{World}", CFGF_NONE), 9 CFG_INT("repeat", 1, CFGF_NONE), 10 CFG_END() 11 }; 12 cfg_opt_t opts[] = 13 { 14 CFG_SEC("greeting", greet_opts, CFGF_TITLE | CFGF_MULTI), 15 CFG_END() 16 }; 17 cfg_t *cfg, *cfg_greet; 18 int repeat; 19 int i, j; 20 21 cfg = cfg_init(opts, CFGF_NONE); 22 if(cfg_parse(cfg, "hello.conf") == CFG_PARSE_ERROR) 23 return 1; 24 25 for(j = 0; j < cfg_size(cfg, "greeting"); j++) 26 { 27 cfg_greet = cfg_getnsec(cfg, "greeting", j); 28 29 repeat = cfg_getint(cfg_greet, "repeat"); 30 while(repeat--) 31 { 32 printf("%s", cfg_title(cfg_greet)); 33 for(i = 0; i < cfg_size(cfg_greet, "targets"); i++) 34 printf(", %s", cfg_getnstr(cfg_greet, "targets", i)); 35 printf("!\n"); 36 } 37 } 38 39 cfg_free(cfg); 40 return 0; 41 } 42
We have renamed the option array from "opts" to "greet_opts", and introduced a
new "opts" array that only has one option: a "greeting" section.
The second parameter of the CFG_SEC()
macro
points to the old greeting options "targets" and "repeat".
We have also used a couple of flags to alter the behaviour of the
section: CFGF_TITLE means that a greeting section should have a
title and the CFGF_MULTI flag tells libConfuse that this section
may be specified multiple times in the configuration file. The
title of a section is retrieved with the
cfg_title()
function.
The outmost loop (with index j) now loops through all given
sections in the configuration file. We retrieve a section with a
cfg_getnsec()
call. The value returned is a
pointer to a cfg_t struct, the same type as returned by
cfg_init()
. Thus we can use the ordinary value
retrieval functions cfg_getstr()
,
cfg_getint()
and so on to retrieve values of
options inside the section.
Ok, so how does the configuration file look like for this setup?
# this is the configuration file for the hello program greeting Hello { targets = {"Life", "Universe", "Everything"} repeat = 1 } greeting Bye { targets = {Adams} repeat = 1 }
The program will loop through the sections in the order specified
in the configuration file. First it will find the "Hello" section.
It prints the title of the section, "Hello", retrieved with
cfg_title()
. Then the targets are printed just
as in the previous exemples, but this time the values are retrieved
from the cfg_greet section. Next, the section titled "Bye" is
found, and the values are retrieved from that section.
When run, the program produces the following:
$ ./listing5 Hello, Life, Universe, Everything! Bye, Adams! $