diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/util/inihelper.c --- a/project_files/frontlib/util/inihelper.c Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/util/inihelper.c Tue Jun 12 21:10:11 2012 +0200 @@ -1,4 +1,7 @@ #include "inihelper.h" +#include "../iniparser/dictionary.h" +#include "../iniparser/iniparser.h" + #include "logging.h" #include "util.h" @@ -9,167 +12,309 @@ #include #include -static bool keychar_needs_urlencoding(char c) { - return !isalnum(c); -} - -char *inihelper_urlencode(const char *inbuf) { - if(!inbuf) { - return NULL; - } - size_t insize = strlen(inbuf); - if(insize > SIZE_MAX/4) { - return NULL; - } - - char *outbuf = flib_malloc(insize*3+1); - if(!outbuf) { - return NULL; - } +struct _flib_ini { + dictionary *inidict; + char *currentSection; +}; - size_t inpos = 0, outpos = 0; - while(inbuf[inpos]) { - if(!keychar_needs_urlencoding(inbuf[inpos])) { - outbuf[outpos++] = inbuf[inpos++]; - } else { - if(snprintf(outbuf+outpos, 4, "%%%02X", (unsigned)((uint8_t*)inbuf)[inpos])<0) { - free(outbuf); - return NULL; - } - inpos++; - outpos += 3; - } - } - outbuf[outpos] = 0; - char *shrunk = realloc(outbuf, outpos+1); - return shrunk ? shrunk : outbuf; -} - -char *inihelper_urldecode(const char *inbuf) { - char *outbuf = flib_malloc(strlen(inbuf)+1); - if(!outbuf) { - return NULL; - } - - size_t inpos = 0, outpos = 0; - while(inbuf[inpos]) { - if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) { - char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0}; - outbuf[outpos++] = strtol(temp, NULL, 16); - inpos += 3; - } else { - outbuf[outpos++] = inbuf[inpos++]; - } - } - outbuf[outpos] = 0; - char *shrunk = realloc(outbuf, outpos+1); - return shrunk ? shrunk : outbuf; -} - -char *inihelper_createDictKey(const char *sectionName, const char *keyName) { - if(!sectionName || !keyName) { - flib_log_e("null parameter in inihelper_createDictKey"); - return NULL; - } +static char *createDictKey(const char *sectionName, const char *keyName) { return flib_asprintf("%s:%s", sectionName, keyName); } -char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - if(!inifile || !sectionName || !keyName) { - flib_log_e("null parameter in inihelper_getstring"); - *error = true; - return NULL; +/** + * Turns a string into a lowercase string, in-place. + */ +static void strToLower(char *str) { + if(str) { + while(*str) { + *str = tolower(*str); + str++; + } } - char *extendedkey = inihelper_createDictKey(sectionName, keyName); - if(!extendedkey) { - *error = true; - return NULL; +} + +flib_ini *flib_ini_create(const char *filename) { + flib_ini *result = NULL; + flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini)); + if(tmpIni) { + if(filename) { + tmpIni->inidict = iniparser_load(filename); + } + if(!tmpIni->inidict) { + tmpIni->inidict = dictionary_new(0); + } + if(tmpIni->inidict) { + result = tmpIni; + tmpIni = NULL; + } } - char *result = iniparser_getstring(inifile, extendedkey, NULL); - free(extendedkey); - if(!result) { - flib_log_d("Missing ini setting: %s/%s", sectionName, keyName); - *error = true; + flib_ini_destroy(tmpIni); + return result; +} + +flib_ini *flib_ini_load(const char *filename) { + flib_ini *result = NULL; + if(!filename) { + flib_log_e("null parameter in flib_ini_load"); + } else { + flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini)); + if(tmpIni) { + tmpIni->inidict = iniparser_load(filename); + if(tmpIni->inidict) { + result = tmpIni; + tmpIni = NULL; + } + } + flib_ini_destroy(tmpIni); } return result; } -char *inihelper_getstringdup(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - return flib_strdupnull(inihelper_getstring(inifile, error, sectionName, keyName)); -} - -int inihelper_getint(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - char *value = inihelper_getstring(inifile, error, sectionName, keyName); - if(!value) { - return 0; +int flib_ini_save(flib_ini *ini, const char *filename) { + int result = INI_ERROR_OTHER; + if(!ini || !filename) { + flib_log_e("null parameter in flib_ini_save"); } else { - errno = 0; - long val = strtol(value, NULL, 10); - if(errno!=0) { - flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", sectionName, keyName, value); - *error = true; - return 0; - } - if(valINT_MAX) { - flib_log_w("ini setting %s/%s = \"%s\" is too large or too small.", sectionName, keyName, value); - *error = true; - return 0; + FILE *file = fopen(filename, "wb"); + if(!file) { + flib_log_e("Error opening file \"%s\" for writing.", filename); + } else { + iniparser_dump_ini(ini->inidict, file); + if(fclose(file)) { + flib_log_e("Write error on ini file \"%s\"", filename); + } else { + result = 0; + } } - return (int)val; - } -} - -bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - char *value = inihelper_getstring(inifile, error, sectionName, keyName); - if(!value) { - return false; - } else { - bool trueval = strchr("1tTyY", value[0]); - bool falseval = strchr("0fFnN", value[0]); - if(!trueval && !falseval) { - flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", sectionName, keyName, value); - *error = true; - return false; - } else { - return trueval; - } - } -} - -int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value) { - int result = -1; - if(!dict || !sectionName || !keyName || !value) { - flib_log_e("null parameter in inihelper_setstr"); - } else { - char *extendedkey = inihelper_createDictKey(sectionName, keyName); - if(extendedkey) { - result = iniparser_set(dict, extendedkey, value); - } - free(extendedkey); } return result; } -int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value) { - int result = -1; - if(!dict || !sectionName || !keyName) { - flib_log_e("null parameter in inihelper_setint"); +void flib_ini_destroy(flib_ini *ini) { + if(ini) { + if(ini->inidict) { + iniparser_freedict(ini->inidict); + } + free(ini->currentSection); + free(ini); + } +} + +int flib_ini_enter_section(flib_ini *ini, const char *section) { + int result = INI_ERROR_OTHER; + if(ini) { + free(ini->currentSection); + ini->currentSection = NULL; + } + if(!ini || !section) { + flib_log_e("null parameter in flib_ini_enter_section"); } else { - char *strvalue = flib_asprintf("%i", value); - if(strvalue) { - result = inihelper_setstr(dict, sectionName, keyName, strvalue); - free(strvalue); + if(!iniparser_find_entry(ini->inidict, section)) { + result = INI_ERROR_NOTFOUND; + } else { + ini->currentSection = flib_strdupnull(section); + if(ini->currentSection) { + // Usually iniparser ignores case, but some section-handling functions don't, + // so we set it to lowercase manually + strToLower(ini->currentSection); + result = 0; + } + } + } + return result; +} + +int flib_ini_create_section(flib_ini *ini, const char *section) { + int result = INI_ERROR_OTHER; + if(!ini || !section) { + flib_log_e("null parameter in flib_ini_create_section"); + } else { + result = flib_ini_enter_section(ini, section); + if(result == INI_ERROR_NOTFOUND) { + if(iniparser_set(ini->inidict, section, NULL)) { + result = INI_ERROR_OTHER; + } else { + result = flib_ini_enter_section(ini, section); + } } } return result; } -int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value) { - int result = -1; - if(!dict || !sectionName || !keyName) { - flib_log_e("null parameter in inihelper_setbool"); +/** + * The result is an internal string of the iniparser, don't free it. + */ +static char *findValue(dictionary *dict, const char *section, const char *key) { + char *result = NULL; + char *dictKey = createDictKey(section, key); + if(dictKey) { + result = iniparser_getstring(dict, dictKey, NULL); + } + free(dictKey); + return result; +} + +int flib_ini_get_str(flib_ini *ini, char **outVar, const char *key) { + char *tmpValue = NULL; + int result = flib_ini_get_str_opt(ini, &tmpValue, key, NULL); + if(result==0) { + if(tmpValue == NULL) { + result = INI_ERROR_NOTFOUND; + } else { + *outVar = tmpValue; + tmpValue = NULL; + } + } + free(tmpValue); + return result; +} + +int flib_ini_get_str_opt(flib_ini *ini, char **outVar, const char *key, const char *def) { + int result = INI_ERROR_OTHER; + if(!ini || !outVar || !key || !ini->currentSection) { + flib_log_e("null parameter or no current section in flib_ini_get_str_opt"); } else { - result = inihelper_setstr(dict, sectionName, keyName, value ? "true" : "false"); + const char *value = findValue(ini->inidict, ini->currentSection, key); + if(!value) { + value = def; + } + char *valueDup = flib_strdupnull(value); + if(valueDup) { + *outVar = valueDup; + result = 0; + } + } + return result; +} + +int flib_ini_get_int(flib_ini *ini, int *outVar, const char *key) { + char *tmpValue = NULL; + int result = flib_ini_get_str(ini, &tmpValue, key); + if(result==0) { + errno = 0; + long val = strtol(tmpValue, NULL, 10); + if(errno!=0 || valINT_MAX) { + flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", ini->currentSection, key, tmpValue); + result = INI_ERROR_FORMAT; + } else { + *outVar = val; + } + } + free(tmpValue); + return result; +} + +int flib_ini_get_int_opt(flib_ini *ini, int *outVar, const char *key, int def) { + int tmpValue; + int result = flib_ini_get_int(ini, &tmpValue, key); + if(result == 0) { + *outVar = tmpValue; + } else if(result == INI_ERROR_NOTFOUND) { + *outVar = def; + result = 0; } return result; } + +int flib_ini_get_bool(flib_ini *ini, bool *outVar, const char *key) { + char *tmpValue = NULL; + int result = flib_ini_get_str(ini, &tmpValue, key); + if(result==0) { + bool trueval = strchr("1tTyY", tmpValue[0]); + bool falseval = strchr("0fFnN", tmpValue[0]); + if(!trueval && !falseval) { + flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", ini->currentSection, key, tmpValue); + result = INI_ERROR_FORMAT; + } else { + *outVar = trueval; + } + } + free(tmpValue); + return result; +} + +int flib_ini_get_bool_opt(flib_ini *ini, bool *outVar, const char *key, bool def) { + bool tmpValue; + int result = flib_ini_get_bool(ini, &tmpValue, key); + if(result == 0) { + *outVar = tmpValue; + } else if(result == INI_ERROR_NOTFOUND) { + *outVar = def; + result = 0; + } + return result; +} + +int flib_ini_set_str(flib_ini *ini, const char *key, const char *value) { + int result = INI_ERROR_OTHER; + if(!ini || !key || !value || !ini->currentSection) { + flib_log_e("null parameter or no current section in flib_ini_set_str"); + } else { + char *dictKey = createDictKey(ini->currentSection, key); + if(dictKey) { + result = iniparser_set(ini->inidict, dictKey, value); + } + free(dictKey); + } + return result; +} + +int flib_ini_set_int(flib_ini *ini, const char *key, int value) { + int result = INI_ERROR_OTHER; + char *strvalue = flib_asprintf("%i", value); + if(strvalue) { + result = flib_ini_set_str(ini, key, strvalue); + } + free(strvalue); + return result; +} + +int flib_ini_set_bool(flib_ini *ini, const char *key, bool value) { + return flib_ini_set_str(ini, key, value ? "true" : "false"); +} + +int flib_ini_get_sectioncount(flib_ini *ini) { + int result = INI_ERROR_OTHER; + if(!ini) { + flib_log_e("null parameter in flib_ini_get_sectioncount"); + } else { + result = iniparser_getnsec(ini->inidict); + } + return result; +} + +char *flib_ini_get_sectionname(flib_ini *ini, int number) { + char *result = NULL; + if(!ini || number<0) { + flib_log_e("bad parameter in flib_ini_get_sectionname"); + } else { + result = flib_strdupnull(iniparser_getsecname(ini->inidict, number)); + } + return result; +} + +int flib_ini_get_keycount(flib_ini *ini) { + int result = INI_ERROR_OTHER; + if(!ini || !ini->currentSection) { + flib_log_e("null parameter or no current section in flib_ini_get_keycount"); + } else { + result = iniparser_getsecnkeys(ini->inidict, ini->currentSection); + } + return result; +} + +char *flib_ini_get_keyname(flib_ini *ini, int number) { + char *result = NULL; + if(!ini || number<0 || !ini->currentSection) { + flib_log_e("bad parameter or no current section in flib_ini_get_keyname"); + } else { + int keyCount = iniparser_getsecnkeys(ini->inidict, ini->currentSection); + char **keys = iniparser_getseckeys(ini->inidict, ini->currentSection); + if(keys && keyCount>number) { + // The keys are in the format section:key, so we have to skip the section and colon. + result = flib_strdupnull(keys[number]+strlen(ini->currentSection)+1); + } + free(keys); + } + return result; +}