Welcome

Wheresoever you go, go with all your heart. (Confucius)

6/03/2011

libconfig - C/C++ Configuration File Library

Libconfig is a great library which can process configuration files base on structured format such as XML.
According tohttp://www.hyperrealm.com/libconfig/, this file format is more compact and more readable than XML. Advantages are the follows:

  1. type-aware: by parser, it is automatically bound to the appropriate type such as int, float, array, and string.
  2. support both the C and C++
  3. works on various operating systems: GNU/Linux, Mac OS X, Solaris, FreeBSD, and Windows (2000, XP, and later)


I tested whether or not it works on Windows 7 and Visual studio 2005. The result is very successful.
Here is a sample configuration file.
#----------------------------
# Example Configuration File
#---------------------------
#

application:
{

 /* This section defines some settings for our
  * main application window, such as size and
  * position.
  */

  window:
  {
    title = "My Application";
    size = { /* width */ w = 640; /* height */ h = 480; };
    pos = { x = 350; y = 250; };
  };

  a = 5;
  b = 6;
  ff = 1E6;
  test-comment = "/* hello\n \"there\"*/";

  test-long-string = "A very long string that spans multiple lines. "
  /* but wait, there's more... */ "Adjacent strings are automatically"
  " concatenated.";

  test-escaped-string = "\"This is\n a test.\"";

  group1:
  {
    x = 5;  y = 10;
    my_array = [ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 ];
    flag = TRUE;

    group2: { zzz = "this is a test"; };

    states = [ "CT", // Connecticut
  "CA", // California
  "TX", // Texas
  "NV", // Nevada
  "FL"  // Florida
    ];
  };

  /* this would cause an error */
  // a = "hi!";
};

binary = [ 0xAA, 0xBB, 0xCC ];

list = ( ( "abc", 123, true ), 1.234, ( /* an empty list */ ) ,[ 1, 2, 3 ],
    { a = (1, 2, true); } );

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; },
          { } );

# miscellaneous stuff

misc:
{
  port = 5000;
  pi = 3.14159265;
  enabled = FALSE;
  mask = 0xAABBCCDD;
  unicode = "STARGΛ̊TE SG-1"; // UTF-8 string
  bigint = 9223372036854775807L;
  bighex = 0x1122334455667788L;
};


### eof

As shown in the sample configuration above, this is so very powerful that I love the libconfig library.
Finally, I provide a sample code to read a configuration file.


#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <libconfig.h++>
using namespace std;
using namespace libconfig;
// This example reads the configuration file 'example.cfg' and displays
// some of its contents.
int main(int argc, char **argv)
{
  Config cfg;
  // Read the file. If there is an error, report it and exit.
  try
  {
    cfg.readFile("example.cfg");
  }
  catch(const FileIOException &fioex)
  {
    std::cerr << "I/O error while reading file." << std::endl;
    return(EXIT_FAILURE);
  }
  catch(const ParseException &pex)
  {
    std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
              << " - " << pex.getError() << std::endl;
    return(EXIT_FAILURE);
  }
  // Get the store name.
  try
  {
    string name = cfg.lookup("name");
    cout << "Store name: " << name << endl << endl;
  }
  catch(const SettingNotFoundException &nfex)
  {
    cerr << "No 'name' setting in configuration file." << endl;
  }
  const Setting& root = cfg.getRoot();
  // Output a list of all books in the inventory.
  try
  {
    const Setting &books = root["inventory"]["books"];
    int count = books.getLength();
    cout << setw(30) << left << "TITLE" << "  "
         << setw(30) << left << "AUTHOR" << "   "
         << setw(6) << left << "PRICE" << "  "
         << "QTY"
         << endl;
    for(int i = 0; i < count; ++i)
    {
      const Setting &book = books[i];
      // Only output the record if all of the expected fields are present.
      string title, author;
      double price;
      int qty;
      if(!(book.lookupValue("title", title)
           && book.lookupValue("author", author)
           && book.lookupValue("price", price)
           && book.lookupValue("qty", qty)))
        continue;
      cout << setw(30) << left << title << "  "
           << setw(30) << left << author << "  "
           << '$' << setw(6) << right << price << "  "
           << qty
           << endl;
    }
    cout << endl;
  }
  catch(const SettingNotFoundException &nfex)
  {
    // Ignore.
  }
  // Output a list of all books in the inventory.
  try
  {
    const Setting &movies = root["inventory"]["movies"];
    int count = movies.getLength();
    cout << setw(30) << left << "TITLE" << "  "
         << setw(10) << left << "MEDIA" << "   "
         << setw(6) << left << "PRICE" << "  "
         << "QTY"
         << endl;
    for(int i = 0; i < count; ++i)
    {
      const Setting &movie = movies[i];
      // Only output the record if all of the expected fields are present.
      string title, media;
      double price;
      int qty;
      if(!(movie.lookupValue("title", title)
           && movie.lookupValue("media", media)
           && movie.lookupValue("price", price)
           && movie.lookupValue("qty", qty)))
        continue;
      cout << setw(30) << left << title << "  "
           << setw(10) << left << media << "  "
           << '$' << setw(6) << right << price << "  "
           << qty
           << endl;
    }
    cout << endl;
  }
  catch(const SettingNotFoundException &nfex)
  {
    // Ignore.
  }
  return(EXIT_SUCCESS);
}

No comments: