/* mr_conf.c * * $Id$ * * Based on the work done by Anton (c)2002-2004 Anton Kulchitsky mailto:anton@kulchitsky.org * Code (c)2006 Bruno Cornec * * Main file of mr_conf : a very small and simple * library for configuration file reading * * Provided under the GPLv2 */ #include #include #include #include "mr_msg.h" #include "mr_mem.h" #include "mr_gettext.h" /* error flags */ #define MRCONF_NO_ERROR 0x0 #define MRCONF_BAD_FILE 0x1 #define MRCONF_ALLOC_FAILED 0x2 #define MRCONF_READING_FAILED 0x3 #define MRCONF_NO_GROUP_START 0x4 #define MRCONF_NO_GROUP_END 0x5 #define MRCONF_FIELD_NOT_FOUND 0x6 #define MRCONF_FIELD_NO_VALUE 0x7 #define MRCONF_TOO_LONG_STRING 0x8 #define MRCONF_CLOSE_BUT_NOT_OPEN 0x9 #define MRCONF_OPEN_OPENED 0xA #define MRCONF_CALL_BUT_NOT_OPEN 0xB /*setting flags*/ #define MRCONF_FLAG_VERBOSE 0x1 /*All strings of the library are here*/ #define MRCONF_STR_ERROR _("MRCONF: Error:") #define MRCONF_STR_WARNING _("MRCONF: Warning:") #define MRCONF_STR_BAD_FILE _("cannot open the file: ") #define MRCONF_STR_ALLOC_FAILED _("cannot allocate the memory") #define MRCONF_STR_READING_FAILED _("cannot read file into buffer") #define MRCONF_STR_DEFAULT_ERROR _("default") #define MRCONF_STR_FIELD_NOT_FOUND _("the field is not found, field:") #define MRCONF_STR_FIELD_NO_VALUE _("the field :") #define MRCONF_STR_OPEN_OPENED _("attempt to open mr_conf, but it is opened: aborted") #define MRCONF_STR_HALT _("MRCONF: Error occured: immidiate halt") /*warnings*/ #define MRCONF_STR_SET_TO_ZERO _("variable will be set to 0") #define MRCONF_STR_IGNORE _("has no value, ignoring it") #define MRCONF_STR_CLOSE_BUT_NOT_OPEN _("attempt to close mr_conf but it has not been opened yet") #define MRCONF_STR_CALL_BUT_NOT_OPEN _("attempt to use mr_conf when it has not been opened yet") /*Flags of internal state*/ #define MRCONF_INTFLAG_OPEN 0x1 /*set if memory allocated */ /* Character for comments */ #define MRCONF_COMM_CHAR '#' /*"private" members declarations*/ static size_t mr_conf_filesize(const char *name); static void mr_conf_error_msg(int error_code, const char *add_line); static void mr_conf_remove_comments(); static int mr_conf_check_int_flag(const int flag); static void mr_conf_set_int_flag(const int flag); static void mr_conf_drop_int_flag(const int flag); /*global "private" variables*/ static char *buffer = NULL; /*buffer for configuration file */ static int internal_flags = 0; /*state of the module */ static FILE *CONF = NULL; /* Configuration file FD */ /*if output all error and warning messages*/ static int mr_conf_flags = MRCONF_FLAG_VERBOSE; /* * Format of the configuration file is as follows: * * attribute1 = int_value * attribute2 = float_value * attribute3 = string_value */ /*open and read file: each call must be coupled with mr_conf_close function: return 0 if success*/ int mr_conf_open(const char *filename) { size_t length; /*length of the buffer/file */ size_t res = 0; /* check if mr_conf is already opened? */ if (mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) { mr_conf_error_msg(MRCONF_OPEN_OPENED, NULL); return MRCONF_OPEN_OPENED; } length = mr_conf_filesize(filename); CONF = fopen(filename, "r"); /*if file is empty or not exist => error */ if (length == 0) { mr_conf_error_msg(MRCONF_BAD_FILE, filename); return (MRCONF_BAD_FILE); } /*creating and reading buffer for file content */ /*allocate memory for the buffers */ buffer = (char *) malloc(sizeof(char) * (length + 1)); if (buffer == NULL) { mr_conf_error_msg(MRCONF_ALLOC_FAILED, ""); return (MRCONF_ALLOC_FAILED); } /*set flag that module is in "open" state */ mr_conf_set_int_flag(MRCONF_INTFLAG_OPEN); /*reading file in buffer (skip all 0 characters) */ res = fread(buffer, sizeof(char), length, CONF); buffer[length] = (char) 0; /*finalize the string */ if (ferror(CONF)) { mr_conf_error_msg(MRCONF_READING_FAILED, ""); return (MRCONF_READING_FAILED); } /* finally we have to remove all comment lines */ mr_conf_remove_comments(); return MRCONF_NO_ERROR; } /*release all memory and prepare to the next possiable config file*/ void mr_conf_close() { /* if not opened => error */ if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) { mr_conf_error_msg(MRCONF_CLOSE_BUT_NOT_OPEN, NULL); } mr_free(buffer); fclose(CONF); /*set flag that module is in "close" state */ mr_conf_drop_int_flag(MRCONF_INTFLAG_OPEN); } /*read field value after string str in the current file*/ static char *mr_conf_read(const char *field_name) { char *p = NULL; /*pointer to the field */ /* check if mr_conf is not yet opened? */ if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) { mr_conf_error_msg(MRCONF_CALL_BUT_NOT_OPEN, NULL); return NULL; } /*read the number */ p = strstr(buffer, field_name); if (p == NULL) { mr_conf_error_msg(MRCONF_FIELD_NOT_FOUND, field_name); return NULL; } else { p += strlen(field_name); while ((*p != '\n') && (*p != '\0') && (*p != '=')) { p++; } if (*p != '=') { mr_conf_error_msg(MRCONF_FIELD_NO_VALUE, field_name); return NULL; } else { /* points after the = sign */ p++; } } /* skip initial spaces and tabs after = */ while ((*p == ' ') || (*p == '\t')) { p++; } return p; } /*read integer number after string str in the current file*/ int mr_conf_iread(const char *field_name) { char *p = NULL; /*pointer to the field */ int ret = 0; /*return value */ p = mr_conf_read(field_name); if (p != NULL) { ret = atoi(p); } return ret; } /*read float/double number after string str in the current file*/ double mr_conf_fread(const char *field_name) { char *p = NULL; /*pointer to the field */ double ret = 0.0; /*return value */ p = mr_conf_read(field_name); if (p != NULL) { ret = atof(p); } return ret; } /* reads string outstr after string str in the current file (between "..."), not more than maxlength symbols: cannot check if outstr has enough length! It must be at least maxlength+1 ! Returns number of read chars */ char *mr_conf_sread(const char *field_name) { char *p = NULL; /*pointer to the field */ char *q = NULL; /*pointer to the field */ char *r = NULL; /*pointer to the field */ char *ret = NULL; /*return value */ int size = 0; /*size of returned string */ int i = 0; ret = NULL; p = mr_conf_read(field_name); if (p == NULL) { return(p); } mr_asprintf(&q, p); /* trunk at first \n */ r = index(q,'\n'); size = r-q+1; /*copy filtered data to the buffer */ ret = (char *) malloc(sizeof(char) * (size)); if (ret == NULL) { mr_conf_error_msg(MRCONF_ALLOC_FAILED, ""); return (NULL); } while (i < size - 1) { ret[i] = *p; i++; p++; } ret[i] = (char) 0; /*and set its length */ mr_free(q); return ret; } /*removes all comments from the buffer*/ static void mr_conf_remove_comments() { char *tmp_buf; /*temporary buffer without comments */ size_t length /*initial length */ ; size_t i; /*iterator */ size_t k; /*conditioned iterator for tmp_buffer */ length = strlen(buffer); /*sizing the new chain */ k = 0; i = 0; while (i < length) { if (buffer[i] != MRCONF_COMM_CHAR) { k++; i++; } else { while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) { i++; } } } /* k is new buffer length now */ tmp_buf = (char *) malloc(sizeof(char) * (k + 1)); if (tmp_buf == NULL) { mr_conf_error_msg(MRCONF_ALLOC_FAILED, ""); return; } k = 0; i = 0; while (i < length) { if (buffer[i] != MRCONF_COMM_CHAR) { tmp_buf[k++] = buffer[i++]; } else { while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) { i++; } } } tmp_buf[k] = (char) 0; /*and set its length */ mr_free(buffer); /*copy filtered data to the buffer */ buffer = tmp_buf; } static int mr_conf_check_int_flag(const int flag) { return (flag & internal_flags); } static void mr_conf_set_int_flag(const int flag) { internal_flags = flag | internal_flags; } static void mr_conf_drop_int_flag(const int flag) { internal_flags = (~flag) & internal_flags; } /*local function to define size of a file. Return 0 for mistake*/ static size_t mr_conf_filesize(const char *name) { FILE *F = fopen(name, "r"); /*file to open */ size_t length; /*number to return */ if (F == NULL) { return 0; } fseek(F, 0, SEEK_END); /*set position to the end of file */ length = ftell(F); /*define number of position=> this is its length */ fclose(F); return length; } /*output error message*/ static void mr_conf_error_msg(int error_code, const char *add_line) { if ((mr_conf_flags & MRCONF_FLAG_VERBOSE)) { /*if verbose mode */ switch (error_code) { case MRCONF_BAD_FILE: mr_msg(0,"%s %s %s\n", MRCONF_STR_ERROR, MRCONF_STR_BAD_FILE, add_line); break; case MRCONF_ALLOC_FAILED: mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_ALLOC_FAILED); break; case MRCONF_READING_FAILED: mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_READING_FAILED); break; case MRCONF_FIELD_NOT_FOUND: mr_msg(1,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NOT_FOUND, add_line); mr_msg(1,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_SET_TO_ZERO); break; case MRCONF_FIELD_NO_VALUE: mr_msg(1,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NO_VALUE, add_line); mr_msg(1,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_IGNORE); break; case MRCONF_CLOSE_BUT_NOT_OPEN: mr_msg(0,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CLOSE_BUT_NOT_OPEN); break; case MRCONF_CALL_BUT_NOT_OPEN: mr_msg(0,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CALL_BUT_NOT_OPEN); break; case MRCONF_OPEN_OPENED: mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_OPEN_OPENED); break; default: mr_msg(1,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_DEFAULT_ERROR); break; } } }