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. 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. Parsing from internal buffers" /><link rel="next" href="ar01s07.html" title="7. Value parsing callback" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6. Validating callback functions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s07.html">Next</a></td></tr></table><hr /></div><div class="sect1" title="6. Validating callback functions"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id442168"></a>6. 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 2, “Other types of options”</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 < 0) 425 { 436 cfg_error(cfg, "integer option '%s' must be positive in section '%s'", 447 opt->name, cfg->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. Installing the callback"><div class="titlepage"><div><div><h3 class="title"><a id="id442390"></a>6.1. 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 <stdio.h> 702 #include <confuse.h> 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 < 0) 768 { 779 cfg_error(cfg, "integer option '%s' must be positive in section '%s'", 7810 opt->name, cfg->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 < 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 < 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> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5. Parsing from internal buffers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 7. Value parsing callback</td></tr></table></div></body></html> 125