Annotation of embedaddon/confuse/doc/tutorial.xml, revision 1.1
1.1 ! misho 1: <?xml version="1.0" standalone="no"?>
! 2: <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
! 3: "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
! 4: [
! 5: <!ENTITY listing1 SYSTEM "listing1.xml">
! 6: <!ENTITY listing2 SYSTEM "listing2.xml">
! 7: <!ENTITY listing3 SYSTEM "listing3.xml">
! 8: <!ENTITY listing4 SYSTEM "listing4.xml">
! 9: <!ENTITY listing5 SYSTEM "listing5.xml">
! 10: <!ENTITY listing6 SYSTEM "listing6.xml">
! 11: <!ENTITY listing7 SYSTEM "listing7.xml">
! 12: <!ENTITY listing8 SYSTEM "listing8.xml">
! 13: ]>
! 14: <article>
! 15: <articleinfo>
! 16: <title>libConfuse tutorial</title>
! 17: <author><firstname>Martin</firstname> <surname>Hedenfalk</surname></author>
! 18: </articleinfo>
! 19: <sect1>
! 20: <title>Introducing libConfuse in an existing program</title>
! 21: <para>Consider this simple program:</para>
! 22: &listing1;
! 23: <para>
! 24: Simple enough, but we want to extend the program so we can greet
! 25: others. Maybe we don't want to greet the whole world, just our
! 26: neighbour. We use libConfuse to let the user decide whom to greet.
! 27: </para>
! 28: &listing2;
! 29: <para>
! 30: All programs using libConfuse must first include the
! 31: <filename>confuse.h</filename> header file. This is done on line
! 32: 2.
! 33: </para>
! 34: <para>
! 35: On line 6 - 10, the options that should be recognized are defined in an
! 36: array of cfg_opt_t structs. This is passed to the
! 37: <function>cfg_init</function> function on line 13. The resulting
! 38: <structname>cfg_t</structname> context is used by
! 39: <function>cfg_parse()</function>, which reads the configuration file
! 40: "hello.conf". When reading the configuration file, only options defined in
! 41: the array of options passed to <function>cfg_init()</function> are
! 42: recognized.
! 43: </para>
! 44: <para>
! 45: The friendly greeting is now replaced with a parameter read from the
! 46: configuration file. The value of the <varname>target</varname> option is retrieved with
! 47: <function>cfg_getstr(cfg, "target")</function>.
! 48: </para>
! 49: <para>
! 50: Lets take a look at the configuration file hello.conf:
! 51: </para>
! 52:
! 53: <programlisting>
! 54: # this is the configuration file for the hello program
! 55:
! 56: target = "Neighbour"
! 57: </programlisting>
! 58: <para>
! 59: Here, the target option is set to the string value "Neighbour".
! 60: What if the configuration file was empty or didn't exist? Then the
! 61: default value for the <varname>target</varname> option would be
! 62: used. When we initialized our options, the second parameter to the
! 63: <function>CFG_STR()</function> macro specified the default value.
! 64: Thus, if no <varname>target</varname> option was specified in the
! 65: configuration file, the hello program would have printed the
! 66: standard greeting "Hello, World".
! 67: </para>
! 68:
! 69: <sect2>
! 70: <title>Environment variables in values</title>
! 71:
! 72: <para>
! 73: What else can we do in the configuration file? We can set the value to an
! 74: environment variable:
! 75: </para>
! 76: <programlisting>
! 77: target = ${USER}
! 78: </programlisting>
! 79: <para>
! 80: This results in the hello program greeting the user who runs it. On some
! 81: systems, the USER variable might not be available, so we want to specify a
! 82: default value in those cases:
! 83: </para>
! 84: <programlisting>
! 85: target = ${USER:-User}
! 86: </programlisting>
! 87: <para>
! 88: Now, if the USER environment variable is unset, the string "User" will be
! 89: used instead.
! 90: </para>
! 91: </sect2>
! 92: </sect1>
! 93: <sect1>
! 94: <title>Other types of options</title>
! 95:
! 96: <para>
! 97: Of course, not only strings can be specified in the configuration file.
! 98: libConfuse can parse strings, integers, booleans and floating point values.
! 99: These are the fundamental values, and they are all also available as lists.
! 100: We'll talk more about lists in the next chapter.
! 101: </para>
! 102: <para>
! 103: The macros used to initialize a string, integer, boolean and a
! 104: float is, respectively, <function>CFG_STR()</function>,
! 105: <function>CFG_INT()</function>, <function>CFG_BOOL()</function>,
! 106: <function>CFG_FLOAT()</function> and
! 107: <function>CFG_PTR()</function>. All macros take three parameters:
! 108: the name of the option, a default value and flags. To retrieve the
! 109: values, use <function>cfg_getstr()</function>,
! 110: <function>cfg_getint()</function>,
! 111: <function>cfg_getbool()</function>,
! 112: <function>cfg_getfloat()</function> or
! 113: <function>cfg_getptr()</function>, respectively.
! 114: </para>
! 115: <para>
! 116: Let's introduce an integer option that tells us how many times to print the
! 117: greeting:
! 118: </para>
! 119: &listing3;
! 120: <para>
! 121: Here we have used the <function>CFG_INT()</function> macro to
! 122: initialize an integer option named "repeat". The default value is 1
! 123: as in the standard greeting. The value is retrieved with
! 124: <function>cfg_getint()</function>.
! 125: </para>
! 126: <para id="negative-repeat-problem">
! 127: But, wait a moment, what if the user specified a negative value for
! 128: "repeat"? Or a too large positive value? libConfuse can handle
! 129: that with a so-called validating callback. We'll come back to this
! 130: problem later on, but we will first take a look at lists.
! 131: </para>
! 132: </sect1>
! 133:
! 134: <sect1>
! 135: <title>Introducing lists</title>
! 136:
! 137: <para>
! 138: That was easy. Now let's extend the program a bit so we can greet more than one
! 139: "target". We'd like to be able to specify a list of targets to greet.
! 140: </para>
! 141: <para>
! 142: The list versions of the initialization macros are named
! 143: <function>CFG_STR_LIST()</function>,
! 144: <function>CFG_INT_LIST()</function>,
! 145: <function>CFG_BOOL_LIST()</function> and
! 146: <function>CFG_FLOAT_LIST()</function>. They take the same
! 147: parameters as the non-list versions, except the default value must
! 148: be a string surrounded by curly braces.
! 149: </para>
! 150: <para>
! 151: The modified program is shown below:
! 152: </para>
! 153: &listing4;
! 154: <para>
! 155: Three things are a bit different here. First, the macro to
! 156: initialize the "targets" option is
! 157: <function>CFG_STR_LIST()</function>. This tells libConfuse that
! 158: "targets" is a list of strings. Second, the default value in the
! 159: second parameter is surrounded by curly braces. This is needed to
! 160: indicate to libConfuse where the list of values ends.
! 161: </para>
! 162: <para>
! 163: The third change is in the printing of the greeting. First we print
! 164: the "Hello" string. Then we loop through all values found for the
! 165: "targets" option. The number of values is retrieved with the
! 166: <function>cfg_size()</function> function. The string values are
! 167: then retrieved with <function>cfg_getnstr()</function>, which is an
! 168: indexed version of <function>cfg_getstr()</function>. In fact,
! 169: <function>cfg_getstr()</function> is equivalent to
! 170: <function>cfg_getnstr()</function> with an index of zero.
! 171: </para>
! 172: <para>
! 173: In the configuration file hello.conf, we can now specify a list of targets to
! 174: greet:
! 175: </para>
! 176: <programlisting>
! 177: # this is the configuration file for the hello program
! 178:
! 179: targets = {"Life", "Universe", "Everything"}
! 180: repeat = 1
! 181: </programlisting>
! 182: <para>
! 183: The output of the hello program, run with the above configuration file, is:
! 184: "Hello, Life, Universe, Everything!"
! 185: </para>
! 186: <para>
! 187: Again, if no targets were configured, the greeting would have been the standard
! 188: "Hello, World!".
! 189: </para>
! 190:
! 191: </sect1>
! 192: <sect1>
! 193: <title>Using sections</title>
! 194:
! 195: <para>
! 196: So far, we have only use a flat configuration file. libConfuse can also handle
! 197: sections to build a hierarchy of options. Sections can be used to group options
! 198: in logical blocks, and those blocks can (optionally) be specified multiple
! 199: times.
! 200: </para>
! 201: <para>
! 202: Sections are initialized with the <function>CFG_SEC()</function> macro. It also takes three
! 203: parameters: the name of the option, an array of options allowed in the section
! 204: and flags.
! 205: </para>
! 206: <para>
! 207: We'll extend the, now rather complex, hello program so we can do other kinds of
! 208: greetings, not just "Hello". Each greeting will have its own settings for
! 209: targets and repeat.
! 210: </para>
! 211: &listing5;
! 212: <para>
! 213: We have renamed the option array from "opts" to "greet_opts", and introduced a
! 214: new "opts" array that only has one option: a "greeting" section.
! 215: The second parameter of the <function>CFG_SEC()</function> macro
! 216: points to the old greeting options "targets" and "repeat".
! 217: </para>
! 218: <para>
! 219: We have also used a couple of flags to alter the behaviour of the
! 220: section: CFGF_TITLE means that a greeting section should have a
! 221: title and the CFGF_MULTI flag tells libConfuse that this section
! 222: may be specified multiple times in the configuration file. The
! 223: title of a section is retrieved with the
! 224: <function>cfg_title()</function> function.
! 225: </para>
! 226: <para>
! 227: The outmost loop (with index j) now loops through all given
! 228: sections in the configuration file. We retrieve a section with a
! 229: <function>cfg_getnsec()</function> call. The value returned is a
! 230: pointer to a cfg_t struct, the same type as returned by
! 231: <function>cfg_init()</function>. Thus we can use the ordinary value
! 232: retrieval functions <function>cfg_getstr()</function>,
! 233: <function>cfg_getint()</function> and so on to retrieve values of
! 234: options inside the section.
! 235: </para>
! 236: <para>
! 237: Ok, so how does the configuration file look like for this setup?
! 238: </para>
! 239: <programlisting>
! 240: # this is the configuration file for the hello program
! 241:
! 242: greeting Hello
! 243: {
! 244: targets = {"Life", "Universe", "Everything"}
! 245: repeat = 1
! 246: }
! 247:
! 248: greeting Bye
! 249: {
! 250: targets = {Adams}
! 251: repeat = 1
! 252: }
! 253: </programlisting>
! 254: <para>
! 255: The program will loop through the sections in the order specified
! 256: in the configuration file. First it will find the "Hello" section.
! 257: It prints the title of the section, "Hello", retrieved with
! 258: <function>cfg_title()</function>. Then the targets are printed just
! 259: as in the previous exemples, but this time the values are retrieved
! 260: from the cfg_greet section. Next, the section titled "Bye" is
! 261: found, and the values are retrieved from that section.
! 262: </para>
! 263: <para>
! 264: When run, the program produces the following:
! 265: </para>
! 266: <programlisting>
! 267: $ ./listing5
! 268: Hello, Life, Universe, Everything!
! 269: Bye, Adams!
! 270: $
! 271: </programlisting>
! 272:
! 273: </sect1>
! 274: <sect1>
! 275: <title>Parsing from internal buffers</title>
! 276: <para>
! 277: So far, we have only parsed configuration data from files.
! 278: libConfuse can also parse buffers, or in-memory character
! 279: strings. We will use this to fix a problem in the previous code.
! 280: </para>
! 281: <para>
! 282: The problem is that without a configuration file, the hello program
! 283: will not print anything. We want it to at least print the standard
! 284: greeting "Hello, World!" if no configuration file is available.
! 285: </para>
! 286: <para>
! 287: We can't have a default value for a section that can be specified
! 288: multiple times (ie, a section with the CFGF_MULTI flag set).
! 289: Instead we will parse a default configuration string if no section
! 290: has been parsed:
! 291: </para>
! 292: &listing6;
! 293: <para>
! 294: Only the changes from the previous code is shown here. We check if
! 295: the size of the "greeting" section is zero (ie, no section has been
! 296: defined). In that case we call <function>cfg_parse_buf()</function>
! 297: to parse a default in-memory string "greeting Hello {}". This
! 298: string defines a greeting section with title Hello, but without any
! 299: sub-options. This way we rely on the default values of the
! 300: (sub-)options "targets" and "repeat".
! 301: </para>
! 302: <para>
! 303: When this program is run, it issues the well-known standard greeting
! 304: "Hello, World!" if no configuration file is present.
! 305: </para>
! 306: </sect1>
! 307:
! 308: <sect1>
! 309: <title>Validating callback functions</title>
! 310: <para>
! 311: Remember the problem about a negative or too large "repeat" value
! 312: in <xref linkend="negative-repeat-problem"/>? The code that prints
! 313: the greeting has those lines:
! 314: </para>
! 315: <programlisting>
! 316: ...
! 317: repeat = cfg_getint(cfg_greet, "repeat");
! 318: while(repeat--)
! 319: ...
! 320: </programlisting>
! 321: <para>
! 322: The repeat variable is defined as an int, a signed integer. If the user
! 323: specified a negative repeat value in the configuration file, this code
! 324: would continue to decrease the repeat variable until it eventually
! 325: underflowed.
! 326: </para>
! 327: <para>
! 328: We'll fix this by not allowing a negative value in the configuration
! 329: file. Of course we could first just check if the value is negative
! 330: and then abort, using <function>cfg_getint()</function> and a test.
! 331: But we will use a validating callback function instead. This way
! 332: <function>cfg_parse()</function> will return an error directly when
! 333: parsing the file, additionally indicating on which line the error
! 334: is.
! 335: </para>
! 336: <para>
! 337: A validating callback function is defined as:
! 338: </para>
! 339: <programlisting>
! 340: typedef int (*cfg_validate_callback_t)(cfg_t *cfg, cfg_opt_t *opt);
! 341: </programlisting>
! 342: <para>
! 343: This function takes two arguments: the section and the option. It
! 344: should return 0 on success (ie, the value validated ok). All other
! 345: values indicates an error, and the parsing is aborted. The callback
! 346: function should notify the error itself, for example by calling
! 347: <function>cfg_error()</function>.
! 348: </para>
! 349: <para>
! 350: Here is the code for the callback function:
! 351: </para>
! 352: &listing7;
! 353: <para>
! 354: Only the last value is validated, because libConfuse will call this
! 355: function once for every value corresponding to the option. Since
! 356: the "repeat" option is not a list, we could instead have used
! 357: <function>cfg_opt_getint(opt)</function> to retrieve the only
! 358: value. However, if we later want to use this callback to validate
! 359: an integer list, it is already lists-aware.
! 360: </para>
! 361:
! 362: <sect2>
! 363: <title>Installing the callback</title>
! 364: <para>
! 365: The validating callback is installed with
! 366: <function>cfg_set_validate_func()</function>. It is called with
! 367: a string specifying which option is affected, and a pointer to
! 368: the callback function. To specify an option in a subsection,
! 369: the section and the option must be separated with a vertical
! 370: bar ("|").
! 371: </para>
! 372: <para>
! 373: We're now also looking at the return code from
! 374: <function>cfg_parse()</function> to verify that the parsing was
! 375: successful. The complete program is now:
! 376: </para>
! 377: &listing8;
! 378: </sect2>
! 379: </sect1>
! 380:
! 381: <sect1>
! 382: <title>Value parsing callback</title>
! 383: <para>
! 384: A value parsing callback is another kind of callback function
! 385: available in libConfuse. This function is used to map a string into
! 386: some other other value. One example is to extend a boolean option
! 387: to accept the values "yes", "no" and "ask" (or perhaps "true",
! 388: "false" and "maybe"). Those values should be mapped to the integers
! 389: 1, 2 and 3.
! 390: </para>
! 391: <programlisting>
! 392: typedef int (*cfg_callback_t)(cfg_t *cfg, cfg_opt_t *opt,
! 393: const char *value, void *result);
! 394: </programlisting>
! 395: <para>
! 396:
! 397: </para>
! 398: </sect1>
! 399:
! 400: <sect1>
! 401: <title>Functions</title>
! 402: <para>
! 403: libConfuse supports functions to parse options that does not fit
! 404: well in the general syntax. Functions can be called with a variable
! 405: number of arguments. No data from the function or any arguments are
! 406: stored by libConfuse after the function has run. It is up to the caller
! 407: to process and/or save the data.
! 408: </para>
! 409: <para>
! 410: A function is defined with a <function>CFG_FUNC</function> macro.
! 411: It takes two arguments: the name of the function and a function
! 412: callback. The callback is defined as:
! 413: </para>
! 414: <programlisting>
! 415: typedef int (*cfg_func_t)(cfg_t *cfg, cfg_opt_t *opt,
! 416: int argc, const char **argv);
! 417: </programlisting>
! 418: <para>
! 419: </para>
! 420:
! 421: <sect2>
! 422: <title>Predefined functions</title>
! 423: <para>
! 424: Currently there is only one pre-defined function:
! 425: <function>cfg_include()</function>. This function includes
! 426: another configuration file. Configuration data is immediately
! 427: read from the included file, and is returned to the position
! 428: right after the include() statement upon end of file.
! 429: </para>
! 430: <para>
! 431: To use this function, include a <function>CFG_FUNC()</function>
! 432: entry in your options:
! 433: </para>
! 434: <programlisting>
! 435: cfg_opt_t opts[] = {
! 436: CFG_FUNC("include", cfg_include),
! 437: CFG_END()
! 438: };
! 439: </programlisting>
! 440: <para>
! 441: In the configuration file, it is used in the following way:
! 442: </para>
! 443: <programlisting>
! 444: include("included.conf")
! 445: </programlisting>
! 446: </sect2>
! 447: </sect1>
! 448:
! 449: <sect1>
! 450: <title>Saving configuration files</title>
! 451: <para>
! 452: </para>
! 453:
! 454: <sect2>
! 455: <title>Altering the printing of certain options</title>
! 456: <para>
! 457: </para>
! 458: </sect2>
! 459: </sect1>
! 460:
! 461: </article>
! 462:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>