root/src/utils/configfile.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. DelSection
  2. gf_cfg_clear
  3. gf_cfg_parse_config_file
  4. gf_cfg_force_new
  5. gf_cfg_new
  6. gf_cfg_get_filename
  7. gf_cfg_save
  8. gf_cfg_discard_changes
  9. gf_cfg_del
  10. gf_cfg_remove
  11. gf_cfg_get_key
  12. gf_cfg_get_ikey
  13. gf_cfg_set_key
  14. gf_cfg_get_section_count
  15. gf_cfg_get_section_name
  16. gf_cfg_get_key_count
  17. gf_cfg_get_key_name
  18. gf_cfg_del_section
  19. gf_cfg_insert_key
  20. gf_cfg_get_sub_key
  21. gf_cfg_set_filename

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2000-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / common tools sub-project
 *
 *  GPAC 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 2, or (at your option)
 *  any later version.
 *
 *  GPAC 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 this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <gpac/config_file.h>
#include <gpac/list.h>

#define MAX_INI_LINE                    2046

typedef struct
{
        char *name;
        char *value;
} IniKey;

typedef struct
{
        char *section_name;
        GF_List *keys;
} IniSection;

struct __tag_config
{
        char *fileName;
        GF_List *sections;
        Bool hasChanged, skip_changes;
};


static void DelSection(IniSection *ptr)
{
        IniKey *k;
        if (!ptr) return;
        if (ptr->keys) {
                while (gf_list_count(ptr->keys)) {
                        k = (IniKey *) gf_list_get(ptr->keys, 0);
                        if (k->value) gf_free(k->value);
                        if (k->name) gf_free(k->name);
                        gf_free(k);
                        gf_list_rem(ptr->keys, 0);
                }
                gf_list_del(ptr->keys);
        }
        if (ptr->section_name) gf_free(ptr->section_name);
        gf_free(ptr);
}

/*!
 * \brief Clear the structure
 * \param iniFile The structure to clear
 */
static void gf_cfg_clear(GF_Config * iniFile) {
        IniSection *p;
        if (!iniFile) return;
        if (iniFile->sections) {
                while (gf_list_count(iniFile->sections)) {
                        p = (IniSection *) gf_list_get(iniFile->sections, 0);
                        DelSection(p);
                        gf_list_rem(iniFile->sections, 0);
                }
                gf_list_del(iniFile->sections);
        }
        if (iniFile->fileName)
                gf_free(iniFile->fileName);
        memset((void *)iniFile, 0, sizeof(GF_Config));
}

/*!
 * \brief Parses the config file if any and clears the existing structure
 */
