/* client_config.c -- Handles reading and parsing of config files * * GPLv2 only - Copyright (C) 2008 - 2010 * David Sommerseth * * 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 client_config.c * @author David Sommerseth * @date 2008-12-01 * * @brief Config file parser * */ #include #include #include #include #include #include #include /** * Retrieve a the full path of a file name. Will try to look for the file in different places, like * if EUREPHIA_DIR is set, it will look here or else in ${HOME}/.eurephia. * * @param env const char * to an environment variable to look for the given filename * @param file File name which we are looking for * * @return Returns a full path to the file name, or NULL on error. */ char *get_config_filename(const char *env, const char *file) { struct stat chk; static char fname[1026]; char *ptr; int flen = 1024 - strlen_nullsafe(file); assert( (file != NULL)); memset(&fname, 0, 1026); if( env != NULL ) { // Use the explicit eurephia session file, if set in environment if( (ptr = getenv(env)) != NULL ) { snprintf(fname, 1024, "%s", ptr); return fname; } } // Use the explicit set eurephia session directory for a session file if( ((ptr = getenv("EUREPHIA_DIR")) != NULL) && (strlen_nullsafe(ptr) <= 1016) ) { strncat(fname, ptr, flen-1); strcat(fname, "/"); strcat(fname, file); // Make sure we have this directory if( stat(ptr, &chk) == -1 ) { if( mkdir(ptr, S_IRWXU) == -1 ) { fprintf(stderr, "Could not create eurephia directory: %s\n", ptr); return NULL; } } return fname; } // Use default ~/.eurephia directory for session file if( ((ptr = getenv("HOME")) != NULL) && (strlen_nullsafe(ptr) <= 1016) ) { flen -= 10; strncat(fname, ptr, flen); strcat(fname, "/.eurephia"); // Make sure we have this directory if( stat(fname, &chk) == -1 ) { if( mkdir(fname, S_IRWXU) == -1 ) { fprintf(stderr, "Could not create eurephia directory: %s\n", fname); return NULL; } } strcat(fname, "/"); strcat(fname, file); return fname; } return NULL; } /** * 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. */ eurephiaVALUES *parse_config_line(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(NULL, 20); ret->key = strdup(key); ret->val = strdup(val); free_nullsafe(NULL, cp); return ret; } /** * Parses a complete config file and puts it into an eurephiaVALUES key/value stack * * @param env Environment table, used for locating the config file * @param cfgname File name of the configuration file. * * @return Returns a pointer to an eurephiaVALUES stack containing the configuration on success, * otherwise NULL. */ eurephiaVALUES *ReadConfig(const char *env, const char *cfgname) { char *fname = NULL; FILE *fp = NULL; char *buf = NULL; eurephiaVALUES *cfg = NULL; struct stat fi; fname = get_config_filename(env, cfgname); if( fname == NULL ) { fprintf(stderr, "Could not find a valid path for the config file\n"); return NULL; } if( stat(fname, &fi) == -1 ) { fprintf(stderr, "Could not open the config file: %s\n", fname); return NULL; } if( (fp = fopen(fname, "r")) == NULL ) { fprintf(stderr, "Could not open the config file: %s\n", fname); return NULL; } buf = (char *) malloc_nullsafe(NULL, fi.st_size+2); cfg = eCreate_value_space(NULL, 20); while( fgets(buf, fi.st_size, fp) != NULL ) { eurephiaVALUES *prm = parse_config_line(buf); if( prm != NULL ) { eAdd_valuestruct(NULL, cfg, prm); } }; free_nullsafe(NULL, buf); fclose(fp); fp = NULL; return cfg; }