<commit_before>/* 
 * Copyright (c) 2005-2008 by KoanLogic s.r.l. - All rights reserved.  
 */

#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>

#include <toolbox/carpal.h>
#include <toolbox/queue.h>
#include <toolbox/list.h>
#include <toolbox/config.h>
#include <toolbox/misc.h>
#include <toolbox/memory.h>
#include <toolbox/str.h>

/**
 *  \defgroup config Configuration
 *  \{
 *      \par Intro
 *          The u_config_t object is used to store, load and parse 
 *          text configuration files.
 *          \n
 *          A configuration file is a plain text file that stores a list of
 *          key=values pair in a tree-ordered structure.
 *          TODO
 */

TAILQ_HEAD(u_config_list_s, u_config_s);
typedef struct u_config_list_s u_config_list_t;

struct u_config_s
{
    TAILQ_ENTRY(u_config_s) np; /* next & prev pointers */
    char *key;                  /* config item key name */
    char *value;                /* config item value    */
    u_config_list_t children;   /* subkeys              */
    u_config_t *parent;         /* parent config obj    */
};

/* file system pre-defined driver */
extern u_config_driver_t u_config_drv_fs;
extern u_config_driver_t u_config_drv_mem;

/* forward declarations */
static int u_config_include(u_config_t*, u_config_driver_t*, u_config_t*, int);

/**
 * \brief  Sort config children 
 *
 * Sort config children using the given comparison function. 
 *
 * The comparison function must return an integer less than, equal to, or
 * greater than zero if the first argument is considered to be respectively
 * less than, equal to, or greater than the second.
 *
 * \param c             configuration object
 * \param config_cmp    comparison function
 *
 * \return \c 0 on success, not zero on failure
 */
int u_config_sort_children(u_config_t *c, 
        int(*config_cmp)(u_config_t**, u_config_t**))
{
    u_config_t *child;
    int i, count;
    u_config_t **children = NULL;

    /* count children */
    count = 0;
    TAILQ_FOREACH(child, &c->children, np)
        count++;

    /* create an array of pointers */
    children = u_zalloc(count * sizeof(u_config_t*));
    dbg_err_if(children == NULL);

    /* populate the array of children */
    i = 0;
    TAILQ_FOREACH(child, &c->children, np)
        children[i++] = child;

    /* sort the list */
    qsort(children, count, sizeof(u_config_t*), 
            (int(*)(const void*,const void*))config_cmp);

    /* remove all items from the list */
    while((child = TAILQ_FIRST(&c->children)) != NULL)
        TAILQ_REMOVE(&c->children, child, np);

    /* reinsert sorted items */
    for(i = 0; i < count; ++i)
        TAILQ_INSERT_TAIL(&c->children, children[i], np);

    U_FREE(children);

    return 0;
err:
    if(children)
        u_free(children);
    return ~0;
}

/**
 * \brief  Print configuration to the given file descriptor
 *
 * Print a configuration object and its children to \c fp. For each config
 * object all keys/values pair will be printed.
 *
 * \param c     configuration object
 * \param fp    output file descriptor
 * \param lev   nesting level; must be zero
 *
 * \return nothing
 */