GF_Err gf_cfg_parse_config_file(GF_Config * tmp, const char * filePath, const char * file_name)
{
        IniSection *p;
        IniKey *k;
        FILE *file;
        char *ret;
        char *line;
        u32 line_alloc = MAX_INI_LINE;
        char fileName[GF_MAX_PATH];

        gf_cfg_clear(tmp);

        if (filePath && ((filePath[strlen(filePath)-1] == '/') || (filePath[strlen(filePath)-1] == '\\')) ) {
                strcpy(fileName, filePath);
                strcat(fileName, file_name);
        } else if (filePath) {
                sprintf(fileName, "%s%c%s", filePath, GF_PATH_SEPARATOR, file_name);
        } else {
                strcpy(fileName, file_name);
        }

        tmp->fileName = gf_strdup(fileName);
        tmp->sections = gf_list_new();
        file = gf_fopen(fileName, "rt");
        if (!file)
                return GF_IO_ERR;
        /* load the file */
        p = NULL;
        line = (char*)gf_malloc(sizeof(char)*line_alloc);
        memset(line, 0, sizeof(char)*line_alloc);

        while (!feof(file)) {
                u32 read, nb_pass;
                ret = fgets(line, line_alloc, file);
                read = (u32) strlen(line);
                nb_pass = 1;
                while (read + nb_pass == line_alloc) {
                        line_alloc += MAX_INI_LINE;
                        line = (char*)gf_realloc(line, sizeof(char)*line_alloc);
                        ret = fgets(line+read, MAX_INI_LINE, file);
                        read = (u32) strlen(line);
                        nb_pass++;
                }
                if (!ret) continue;

                /* get rid of the end of line stuff */
                while (1) {
                        u32 len = (u32) strlen(line);
                        if (!len) break;
                        if ((line[len-1] != '\n') && (line[len-1] != '\r')) break;
                        line[len-1] = 0;
                }
                if (!strlen(line)) continue;
                if (line[0] == '#') continue;


                /* new section */
                if (line[0] == '[') {
                        p = (IniSection *) gf_malloc(sizeof(IniSection));
                        p->keys = gf_list_new();
                        p->section_name = gf_strdup(line + 1);
                        p->section_name[strlen(line) - 2] = 0;
                        while (p->section_name[strlen(p->section_name) - 1] == ']' || p->section_name[strlen(p->section_name) - 1] == ' ') p->section_name[strlen(p->section_name) - 1] = 0;
                        gf_list_add(tmp->sections, p);
                }
                else if (strlen(line) && (strchr(line, '=') != NULL) ) {
                        if (!p) {
                                gf_list_del(tmp->sections);
                                gf_free(tmp->fileName);
                                gf_free(tmp);
                                gf_fclose(file);
                                gf_free(line);
                                return GF_IO_ERR;
                        }

                        k = (IniKey *) gf_malloc(sizeof(IniKey));
                        memset((void *)k, 0, sizeof(IniKey));
                        ret = strchr(line, '=');
                        if (ret) {
                                ret[0] = 0;
                                k->name = gf_strdup(line);
                                while (k->name[strlen(k->name) - 1] == ' ') k->name[strlen(k->name) - 1] = 0;
                                ret[0] = '=';
                                ret += 1;
                                while (ret[0] == ' ') ret++;
                                if ( ret[0] != 0) {
                                        k->value = gf_strdup(ret);
                                        while (k->value[strlen(k->value) - 1] == ' ') k->value[strlen(k->value) - 1] = 0;
                                } else {
                                        k->value = gf_strdup("");
                                }
                        }
                        gf_list_add(p->keys, k);
                }
        }
        gf_free(line);
        gf_fclose(file);
        return GF_OK;
}

GF_EXPORT
GF_Config *gf_cfg_force_new(const char *filePath, const char* file_name) {
        GF_Config *tmp = (GF_Config *)gf_malloc(sizeof(GF_Config));
        memset((void *)tmp, 0, sizeof(GF_Config));
        gf_cfg_parse_config_file(tmp, filePath, file_name);
        return tmp;
}


GF_EXPORT
GF_Config *gf_cfg_new(const char *filePath, const char* file_name)
{
        GF_Config *tmp = (GF_Config *)gf_malloc(sizeof(GF_Config));
        memset((void *)tmp, 0, sizeof(GF_Config));
        if (!filePath && !file_name) {
                tmp->sections = gf_list_new();
                return tmp;
        }

        if (gf_cfg_parse_config_file(tmp, filePath, file_name)) {
                gf_cfg_clear(tmp);
                gf_free(tmp);
                tmp = NULL;
        }
        return tmp;
}

GF_EXPORT
char * gf_cfg_get_filename(GF_Config *iniFile)
{
        if (!iniFile)
                return NULL;
        return iniFile->fileName ? gf_strdup(iniFile->fileName) : NULL;
}

GF_EXPORT
GF_Err gf_cfg_save(GF_Config *iniFile)
{
        u32 i, j;
        IniSection *sec;
        IniKey *key;
        FILE *file;

        if (!iniFile->hasChanged) return GF_OK;
        if (iniFile->skip_changes) return GF_OK;
        if (!iniFile->fileName) return GF_OK;

        file = gf_fopen(iniFile->fileName, "wt");
        if (!file) return GF_IO_ERR;

        i=0;
        while ( (sec = (IniSection *) gf_list_enum(iniFile->sections, &i)) ) {
                /*Temporary sections are not saved*/
                if (!strnicmp(sec->section_name, "Temp", 4)) continue;

                fprintf(file, "[%s]\n", sec->section_name);
                j=0;
                while ( (key = (IniKey *) gf_list_enum(sec->keys, &j)) ) {
                        fprintf(file, "%s=%s\n", key->name, key->value);
                }
                /* end of section */
                fprintf(file, "\n");
        }
        gf_fclose(file);
        return GF_OK;
}

