Featured Post

Trie implementation in C

libconfig to read configuration files in C/C++

There are so many open-source libraries already available for parsing configuration files in c/c++ , but still we there are some which make their place up than rest of the others. One such library is libconfig . The reason being its simplicity and much lesser memory footprint. Most of the library for configuration files are XML based , but this library is text based and the structure of the configuration files is pretty simple.
e.g. In its simplest form a configuration file can look like :


port = 5000;


It can provide even more simpler configuration file for much complex data group. For example :

books = ( "inventory",
          { title  = "Treasure Island";
            author = "Robert Louis Stevenson";
            price  = 29.99;
            qty    = 5; },
          { title  = "Snow Crash";
            author = "Neal Stephenson";
            price  = 9.99;
            qty    = 8; }, 
{ } );

Here there is a set of data for the inventory of books with multiple fields for each book.

One of the most important feature of this library is that it supports a fully re-entrant parser which means that different configurations can be parsed in concurrent threads at the same time. Moreover the APIs are available for both C and C++ languages and there are hooks provided in the library to facilitate its use in other programming languages too.


The detailed documentation of this library can be found at Libconfig Manual. It supports multiple platforms such as Windows, Linux , Mac OS X and Solaris (POSIX compliant platforms).

To use it in a C/C++ program one just needs to add a single preprocessor directive


#include <libconfig.h>      /*For C*/  
#include <libconfig.h++>    /*For C++*/


For dynamic linking -lconfig/-lconfig++ must be used for C/C++ respectively. Otherwise the libraries can be statically linked using the static linking option during the compilation. 


e.g. ( -static $(LIBPTHREAD_INSTALL_DIR)/libpthread.a) 


Issues as per the libconfig website



  • Libconfig is fully reentrant; the functions in the library do not make use of global variables and do not maintain state between successive calls. Therefore two independent configurations may be safely manipulated concurrently by two distinct threads.
  • Libconfig is not thread-safe. The library is not aware of the presence of threads and knows nothing about the host system's threading model. Therefore, if an instance of a configuration is to be accessed from multiple threads, it must be suitably protected by synchronization mechanisms like read-write locks or mutexes; the standard rules for safe multithreaded access to shared data must be observed.
  • Libconfig is not async-safe. Calls should not be made into the library from signal handlers, because some of the C library routines that it uses may not be async-safe.
  • Libconfig is not guaranteed to be cancel-safe. Since it is not aware of the host system's threading model, the library does not contain any thread cancellation points. In most cases this will not be an issue for multithreaded programs. However, be aware that some of the routines in the library (namely those that read/write configurations from/to files or streams) perform I/O using C library routines which may potentially block; whether or not these C library routines are cancel-safe depends on the host system.
We will provide a simple example of how to read from a configuration file using libconfig:
 
/*config.c*/
/*
To compile : gcc -o config config.c -lconfig
To run     : ./config
*/
#include 
#include 

int main()
{
    config_t cfg;               /*Returns all parameters in this structure */
    config_setting_t *setting;
    const char *str1, *str2;
    int tmp;

    char *config_file_name = "config.txt";

    /*Initialization */
    config_init(&cfg);

    /* Read the file. If there is an error, report it and exit. */
    if (!config_read_file(&cfg, config_file_name))
    {
        printf("\n%s:%d - %s", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
        config_destroy(&cfg);
        return -1;
    }

    /* Get the configuration file name. */
    if (config_lookup_string(&cfg, "filename", &str1))
        printf("\nFile Type: %s", str1);
    else
        printf("\nNo 'filename' setting in configuration file.");

    /*Read the parameter group*/
    setting = config_lookup(&cfg, "params");
    if (setting != NULL)
    {
        /*Read the string*/
        if (config_setting_lookup_string(setting, "param1", &str2))
        {
            printf("\nParam1: %s", str2);
        }
        else
            printf("\nNo 'param1' setting in configuration file.");

        /*Read the integer*/
        if (config_setting_lookup_int(setting, "param2", &tmp))
        {
            printf("\nParam2: %d", tmp);
        }
        else
            printf("\nNo 'param2' setting in configuration file.");

        printf("\n");
    }

    config_destroy(&cfg);
}


And corresponding configuration file :
 
//config.txt
// Basic Information:
filename = "Sample Configuration File";

// Parameters
params = 
{
param1 = "Hello";

param2 = 1234;
};

Comments

Post a Comment

Please post your valuable suggestions