void u_config_print_to_fp(u_config_t *c, FILE *fp, int lev)
{
#define U_CONFIG_INDENT(fp, l)  \
    do { int i; for(i = 0; i < l; ++i) fprintf(fp, "  "); } while (0);

    u_config_t *item;

    U_CONFIG_INDENT(fp, lev);

    if (c->key)
        fprintf(fp, "%s  %s\n", c->key, c->value == NULL ? "" : c->value);

    ++lev;

    if(u_config_has_children(c))
    {
        if(c->parent)
        {
            /* align braces to the previous level */
            U_CONFIG_INDENT(fp, lev - 1);
            fprintf(fp, "{\n");
        }

        TAILQ_FOREACH(item, &c->children, np)
            u_config_print_to_fp(item, fp, lev);

        if(c->parent)<commit_msg>[libu] fix indentation in u_config_print_to_fp (push back by one)<commit_after>/* 
 * Copyright (c) 2005-2008 by KoanLogic s.r.l. - All rights reserved.  
 */

#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>

#include <toolbox/carpal.h>
#include <toolbox/queue.h>
#include <toolbox/list.h>
#include <toolbox/config.h>
#include <toolbox/misc.h>
#include <toolbox/memory.h>
#include <toolbox/str.h>

/**
 *  \defgroup config Configuration
 *  \{
 *      \par Intro
 *          The u_config_t object is used to store, load and parse 
 *          text configuration files.
 *          \n
 *          A configuration file is a plain text file that stores a list of
 *          key=values pair in a tree-ordered structure.
 *          TODO
 */

TAILQ_HEAD(u_config_list_s, u_config_s);
typedef struct u_config_list_s u_config_list_t;

struct u_config_s
{
    TAILQ_ENTRY(u_config_s) np; /* next & prev pointers */
    char *key;                  /* config item key name */
    char *value;                /* config item value    */
    u_config_list_t children;   /* subkeys              */
    u_config_t *parent;         /* parent config obj    */
};

/* file system pre-defined driver */
extern u_config_driver_t u_config_drv_fs;
extern u_config_driver_t u_config_drv_mem;

/* forward declarations */
static int u_config_include(u_config_t*, u_config_driver_t*, u_config_t*, int);

/**
 * \brief  Sort config children 
 *
 * Sort config children using the given comparison function. 
 *
 * The comparison function must return an integer less than, equal to, or
 * greater than zero if the first argument is considered to be respectively
 * less than, equal to, or greater than the second.
 *
 * \param c             configuration object
 * \param config_cmp    comparison function
 *
 * \return \c 0 on success, not zero on failure
 */
int u_config_sort_children(u_config_t *c, 
        int(*config_cmp)(u_config_t**, u_config_t**))
{
    u_config_t *child;
    int i, count;
    u_config_t **children = NULL;

    /* count children */
    count = 0;
    TAILQ_FOREACH(child, &c->children, np)
        count++;

    /* create an array of pointers */
    children = u_zalloc(count * sizeof(u_config_t*));
    dbg_err_if(children == NULL);

    /* populate the array of children */
    i = 0;
    TAILQ_FOREACH(child, &c->children, np)
        children[i++] = child;

    /* sort the list */
    qsort(children, count, sizeof(u_config_t*), 
            (int(*)(const void*,const void*))config_cmp);

    /* remove all items from the list */
    while((child = TAILQ_FIRST(&c->children)) != NULL)
        TAILQ_REMOVE(&c->children, child, np);

    /* reinsert sorted items */
    for(i = 0; i < count; ++i)
        TAILQ_INSERT_TAIL(&c->children, children[i], np);

    U_FREE(children);

    return 0;
err:
    if(children)
        u_free(children);
    return ~0;
}

/**
 * \brief  Print configuration to the given file descriptor
 *
 * Print a configuration object and its children to \c fp. For each config
 * object all keys/values pair will be printed.
 *
 * \param c     configuration object
 * \param fp    output file descriptor
 * \param lev   nesting level; must be zero
 *
 * \return nothing
 */
void u_config_print_to_fp(u_config_t *c, FILE *fp, int lev)
{
#define U_CONFIG_INDENT(fp, l)  \
    do { int i; for(i = 1; i < l; ++i) fputs("  ", fp); } while (0);

    u_config_t *item;

    U_CONFIG_INDENT(fp, lev);

    if (c->key)
        fprintf(fp, "%s  %s\n", c->key, c->value == NULL ? "" : c->value);

    ++lev;

    if(u_config_has_children(c))
    {
        if(c->parent)
        {
            /* align braces to the previous level */
            U_CONFIG_INDENT(fp, lev - 1);
            fprintf(fp, "{\n");
        }

        TAILQ_FOREACH(item, &c->children, np)
            u_config_print_to_fp(item, fp, lev);

        if(c->parent)
{'fraction_non_alphanumeric': 0.12407075108946423, 'fraction_numerical': 0.004357856959753909, 'mean_word_length': 2.581000458926113, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1033514', 'n_tokens_mistral': 2686, 'n_tokens_neox': 2584, 'n_words': 750}