4. Using sections

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!
$