#include "config-ini.h" #include "types.h" #include #include #include #include #include static void free_field(ini_field_t *field) { free(field->key); free(field->value); free(field); } static void free_section(ini_section_t *section) { ini_field_t *field, *tmp; list_for_each_entry_safe(field, tmp, §ion->fields, node) free_field(field); free(section->name); free(section); } void free_ini_file(ini_file_t *file) { ini_section_t *section, *tmp; list_for_each_entry_safe(section, tmp, &file->sections, node) free_section(section); free(file); } static bool add_field(ini_section_t *section, const char *key, const char *value) { ini_field_t *field = calloc(1, sizeof(*field)); if (!field) return false; field->key = strdup(key); field->value = strdup(value); if (!field->key || !field->value) { free_field(field); return false; } list_add_tail(&field->node, §ion->fields); return true; } static ini_section_t * add_section(ini_file_t *file, const char *name) { ini_section_t *section = calloc(1, sizeof(*section)); if (!section) return NULL; section->name = strdup(name); if (!section->name) { free(section); return false; } INIT_LIST_HEAD(§ion->fields); list_add_tail(§ion->node, &file->sections); return section; } ini_file_t * read_ini_file(const char *filename) { FILE *f = fopen(filename, "r"); if (!f) return NULL; ini_file_t *file = calloc(1, sizeof(*file)); if (!file) goto error; INIT_LIST_HEAD(&file->sections); ini_section_t *section = NULL; int err = 0; char *line = NULL; size_t n = 0; while (getline(&line, &n, f) >= 0) { char *input = line; while (isspace(input[0])) input++; if (input[0] == '#' || input[0] == '\0') continue; size_t len = strlen(input); while (isspace(input[len-1])) len--; if (input[0] == '[') { if (input[len-1] != ']') { err = EINVAL; goto error; } input[len-1] = '\0'; section = add_section(file, input+1); if (!section) goto error; } else { if (!section) { err = EINVAL; goto error; } input[len] = '\0'; char *delim = strchr(input, '='); if (!delim) { err = EINVAL; goto error; } *delim = '\0'; if (!add_field(section, input, delim+1)) goto error; } } if (ferror(f)) err = EIO; error: free(line); fclose(f); if (err) { free_ini_file(file); errno = err; return NULL; } return file; }