#include #include #include #include "nfcommander.h" #include "config.h" typedef struct /*_config_section*/ { char* name; size_t entries; char** keys; char** values; } config_section_t; size_t nsections = 0, current_section = 0; config_section_t* sections = NULL; static int config_section(char* section){ size_t n = 0; //check if section already exists for(n = 0; n < nsections; n++){ if(!strcmp(sections[n].name, section)){ current_section = n; return 0; } } //create new section sections = realloc(sections, (nsections + 1) * sizeof(config_section_t)); if(!sections){ nsections = 0; printf("Failed to allocate memory\n"); return -1; } memset(sections + nsections, 0, sizeof(config_section_t)); sections[nsections].name = strdup(section); if(!sections[nsections].name){ printf("Failed to allocate memory\n"); return -1; } current_section = nsections; nsections++; return 0; } static int config_set(char* key, char* value){ size_t n = 0; if(!sections || !nsections){ printf("Assignment outside of section\n"); return 1; } //check if property already present for(n = 0; n < sections[current_section].entries; n++){ if(!strcmp(sections[current_section].keys[n], key)){ printf("Overriding previous value of %s.%s with %s\n", sections[current_section].name, key, value); free(sections[current_section].values[n]); sections[current_section].values[n] = strdup(value); return 0; } } //add property sections[current_section].keys = realloc(sections[current_section].keys, (sections[current_section].entries + 1) * sizeof(char*)); sections[current_section].values = realloc(sections[current_section].values, (sections[current_section].entries + 1) * sizeof(char*)); if(!sections[current_section].keys || !sections[current_section].values){ printf("Filed to allocate memory\n"); sections[current_section].entries = 0; return 1; } sections[current_section].keys[sections[current_section].entries] = strdup(key); sections[current_section].values[sections[current_section].entries] = strdup(value); sections[current_section].entries++; return 0; } static int config_handle_line(char* line){ char* next_token = NULL; size_t len = 0; //ignore comments if(line[0] == ';'){ return 0; } //select or create section if(line[0] == '['){ next_token = strchr(line, ']'); if(!next_token){ printf("Unterminated start of section\n"); return 1; } *next_token = 0; return config_section(line + 1); } next_token = strchr(line, '='); if(!next_token){ printf("Not an assignment: %s\n", line); return 1; } *next_token = 0; next_token++; //rtrim line len = strlen(line); for(; len && !isgraph(line[len]); len--){ line[len] = 0; } //ltrim value for(; *next_token && !isgraph(*next_token); next_token++){ } if(len && strlen(next_token)){ return config_set(line, next_token); } printf("Invalid assignment\n"); return 1; } int config_read(char* path){ ssize_t line_len = 0; size_t line_alloc = 0, line_number = 1; char* line = NULL; FILE* input = fopen(path, "r"); if(!input){ printf("Failed to open %s as configuration file\n", path); return 1; } printf("Reading config file %s\n", path); for(line_len = getline(&line, &line_alloc, input); line_len >= 0; line_len = getline(&line, &line_alloc, input)){ //right-trim for(; line_len && !isgraph(line[line_len]); line_len--){ line[line_len] = 0; } if(!line_len){ continue; } if(config_handle_line(line)){ printf("Failed parsing %s at line %lu\n", path, line_number); return 1; } line_number++; } free(line); fclose(input); return 0; } char* config_get(char* section, char* property){ size_t n = 0, p = 0; //find section for(n = 0; n < nsections; n++){ if(!strcmp(section, sections[n].name)){ break; } } if(n == nsections){ printf("Requested config section %s not found\n", section); return NULL; } //find key for(p = 0; p < sections[n].entries; p++){ if(!strcmp(sections[n].keys[p], property)){ return sections[n].values[p]; } } printf("Requested property %s.%s not configured\n", section, property); return NULL; } void config_free(){ size_t n = 0, p = 0; for(n = 0; n < nsections; n++){ free(sections[n].name); for(p = 0; p < sections[n].entries; p++){ free(sections[n].keys[p]); free(sections[n].values[p]); } free(sections[n].keys); free(sections[n].values); } free(sections); sections = NULL; nsections = 0; }