Example Programs

Usage from a Shell script

Many shell scripts used for system initialization and configuration contain hard-coded configuration values. Some attempt to isolate these values to a header of variables, but locating the script and then modifying it can be intimidating to novice users, no matter how well the script has been written.

This section presents the steps need to convert an existing script to make use of the kunf library. The example used involves setting up a nonstandard second serial port (/dev/ttyS1 using irq 5 instead of the more common irq 3), a common location for a modem. A typical script to perform this task would reside in /etc/rc.d/rc.serial and look like this: Note: This is an illustrative example only. Your system probably has different settings.


#!/bin/sh
/bin/setserial /dev/ttyS1 uart 16450 port 0x2F8 irq 5

A script of this type can be improved by isolating the system dependent values in a header like this:

#!/bin/sh
SECOND_SERIAL_UART=16450
SECOND_SERIAL_PORT=0x2F8
SECOND_SERIAL_IRQ=5

/bin/setserial /dev/ttyS1 uart $SECOND_SERIAL_UART port $SECOND_SERIAL_PORT irq $SECOND_SERIAL_IRQ

The above script can now easily be modified to be used with the kunf library, by adding the following entry to the configuration system:

[devices:ttyS1]
 uart=16450
 port=0x2F8
 irq=5

Then the script can now be rewritten as follows:

#!/bin/sh
eval `/usr/bin/kunfenv devices:ttyS1`

/bin/setserial /dev/ttyS1 uart $devices_ttyS1_uart port $devices_ttyS1_port irq $devices_ttyS1_irq

Note that a sensible script would check if kunfenv managed to acquire the desired values, but this has been omitted for the sake of brevity.

This method of configuring the system has the advantage that the system administrator only needs to edit the configuration files (possibly using a menu driven utility) instead of having to find, understand and edit the script by hand (Most novices will have difficulty finding the script within the /etc/rc.d/ hierarchy).


Usage from a C program

Note that the example in this section is more complex and attempts to illustrate some of the more sophisticated features. It does start quite simply though. For the sake of this discussion we will use a hypothetical program called foo. Foo is a small mail reader. Foo allows the user to set the following options:

Foreground Colour, Background Colour, Full User Name, Signature File, Reply-to Address, Location of Mailbox as well as Directory for Temporary Files.

The first task is to decide on the naming of the options. A sensible approach would be to subdivide the options into three sections... something like interface, identity and backend. This allows the system administrator a finer grain of control as we shall see later. So a typical configuration file entry would look something like:


[mail:foo:interface]
fgcolor="bright yellow"
bgcolor="blue"

[mail:foo:identity]
name="J. Soap"
signature="/home/jsoap/.signature"
replyto="jsoap@frogstar5.com"

[mail:foo:backend]
mailbox="/var/spool/mail/jsoap"
tmpdir="/var/tmp"

Those readers who are wondering how such a configuration entry can be used system-wide (where a user need not create his or her own configuration file) should read the description of the syntax of the configuration file. Otherwise take it on faith that it is possible.

The corresponding snippet of client C code to look up the values can look like this:

  ...
  #include <kunf.h>  /* include the function declarations */
  ...
  /* somewhere inside a function */
  ...
  char *str;         /* the string to store the values */

  kunfig_open(NULL,KUNFIG_OPEN_STANDARD);
                     /* use default settings */

  str=kunfig_findvalue(4,"mail","foo","interface","fgcolor");
  ...
  /* now use the value of str to get the foreground colour */
  /* but do check that str!=NULL. Do not free(str). */
  ...
  str=kunfig_findvalue(4,"mail","foo","interface","bgcolor");
  ...
  /* now use str to determine background colour */
  ...
  str=kunfig_findvalue(4,"mail","foo","identity","name");
  ...
  str=kunfig_findvalue(4,"mail","foo","identity","signature");
  ...
  str=kunfig_findvalue(4,"mail","foo","identity","replyto");
  ...
  str=kunfig_findvalue(4,"mail","foo","backend","mailbox");
  ...
  str=kunfig_findvalue(4,"mail","foo","backend","tmpdir");
  ...
  kunfig_close();   
  /* at this point all values returned by kunfig_findvalue */ 
  /* have become invalid (they have been deallocated) */
  ...
  /* continue with your program */

The C code should be linked to the kunf library using the option -lkunf. The following points should be stressed:

Usage from a C program - the plot thickens...

The observant reader might have noticed that the method used to access the configuration entries only works for entries of which their full name is known - this is true for almost every case, but there is bound to be an exception. To cater for this special case, an alternate interface to the configuration files has been provided.

Here is a hypothetical case which makes use of this feature. The author of foo has decided to allow the user to source boilerplate letters. These templates are stored in globally accessible directories, but are known to the user by a short name. These definitions are stored in another section:


[mail:foo:templates]
thanks="/usr/lib/foo/thank.template"
complaint="/usr/lib/foo/complain.template"
birthdays="/home/fred/foo/birthday.template"

To access these entries the following code can be used:
  ...
  #include <kunf.h>  /* include the function declarations */
  ...
  /* somewhere inside a function */
  ...
  KITEM *handle;     /* a handle to an opaque internal structure */
  char  *name;       /* the string to store the names */
  char  *value;      /* the string to store the values */

  kunfig_open(NULL,KUNFIG_OPEN_STANDARD);
                     /* use default settings */
  ...
  /* acquire other sections as in previous example */
  ...

  /* find all entries in the templates section */
  handle=kunfig_findentry(3,"mail","foo","templates");
  /* make sure we have found a valid header */
  if(handle!=NULL&&kunfig_isheader(handle)){
  /* get the first entry of that section */
    handle=kunfig_down(handle);
  /* iterate over all entries */
    while(handle!=NULL){
  /* if a valid entry - it could be a header */
      if(kunfig_isentry(handle)){
  /* acquire name and value */
        name=kunfig_getname(handle);
        value=kunfig_getvalue(handle);
  /* on first iteration name="thanks" */
  /* and value="/usr/lib/foo/thanks.template" */
        ...
  /* process name and value as you see fit */
        ...
      }
  /* get next entry */
      handle=kunfig_next(handle);
    }
  }
  ...
  kunfig_close();   
  /* at this point all values returned by kunfig_findvalue */ 
  /* have become invalid (they have been deallocated) */

The following points should be stressed:
Next: The C language API