/*************************************************************************** * Copyright (C) 03/2010 by Olaf Rempel * * razzor@kopf-tisch.de * * * * 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., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include "configfile.h" #include "list.h" #include "logging.h" #define BUFSIZE 1024 struct conf_section { struct list_head list; struct list_head tupel_list; const char *name; }; struct conf_tupel { struct list_head list; const char *option; const char *parameter; }; static LIST_HEAD(config_list); static struct conf_section * config_add_section(const char *name) { struct conf_section *section; section = malloc(sizeof(struct conf_section) + strlen(name)); if (section == NULL) return NULL; INIT_LIST_HEAD(§ion->list); INIT_LIST_HEAD(§ion->tupel_list); section->name = strdup(name); if (section->name == NULL) { free(section); return NULL; } list_add_tail(§ion->list, &config_list); return section; } static int config_add_tupel(struct conf_section *section, const char *option, const char *parameter) { struct conf_tupel *tupel = malloc(sizeof(struct conf_tupel)); if (tupel == NULL) return -1; INIT_LIST_HEAD(&tupel->list); tupel->option = strdup(option); tupel->parameter = strdup(parameter); if (tupel->option == NULL || tupel->parameter == NULL) { free(tupel); return -1; } list_add_tail(&tupel->list, §ion->tupel_list); return 0; } int config_parse(const char *config) { FILE *fz = fopen(config, "r"); if (fz == NULL) { log_print(LOG_ERROR, "%s(): failed to open config '%s'", __FUNCTION__, config); return -1; } char *line = malloc(BUFSIZE); if (line == NULL) { log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__); fclose(fz); return -1; } int linenum = 0; struct conf_section *section = NULL; while (fgets(line, BUFSIZE, fz) != NULL) { linenum++; if (line[0] == '#' || line[0] <= ' ') { continue; } else if (line[0] == '[') { char *tok = strtok(line +1, " ]\n"); if (tok == NULL || (section = config_add_section(tok)) == NULL) { log_print(LOG_WARN, "%s(): invalid section in row %d", __FUNCTION__, linenum); free(line); fclose(fz); return -1; } continue; } else if (section == NULL) { log_print(LOG_WARN, "%s(): missing section in row %d", __FUNCTION__, linenum); free(line); fclose(fz); return -1; } char *tmp, *tok = strtok_r(line, " \t\n", &tmp); if (tok != NULL) { char *tok2; while ((tok2 = strtok_r(NULL, " \n", &tmp))) { if (config_add_tupel(section, tok, tok2) != 0) log_print(LOG_WARN, "%s(): invalid row %d", __FUNCTION__, linenum); } } } fclose(fz); free(line); return 0; } void config_free(void) { struct conf_section *section, *section_tmp; struct conf_tupel *tupel, *tupel_tmp; list_for_each_entry_safe(section, section_tmp, &config_list, list) { list_for_each_entry_safe(tupel, tupel_tmp, §ion->tupel_list, list) { list_del(&tupel->list); free((char *)tupel->option); free((char *)tupel->parameter); free(tupel); } list_del(§ion->list); free(section); } } static struct conf_section * config_get_section(const char *name) { struct conf_section *section; list_for_each_entry(section, &config_list, list) { if (!strcmp(section->name, name)) return section; } return NULL; } const char * config_get_string(const char *section_str, const char *option, const char *def) { struct conf_section *section = config_get_section(section_str); if (section != NULL) { struct conf_tupel *tupel; list_for_each_entry(tupel, §ion->tupel_list, list) { if (!strcmp(tupel->option, option)) return tupel->parameter; } } if (def != NULL) log_print(LOG_WARN, "config [%s:%s] not found, using default: '%s'", section_str, option, def); return def; } int config_get_int(const char *section, const char *option, int *value, int def) { const char *ret = config_get_string(section, option, NULL); if (ret == NULL) { log_print(LOG_WARN, "config [%s:%s] not found, using default: '%d'", section, option, def); *value = def; return -1; } char *tmp; *value = strtol(ret, &tmp, 0); if (*tmp != '\0' && !isspace(*tmp)) { log_print(LOG_WARN, "config [%s:%s] not an integer: '%s', using default '%d'", section, option, ret, def); *value = def; return -1; } return 0; } int config_get_strings(const char *section_str, const char *option, int (*callback)(const char *value, void *privdata), void *privdata) { struct conf_section *section = config_get_section(section_str); if (section == NULL) return -1; int cnt = 0; struct conf_tupel *tupel; list_for_each_entry(tupel, §ion->tupel_list, list) { if (!strcmp(tupel->option, option)) if (callback(tupel->parameter, privdata) == 0) cnt++; } return cnt; } struct strtoken * strtokenize(const char *input, const char *delim, int maxfields) { struct strtoken *tokens = malloc(sizeof(struct strtoken) + (maxfields +1) * sizeof(char *) + strlen(input)); if (tokens == NULL) return NULL; char *ptr = (char *)&tokens->field[maxfields]; strcpy(ptr, input); tokens->input = input; tokens->delim = delim; tokens->maxfields = maxfields; int i; char *tmp; tokens->count = 0; for (i = 0; i < maxfields; i++) { tokens->field[i] = strtok_r(ptr, delim, &tmp); ptr = NULL; if (tokens->field[i] != NULL) tokens->count++; } return tokens; } struct strtoken * config_get_strtoken(const char *section, const char *option, const char *delim, int maxfields) { const char *ret = config_get_string(section, option, NULL); if (ret == NULL) { log_print(LOG_WARN, "config [%s:%s] not found", section, option); return NULL; } return strtokenize(ret, delim, maxfields); } int config_get_strtokens(const char *section_str, const char *option, const char *delim, int maxfields, int (*callback)(struct strtoken *data, void *privdata), void *privdata) { struct conf_section *section = config_get_section(section_str); if (section == NULL) return -1; int cnt = 0; struct conf_tupel *tupel; list_for_each_entry(tupel, §ion->tupel_list, list) { if (!strcmp(tupel->option, option)) { struct strtoken *tokens = strtokenize(tupel->parameter, delim, maxfields); if (tokens != NULL) { if (callback(tokens, privdata) == 0) cnt++; free(tokens); } } } return cnt; }