1<?xml version="1.0" encoding="ANSI_X3.4-1968" standalone="no"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ANSI_X3.4-1968" /><title>6.&#160;Validating callback functions</title><link rel="stylesheet" href="tutorial.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.75.2" /><link rel="home" href="index.html" title="libConfuse tutorial" /><link rel="up" href="index.html" title="libConfuse tutorial" /><link rel="prev" href="ar01s05.html" title="5.&#160;Parsing from internal buffers" /><link rel="next" href="ar01s07.html" title="7.&#160;Value parsing callback" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.&#160;Validating callback functions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a>&#160;</td><th width="60%" align="center">&#160;</th><td width="20%" align="right">&#160;<a accesskey="n" href="ar01s07.html">Next</a></td></tr></table><hr /></div><div class="sect1" title="6.&#160;Validating callback functions"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id442168"></a>6.&#160;Validating callback functions</h2></div></div></div><p>
4            Remember the problem about a negative or too large "repeat" value
5            in <a class="xref" href="ar01s02.html#negative-repeat-problem">Section&#160;2, &#8220;Other types of options&#8221;</a>?  The code that prints
6            the greeting has those lines:
7        </p><pre class="programlisting">
8...
9repeat = cfg_getint(cfg_greet, "repeat");
10while(repeat--)
11...
12        </pre><p>
13            The repeat variable is defined as an int, a signed integer. If the user
14            specified a negative repeat value in the configuration file, this code
15            would continue to decrease the repeat variable until it eventually
16            underflowed.
17        </p><p>
18            We'll fix this by not allowing a negative value in the configuration
19            file. Of course we could first just check if the value is negative
20            and then abort, using <code class="function">cfg_getint()</code> and a test.
21            But we will use a validating callback function instead. This way
22            <code class="function">cfg_parse()</code> will return an error directly when
23            parsing the file, additionally indicating on which line the error
24            is.
25        </p><p>
26            A validating callback function is defined as:
27        </p><pre class="programlisting">
28typedef int (*cfg_validate_callback_t)(cfg_t *cfg, cfg_opt_t *opt);
29        </pre><p>
30            This function takes two arguments: the section and the option. It
31            should return 0 on success (ie, the value validated ok). All other
32            values indicates an error, and the parsing is aborted. The callback
33            function should notify the error itself, for example by calling
34            <code class="function">cfg_error()</code>.
35        </p><p>
36            Here is the code for the callback function:
37        </p><a id="listing7"></a><pre class="programlisting">
381	int validate_unsigned_int(cfg_t *cfg, cfg_opt_t *opt)
392	{
403	    int value = cfg_opt_getnint(opt, cfg_opt_size(opt) - 1);
414	    if(value &lt; 0)
425	    {
436	        cfg_error(cfg, "integer option '%s' must be positive in section '%s'",
447	                opt-&gt;name, cfg-&gt;name);
458	        return -1;
469	    }
4710	    return 0;
4811	}
4912	
50</pre><p>
51            Only the last value is validated, because libConfuse will call this
52            function once for every value corresponding to the option. Since
53            the "repeat" option is not a list, we could instead have used
54            <code class="function">cfg_opt_getint(opt)</code> to retrieve the only
55            value. However, if we later want to use this callback to validate
56            an integer list, it is already lists-aware.
57        </p><div class="sect2" title="6.1.&#160;Installing the callback"><div class="titlepage"><div><div><h3 class="title"><a id="id442390"></a>6.1.&#160;Installing the callback</h3></div></div></div><p>
58                The validating callback is installed with
59                <code class="function">cfg_set_validate_func()</code>. It is called with
60                a string specifying which option is affected, and a pointer to
61                the callback function. To specify an option in a subsection,
62                the section and the option must be separated with a vertical
63                bar ("|").
64            </p><p>
65                We're now also looking at the return code from
66                <code class="function">cfg_parse()</code> to verify that the parsing was
67                successful. The complete program is now:
68            </p><a id="listing8"></a><pre class="programlisting">
691	#include &lt;stdio.h&gt;
702	#include &lt;confuse.h&gt;
713	
724	int validate_unsigned_int(cfg_t *cfg, cfg_opt_t *opt)
735	{
746	    int value = cfg_opt_getnint(opt, cfg_opt_size(opt) - 1);
757	    if(value &lt; 0)
768	    {
779	        cfg_error(cfg, "integer option '%s' must be positive in section '%s'",
7810	                opt-&gt;name, cfg-&gt;name);
7911	        return -1;
8012	    }
8113	    return 0;
8214	}
8315	
8416	int main(void)
8517	{
8618	    cfg_opt_t greet_opts[] =
8719	    {
8820	        CFG_STR_LIST("targets", "{World}", CFGF_NONE),
8921	        CFG_INT("repeat", 1, CFGF_NONE),
9022	        CFG_END()
9123	    };
9224	    cfg_opt_t opts[] =
9325	    {
9426	        CFG_SEC("greeting", greet_opts, CFGF_TITLE | CFGF_MULTI),
9527	        CFG_END()
9628	    };
9729	    cfg_t *cfg, *cfg_greet;
9830	    int repeat;
9931	    int i, j;
10032	
10133	    cfg = cfg_init(opts, CFGF_NONE);
10234	    cfg_set_validate_func(cfg, "greeting|repeat", validate_unsigned_int);
10335	    if(cfg_parse(cfg, "hello.conf") == CFG_PARSE_ERROR)
10436	        return 1;
10537	
10638	    for(j = 0; j &lt; cfg_size(cfg, "greeting"); j++)
10739	    {
10840	        cfg_greet = cfg_getnsec(cfg, "greeting", j);
10941	
11042	        repeat = cfg_getint(cfg_greet, "repeat");
11143	        while(repeat--)
11244	        {
11345	            printf("%s", cfg_title(cfg_greet));
11446	            for(i = 0; i &lt; cfg_size(cfg_greet, "targets"); i++)
11547	                printf(", %s", cfg_getnstr(cfg_greet, "targets", i));
11648	            printf("!\n");
11749	        }
11850	    }
11951	
12052	    cfg_free(cfg);
12153	    return 0;
12254	}
12355	
124</pre></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a>&#160;</td><td width="20%" align="center">&#160;</td><td width="40%" align="right">&#160;<a accesskey="n" href="ar01s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5.&#160;Parsing from internal buffers&#160;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&#160;7.&#160;Value parsing callback</td></tr></table></div></body></html>
125