project_files/frontlib/util/inihelper.c
author Medo <smaxein@googlemail.com>
Tue, 12 Jun 2012 21:10:11 +0200
changeset 7227 1c859f572d72
parent 7224 5143861c83bd
child 7230 240620f46dd7
permissions -rw-r--r--
frontlib: Rewrote the ini helper code, finished ini reading/writing support for all relevant file types

#include "inihelper.h"
#include "../iniparser/dictionary.h"
#include "../iniparser/iniparser.h"

#include "logging.h"
#include "util.h"

#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <stdarg.h>

struct _flib_ini {
	dictionary *inidict;
	char *currentSection;
};

static char *createDictKey(const char *sectionName, const char *keyName) {
	return flib_asprintf("%s:%s", sectionName, keyName);
}

/**
 * Turns a string into a lowercase string, in-place.
 */
static void strToLower(char *str) {
	if(str) {
		while(*str) {
			*str = tolower(*str);
			str++;
		}
	}
}

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;
		}
	}
	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;
}

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 {
		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 result;
}

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 {
		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;
}

/**
 * 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 {
		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 || val<INT_MIN || val>INT_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;
}