GF_EXPORT
GF_Err gf_cfg_discard_changes(GF_Config *iniFile)
{
        if (!iniFile) return GF_BAD_PARAM;
        iniFile->skip_changes = GF_TRUE;
        return GF_OK;
}

GF_EXPORT
void gf_cfg_del(GF_Config *iniFile)
{
        if (!iniFile) return;
        gf_cfg_save(iniFile);
        gf_cfg_clear(iniFile);
        gf_free(iniFile);
}

void gf_cfg_remove(GF_Config *iniFile)
{
        if (!iniFile) return;
        gf_delete_file(iniFile->fileName);
        gf_cfg_clear(iniFile);
        gf_free(iniFile);
}


GF_EXPORT
const char *gf_cfg_get_key(GF_Config *iniFile, const char *secName, const char *keyName)
{
        u32 i;
        IniSection *sec;
        IniKey *key;

        i=0;
        while ( (sec = (IniSection *) gf_list_enum(iniFile->sections, &i)) ) {
                if (!strcmp(secName, sec->section_name)) goto get_key;
        }
        return NULL;

get_key:
        i=0;
        while ( (key = (IniKey *) gf_list_enum(sec->keys, &i)) ) {
                if (!strcmp(key->name, keyName)) return key->value;
        }
        return NULL;
}

GF_EXPORT
const char *gf_cfg_get_ikey(GF_Config *iniFile, const char *secName, const char *keyName)
{
        u32 i;
        IniSection *sec;
        IniKey *key;

        i=0;
        while ( (sec = (IniSection *) gf_list_enum(iniFile->sections, &i)) ) {
                if (!stricmp(secName, sec->section_name)) goto get_key;
        }
        return NULL;

get_key:
        i=0;
        while ( (key = (IniKey *) gf_list_enum(sec->keys, &i)) ) {
                if (!stricmp(key->name, keyName)) return key->value;
        }
        return NULL;
}


GF_EXPORT
GF_Err gf_cfg_set_key(GF_Config *iniFile, const char *secName, const char *keyName, const char *keyValue)
{
        u32 i;
        Bool has_changed = GF_TRUE;
        IniSection *sec;
        IniKey *key;

        if (!iniFile || !secName || !keyName) return GF_BAD_PARAM;

        if (!strnicmp(secName, "temp", 4)) has_changed = GF_FALSE;

        i=0;
        while ((sec = (IniSection *) gf_list_enum(iniFile->sections, &i)) ) {
                if (!strcmp(secName, sec->section_name)) goto get_key;
        }
        /* need a new key */
        sec = (IniSection *) gf_malloc(sizeof(IniSection));
        sec->section_name = gf_strdup(secName);
        sec->keys = gf_list_new();
        if (has_changed) iniFile->hasChanged = GF_TRUE;
        gf_list_add(iniFile->sections, sec);

get_key:
        i=0;
        while ( (key = (IniKey *) gf_list_enum(sec->keys, &i) ) ) {
                if (!strcmp(key->name, keyName)) goto set_value;
        }
        if (!keyValue) return GF_OK;
        /* need a new key */
        key = (IniKey *) gf_malloc(sizeof(IniKey));
        key->name = gf_strdup(keyName);
        key->value = gf_strdup("");
        if (has_changed) iniFile->hasChanged = GF_TRUE;
        gf_list_add(sec->keys, key);

set_value:
        if (!keyValue) {
                gf_list_del_item(sec->keys, key);
                if (key->name) gf_free(key->name);
                if (key->value) gf_free(key->value);
                gf_free(key);
                if (has_changed) iniFile->hasChanged = GF_TRUE;
                return GF_OK;
        }
        /* same value, don't update */
        if (!strcmp(key->value, keyValue)) return GF_OK;

        if (key->value) gf_free(key->value);
        key->value = gf_strdup(keyValue);
        if (has_changed) iniFile->hasChanged = GF_TRUE;
        return GF_OK;
}

