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>