From 3d9eec0c88ee22f4f4ea65d675f2aaeae89d48b1 Mon Sep 17 00:00:00 2001
From: Dmitri Pal <dpal@redhat.com>
Date: Thu, 15 Apr 2010 17:27:04 -0400
Subject: [PATCH] [INI] Code restructuring

Time came to split ini_config.c
into many much smaller pieces.

1) ini_parse.c - will have parsing functions
2) ini_get_value.c - will have single value
interpretation functions
3) ini_get_array.c - will have array interpretation
functions.
4) ini_print.c - error printing
5) ini_defines.h - common constants
6) ini_parse.h header for parsing functions
7) ini_list.c - will have list processing functions
---
 common/ini/Makefile.am     |   11 +-
 common/ini/ini_config.c    | 1476 +-------------------------------------------
 common/ini/ini_config.h    |    3 +
 common/ini/ini_defines.h   |   74 +++
 common/ini/ini_get_array.c |  354 +++++++++++
 common/ini/ini_get_value.c |  523 ++++++++++++++++
 common/ini/ini_list.c      |  123 ++++
 common/ini/ini_parse.c     |  190 ++++++
 common/ini/ini_parse.h     |   36 ++
 common/ini/ini_print.c     |  387 ++++++++++++
 10 files changed, 1705 insertions(+), 1472 deletions(-)
 create mode 100644 common/ini/ini_defines.h
 create mode 100644 common/ini/ini_get_array.c
 create mode 100644 common/ini/ini_get_value.c
 create mode 100644 common/ini/ini_list.c
 create mode 100644 common/ini/ini_parse.c
 create mode 100644 common/ini/ini_parse.h
 create mode 100644 common/ini/ini_print.c

diff --git a/common/ini/Makefile.am b/common/ini/Makefile.am
index a72ce3a..1dc55d9 100644
--- a/common/ini/Makefile.am
+++ b/common/ini/Makefile.am
@@ -34,8 +34,17 @@ dist_include_HEADERS = \
 lib_LTLIBRARIES = libini_config.la
 libini_config_la_SOURCES = \
     ini_config.c \
+    ini_config.h \
+    ini_get_value.c \
+    ini_get_array.c \
+    ini_list.c \
+    ini_print.c \
+    ini_parse.c \
+    ini_parse.h \
     ini_metadata.c \
-    ini_metadata.h
+    ini_metadata.h \
+    ini_defines.h
+
 
 libini_config_la_LIBADD = \
     -L$(topbuilddir)/collection \
diff --git a/common/ini/ini_config.c b/common/ini/ini_config.c
index 1c8e4ae..b9cd6eb 100644
--- a/common/ini/ini_config.c
+++ b/common/ini/ini_config.c
@@ -21,220 +21,19 @@
 */
 
 #define _GNU_SOURCE
-#include <stdio.h>
 #include <errno.h>
 #include <string.h>
-#include <ctype.h>
 #include <stdlib.h>
-#include <locale.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
 #include "config.h"
-/* For error text */
-#include <libintl.h>
-#define _(String) gettext (String)
-/* INI file is used as a collection */
+#include "trace.h"
 #include "collection.h"
 #include "collection_tools.h"
-#include "trace.h"
-#include "ini_config.h"
-#include "ini_metadata.h"
 #include "path_utils.h"
+#include "ini_defines.h"
+#include "ini_parse.h"
+#include "ini_metadata.h"
+#include "ini_config.h"
 
