/* eurephia_cfgfile.c
 *
 *  Simple generic ini-style config file parser
 *
 *  GPLv2 only - Copyright (C) 2011 - 2012
 *               David Sommerseth <dazo@users.sourceforge.net>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; version 2
 *  of the License.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

/**
 * @file   eurephia_cfgfile.c
 * @author David Sommerseth <dazo@users.sourceforge.net>
 * @date   2011-07-23
 *
 * @brief A simple, generic ini-style config file parser
 *
 */

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>

#include <eurephia_nullsafe.h>
#include <eurephia_context.h>
#include <eurephia_log.h>
#include <eurephia_values.h>


/**
 * Parse one single configuration line into a eurephiaVALUES key/value
 * pair.  It will also ignore comment lines, and also remove the
 * comments on the line of the configuration line so that only the
 * key/value information is extracted.
 *
 * @param line Input configuration line
 *
 * @return eurephiaVALUES pointer containing the parsed result.  On
 *         error or if no valid config line was found, NULL is returned.
 */
static inline eurephiaVALUES *parse_config_line(eurephiaCTX *ctx, const char *line) {
        char *cp = NULL, *key = NULL, *val = NULL, *ptr = NULL;
        eurephiaVALUES *ret = NULL;

        if( *line == '#' ) {
                return NULL;
        }

        cp = strdup(line);
        key = cp;
        val = strpbrk(cp, "=");
        if( val == NULL ) {
                free_nullsafe(NULL, cp);
                return NULL;
        }
        *val = '\0'; val++;

        // Discard comments at the end of a line
        if( (ptr = strpbrk(val, "#")) != NULL ) {
                *ptr = '\0';
        }

        // Left trim
        while( ((*key == 0x20) || (*key == 0x0A) || (*key == 0x0D)) ) {
                key++;
        }
        while( ((*val == 0x20) || (*val == 0x0A) || (*val == 0x0D)) ) {
                val++;
        }

        // Right trim
        ptr = key + strlen_nullsafe(key) - 1;
        while( ((*ptr == 0x20) || (*ptr == 0x0A) || (*ptr == 0x0D)) && (ptr > key) ) {
                ptr--;
        }
        ptr++;
        *ptr = '\0';

        ptr = val + strlen_nullsafe(val) - 1;
        while( ((*ptr == 0x20) || (*ptr == 0x0A) || (*ptr == 0x0D)) && (ptr > val) ) {
                ptr--;
        }
        ptr++;
        *ptr = '\0';

        // Put key/value into a eurephiaVALUES struct and return it
        ret = eCreate_value_space(ctx, 20);
        ret->key = strdup(key);
        ret->val = strdup(val);

        free_nullsafe(ctx, cp);
        return ret;
}


/**
 * Parses a complete config file and puts it into an eurephiaVALUES
 * key/value stack
 *
 * @param fname Complete file name with full path to the configuration
 *        file to parse
 *
 * @return Returns a pointer to an eurephiaVALUES stack containing the
 *         configuration on success, otherwise NULL.
 */
eurephiaVALUES *ecfg_ReadConfig(eurephiaCTX *ctx, const char *fname)
{
        FILE *fp = NULL;
        char *buf = NULL;
        eurephiaVALUES *cfg = NULL;
        struct stat fi;

        if( stat(fname, &fi) == -1 ) {
                eurephia_log(ctx, LOG_CRITICAL, 0,
                             "Could not open the config file: %s\n", fname);
                return NULL;
        }

        if( (fp = fopen(fname, "r")) == NULL ) {
                eurephia_log(ctx, LOG_CRITICAL, 0,
                             "Could not open the config file: %s\n", fname);
                return NULL;
        }

        buf = (char *) malloc_nullsafe(ctx, fi.st_size+2);

        cfg = eCreate_value_space(ctx, 20);
        while( fgets(buf, fi.st_size, fp) != NULL ) {
                eurephiaVALUES *prm = parse_config_line(ctx, buf);
                if( prm != NULL ) {
                        eAdd_valuestruct(ctx, cfg, prm);
                }
        };
        free_nullsafe(ctx, buf);
        fclose(fp); fp = NULL;

        return cfg;
}

