File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / confuse / doc / tutorial.xml
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:49:17 2021 UTC (3 years, 3 months ago) by misho
Branches: confuse, MAIN
CVS tags: v3_3, HEAD
confuse 3.3

    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 examples, 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 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>