-#define NAME_OVERHEAD   10
-
-#define SLASH           "/"
-
-#define EXCLUDE_EMPTY   0
-#define INCLUDE_EMPTY   1
-
-/* Name of the special collection used to store parsing errors */
-#define FILE_ERROR_SET  "ini_file_error_set"
-
-/* Text error strings used when errors are printed out */
-#define WARNING_TXT         _("Warning")
-#define ERROR_TXT           _("Error")
-/* For parse errors */
-#define WRONG_COLLECTION    _("Passed in list is not a list of parse errors.\n")
-#define FAILED_TO_PROCCESS  _("Internal Error. Failed to process error list.\n")
-#define ERROR_HEADER        _("Parsing errors and warnings in file: %s\n")
-/* For grammar errors */
-#define WRONG_GRAMMAR       _("Passed in list is not a list of grammar errors.\n")
-#define FAILED_TO_PROC_G    _("Internal Error. Failed to process list of grammar errors.\n")
-#define ERROR_HEADER_G      _("Logical errors and warnings in file: %s\n")
-/* For validation errors */
-#define WRONG_VALIDATION    _("Passed in list is not a list of validation errors.\n")
-#define FAILED_TO_PROC_V    _("Internal Error. Failed to process list of validation errors.\n")
-#define ERROR_HEADER_V      _("Validation errors and warnings in file: %s\n")
-
-#define LINE_FORMAT         _("%s (%d) on line %d: %s\n")
-
-
-/* Codes that parsing function can return */
-#define RET_PAIR        0
-#define RET_COMMENT     1
-#define RET_SECTION     2
-#define RET_INVALID     3
-#define RET_EMPTY       4
-#define RET_EOF         5
-#define RET_ERROR       6
-
-#define INI_ERROR       "errors"
-#define INI_ERROR_NAME  "errname"
-
-/* Internal sizes. MAX_KEY is defined in config.h */
-#define MAX_VALUE       PATH_MAX
-#define BUFFER_SIZE     MAX_KEY + MAX_VALUE + 3
-
-/* Beffer length used for int to string conversions */
-#define CONVERSION_BUFFER 80
-
-/*============================================================*/
-/* The following classes moved here from the public header
- * They are reserved for future use.
- *
- * NOTE: before exposing these constants again in the common header
- * check that the class IDs did not get reused over time by
- * other classes.
- */
-/** @brief Collection of grammar errors.
- *
- * Reserved for future use.
- */
-#define COL_CLASS_INI_GERROR      COL_CLASS_INI_BASE + 5
-/** @brief Collection of validation errors.
- *
- * Reserved for future use.
- */
-#define COL_CLASS_INI_VERROR      COL_CLASS_INI_BASE + 6
-
-#ifdef HAVE_VALIDATION
-
-/** @brief Collection of lines from the INI file.
- *
- * Reserved for future use
- */
-#define COL_CLASS_INI_LINES       COL_CLASS_INI_BASE + 7
-
-#endif /* HAVE_VALIDATION */
-/*============================================================*/
-
-
-/* Different error string functions can be passed as callbacks */
-typedef const char * (*error_fn)(int error);
-
-/* Function to return parsing error */
-const char *parsing_error_str(int parsing_error)
-{
-    const char *placeholder= _("Unknown pasing error.");
-    const char *str_error[] = { _("Data is too long."),
-                                _("No closing bracket."),
-                                _("Section name is missing."),
-                                _("Section name is too long."),
-                                _("Equal sign is missing."),
-                                _("Property name is missing."),
-                                _("Property name is too long.")
-    };
-
-    /* Check the range */
-    if ((parsing_error < 1) || (parsing_error > ERR_MAXPARSE))
-            return placeholder;
-    else
-            return str_error[parsing_error-1];
-}
-
-/* Function to return grammar error.
- * This function is currently not used.
- * It is planned to be used by the INI
- * file grammar parser.
- *
- * The following doxygen description is moved here.
- * When the function gets exposed move it into
- * the header file.
- */
-/** @brief Function to return a grammar error in template.
- *
- * EXPERIMENTAL. Reserved for future use.
- *
- * This error is returned when the template
- * is translated into the grammar object.
- *
- * @param[in] parsing_error    Error code for the grammar error.
- *
- * @return Error string.
- */
-
-const char *grammar_error_str(int grammar_error)
-{
-    const char *placeholder= _("Unknown grammar error.");
-    /* THIS IS A TEMPORARY PLACEHOLDER !!!! */
-    const char *str_error[] = { _(""),
-                                _(""),
-                                _(""),
-                                _(""),
-                                _(""),
-                                _(""),
-                                _("")
-    };
-
-    /* Check the range */
-    if ((grammar_error < 1) || (grammar_error > ERR_MAXGRAMMAR))
-            return placeholder;
-    else
-            return str_error[grammar_error-1];
-}
-
-/* Function to return validation error.
- * This function is currently not used.
- * It is planned to be used by the INI
- * file grammar validator.
- *
- * The following doxygen description is moved here.
- * When the function gets exposed move it into
- * the header file.
- */
-/** @brief Function to return a validation error.
- *
- * EXPERIMENTAL. Reserved for future use.
- *
- * This is the error that it is returned when
- * the INI file is validated against the
- * grammar object.
- *
- * @param[in] parsing_error    Error code for the validation error.
- *
- * @return Error string.
- */
-const char *validation_error_str(int validation_error)
-{
-    const char *placeholder= _("Unknown validation error.");
-    /* THIS IS A TEMPORARY PLACEHOLDER !!!! */
-    const char *str_error[] = { _(""),
-                                _(""),
-                                _(""),
-                                _(""),
-                                _(""),
-                                _(""),
-                                _("")
-    };
-
-    /* Check the range */
-    if ((validation_error < 1) || (validation_error > ERR_MAXVALID))
-            return placeholder;
-    else
-            return str_error[validation_error-1];
-}
-
-
-/* Internal function to read line from INI file */
-int read_line(FILE *file,
-              char *buf,
-              int read_size,
-              char **key,
-              char **value,
-              int *length,
-              int *ext_error);
 
 /***************************************************************************/
 /* Function to read single ini file and pupulate
@@ -1035,1268 +834,3 @@ int config_for_app(const char *application,
     TRACE_FLOW_NUMBER("config_for_app. Returning", error);
     return error;
 }
-
-
-
-/* Reads a line from the file */
-int read_line(FILE *file,
-              char *buf,
-              int read_size,
-              char **key, char **value,
-              int *length,
-              int *ext_error)
-{
-
-    char *res;
-    int len;
-    char *buffer;
-    int i;
-    char *eq;
-
-    TRACE_FLOW_STRING("read_line", "Entry");
-
-    *ext_error = 0;
-
-    buffer = buf;
-
-    /* Get data from file */
-    res = fgets(buffer, read_size - 1, file);
-    if (res == NULL) {
-        TRACE_ERROR_STRING("Read nothing", "");
-        return RET_EOF;
-    }
-
-    /* Make sure the buffer is NULL terminated */
-    buffer[read_size - 1] = '\0';
-
-    len = strlen(buffer);
-    if (len == 0) {
-        TRACE_ERROR_STRING("Nothing was read.", "");
-        return RET_EMPTY;
-    }
-
-    /* Added \r just in case we deal with Windows in future */
-    if ((buffer[len - 1] != '\n') && (buffer[len - 1] != '\r')) {
-        TRACE_ERROR_STRING("String it too big!", "");
-        *ext_error = ERR_LONGDATA;
-        return RET_ERROR;
-    }
-
-    /* Ingnore comments */
-    if ((*buffer == ';') || (*buffer == '#')) {
-        TRACE_FLOW_STRING("Comment", buf);
-        return RET_COMMENT;
-    }
-
-    TRACE_INFO_STRING("BUFFER before trimming:", buffer);
-
-    /* Trucate trailing spaces and CRs */
-    /* Make sure not to step before the beginning */
-    while (len && isspace(buffer[len - 1])) {
-        buffer[len - 1] = '\0';
-        len--;
-    }
-
-    TRACE_INFO_STRING("BUFFER after trimming trailing spaces:", buffer);
-
-    /* Trucate leading spaces  */
-    while (isspace(*buffer)) {
-        buffer++;
-        len--;
-    }
-
-    TRACE_INFO_STRING("BUFFER after trimming leading spaces:", buffer);
-    TRACE_INFO_NUMBER("BUFFER length:", len);
-
-    /* Empty line */
-    if (len == 0) {
-        TRACE_FLOW_STRING("Empty line", buf);
-        return RET_EMPTY;
-    }
-
-    /* Section */
-    if (*buffer == '[') {
-        if (buffer[len-1] != ']') {
-            TRACE_ERROR_STRING("Invalid format for section", buf);
-            *ext_error = ERR_NOCLOSESEC;
-            return RET_ERROR;
-        }
-        buffer++;
-        len--;
-        while (isspace(*buffer)) {
-            buffer++;
-            len--;
-        }
-        if (len == 0) {
-            TRACE_ERROR_STRING("Invalid format for section", buf);
-            *ext_error = ERR_NOSECTION;
-            return RET_ERROR;
-        }
-
-        buffer[len - 1] = '\0';
-        len--;
-        while (isspace(buffer[len - 1])) {
-            buffer[len - 1] = '\0';
-            len--;
-        }
-        if (len >= MAX_KEY) {
-            TRACE_ERROR_STRING("Section name is too long", buf);
-            *ext_error = ERR_SECTIONLONG;
-            return RET_ERROR;
-        }
-
-        *key = buffer;
-        return RET_SECTION;
-    }
-
-    /* Assume we are dealing with the K-V here */
-    /* Find "=" */
-    eq = strchr(buffer, '=');
-    if (eq == NULL) {
-        TRACE_ERROR_STRING("No equal sign", buf);
-        *ext_error = ERR_NOEQUAL;
-        return RET_INVALID;
-    }
-
-    len -= eq-buffer;
-
-    /* Strip spaces around "=" */
-    i = eq - buffer - 1;
-    while ((i >= 0) && isspace(buffer[i])) i--;
-    if (i < 0) {
-        TRACE_ERROR_STRING("No key", buf);
-        *ext_error = ERR_NOKEY;
-        return RET_INVALID;
-    }
-
-    /* Copy key into provided buffer */
-    if(i >= MAX_KEY) {
-        TRACE_ERROR_STRING("Section name is too long", buf);
-        *ext_error = ERR_LONGKEY;
-        return RET_INVALID;
-    }
-    *key = buffer;
-    buffer[i + 1] = '\0';
-    TRACE_INFO_STRING("KEY:", *key);
-
-    eq++;
-    len--;
-    while (isspace(*eq)) {
-        eq++;
-        len--;
-    }
-
-    *value = eq;
-    /* Make sure we include trailing 0 into data */
-    *length = len + 1;
-
-    TRACE_INFO_STRING("VALUE:", *value);
-    TRACE_INFO_NUMBER("LENGTH:", *length);
-
-    TRACE_FLOW_STRING("read_line", "Exit");
-    return RET_PAIR;
-}
-
-
-
-/* Internal function that prints errors */
-static void print_error_list(FILE *file,
-                             struct collection_item *error_list,
-                             int cclass,
-                             char *wrong_col_error,
-                             char *failed_to_process,
-                             char *error_header,
-                             char *line_format,
-                             error_fn error_function)
-{
-    struct collection_iterator *iterator;
-    int error;
-    struct collection_item *item = NULL;
-    struct parse_error *pe;
-    unsigned int count;
-
-    TRACE_FLOW_STRING("print_error_list", "Entry");
-
-    /* If we have something to print print it */
-    if (error_list == NULL) {
-        TRACE_ERROR_STRING("No error list","");
-        return;
-    }
-
-    /* Make sure we go the right collection */
-    if (!col_is_of_class(error_list, cclass)) {
-        TRACE_ERROR_STRING("Wrong collection class:", wrong_col_error);
-        fprintf(file,"%s\n", wrong_col_error);
-        return;
-    }
-
-    /* Bind iterator */
-    error =  col_bind_iterator(&iterator, error_list, COL_TRAVERSE_DEFAULT);
-    if (error) {
-        TRACE_ERROR_STRING("Error (bind):", failed_to_process);
-        fprintf(file, "%s\n", failed_to_process);
-        return;
-    }
-
-    while(1) {
-        /* Loop through a collection */
-        error = col_iterate_collection(iterator, &item);
-        if (error) {
-            TRACE_ERROR_STRING("Error (iterate):", failed_to_process);
-            fprintf(file, "%s\n", failed_to_process);
-            col_unbind_iterator(iterator);
-            return;
-        }
-
-        /* Are we done ? */
-        if (item == NULL) break;
-
-        /* Process collection header */
-        if (col_get_item_type(item) == COL_TYPE_COLLECTION) {
-            col_get_collection_count(item, &count);
-            if (count <= 2) break;
-        } else if (col_get_item_type(item) == COL_TYPE_STRING) {
-            fprintf(file, error_header, (char *)col_get_item_data(item));
-        }
-        else {
-            /* Put error into provided format */
-            pe = (struct parse_error *)(col_get_item_data(item));
-            fprintf(file, line_format,
-                    col_get_item_property(item, NULL),      /* Error or warning */
-                    pe->error,                          /* Error */
-                    pe->line,                           /* Line */
-                    error_function(pe->error));         /* Error str */
-        }
-
-    }
-
-    /* Do not forget to unbind iterator - otherwise there will be a leak */
-    col_unbind_iterator(iterator);
-
-    TRACE_FLOW_STRING("print_error_list", "Exit");
-}
-
-/* Print errors and warnings that were detected while parsing one file */
-void print_file_parsing_errors(FILE *file,
-                               struct collection_item *error_list)
-{
-    print_error_list(file,
-                     error_list,
-                     COL_CLASS_INI_PERROR,
-                     WRONG_COLLECTION,
-                     FAILED_TO_PROCCESS,
-                     ERROR_HEADER,
-                     LINE_FORMAT,
-                     parsing_error_str);
-}
-
-
-/* Print errors and warnings that were detected while processing grammar.
- *
- * The following doxygen description is moved here.
- * When the function gets exposed move it into
- * the header file.
- */
-/**
- * @brief Print errors and warnings that were detected while
- * checking grammar of the template.
- *
- * EXPERIMENTAL. Reserved for future use.
- *
- * @param[in] file           File descriptor.
- * @param[in] error_list     List of the parsing errors.
- *
- */
-void print_grammar_errors(FILE *file,
-                          struct collection_item *error_list)
-{
-    print_error_list(file,
-                     error_list,
-                     COL_CLASS_INI_GERROR,
-                     WRONG_GRAMMAR,
-                     FAILED_TO_PROC_G,
-                     ERROR_HEADER_G,
-                     LINE_FORMAT,
-                     grammar_error_str);
-}
-
-/* Print errors and warnings that were detected while validating INI file.
- *
- * The following doxygen description is moved here.
- * When the function gets exposed move it into
- * the header file.
- */
-/**
- * @brief Print errors and warnings that were detected while
- * checking INI file against the grammar object.
- *
- * EXPERIMENTAL. Reserved for future use.
- *
- * @param[in] file           File descriptor.
- * @param[in] error_list     List of the parsing errors.
- *
- */
-void print_validation_errors(FILE *file,
-                             struct collection_item *error_list)
-{
-    print_error_list(file,
-                     error_list,
-                     COL_CLASS_INI_VERROR,
-                     WRONG_VALIDATION,
-                     FAILED_TO_PROC_V,
-                     ERROR_HEADER_V,
-                     LINE_FORMAT,
-                     validation_error_str);
-}
-
-/* Print errors and warnings that were detected while parsing
- * the whole configuration */
-void print_config_parsing_errors(FILE *file,
-                                 struct collection_item *error_list)
-{
-    struct collection_iterator *iterator;
-    int error;
-    struct collection_item *item = NULL;
-    struct collection_item *file_errors = NULL;
-
-    TRACE_FLOW_STRING("print_config_parsing_errors", "Entry");
-
-    /* If we have something to print print it */
-    if (error_list == NULL) {
-        TRACE_ERROR_STRING("No error list", "");
-        return;
-    }
-
-    /* Make sure we go the right collection */
-    if (!col_is_of_class(error_list, COL_CLASS_INI_PESET)) {
-        TRACE_ERROR_STRING("Wrong collection class:", WRONG_COLLECTION);
-        fprintf(file, "%s\n", WRONG_COLLECTION);
-        return;
-    }
-
-    /* Bind iterator */
-    error =  col_bind_iterator(&iterator, error_list, COL_TRAVERSE_DEFAULT);
-    if (error) {
-        TRACE_ERROR_STRING("Error (bind):", FAILED_TO_PROCCESS);
-        fprintf(file,"%s\n", FAILED_TO_PROCCESS);
-        return;
-    }
-
-    while(1) {
-        /* Loop through a collection */
-        error = col_iterate_collection(iterator, &item);
-        if (error) {
-            TRACE_ERROR_STRING("Error (iterate):", FAILED_TO_PROCCESS);
-            fprintf(file, "%s\n", FAILED_TO_PROCCESS);
-            col_unbind_iterator(iterator);
-            return;
-        }
-
-        /* Are we done ? */
-        if (item == NULL) break;
-
-        /* Print per file sets of errors */
-        if (col_get_item_type(item) == COL_TYPE_COLLECTIONREF) {
-            /* Extract a sub collection */
-            error = col_get_reference_from_item(item, &file_errors);
-            if (error) {
-                TRACE_ERROR_STRING("Error (extract):", FAILED_TO_PROCCESS);
-                fprintf(file, "%s\n", FAILED_TO_PROCCESS);
-                col_unbind_iterator(iterator);
-                return;
-            }
-            print_file_parsing_errors(file, file_errors);
-            col_destroy_collection(file_errors);
-        }
-    }
-
-    /* Do not forget to unbind iterator - otherwise there will be a leak */
-    col_unbind_iterator(iterator);
-
-    TRACE_FLOW_STRING("print_config_parsing_errors", "Exit");
-}
-
-
-/* Function to get value from the configration handle */
-int get_config_item(const char *section,
-                    const char *name,
-                    struct collection_item *ini_config,
-                    struct collection_item **item)
-{
-    int error = EOK;
-    struct collection_item *section_handle = NULL;
-    const char *to_find;
-    char default_section[] = INI_DEFAULT_SECTION;
-
-    TRACE_FLOW_STRING("get_config_item", "Entry");
-
-    /* Do we have the accepting memory ? */
-    if (item == NULL) {
-        TRACE_ERROR_NUMBER("No buffer - invalid argument.", EINVAL);
-        return EINVAL;
-    }
-
-    /* Is the collection of a right type */
-    if ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
-        (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) {
-        TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
-        return EINVAL;
-    }
-
-    *item = NULL;
-
-    if (section == NULL) to_find = default_section;
-    else to_find = section;
-
-    TRACE_INFO_STRING("Getting Name:", name);
-    TRACE_INFO_STRING("In Section:", section);
-
-    /* Get Subcollection */
-    error = col_get_collection_reference(ini_config, &section_handle, to_find);
-    /* Check error */
-    if (error && (error != ENOENT)) {
-        TRACE_ERROR_NUMBER("Failed to get section", error);
-        return error;
-    }
-
-    /* Did we find a section */
-    if ((error == ENOENT) || (section_handle == NULL)) {
-        /* We have not found section - return success */
-        TRACE_FLOW_STRING("get_value_from_config", "No such section");
-        return EOK;
-    }
-
-    /* Get item */
-    error = col_get_item(section_handle, name,
-                         COL_TYPE_STRING, COL_TRAVERSE_ONELEVEL, item);
-
-    /* Make sure we free the section we found */
-    col_destroy_collection(section_handle);
-
-    TRACE_FLOW_NUMBER("get_config_item returning", error);
-    return error;
-}
-
-/* Get long long value from config item */
-static long long get_llong_config_value(struct collection_item *item,
-                                        int strict,
-                                        long long def,
-                                        int *error)
-{
-    int err;
-    const char *str;
-    char *endptr;
-    long long val = 0;
-
-    TRACE_FLOW_STRING("get_long_config_value", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-       (col_get_item_type(item) != COL_TYPE_STRING)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return def;
-    }
-
-    if (error) *error = EOK;
-
-    /* Try to parse the value */
-    str = (const char *)col_get_item_data(item);
-    errno = 0;
-    val = strtoll(str, &endptr, 10);
-    err = errno;
-
-    /* Check for various possible errors */
-    if (err != 0) {
-        TRACE_ERROR_NUMBER("Conversion failed", err);
-        if (error) *error = err;
-        return def;
-    }
-
-    /* Other error cases */
-    if ((endptr == str) || (strict && (*endptr != '\0'))) {
-        TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
-        if (error) *error = EIO;
-        return def;
-    }
-
-    TRACE_FLOW_NUMBER("get_long_config_value returning", (long)val);
-    return val;
-}
-
-/* Get unsigned long long value from config item */
-static unsigned long long get_ullong_config_value(struct collection_item *item,
-                                                  int strict,
-                                                  unsigned long long def,
-                                                  int *error)
-{
-    int err;
-    const char *str;
-    char *endptr;
-    unsigned long long val = 0;
-
-    TRACE_FLOW_STRING("get_ullong_config_value", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-       (col_get_item_type(item) != COL_TYPE_STRING)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return def;
-    }
-
-    if (error) *error = EOK;
-
-    /* Try to parse the value */
-    str = (const char *)col_get_item_data(item);
-    errno = 0;
-    val = strtoull(str, &endptr, 10);
-    err = errno;
-
-    /* Check for various possible errors */
-    if (err != 0) {
-        TRACE_ERROR_NUMBER("Conversion failed", err);
-        if (error) *error = err;
-        return def;
-    }
-
-    /* Other error cases */
-    if ((endptr == str) || (strict && (*endptr != '\0'))) {
-        TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
-        if (error) *error = EIO;
-        return def;
-    }
-
-    TRACE_FLOW_NUMBER("get_ullong_config_value returning", (long)val);
-    return val;
-}
-
-
-/* Get integer value from config item */
-int get_int_config_value(struct collection_item *item,
-                         int strict,
-                         int def,
-                         int *error)
-{
-    long long val = 0;
-    int err = 0;
-
-    TRACE_FLOW_STRING("get_int_config_value", "Entry");
-
-    val = get_llong_config_value(item, strict, def, &err);
-    if (err == 0) {
-        if ((val > INT_MAX) || (val < INT_MIN)) {
-            val = def;
-            err = ERANGE;
-        }
-    }
-
-    if (error) *error = err;
-
-    TRACE_FLOW_NUMBER("get_int_config_value returning", (int)val);
-    return (int)val;
-}
-
-/* Get unsigned integer value from config item */
-unsigned get_unsigned_config_value(struct collection_item *item,
-                                   int strict,
-                                   unsigned def,
-                                   int *error)
-{
-    unsigned long long val = 0;
-    int err = 0;
-
-    TRACE_FLOW_STRING("get_unsigned_config_value", "Entry");
-
-    val = get_ullong_config_value(item, strict, def, &err);
-    if (err == 0) {
-        if (val > UINT_MAX) {
-            val = def;
-            err = ERANGE;
-        }
-    }
-
-    if (error) *error = err;
-
-    TRACE_FLOW_NUMBER("get_unsigned_config_value returning",
-                      (unsigned)val);
-    return (unsigned)val;
-}
-
-/* Get long value from config item */
-long get_long_config_value(struct collection_item *item,
-                           int strict,
-                           long def,
-                           int *error)
-{
-    long long val = 0;
-    int err = 0;
-
-    TRACE_FLOW_STRING("get_long_config_value", "Entry");
-
-    val = get_llong_config_value(item, strict, def, &err);
-    if (err == 0) {
-        if ((val > LONG_MAX) || (val < LONG_MIN)) {
-            val = def;
-            err = ERANGE;
-        }
-    }
-
-    if (error) *error = err;
-
-    TRACE_FLOW_NUMBER("get_long_config_value returning",
-                      (long)val);
-    return (long)val;
-}
-
-/* Get unsigned long value from config item */
-unsigned long get_ulong_config_value(struct collection_item *item,
-                                     int strict,
-                                     unsigned long def,
-                                     int *error)
-{
-    unsigned long long val = 0;
-    int err = 0;
-
-    TRACE_FLOW_STRING("get_ulong_config_value", "Entry");
-
-    val = get_ullong_config_value(item, strict, def, &err);
-    if (err == 0) {
-        if (val > ULONG_MAX) {
-            val = def;
-            err = ERANGE;
-        }
-    }
-
-    if (error) *error = err;
-
-    TRACE_FLOW_NUMBER("get_ulong_config_value returning",
-                      (unsigned long)val);
-    return (unsigned long)val;
-}
-
-
-/* Get double value */
-double get_double_config_value(struct collection_item *item,
-                               int strict, double def, int *error)
-{
-    const char *str;
-    char *endptr;
-    double val = 0;
-
-    TRACE_FLOW_STRING("get_double_config_value", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-        (col_get_item_type(item) != COL_TYPE_STRING)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return def;
-    }
-
-    if (error) *error = EOK;
-
-    /* Try to parse the value */
-    str = (const char *)col_get_item_data(item);
-    errno = 0;
-    val = strtod(str, &endptr);
-
-    /* Check for various possible errors */
-    if ((errno == ERANGE) ||
-        ((errno != 0) && (val == 0)) ||
-        (endptr == str)) {
-        TRACE_ERROR_NUMBER("Conversion failed", EIO);
-        if (error) *error = EIO;
-        return def;
-    }
-
-    if (strict && (*endptr != '\0')) {
-        TRACE_ERROR_NUMBER("More characters than expected", EIO);
-        if (error) *error = EIO;
-        val = def;
-    }
-
-    TRACE_FLOW_NUMBER("get_double_config_value returning", val);
-    return val;
-}
-
-/* Get boolean value */
-unsigned char get_bool_config_value(struct collection_item *item,
-                                    unsigned char def, int *error)
-{
-    const char *str;
-    int len;
-
-    TRACE_FLOW_STRING("get_bool_config_value", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-        (col_get_item_type(item) != COL_TYPE_STRING)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return def;
-    }
-
-    if (error) *error = EOK;
-
-    str = (const char *)col_get_item_data(item);
-    len = col_get_item_length(item);
-
-    /* Try to parse the value */
-    if ((strncasecmp(str, "true", len) == 0) ||
-        (strncasecmp(str, "yes", len) == 0)) {
-        TRACE_FLOW_STRING("Returning", "true");
-        return '\1';
-    }
-    else if ((strncasecmp(str, "false", len) == 0) ||
-             (strncasecmp(str, "no", len) == 0)) {
-        TRACE_FLOW_STRING("Returning", "false");
-        return '\0';
-    }
-
-    TRACE_ERROR_STRING("Returning", "error");
-    if (error) *error = EIO;
-    return def;
-}
-
-/* Return a string out of the value */
-char *get_string_config_value(struct collection_item *item,
-                              int *error)
-{
-    char *str = NULL;
-
-    TRACE_FLOW_STRING("get_string_config_value", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-        (col_get_item_type(item) != COL_TYPE_STRING)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    str = strdup((const char *)col_get_item_data(item));
-    if (str == NULL) {
-        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
-        if (error) *error = ENOMEM;
-        return NULL;
-    }
-
-    if (error) *error = EOK;
-
-    TRACE_FLOW_STRING("get_string_config_value returning", str);
-    return str;
-}
-
-/* Get string from item */
-const char *get_const_string_config_value(struct collection_item *item, int *error)
-{
-    const char *str;
-
-    TRACE_FLOW_STRING("get_const_string_config_value", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-        (col_get_item_type(item) != COL_TYPE_STRING)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    str = (const char *)col_get_item_data(item);
-
-    if (error) *error = EOK;
-
-    TRACE_FLOW_STRING("get_const_string_config_value returning", str);
-    return str;
-}
-
-/* A special hex format is assumed.
- * The string should be taken in single quotes
- * and consist of hex encoded value two hex digits per byte.
- * Example: '0A2BFECC'
- * Case does not matter.
- */
-char *get_bin_config_value(struct collection_item *item,
-                           int *length, int *error)
-{
-    int i;
-    char *value = NULL;
-    const char *buff;
-    int size = 0;
-    unsigned char hex;
-    int len;
-    const char *str;
-
-    TRACE_FLOW_STRING("get_bin_config_value", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-        (col_get_item_type(item) != COL_TYPE_STRING)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    /* Check the length */
-    len = col_get_item_length(item)-1;
-    if ((len%2) != 0) {
-        TRACE_ERROR_STRING("Invalid length for binary data", "");
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    str = (const char *)col_get_item_data(item);
-
-    /* Is the format correct ? */
-    if ((*str != '\'') ||
-        (str[len -1] != '\'')) {
-        TRACE_ERROR_STRING("String is not escaped","");
-        if (error) *error = EIO;
-        return NULL;
-    }
-
-    /* Check that all the symbols are ok */
-    buff = str + 1;
-    len -= 2;
-    for (i = 0; i < len; i += 2) {
-        if (!isxdigit(buff[i]) || !isxdigit(buff[i + 1])) {
-            TRACE_ERROR_STRING("Invalid encoding for binary data", buff + i);
-            if (error) *error = EIO;
-            return NULL;
-        }
-    }
-
-    /* The value is good so we can allocate memory for it */
-    value = malloc(len / 2);
-    if (value == NULL) {
-        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
-        if (error) *error = ENOMEM;
-        return NULL;
-    }
-
-    /* Convert the value */
-    for (i = 0; i < len; i += 2) {
-        if (isdigit(buff[i])) {
-            if (isdigit(buff[i+1]))
-                hex = 16 * (buff[i] - '0') + (buff[i+1] - '0');
-            else
-                hex = 16 * (buff[i] - '0') + (tolower(buff[i+1]) - 'a' + 10);
-        }
-        else {
-            if (isdigit(buff[i+1]))
-                hex = 16 * (tolower(buff[i]) - 'a') + (buff[i+1] - '0');
-            else
-                hex = 16 * (tolower(buff[i]) - 'a' + 10) + (tolower(buff[i+1]) - 'a' + 10);
-        }
-
-        value[size] = (char)(hex);
-        size++;
-    }
-
-    if (error) *error = EOK;
-    if (length) *length = size;
-    TRACE_FLOW_STRING("get_bin_config_value", "Exit");
-    return value;
-}
-
-/* Function to free binary configuration value */
-void free_bin_config_value(char *value)
-{
-    if (value) free(value);
-}
-
-/* Arrays of stings */
-static char **get_str_cfg_array(struct collection_item *item,
-                                int include,
-                                const char *sep,
-                                int *size,
-                                int *error)
-{
-    char *copy = NULL;
-    char *dest = NULL;
-    char locsep[4];
-    int lensep;
-    char *buff;
-    int count = 0;
-    int len = 0;
-    int resume_len;
-    char **array;
-    char *start;
-    int i, j;
-    int dlen;
-
-    TRACE_FLOW_STRING("get_str_cfg_array", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-        (col_get_item_type(item) != COL_TYPE_STRING)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    /* Handle the separators */
-    if (sep == NULL) {
-        locsep[0] = ',';
-        locsep[1] = '\0';
-        lensep = 2;
-    }
-    else {
-        strncpy(locsep, sep, 3);
-        locsep[3] = '\0';
-        lensep = strlen(locsep) + 1;
-    }
-
-    /* Allocate memory for the copy of the string */
-    copy = malloc(col_get_item_length(item));
-    if (copy == NULL) {
-        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
-        if (error) *error = ENOMEM;
-        return NULL;
-    }
-
-    /* Loop through the string */
-    dest = copy;
-    buff = col_get_item_data(item);
-    start = buff;
-    dlen = col_get_item_length(item);
-    for(i = 0; i < dlen; i++) {
-        for(j = 0; j < lensep; j++) {
-            if(buff[i] == locsep[j]) {
-                /* If we found one of the separators trim spaces around */
-                resume_len = len;
-                while (len > 0) {
-                    if (isspace(start[len - 1])) len--;
-                    else break;
-                }
-                TRACE_INFO_STRING("Current:", start);
-                TRACE_INFO_NUMBER("Length:", len);
-                if (len > 0) {
-                    /* Save block aside */
-                    memcpy(dest, start, len);
-                    count++;
-                    dest += len;
-                    *dest = '\0';
-                    dest++;
-                }
-                else if(include) {
-                    count++;
-                    *dest = '\0';
-                    dest++;
-                }
-                if (locsep[j] == '\0') break; /* We are done */
-
-                /* Move forward and trim spaces if any */
-                start += resume_len + 1;
-                i++;
-                TRACE_INFO_STRING("Other pointer :", buff + i);
-                while ((i < dlen) && (isspace(*start))) {
-                    i++;
-                    start++;
-                }
-                len = -1; /* Len will be increased in the loop */
-                i--; /* i will be increas so we need to step back */
-                TRACE_INFO_STRING("Remaining buffer after triming spaces:", start);
-                break;
-            }
-        }
-        len++;
-    }
-
-    /* Now we know how many items are there in the list */
-    array = malloc((count + 1) * sizeof(char *));
-    if (array == NULL) {
-        free(copy);
-        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
-        if (error) *error = ENOMEM;
-        return NULL;
-    }
-
-    /* Loop again to fill in the pointers */
-    start = copy;
-    for (i = 0; i < count; i++) {
-        TRACE_INFO_STRING("Token :", start);
-        TRACE_INFO_NUMBER("Item :", i);
-        array[i] = start;
-        /* Move to next item */
-        while(*start) start++;
-        start++;
-    }
-    array[count] = NULL;
-
-    if (error) *error = EOK;
-    if (size) *size = count;
-    TRACE_FLOW_STRING("get_str_cfg_array", "Exit");
-    return array;
-}
-
-/* Get array of strings from item eliminating empty tokens */
-char **get_string_config_array(struct collection_item *item,
-                               const char *sep, int *size, int *error)
-{
-    TRACE_FLOW_STRING("get_string_config_array", "Called.");
-    return get_str_cfg_array(item, EXCLUDE_EMPTY, sep, size, error);
-}
-/* Get array of strings from item preserving empty tokens */
-char **get_raw_string_config_array(struct collection_item *item,
-                                   const char *sep, int *size, int *error)
-{
-    TRACE_FLOW_STRING("get_raw_string_config_array", "Called.");
-    return get_str_cfg_array(item, INCLUDE_EMPTY, sep, size, error);
-}
-
-/* Special function to free string config array */
-void free_string_config_array(char **str_config)
-{
-    TRACE_FLOW_STRING("free_string_config_array", "Entry");
-
-    if (str_config != NULL) {
-        if (*str_config != NULL) free(*str_config);
-        free(str_config);
-    }
-
-    TRACE_FLOW_STRING("free_string_config_array", "Exit");
-}
-
-/* Get an array of long values.
- * NOTE: For now I leave just one function that returns numeric arrays.
- * In future if we need other numeric types we can change it to do strtoll
- * internally and wrap it for backward compatibility.
- */
-long *get_long_config_array(struct collection_item *item, int *size, int *error)
-{
-    const char *str;
-    char *endptr;
-    long val = 0;
-    long *array;
-    int count = 0;
-    int err;
-
-    TRACE_FLOW_STRING("get_long_config_array", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-        (col_get_item_type(item) != COL_TYPE_STRING) ||
-        (size == NULL)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    /* Assume that we have maximum number of different numbers */
-    array = (long *)malloc(sizeof(long) * col_get_item_length(item)/2);
-    if (array == NULL) {
-        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
-        if (error) *error = ENOMEM;
-        return NULL;
-    }
-
-    /* Now parse the string */
-    str = (const char *)col_get_item_data(item);
-    while (*str) {
-
-        errno = 0;
-        val = strtol(str, &endptr, 10);
-        err = errno;
-
-        if (err) {
-            TRACE_ERROR_NUMBER("Conversion failed", err);
-            free(array);
-            if (error) *error = err;
-            return NULL;
-        }
-
-        if (endptr == str) {
-            TRACE_ERROR_NUMBER("Nothing processed", EIO);
-            free(array);
-            if (error) *error = EIO;
-            return NULL;
-        }
-
-        /* Save value */
-        array[count] = val;
-        count++;
-        /* Are we done? */
-        if (*endptr == 0) break;
-        /* Advance to the next valid number */
-        for (str = endptr; *str; str++) {
-            if (isdigit(*str) || (*str == '-') || (*str == '+')) break;
-        }
-    }
-
-    *size = count;
-    if (error) *error = EOK;
-
-    TRACE_FLOW_NUMBER("get_long_config_value returning", val);
-    return array;
-
-}
-
-/* Get an array of double values */
-double *get_double_config_array(struct collection_item *item, int *size, int *error)
-{
-    const char *str;
-    char *endptr;
-    double val = 0;
-    double *array;
-    int count = 0;
-    struct lconv *loc;
-
-    TRACE_FLOW_STRING("get_double_config_array", "Entry");
-
-    /* Do we have the item ? */
-    if ((item == NULL) ||
-        (col_get_item_type(item) != COL_TYPE_STRING) ||
-        (size == NULL)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    /* Assume that we have maximum number of different numbers */
-    array = (double *)malloc(sizeof(double) * col_get_item_length(item)/2);
-    if (array == NULL) {
-        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
-        if (error) *error = ENOMEM;
-        return NULL;
-    }
-
-    /* Get locale information so that we can check for decimal point character.
-     * Based on the man pages it is unclear if this is an allocated memory or not.
-     * Seems like it is a static thread or process local structure so
-     * I will not try to free it after use.
-     */
-    loc = localeconv();
-
-    /* Now parse the string */
-    str = (const char *)col_get_item_data(item);
-    while (*str) {
-        TRACE_INFO_STRING("String to convert",str);
-        errno = 0;
-        val = strtod(str, &endptr);
-        if ((errno == ERANGE) ||
-            ((errno != 0) && (val == 0)) ||
-            (endptr == str)) {
-            TRACE_ERROR_NUMBER("Conversion failed", EIO);
-            free(array);
-            if (error) *error = EIO;
-            return NULL;
-        }
-        /* Save value */
-        array[count] = val;
-        count++;
-        /* Are we done? */
-        if (*endptr == 0) break;
-        TRACE_INFO_STRING("End pointer after conversion",endptr);
-        /* Advance to the next valid number */
-        for (str = endptr; *str; str++) {
-            if (isdigit(*str) || (*str == '-') || (*str == '+') ||
-               /* It is ok to do this since the string is null terminated */
-               ((*str == *(loc->decimal_point)) && isdigit(str[1]))) break;
-        }
-    }
-
-    *size = count;
-    if (error) *error = EOK;
-
-    TRACE_FLOW_NUMBER("get_double_config_value returning", val);
-    return array;
-
-}
-
-
-/* Special function to free long config array */
-void free_long_config_array(long *array)
-{
-    if (array != NULL) free(array);
-}
-
-/* Special function to free double config array */
-void free_double_config_array(double *array)
-{
-    if (array != NULL) free(array);
-}
-
-/* The section array should be freed using this function */
-void free_section_list(char **section_list)
-{
-    TRACE_FLOW_STRING("free_section_list","Entry");
-
-    col_free_property_list(section_list);
-
-    TRACE_FLOW_STRING("free_section_list","Exit");
-}
-
-/* The section array should be freed using this function */
-void free_attribute_list(char **section_list)
-{
-    TRACE_FLOW_STRING("free_section_list","Entry");
-
-    col_free_property_list(section_list);
-
-    TRACE_FLOW_STRING("free_section_list","Exit");
-}
-
-
-/* Get list of sections as an array of strings.
- * Function allocates memory for the array of the sections.
- */
-char **get_section_list(struct collection_item *ini_config, int *size, int *error)
-{
-    char **list;
-
-    TRACE_FLOW_STRING("get_section_list","Entry");
-    /* Do we have the item ? */
-    if ((ini_config == NULL) ||
-        ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
-         (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0))) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    /* Pass it to the function from collection API */
-    list = col_collection_to_list(ini_config, size, error);
-
-    TRACE_FLOW_STRING("get_section_list returning", ((list == NULL) ? "NULL" : list[0]));
-    return list;
-}
-
-/* Get list of attributes in a section as an array of strings.
- * Function allocates memory for the array of the strings.
- */
-char **get_attribute_list(struct collection_item *ini_config, const char *section, int *size, int *error)
-{
-    struct collection_item *subcollection = NULL;
-    char **list;
-    int err;
-
-    TRACE_FLOW_STRING("get_attribute_list","Entry");
-    /* Do we have the item ? */
-    if ((ini_config == NULL) ||
-        ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
-         (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) ||
-        (section == NULL)) {
-        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    /* Fetch section */
-    err = col_get_collection_reference(ini_config, &subcollection, section);
-    /* Check error */
-    if (err && (subcollection == NULL)) {
-        TRACE_ERROR_NUMBER("Failed to get section", err);
-        if (error) *error = EINVAL;
-        return NULL;
-    }
-
-    /* Pass it to the function from collection API */
-    list = col_collection_to_list(subcollection, size, error);
-
-    col_destroy_collection(subcollection);
-
-    TRACE_FLOW_STRING("get_attribute_list returning", ((list == NULL) ? "NULL" : list[0]));
-    return list;
-}
diff --git a/common/ini/ini_config.h b/common/ini/ini_config.h
index a5fd4a9..3b58a11 100644
--- a/common/ini/ini_config.h
+++ b/common/ini/ini_config.h
@@ -23,6 +23,9 @@
 #ifndef INI_CONFIG_H
 #define INI_CONFIG_H
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <limits.h>
 #include <stdio.h>
 #include "collection.h"
diff --git a/common/ini/ini_defines.h b/common/ini/ini_defines.h
new file mode 100644
index 0000000..46ed00f
--- /dev/null
+++ b/common/ini/ini_defines.h
@@ -0,0 +1,74 @@
+/*
+    INI LIBRARY
+
+    Header file for the internal constants for the INI interface.
+
+    Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
+
+    INI Library is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    INI Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INI_DEFINES_H
+#define INI_DEFINES_H
+
+#define NAME_OVERHEAD   10
+
+#define SLASH           "/"
+
+
+/* Name of the special collection used to store parsing errors */
+#define FILE_ERROR_SET  "ini_file_error_set"
+
+/* Text error strings used when errors are printed out */
+#define WARNING_TXT         _("Warning")
+#define ERROR_TXT           _("Error")
+/* For parse errors */
+#define WRONG_COLLECTION    _("Passed in list is not a list of parse errors.\n")
+#define FAILED_TO_PROCCESS  _("Internal Error. Failed to process error list.\n")
+#define ERROR_HEADER        _("Parsing errors and warnings in file: %s\n")
+/* For grammar errors */
+#define WRONG_GRAMMAR       _("Passed in list is not a list of grammar errors.\n")
+#define FAILED_TO_PROC_G    _("Internal Error. Failed to process list of grammar errors.\n")
+#define ERROR_HEADER_G      _("Logical errors and warnings in file: %s\n")
+/* For validation errors */
+#define WRONG_VALIDATION    _("Passed in list is not a list of validation errors.\n")
+#define FAILED_TO_PROC_V    _("Internal Error. Failed to process list of validation errors.\n")
+#define ERROR_HEADER_V      _("Validation errors and warnings in file: %s\n")
+
+#define LINE_FORMAT         _("%s (%d) on line %d: %s\n")
+
+
+/* Codes that parsing function can return */
+#define RET_PAIR        0
+#define RET_COMMENT     1
+#define RET_SECTION     2
+#define RET_INVALID     3
+#define RET_EMPTY       4
+#define RET_EOF         5
+#define RET_ERROR       6
+
+#define INI_ERROR       "errors"
+#define INI_ERROR_NAME  "errname"
+
+/* Internal sizes. MAX_KEY is defined in config.h */
+#define MAX_VALUE       PATH_MAX
+#define BUFFER_SIZE     MAX_KEY + MAX_VALUE + 3
+
+/* Beffer length used for int to string conversions */
+#define CONVERSION_BUFFER 80
+
+/* Different error string functions can be passed as callbacks */
+typedef const char * (*error_fn)(int error);
+
+#endif
diff --git a/common/ini/ini_get_array.c b/common/ini/ini_get_array.c
new file mode 100644
index 0000000..c2c6362
--- /dev/null
+++ b/common/ini/ini_get_array.c
@@ -0,0 +1,354 @@
+/*
+    INI LIBRARY
+
+    Value interpretation functions for arrays of values
+    and corresponding memory cleanup functions.
+
+    Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
+
+    INI Library is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    INI Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <locale.h>
+#include "config.h"
+#include "trace.h"
+#include "collection.h"
+#include "collection_tools.h"
+#include "ini_defines.h"
+#include "ini_config.h"
+
+/*
+ * Internal contants to indicate how
+ * to process the lists of strings.
+ */
+#define EXCLUDE_EMPTY   0
+#define INCLUDE_EMPTY   1
+
+/* Arrays of stings */
+static char **get_str_cfg_array(struct collection_item *item,
+                                int include,
+                                const char *sep,
+                                int *size,
+                                int *error)
+{
+    char *copy = NULL;
+    char *dest = NULL;
+    char locsep[4];
+    int lensep;
+    char *buff;
+    int count = 0;
+    int len = 0;
+    int resume_len;
+    char **array;
+    char *start;
+    int i, j;
+    int dlen;
+
+    TRACE_FLOW_STRING("get_str_cfg_array", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+        (col_get_item_type(item) != COL_TYPE_STRING)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    /* Handle the separators */
+    if (sep == NULL) {
+        locsep[0] = ',';
+        locsep[1] = '\0';
+        lensep = 2;
+    }
+    else {
+        strncpy(locsep, sep, 3);
+        locsep[3] = '\0';
+        lensep = strlen(locsep) + 1;
+    }
+
+    /* Allocate memory for the copy of the string */
+    copy = malloc(col_get_item_length(item));
+    if (copy == NULL) {
+        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+        if (error) *error = ENOMEM;
+        return NULL;
+    }
+
+    /* Loop through the string */
+    dest = copy;
+    buff = col_get_item_data(item);
+    start = buff;
+    dlen = col_get_item_length(item);
+    for(i = 0; i < dlen; i++) {
+        for(j = 0; j < lensep; j++) {
+            if(buff[i] == locsep[j]) {
+                /* If we found one of the separators trim spaces around */
+                resume_len = len;
+                while (len > 0) {
+                    if (isspace(start[len - 1])) len--;
+                    else break;
+                }
+                TRACE_INFO_STRING("Current:", start);
+                TRACE_INFO_NUMBER("Length:", len);
+                if (len > 0) {
+                    /* Save block aside */
+                    memcpy(dest, start, len);
+                    count++;
+                    dest += len;
+                    *dest = '\0';
+                    dest++;
+                }
+                else if(include) {
+                    count++;
+                    *dest = '\0';
+                    dest++;
+                }
+                if (locsep[j] == '\0') break; /* We are done */
+
+                /* Move forward and trim spaces if any */
+                start += resume_len + 1;
+                i++;
+                TRACE_INFO_STRING("Other pointer :", buff + i);
+                while ((i < dlen) && (isspace(*start))) {
+                    i++;
+                    start++;
+                }
+                len = -1; /* Len will be increased in the loop */
+                i--; /* i will be increas so we need to step back */
+                TRACE_INFO_STRING("Remaining buffer after triming spaces:", start);
+                break;
+            }
+        }
+        len++;
+    }
+
+    /* Now we know how many items are there in the list */
+    array = malloc((count + 1) * sizeof(char *));
+    if (array == NULL) {
+        free(copy);
+        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+        if (error) *error = ENOMEM;
+        return NULL;
+    }
+
+    /* Loop again to fill in the pointers */
+    start = copy;
+    for (i = 0; i < count; i++) {
+        TRACE_INFO_STRING("Token :", start);
+        TRACE_INFO_NUMBER("Item :", i);
+        array[i] = start;
+        /* Move to next item */
+        while(*start) start++;
+        start++;
+    }
+    array[count] = NULL;
+
+    if (error) *error = EOK;
+    if (size) *size = count;
+    TRACE_FLOW_STRING("get_str_cfg_array", "Exit");
+    return array;
+}
+
+/* Get array of strings from item eliminating empty tokens */
+char **get_string_config_array(struct collection_item *item,
+                               const char *sep, int *size, int *error)
+{
+    TRACE_FLOW_STRING("get_string_config_array", "Called.");
+    return get_str_cfg_array(item, EXCLUDE_EMPTY, sep, size, error);
+}
+/* Get array of strings from item preserving empty tokens */
+char **get_raw_string_config_array(struct collection_item *item,
+                                   const char *sep, int *size, int *error)
+{
+    TRACE_FLOW_STRING("get_raw_string_config_array", "Called.");
+    return get_str_cfg_array(item, INCLUDE_EMPTY, sep, size, error);
+}
+
+/* Special function to free string config array */
+void free_string_config_array(char **str_config)
+{
+    TRACE_FLOW_STRING("free_string_config_array", "Entry");
+
+    if (str_config != NULL) {
+        if (*str_config != NULL) free(*str_config);
+        free(str_config);
+    }
+
+    TRACE_FLOW_STRING("free_string_config_array", "Exit");
+}
+
+/* Get an array of long values.
+ * NOTE: For now I leave just one function that returns numeric arrays.
+ * In future if we need other numeric types we can change it to do strtoll
+ * internally and wrap it for backward compatibility.
+ */
+long *get_long_config_array(struct collection_item *item, int *size, int *error)
+{
+    const char *str;
+    char *endptr;
+    long val = 0;
+    long *array;
+    int count = 0;
+    int err;
+
+    TRACE_FLOW_STRING("get_long_config_array", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+        (col_get_item_type(item) != COL_TYPE_STRING) ||
+        (size == NULL)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    /* Assume that we have maximum number of different numbers */
+    array = (long *)malloc(sizeof(long) * col_get_item_length(item)/2);
+    if (array == NULL) {
+        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+        if (error) *error = ENOMEM;
+        return NULL;
+    }
+
+    /* Now parse the string */
+    str = (const char *)col_get_item_data(item);
+    while (*str) {
+
+        errno = 0;
+        val = strtol(str, &endptr, 10);
+        err = errno;
+
+        if (err) {
+            TRACE_ERROR_NUMBER("Conversion failed", err);
+            free(array);
+            if (error) *error = err;
+            return NULL;
+        }
+
+        if (endptr == str) {
+            TRACE_ERROR_NUMBER("Nothing processed", EIO);
+            free(array);
+            if (error) *error = EIO;
+            return NULL;
+        }
+
+        /* Save value */
+        array[count] = val;
+        count++;
+        /* Are we done? */
+        if (*endptr == 0) break;
+        /* Advance to the next valid number */
+        for (str = endptr; *str; str++) {
+            if (isdigit(*str) || (*str == '-') || (*str == '+')) break;
+        }
+    }
+
+    *size = count;
+    if (error) *error = EOK;
+
+    TRACE_FLOW_NUMBER("get_long_config_value returning", val);
+    return array;
+
+}
+
+/* Get an array of double values */
+double *get_double_config_array(struct collection_item *item, int *size, int *error)
+{
+    const char *str;
+    char *endptr;
+    double val = 0;
+    double *array;
+    int count = 0;
+    struct lconv *loc;
+
+    TRACE_FLOW_STRING("get_double_config_array", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+        (col_get_item_type(item) != COL_TYPE_STRING) ||
+        (size == NULL)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    /* Assume that we have maximum number of different numbers */
+    array = (double *)malloc(sizeof(double) * col_get_item_length(item)/2);
+    if (array == NULL) {
+        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+        if (error) *error = ENOMEM;
+        return NULL;
+    }
+
+    /* Get locale information so that we can check for decimal point character.
+     * Based on the man pages it is unclear if this is an allocated memory or not.
+     * Seems like it is a static thread or process local structure so
+     * I will not try to free it after use.
+     */
+    loc = localeconv();
+
+    /* Now parse the string */
+    str = (const char *)col_get_item_data(item);
+    while (*str) {
+        TRACE_INFO_STRING("String to convert",str);
+        errno = 0;
+        val = strtod(str, &endptr);
+        if ((errno == ERANGE) ||
+            ((errno != 0) && (val == 0)) ||
+            (endptr == str)) {
+            TRACE_ERROR_NUMBER("Conversion failed", EIO);
+            free(array);
+            if (error) *error = EIO;
+            return NULL;
+        }
+        /* Save value */
+        array[count] = val;
+        count++;
+        /* Are we done? */
+        if (*endptr == 0) break;
+        TRACE_INFO_STRING("End pointer after conversion",endptr);
+        /* Advance to the next valid number */
+        for (str = endptr; *str; str++) {
+            if (isdigit(*str) || (*str == '-') || (*str == '+') ||
+               /* It is ok to do this since the string is null terminated */
+               ((*str == *(loc->decimal_point)) && isdigit(str[1]))) break;
+        }
+    }
+
+    *size = count;
+    if (error) *error = EOK;
+
+    TRACE_FLOW_NUMBER("get_double_config_value returning", val);
+    return array;
+
+}
+
+
+/* Special function to free long config array */
+void free_long_config_array(long *array)
+{
+    if (array != NULL) free(array);
+}
+
+/* Special function to free double config array */
+void free_double_config_array(double *array)
+{
+    if (array != NULL) free(array);
+}
diff --git a/common/ini/ini_get_value.c b/common/ini/ini_get_value.c
new file mode 100644
index 0000000..70d940f
--- /dev/null
+++ b/common/ini/ini_get_value.c
@@ -0,0 +1,523 @@
+/*
+    INI LIBRARY
+
+    Value interpretation functions for single values
+    and corresponding memory cleanup functions.
+
+    Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
+
+    INI Library is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    INI Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "config.h"
+#include "trace.h"
+#include "collection.h"
+#include "collection_tools.h"
+#include "ini_defines.h"
+#include "ini_config.h"
+
+/* Function to get value from the configuration handle */
+int get_config_item(const char *section,
+                    const char *name,
+                    struct collection_item *ini_config,
+                    struct collection_item **item)
+{
+    int error = EOK;
+    struct collection_item *section_handle = NULL;
+    const char *to_find;
+    char default_section[] = INI_DEFAULT_SECTION;
+
+    TRACE_FLOW_STRING("get_config_item", "Entry");
+
+    /* Do we have the accepting memory ? */
+    if (item == NULL) {
+        TRACE_ERROR_NUMBER("No buffer - invalid argument.", EINVAL);
+        return EINVAL;
+    }
+
+    /* Is the collection of a right type */
+    if ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
+        (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) {
+        TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
+        return EINVAL;
+    }
+
+    *item = NULL;
+
+    if (section == NULL) to_find = default_section;
+    else to_find = section;
+
+    TRACE_INFO_STRING("Getting Name:", name);
+    TRACE_INFO_STRING("In Section:", section);
+
+    /* Get Subcollection */
+    error = col_get_collection_reference(ini_config, &section_handle, to_find);
+    /* Check error */
+    if (error && (error != ENOENT)) {
+        TRACE_ERROR_NUMBER("Failed to get section", error);
+        return error;
+    }
+
+    /* Did we find a section */
+    if ((error == ENOENT) || (section_handle == NULL)) {
+        /* We have not found section - return success */
+        TRACE_FLOW_STRING("get_value_from_config", "No such section");
+        return EOK;
+    }
+
+    /* Get item */
+    error = col_get_item(section_handle, name,
+                         COL_TYPE_STRING, COL_TRAVERSE_ONELEVEL, item);
+
+    /* Make sure we free the section we found */
+    col_destroy_collection(section_handle);
+
+    TRACE_FLOW_NUMBER("get_config_item returning", error);
+    return error;
+}
+
+/* Get long long value from config item */
+static long long get_llong_config_value(struct collection_item *item,
+                                        int strict,
+                                        long long def,
+                                        int *error)
+{
+    int err;
+    const char *str;
+    char *endptr;
+    long long val = 0;
+
+    TRACE_FLOW_STRING("get_long_config_value", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+       (col_get_item_type(item) != COL_TYPE_STRING)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return def;
+    }
+
+    if (error) *error = EOK;
+
+    /* Try to parse the value */
+    str = (const char *)col_get_item_data(item);
+    errno = 0;
+    val = strtoll(str, &endptr, 10);
+    err = errno;
+
+    /* Check for various possible errors */
+    if (err != 0) {
+        TRACE_ERROR_NUMBER("Conversion failed", err);
+        if (error) *error = err;
+        return def;
+    }
+
+    /* Other error cases */
+    if ((endptr == str) || (strict && (*endptr != '\0'))) {
+        TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
+        if (error) *error = EIO;
+        return def;
+    }
+
+    TRACE_FLOW_NUMBER("get_long_config_value returning", (long)val);
+    return val;
+}
+
+/* Get unsigned long long value from config item */
+static unsigned long long get_ullong_config_value(struct collection_item *item,
+                                                  int strict,
+                                                  unsigned long long def,
+                                                  int *error)
+{
+    int err;
+    const char *str;
+    char *endptr;
+    unsigned long long val = 0;
+
+    TRACE_FLOW_STRING("get_ullong_config_value", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+       (col_get_item_type(item) != COL_TYPE_STRING)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return def;
+    }
+
+    if (error) *error = EOK;
+
+    /* Try to parse the value */
+    str = (const char *)col_get_item_data(item);
+    errno = 0;
+    val = strtoull(str, &endptr, 10);
+    err = errno;
+
+    /* Check for various possible errors */
+    if (err != 0) {
+        TRACE_ERROR_NUMBER("Conversion failed", err);
+        if (error) *error = err;
+        return def;
+    }
+
+    /* Other error cases */
+    if ((endptr == str) || (strict && (*endptr != '\0'))) {
+        TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
+        if (error) *error = EIO;
+        return def;
+    }
+
+    TRACE_FLOW_NUMBER("get_ullong_config_value returning", (long)val);
+    return val;
+}
+
+
+/* Get integer value from config item */
+int get_int_config_value(struct collection_item *item,
+                         int strict,
+                         int def,
+                         int *error)
+{
+    long long val = 0;
+    int err = 0;
+
+    TRACE_FLOW_STRING("get_int_config_value", "Entry");
+
+    val = get_llong_config_value(item, strict, def, &err);
+    if (err == 0) {
+        if ((val > INT_MAX) || (val < INT_MIN)) {
+            val = def;
+            err = ERANGE;
+        }
+    }
+
+    if (error) *error = err;
+
+    TRACE_FLOW_NUMBER("get_int_config_value returning", (int)val);
+    return (int)val;
+}
+
+/* Get unsigned integer value from config item */
+unsigned get_unsigned_config_value(struct collection_item *item,
+                                   int strict,
+                                   unsigned def,
+                                   int *error)
+{
+    unsigned long long val = 0;
+    int err = 0;
+
+    TRACE_FLOW_STRING("get_unsigned_config_value", "Entry");
+
+    val = get_ullong_config_value(item, strict, def, &err);
+    if (err == 0) {
+        if (val > UINT_MAX) {
+            val = def;
+            err = ERANGE;
+        }
+    }
+
+    if (error) *error = err;
+
+    TRACE_FLOW_NUMBER("get_unsigned_config_value returning",
+                      (unsigned)val);
+    return (unsigned)val;
+}
+
+/* Get long value from config item */
+long get_long_config_value(struct collection_item *item,
+                           int strict,
+                           long def,
+                           int *error)
+{
+    long long val = 0;
+    int err = 0;
+
+    TRACE_FLOW_STRING("get_long_config_value", "Entry");
+
+    val = get_llong_config_value(item, strict, def, &err);
+    if (err == 0) {
+        if ((val > LONG_MAX) || (val < LONG_MIN)) {
+            val = def;
+            err = ERANGE;
+        }
+    }
+
+    if (error) *error = err;
+
+    TRACE_FLOW_NUMBER("get_long_config_value returning",
+                      (long)val);
+    return (long)val;
+}
+
+/* Get unsigned long value from config item */
+unsigned long get_ulong_config_value(struct collection_item *item,
+                                     int strict,
+                                     unsigned long def,
+                                     int *error)
+{
+    unsigned long long val = 0;
+    int err = 0;
+
+    TRACE_FLOW_STRING("get_ulong_config_value", "Entry");
+
+    val = get_ullong_config_value(item, strict, def, &err);
+    if (err == 0) {
+        if (val > ULONG_MAX) {
+            val = def;
+            err = ERANGE;
+        }
+    }
+
+    if (error) *error = err;
+
+    TRACE_FLOW_NUMBER("get_ulong_config_value returning",
+                      (unsigned long)val);
+    return (unsigned long)val;
+}
+
+
+/* Get double value */
+double get_double_config_value(struct collection_item *item,
+                               int strict, double def, int *error)
+{
+    const char *str;
+    char *endptr;
+    double val = 0;
+
+    TRACE_FLOW_STRING("get_double_config_value", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+        (col_get_item_type(item) != COL_TYPE_STRING)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return def;
+    }
+
+    if (error) *error = EOK;
+
+    /* Try to parse the value */
+    str = (const char *)col_get_item_data(item);
+    errno = 0;
+    val = strtod(str, &endptr);
+
+    /* Check for various possible errors */
+    if ((errno == ERANGE) ||
+        ((errno != 0) && (val == 0)) ||
+        (endptr == str)) {
+        TRACE_ERROR_NUMBER("Conversion failed", EIO);
+        if (error) *error = EIO;
+        return def;
+    }
+
+    if (strict && (*endptr != '\0')) {
+        TRACE_ERROR_NUMBER("More characters than expected", EIO);
+        if (error) *error = EIO;
+        val = def;
+    }
+
+    TRACE_FLOW_NUMBER("get_double_config_value returning", val);
+    return val;
+}
+
+/* Get boolean value */
+unsigned char get_bool_config_value(struct collection_item *item,
+                                    unsigned char def, int *error)
+{
+    const char *str;
+    int len;
+
+    TRACE_FLOW_STRING("get_bool_config_value", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+        (col_get_item_type(item) != COL_TYPE_STRING)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return def;
+    }
+
+    if (error) *error = EOK;
+
+    str = (const char *)col_get_item_data(item);
+    len = col_get_item_length(item);
+
+    /* Try to parse the value */
+    if ((strncasecmp(str, "true", len) == 0) ||
+        (strncasecmp(str, "yes", len) == 0)) {
+        TRACE_FLOW_STRING("Returning", "true");
+        return '\1';
+    }
+    else if ((strncasecmp(str, "false", len) == 0) ||
+             (strncasecmp(str, "no", len) == 0)) {
+        TRACE_FLOW_STRING("Returning", "false");
+        return '\0';
+    }
+
+    TRACE_ERROR_STRING("Returning", "error");
+    if (error) *error = EIO;
+    return def;
+}
+
+/* Return a string out of the value */
+char *get_string_config_value(struct collection_item *item,
+                              int *error)
+{
+    char *str = NULL;
+
+    TRACE_FLOW_STRING("get_string_config_value", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+        (col_get_item_type(item) != COL_TYPE_STRING)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    str = strdup((const char *)col_get_item_data(item));
+    if (str == NULL) {
+        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+        if (error) *error = ENOMEM;
+        return NULL;
+    }
+
+    if (error) *error = EOK;
+
+    TRACE_FLOW_STRING("get_string_config_value returning", str);
+    return str;
+}
+
+/* Get string from item */
+const char *get_const_string_config_value(struct collection_item *item, int *error)
+{
+    const char *str;
+
+    TRACE_FLOW_STRING("get_const_string_config_value", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+        (col_get_item_type(item) != COL_TYPE_STRING)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    str = (const char *)col_get_item_data(item);
+
+    if (error) *error = EOK;
+
+    TRACE_FLOW_STRING("get_const_string_config_value returning", str);
+    return str;
+}
+
+/* A special hex format is assumed.
+ * The string should be taken in single quotes
+ * and consist of hex encoded value two hex digits per byte.
+ * Example: '0A2BFECC'
+ * Case does not matter.
+ */
+char *get_bin_config_value(struct collection_item *item,
+                           int *length, int *error)
+{
+    int i;
+    char *value = NULL;
+    const char *buff;
+    int size = 0;
+    unsigned char hex;
+    int len;
+    const char *str;
+
+    TRACE_FLOW_STRING("get_bin_config_value", "Entry");
+
+    /* Do we have the item ? */
+    if ((item == NULL) ||
+        (col_get_item_type(item) != COL_TYPE_STRING)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    /* Check the length */
+    len = col_get_item_length(item)-1;
+    if ((len%2) != 0) {
+        TRACE_ERROR_STRING("Invalid length for binary data", "");
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    str = (const char *)col_get_item_data(item);
+
+    /* Is the format correct ? */
+    if ((*str != '\'') ||
+        (str[len -1] != '\'')) {
+        TRACE_ERROR_STRING("String is not escaped","");
+        if (error) *error = EIO;
+        return NULL;
+    }
+
+    /* Check that all the symbols are ok */
+    buff = str + 1;
+    len -= 2;
+    for (i = 0; i < len; i += 2) {
+        if (!isxdigit(buff[i]) || !isxdigit(buff[i + 1])) {
+            TRACE_ERROR_STRING("Invalid encoding for binary data", buff + i);
+            if (error) *error = EIO;
+            return NULL;
+        }
+    }
+
+    /* The value is good so we can allocate memory for it */
+    value = malloc(len / 2);
+    if (value == NULL) {
+        TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+        if (error) *error = ENOMEM;
+        return NULL;
+    }
+
+    /* Convert the value */
+    for (i = 0; i < len; i += 2) {
+        if (isdigit(buff[i])) {
+            if (isdigit(buff[i+1]))
+                hex = 16 * (buff[i] - '0') + (buff[i+1] - '0');
+            else
+                hex = 16 * (buff[i] - '0') + (tolower(buff[i+1]) - 'a' + 10);
+        }
+        else {
+            if (isdigit(buff[i+1]))
+                hex = 16 * (tolower(buff[i]) - 'a') + (buff[i+1] - '0');
+            else
+                hex = 16 * (tolower(buff[i]) - 'a' + 10) + (tolower(buff[i+1]) - 'a' + 10);
+        }
+
+        value[size] = (char)(hex);
+        size++;
+    }
+
+    if (error) *error = EOK;
+    if (length) *length = size;
+    TRACE_FLOW_STRING("get_bin_config_value", "Exit");
+    return value;
+}
+
+/* Function to free binary configuration value */
+void free_bin_config_value(char *value)
+{
+    if (value) free(value);
+}
diff --git a/common/ini/ini_list.c b/common/ini/ini_list.c
new file mode 100644
index 0000000..95894a1
--- /dev/null
+++ b/common/ini/ini_list.c
@@ -0,0 +1,123 @@
+/*
+    INI LIBRARY
+
+    Value interpretation functions for single values
+    and corresponding memory cleanup functions.
+
+    Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
+
+    INI Library is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    INI Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+/*
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+*/
+#include "config.h"
+#include "trace.h"
+#include "collection.h"
+#include "collection_tools.h"
+#include "ini_config.h"
+
+
+/* The section array should be freed using this function */
+void free_section_list(char **section_list)
+{
+    TRACE_FLOW_STRING("free_section_list","Entry");
+
+    col_free_property_list(section_list);
+
+    TRACE_FLOW_STRING("free_section_list","Exit");
+}
+
+/* The section array should be freed using this function */
+void free_attribute_list(char **section_list)
+{
+    TRACE_FLOW_STRING("free_attribute_list","Entry");
+
+    col_free_property_list(section_list);
+
+    TRACE_FLOW_STRING("free_attribute_list","Exit");
+}
+
+
+/* Get list of sections as an array of strings.
+ * Function allocates memory for the array of the sections.
+ */
+char **get_section_list(struct collection_item *ini_config, int *size, int *error)
+{
+    char **list;
+
+    TRACE_FLOW_STRING("get_section_list","Entry");
+    /* Do we have the item ? */
+    if ((ini_config == NULL) ||
+        ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
+         (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0))) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    /* Pass it to the function from collection API */
+    list = col_collection_to_list(ini_config, size, error);
+
+    TRACE_FLOW_STRING("get_section_list returning", ((list == NULL) ? "NULL" : list[0]));
+    return list;
+}
+
+/* Get list of attributes in a section as an array of strings.
+ * Function allocates memory for the array of the strings.
+ */
+char **get_attribute_list(struct collection_item *ini_config, const char *section, int *size, int *error)
+{
+    struct collection_item *subcollection = NULL;
+    char **list;
+    int err;
+
+    TRACE_FLOW_STRING("get_attribute_list","Entry");
+    /* Do we have the item ? */
+    if ((ini_config == NULL) ||
+        ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
+         (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) ||
+        (section == NULL)) {
+        TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    /* Fetch section */
+    err = col_get_collection_reference(ini_config, &subcollection, section);
+    /* Check error */
+    if (err && (subcollection == NULL)) {
+        TRACE_ERROR_NUMBER("Failed to get section", err);
+        if (error) *error = EINVAL;
+        return NULL;
+    }
+
+    /* Pass it to the function from collection API */
+    list = col_collection_to_list(subcollection, size, error);
+
+    col_destroy_collection(subcollection);
+
+    TRACE_FLOW_STRING("get_attribute_list returning", ((list == NULL) ? "NULL" : list[0]));
+    return list;
+}
diff --git a/common/ini/ini_parse.c b/common/ini/ini_parse.c
new file mode 100644
index 0000000..be733d6
--- /dev/null
+++ b/common/ini/ini_parse.c
@@ -0,0 +1,190 @@
+/*
+    INI LIBRARY
+
+    Low level parsing functions
+
+    Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
+
+    INI Library is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    INI Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include "config.h"
+#include "trace.h"
+#include "ini_parse.h"
+#include "ini_defines.h"
+#include "ini_config.h"
+
+
+/* Reads a line from the file */
+int read_line(FILE *file,
+              char *buf,
+              int read_size,
+              char **key, char **value,
+              int *length,
+              int *ext_error)
+{
+
+    char *res;
+    int len;
+    char *buffer;
+    int i;
+    char *eq;
+
+    TRACE_FLOW_STRING("read_line", "Entry");
+
+    *ext_error = 0;
+
+    buffer = buf;
+
+    /* Get data from file */
+    res = fgets(buffer, read_size - 1, file);
+    if (res == NULL) {
+        TRACE_ERROR_STRING("Read nothing", "");
+        return RET_EOF;
+    }
+
+    /* Make sure the buffer is NULL terminated */
+    buffer[read_size - 1] = '\0';
+
+    len = strlen(buffer);
+    if (len == 0) {
+        TRACE_ERROR_STRING("Nothing was read.", "");
+        return RET_EMPTY;
+    }
+
+    /* Added \r just in case we deal with Windows in future */
+    if ((buffer[len - 1] != '\n') && (buffer[len - 1] != '\r')) {
+        TRACE_ERROR_STRING("String it too big!", "");
+        *ext_error = ERR_LONGDATA;
+        return RET_ERROR;
+    }
+
+    /* Ingnore comments */
+    if ((*buffer == ';') || (*buffer == '#')) {
+        TRACE_FLOW_STRING("Comment", buf);
+        return RET_COMMENT;
+    }
+
+    TRACE_INFO_STRING("BUFFER before trimming:", buffer);
+
+    /* Trucate trailing spaces and CRs */
+    /* Make sure not to step before the beginning */
+    while (len && isspace(buffer[len - 1])) {
+        buffer[len - 1] = '\0';
+        len--;
+    }
+
+    TRACE_INFO_STRING("BUFFER after trimming trailing spaces:", buffer);
+
+    /* Trucate leading spaces  */
+    while (isspace(*buffer)) {
+        buffer++;
+        len--;
+    }
+
+    TRACE_INFO_STRING("BUFFER after trimming leading spaces:", buffer);
+    TRACE_INFO_NUMBER("BUFFER length:", len);
+
+    /* Empty line */
+    if (len == 0) {
+        TRACE_FLOW_STRING("Empty line", buf);
+        return RET_EMPTY;
+    }
+
+    /* Section */
+    if (*buffer == '[') {
+        if (buffer[len-1] != ']') {
+            TRACE_ERROR_STRING("Invalid format for section", buf);
+            *ext_error = ERR_NOCLOSESEC;
+            return RET_ERROR;
+        }
+        buffer++;
+        len--;
+        while (isspace(*buffer)) {
+            buffer++;
+            len--;
+        }
+        if (len == 0) {
+            TRACE_ERROR_STRING("Invalid format for section", buf);
+            *ext_error = ERR_NOSECTION;
+            return RET_ERROR;
+        }
+
+        buffer[len - 1] = '\0';
+        len--;
+        while (isspace(buffer[len - 1])) {
+            buffer[len - 1] = '\0';
+            len--;
+        }
+        if (len >= MAX_KEY) {
+            TRACE_ERROR_STRING("Section name is too long", buf);
+            *ext_error = ERR_SECTIONLONG;
+            return RET_ERROR;
+        }
+
+        *key = buffer;
+        return RET_SECTION;
+    }
+
+    /* Assume we are dealing with the K-V here */
+    /* Find "=" */
+    eq = strchr(buffer, '=');
+    if (eq == NULL) {
+        TRACE_ERROR_STRING("No equal sign", buf);
+        *ext_error = ERR_NOEQUAL;
+        return RET_INVALID;
+    }
+
+    len -= eq-buffer;
+
+    /* Strip spaces around "=" */
+    i = eq - buffer - 1;
+    while ((i >= 0) && isspace(buffer[i])) i--;
+    if (i < 0) {
+        TRACE_ERROR_STRING("No key", buf);
+        *ext_error = ERR_NOKEY;
+        return RET_INVALID;
+    }
+
+    /* Copy key into provided buffer */
+    if(i >= MAX_KEY) {
+        TRACE_ERROR_STRING("Section name is too long", buf);
+        *ext_error = ERR_LONGKEY;
+        return RET_INVALID;
+    }
+    *key = buffer;
+    buffer[i + 1] = '\0';
+    TRACE_INFO_STRING("KEY:", *key);
+
+    eq++;
+    len--;
+    while (isspace(*eq)) {
+        eq++;
+        len--;
+    }
+
+    *value = eq;
+    /* Make sure we include trailing 0 into data */
+    *length = len + 1;
+
+    TRACE_INFO_STRING("VALUE:", *value);
+    TRACE_INFO_NUMBER("LENGTH:", *length);
+
+    TRACE_FLOW_STRING("read_line", "Exit");
+    return RET_PAIR;
+}
diff --git a/common/ini/ini_parse.h b/common/ini/ini_parse.h
new file mode 100644
index 0000000..56a0db9
--- /dev/null
+++ b/common/ini/ini_parse.h
@@ -0,0 +1,36 @@
+/*
+    INI LIBRARY
+
+    Header file for the internal parsing functions.
+
+    Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
+
+    INI Library is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    INI Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INI_PARSE_H
+#define INI_PARSE_H
+
+#include <stdio.h>
+
+/* Internal function to read line from INI file */
+int read_line(FILE *file,
+              char *buf,
+              int read_size,
+              char **key,
+              char **value,
+              int *length,
+              int *ext_error);
+
+#endif
diff --git a/common/ini/ini_print.c b/common/ini/ini_print.c
new file mode 100644
index 0000000..e8f9186
--- /dev/null
+++ b/common/ini/ini_print.c
@@ -0,0 +1,387 @@
+/*
+    INI LIBRARY
+
+    Parsing functions of the INI interface
+
+    Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+    INI Library is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    INI Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include "config.h"
+/* For error text */
+#include <libintl.h>
+#define _(String) gettext (String)
+/* INI file is used as a collection */
+#include "trace.h"
+#include "collection.h"
+#include "collection_tools.h"
+#include "ini_defines.h"
+#include "ini_config.h"
+
+
+/*============================================================*/
+/* The following classes moved here from the public header
+ * They are reserved for future use.
+ *
+ * NOTE: before exposing these constants again in the common header
+ * check that the class IDs did not get reused over time by
+ * other classes.
+ */
+/** @brief Collection of grammar errors.
+ *
+ * Reserved for future use.
+ */
+#define COL_CLASS_INI_GERROR      COL_CLASS_INI_BASE + 5
+/** @brief Collection of validation errors.
+ *
+ * Reserved for future use.
+ */
+#define COL_CLASS_INI_VERROR      COL_CLASS_INI_BASE + 6
+
+#ifdef HAVE_VALIDATION
+
+/** @brief Collection of lines from the INI file.
+ *
+ * Reserved for future use
+ */
+#define COL_CLASS_INI_LINES       COL_CLASS_INI_BASE + 7
+
+#endif /* HAVE_VALIDATION */
+/*============================================================*/
+
+
+/* Function to return parsing error */
+const char *parsing_error_str(int parsing_error)
+{
+    const char *placeholder= _("Unknown pasing error.");
+    const char *str_error[] = { _("Data is too long."),
+                                _("No closing bracket."),
+                                _("Section name is missing."),
+                                _("Section name is too long."),
+                                _("Equal sign is missing."),
+                                _("Property name is missing."),
+                                _("Property name is too long.")
+    };
+
+    /* Check the range */
+    if ((parsing_error < 1) || (parsing_error > ERR_MAXPARSE))
+            return placeholder;
+    else
+            return str_error[parsing_error-1];
+}
+
+/* Function to return grammar error.
+ * This function is currently not used.
+ * It is planned to be used by the INI
+ * file grammar parser.
+ *
+ * The following doxygen description is moved here.
+ * When the function gets exposed move it into
+ * the header file.
+ */
+/** @brief Function to return a grammar error in template.
+ *
+ * EXPERIMENTAL. Reserved for future use.
+ *
+ * This error is returned when the template
+ * is translated into the grammar object.
+ *
+ * @param[in] parsing_error    Error code for the grammar error.
+ *
+ * @return Error string.
+ */
+
+const char *grammar_error_str(int grammar_error)
+{
+    const char *placeholder= _("Unknown grammar error.");
+    /* THIS IS A TEMPORARY PLACEHOLDER !!!! */
+    const char *str_error[] = { _(""),
+                                _(""),
+                                _(""),
+                                _(""),
+                                _(""),
+                                _(""),
+                                _("")
+    };
+
+    /* Check the range */
+    if ((grammar_error < 1) || (grammar_error > ERR_MAXGRAMMAR))
+            return placeholder;
+    else
+            return str_error[grammar_error-1];
+}
+
+/* Function to return validation error.
+ * This function is currently not used.
+ * It is planned to be used by the INI
+ * file grammar validator.
+ *
+ * The following doxygen description is moved here.
+ * When the function gets exposed move it into
+ * the header file.
+ */
+/** @brief Function to return a validation error.
+ *
+ * EXPERIMENTAL. Reserved for future use.
+ *
+ * This is the error that it is returned when
+ * the INI file is validated against the
+ * grammar object.
+ *
+ * @param[in] parsing_error    Error code for the validation error.
+ *
+ * @return Error string.
+ */
+const char *validation_error_str(int validation_error)
+{
+    const char *placeholder= _("Unknown validation error.");
+    /* THIS IS A TEMPORARY PLACEHOLDER !!!! */
+    const char *str_error[] = { _(""),
+                                _(""),
+                                _(""),
+                                _(""),
+                                _(""),
+                                _(""),
+                                _("")
+    };
+
+    /* Check the range */
+    if ((validation_error < 1) || (validation_error > ERR_MAXVALID))
+            return placeholder;
+    else
+            return str_error[validation_error-1];
+}
+
+
+
+/* Internal function that prints errors */
+static void print_error_list(FILE *file,
+                             struct collection_item *error_list,
+                             int cclass,
+                             char *wrong_col_error,
+                             char *failed_to_process,
+                             char *error_header,
+                             char *line_format,
+                             error_fn error_function)
+{
+    struct collection_iterator *iterator;
+    int error;
+    struct collection_item *item = NULL;
+    struct parse_error *pe;
+    unsigned int count;
+
+    TRACE_FLOW_STRING("print_error_list", "Entry");
+
+    /* If we have something to print print it */
+    if (error_list == NULL) {
+        TRACE_ERROR_STRING("No error list","");
+        return;
+    }
+
+    /* Make sure we go the right collection */
+    if (!col_is_of_class(error_list, cclass)) {
+        TRACE_ERROR_STRING("Wrong collection class:", wrong_col_error);
+        fprintf(file,"%s\n", wrong_col_error);
+        return;
+    }
+
+    /* Bind iterator */
+    error =  col_bind_iterator(&iterator, error_list, COL_TRAVERSE_DEFAULT);
+    if (error) {
+        TRACE_ERROR_STRING("Error (bind):", failed_to_process);
+        fprintf(file, "%s\n", failed_to_process);
+        return;
+    }
+
+    while(1) {
+        /* Loop through a collection */
+        error = col_iterate_collection(iterator, &item);
+        if (error) {
+            TRACE_ERROR_STRING("Error (iterate):", failed_to_process);
+            fprintf(file, "%s\n", failed_to_process);
+            col_unbind_iterator(iterator);
+            return;
+        }
+
+        /* Are we done ? */
+        if (item == NULL) break;
+
+        /* Process collection header */
+        if (col_get_item_type(item) == COL_TYPE_COLLECTION) {
+            col_get_collection_count(item, &count);
+            if (count <= 2) break;
+        } else if (col_get_item_type(item) == COL_TYPE_STRING) {
+            fprintf(file, error_header, (char *)col_get_item_data(item));
+        }
+        else {
+            /* Put error into provided format */
+            pe = (struct parse_error *)(col_get_item_data(item));
+            fprintf(file, line_format,
+                    col_get_item_property(item, NULL),      /* Error or warning */
+                    pe->error,                          /* Error */
+                    pe->line,                           /* Line */
+                    error_function(pe->error));         /* Error str */
+        }
+
+    }
+
+    /* Do not forget to unbind iterator - otherwise there will be a leak */
+    col_unbind_iterator(iterator);
+
+    TRACE_FLOW_STRING("print_error_list", "Exit");
+}
+
+/* Print errors and warnings that were detected while parsing one file */
+void print_file_parsing_errors(FILE *file,
+                               struct collection_item *error_list)
+{
+    print_error_list(file,
+                     error_list,
+                     COL_CLASS_INI_PERROR,
+                     WRONG_COLLECTION,
+                     FAILED_TO_PROCCESS,
+                     ERROR_HEADER,
+                     LINE_FORMAT,
+                     parsing_error_str);
+}
+
+
+/* Print errors and warnings that were detected while processing grammar.
+ *
+ * The following doxygen description is moved here.
+ * When the function gets exposed move it into
+ * the header file.
+ */
+/**
+ * @brief Print errors and warnings that were detected while
+ * checking grammar of the template.
+ *
+ * EXPERIMENTAL. Reserved for future use.
+ *
+ * @param[in] file           File descriptor.
+ * @param[in] error_list     List of the parsing errors.
+ *
+ */
+void print_grammar_errors(FILE *file,
+                          struct collection_item *error_list)
+{
+    print_error_list(file,
+                     error_list,
+                     COL_CLASS_INI_GERROR,
+                     WRONG_GRAMMAR,
+                     FAILED_TO_PROC_G,
+                     ERROR_HEADER_G,
+                     LINE_FORMAT,
+                     grammar_error_str);
+}
+
+/* Print errors and warnings that were detected while validating INI file.
+ *
+ * The following doxygen description is moved here.
+ * When the function gets exposed move it into
+ * the header file.
+ */
+/**
+ * @brief Print errors and warnings that were detected while
+ * checking INI file against the grammar object.
+ *
+ * EXPERIMENTAL. Reserved for future use.
+ *
+ * @param[in] file           File descriptor.
+ * @param[in] error_list     List of the parsing errors.
+ *
+ */
+void print_validation_errors(FILE *file,
+                             struct collection_item *error_list)
+{
+    print_error_list(file,
+                     error_list,
+                     COL_CLASS_INI_VERROR,
+                     WRONG_VALIDATION,
+                     FAILED_TO_PROC_V,
+                     ERROR_HEADER_V,
+                     LINE_FORMAT,
+                     validation_error_str);
+}
+
+/* Print errors and warnings that were detected while parsing
+ * the whole configuration */
+void print_config_parsing_errors(FILE *file,
+                                 struct collection_item *error_list)
+{
+    struct collection_iterator *iterator;
+    int error;
+    struct collection_item *item = NULL;
+    struct collection_item *file_errors = NULL;
+
+    TRACE_FLOW_STRING("print_config_parsing_errors", "Entry");
+
+    /* If we have something to print print it */
+    if (error_list == NULL) {
+        TRACE_ERROR_STRING("No error list", "");
+        return;
+    }
+
+    /* Make sure we go the right collection */
+    if (!col_is_of_class(error_list, COL_CLASS_INI_PESET)) {
+        TRACE_ERROR_STRING("Wrong collection class:", WRONG_COLLECTION);
+        fprintf(file, "%s\n", WRONG_COLLECTION);
+        return;
+    }
+
+    /* Bind iterator */
+    error =  col_bind_iterator(&iterator, error_list, COL_TRAVERSE_DEFAULT);
+    if (error) {
+        TRACE_ERROR_STRING("Error (bind):", FAILED_TO_PROCCESS);
+        fprintf(file,"%s\n", FAILED_TO_PROCCESS);
+        return;
+    }
+
+    while(1) {
+        /* Loop through a collection */
+        error = col_iterate_collection(iterator, &item);
+        if (error) {
+            TRACE_ERROR_STRING("Error (iterate):", FAILED_TO_PROCCESS);
+            fprintf(file, "%s\n", FAILED_TO_PROCCESS);
+            col_unbind_iterator(iterator);
+            return;
+        }
+
+        /* Are we done ? */
+        if (item == NULL) break;
+
+        /* Print per file sets of errors */
+        if (col_get_item_type(item) == COL_TYPE_COLLECTIONREF) {
+            /* Extract a sub collection */
+            error = col_get_reference_from_item(item, &file_errors);
+            if (error) {
+                TRACE_ERROR_STRING("Error (extract):", FAILED_TO_PROCCESS);
+                fprintf(file, "%s\n", FAILED_TO_PROCCESS);
+                col_unbind_iterator(iterator);
+                return;
+            }
+            print_file_parsing_errors(file, file_errors);
+            col_destroy_collection(file_errors);
+        }
+    }
+
+    /* Do not forget to unbind iterator - otherwise there will be a leak */
+    col_unbind_iterator(iterator);
+
+    TRACE_FLOW_STRING("print_config_parsing_errors", "Exit");
+}
-- 
1.5.5.6