GF_EXPORT
u32 gf_cfg_get_section_count(GF_Config *iniFile)
{
        return gf_list_count(iniFile->sections);
}

GF_EXPORT
const char *gf_cfg_get_section_name(GF_Config *iniFile, u32 secIndex)
{
        IniSection *is = (IniSection *) gf_list_get(iniFile->sections, secIndex);
        if (!is) return NULL;
        return is->section_name;
}

GF_EXPORT
u32 gf_cfg_get_key_count(GF_Config *iniFile, const char *secName)
{
        u32 i = 0;
        IniSection *sec;
        while ( (sec = (IniSection *) gf_list_enum(iniFile->sections, &i)) ) {
                if (!strcmp(secName, sec->section_name)) return gf_list_count(sec->keys);
        }
        return 0;
}

GF_EXPORT
const char *gf_cfg_get_key_name(GF_Config *iniFile, const char *secName, u32 keyIndex)
{
        u32 i = 0;
        IniSection *sec;
        while ( (sec = (IniSection *) gf_list_enum(iniFile->sections, &i) ) ) {
                if (!strcmp(secName, sec->section_name)) {
                        IniKey *key = (IniKey *) gf_list_get(sec->keys, keyIndex);
                        return key ? key->name : NULL;
                }
        }
        return NULL;
}

GF_EXPORT
void gf_cfg_del_section(GF_Config *iniFile, const char *secName)
{
        u32 i;
        IniSection *p;
        if (!iniFile) return;

        i = 0;
        while ((p = (IniSection*)gf_list_enum(iniFile->sections, &i))) {
                if (!strcmp(secName, p->section_name)) {
                        DelSection(p);
                        gf_list_rem(iniFile->sections, i-1);
                        iniFile->hasChanged = GF_TRUE;
                        return;
                }
        }
}

GF_EXPORT
GF_Err gf_cfg_insert_key(GF_Config *iniFile, const char *secName, const char *keyName, const char *keyValue, u32 index)
{
        u32 i;
        IniSection *sec;
        IniKey *key;

        if (!iniFile || !secName || !keyName|| !keyValue) return GF_BAD_PARAM;

        i=0;
        while ( (sec = (IniSection *) gf_list_enum(iniFile->sections, &i) ) ) {
                if (!strcmp(secName, sec->section_name)) break;
        }
        if (!sec) return GF_BAD_PARAM;

        i=0;
        while ( (key = (IniKey *) gf_list_enum(sec->keys, &i) ) ) {
                if (!strcmp(key->name, keyName)) return GF_BAD_PARAM;
        }

        key = (IniKey *) gf_malloc(sizeof(IniKey));
        key->name = gf_strdup(keyName);
        key->value = gf_strdup(keyValue);
        gf_list_insert(sec->keys, key, index);
        iniFile->hasChanged = GF_TRUE;
        return GF_OK;
}

GF_EXPORT
const char *gf_cfg_get_sub_key(GF_Config *iniFile, const char *secName, const char *keyName, u32 sub_index)
{
        u32 j;
        char *subKeyValue, *returnKey;
        char *keyValue;


        keyValue = gf_strdup(gf_cfg_get_key(iniFile, secName, keyName));
        if (!keyValue) {
                return NULL;
        }

        j = 0;
        subKeyValue = strtok((char*)keyValue,";");
        while (subKeyValue!=NULL) {
                if (j==sub_index) {
                        returnKey = gf_strdup(subKeyValue);
                        gf_free(keyValue);
                        return returnKey;
                }
                j++;
                subKeyValue = strtok (NULL, ";");
        }
        gf_free(keyValue);
        return NULL;
}

GF_EXPORT
GF_Err gf_cfg_set_filename(GF_Config *iniFile, const char * fileName)
{
        if (!fileName) return GF_OK;
        if (iniFile->fileName) gf_free(iniFile->fileName);
        iniFile->fileName = gf_strdup(fileName);
        return iniFile->fileName ? GF_OK : GF_OUT_OF_MEM;
}

/* [<][>][^][v][top][bottom][index][help] */