project_files/frontlib/util/inihelper.c
branchhedgeroid
changeset 7857 2bc61f8841a1
parent 7467 a9ab8067a2d1
child 10017 de822cd3df3a
equal deleted inserted replaced
7855:ddcdedd3330b 7857:2bc61f8841a1
       
     1 /*
       
     2  * Hedgewars, a free turn based strategy game
       
     3  * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU General Public License
       
     7  * as published by the Free Software Foundation; either version 2
       
     8  * of the License, or (at your option) any later version.
       
     9  *
       
    10  * This program is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    13  * GNU General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License
       
    16  * along with this program; if not, write to the Free Software
       
    17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
       
    18  */
       
    19 
       
    20 #include "inihelper.h"
       
    21 #include "../iniparser/dictionary.h"
       
    22 #include "../iniparser/iniparser.h"
       
    23 
       
    24 #include "logging.h"
       
    25 #include "util.h"
       
    26 
       
    27 #include <string.h>
       
    28 #include <stdlib.h>
       
    29 #include <ctype.h>
       
    30 #include <limits.h>
       
    31 #include <errno.h>
       
    32 #include <stdarg.h>
       
    33 
       
    34 struct _flib_ini {
       
    35 	dictionary *inidict;
       
    36 	char *currentSection;
       
    37 };
       
    38 
       
    39 static char *createDictKey(const char *sectionName, const char *keyName) {
       
    40 	return flib_asprintf("%s:%s", sectionName, keyName);
       
    41 }
       
    42 
       
    43 /**
       
    44  * Turns a string into a lowercase string, in-place.
       
    45  */
       
    46 static void strToLower(char *str) {
       
    47 	if(str) {
       
    48 		while(*str) {
       
    49 			*str = tolower(*str);
       
    50 			str++;
       
    51 		}
       
    52 	}
       
    53 }
       
    54 
       
    55 flib_ini *flib_ini_create(const char *filename) {
       
    56 	flib_ini *result = NULL;
       
    57 	flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini));
       
    58 	if(tmpIni) {
       
    59 		if(filename) {
       
    60 			tmpIni->inidict = iniparser_load(filename);
       
    61 		}
       
    62 		if(!tmpIni->inidict) {
       
    63 			tmpIni->inidict = dictionary_new(0);
       
    64 		}
       
    65 		if(tmpIni->inidict) {
       
    66 			result = tmpIni;
       
    67 			tmpIni = NULL;
       
    68 		}
       
    69 	}
       
    70 	flib_ini_destroy(tmpIni);
       
    71 	return result;
       
    72 }
       
    73 
       
    74 flib_ini *flib_ini_load(const char *filename) {
       
    75 	flib_ini *result = NULL;
       
    76 	if(!log_badargs_if(filename==NULL)) {
       
    77 		flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini));
       
    78 		if(tmpIni) {
       
    79 			tmpIni->inidict = iniparser_load(filename);
       
    80 			if(tmpIni->inidict) {
       
    81 				result = tmpIni;
       
    82 				tmpIni = NULL;
       
    83 			}
       
    84 		}
       
    85 		flib_ini_destroy(tmpIni);
       
    86 	}
       
    87 	return result;
       
    88 }
       
    89 
       
    90 int flib_ini_save(flib_ini *ini, const char *filename) {
       
    91 	int result = INI_ERROR_OTHER;
       
    92 	if(!log_badargs_if2(ini==NULL, filename==NULL)) {
       
    93 		FILE *file = fopen(filename, "wb");
       
    94 		if(!file) {
       
    95 			flib_log_e("Error opening file \"%s\" for writing.", filename);
       
    96 		} else {
       
    97 			iniparser_dump_ini(ini->inidict, file);
       
    98 			if(fclose(file)) {
       
    99 				flib_log_e("Write error on ini file \"%s\"", filename);
       
   100 			} else {
       
   101 				result = 0;
       
   102 			}
       
   103 		}
       
   104 	}
       
   105 	return result;
       
   106 }
       
   107 
       
   108 void flib_ini_destroy(flib_ini *ini) {
       
   109 	if(ini) {
       
   110 		if(ini->inidict) {
       
   111 			iniparser_freedict(ini->inidict);
       
   112 		}
       
   113 		free(ini->currentSection);
       
   114 		free(ini);
       
   115 	}
       
   116 }
       
   117 
       
   118 int flib_ini_enter_section(flib_ini *ini, const char *section) {
       
   119 	int result = INI_ERROR_OTHER;
       
   120 	if(ini) {
       
   121 		free(ini->currentSection);
       
   122 		ini->currentSection = NULL;
       
   123 	}
       
   124 	if(!log_badargs_if2(ini==NULL, section==NULL)) {
       
   125 		if(!iniparser_find_entry(ini->inidict, section)) {
       
   126 			flib_log_d("Ini section %s not found", section);
       
   127 			result = INI_ERROR_NOTFOUND;
       
   128 		} else {
       
   129 			ini->currentSection = flib_strdupnull(section);
       
   130 			if(ini->currentSection) {
       
   131 				// Usually iniparser ignores case, but some section-handling functions don't,
       
   132 				// so we set it to lowercase manually
       
   133 				strToLower(ini->currentSection);
       
   134 				result = 0;
       
   135 			}
       
   136 		}
       
   137 	}
       
   138 	return result;
       
   139 }
       
   140 
       
   141 int flib_ini_create_section(flib_ini *ini, const char *section) {
       
   142 	int result = INI_ERROR_OTHER;
       
   143 	if(!log_badargs_if2(ini==NULL, section==NULL)) {
       
   144 		result = flib_ini_enter_section(ini, section);
       
   145 		if(result == INI_ERROR_NOTFOUND) {
       
   146 			if(iniparser_set(ini->inidict, section, NULL)) {
       
   147 				flib_log_e("Error creating ini section %s", section);
       
   148 				result = INI_ERROR_OTHER;
       
   149 			} else {
       
   150 				result = flib_ini_enter_section(ini, section);
       
   151 			}
       
   152 		}
       
   153 	}
       
   154 	return result;
       
   155 }
       
   156 
       
   157 /**
       
   158  * The result is an internal string of the iniparser, don't free it.
       
   159  */
       
   160 static char *findValue(dictionary *dict, const char *section, const char *key) {
       
   161 	char *result = NULL;
       
   162 	char *dictKey = createDictKey(section, key);
       
   163 	if(dictKey) {
       
   164 		result = iniparser_getstring(dict, dictKey, NULL);
       
   165 	}
       
   166 	free(dictKey);
       
   167 	return result;
       
   168 }
       
   169 
       
   170 int flib_ini_get_str(flib_ini *ini, char **outVar, const char *key) {
       
   171 	char *tmpValue = NULL;
       
   172 	int result = flib_ini_get_str_opt(ini, &tmpValue, key, NULL);
       
   173 	if(result==0) {
       
   174 		if(tmpValue == NULL) {
       
   175 			result = INI_ERROR_NOTFOUND;
       
   176 		} else {
       
   177 			*outVar = tmpValue;
       
   178 			tmpValue = NULL;
       
   179 		}
       
   180 	}
       
   181 	free(tmpValue);
       
   182 	return result;
       
   183 }
       
   184 
       
   185 int flib_ini_get_str_opt(flib_ini *ini, char **outVar, const char *key, const char *def) {
       
   186 	int result = INI_ERROR_OTHER;
       
   187 	if(!log_badargs_if4(ini==NULL, ini->currentSection==NULL, outVar==NULL, key==NULL)) {
       
   188 		const char *value = findValue(ini->inidict, ini->currentSection, key);
       
   189 		if(!value) {
       
   190 			value = def;
       
   191 		}
       
   192 		char *valueDup = flib_strdupnull(value);
       
   193 		if(valueDup || !def) {
       
   194 			*outVar = valueDup;
       
   195 			result = 0;
       
   196 		}
       
   197 	}
       
   198 	return result;
       
   199 }
       
   200 
       
   201 int flib_ini_get_int(flib_ini *ini, int *outVar, const char *key) {
       
   202 	char *tmpValue = NULL;
       
   203 	int result = flib_ini_get_str(ini, &tmpValue, key);
       
   204 	if(result==0) {
       
   205 		errno = 0;
       
   206 		long val = strtol(tmpValue, NULL, 10);
       
   207 		if(errno!=0 || val<INT_MIN || val>INT_MAX) {
       
   208 			flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", ini->currentSection, key, tmpValue);
       
   209 			result = INI_ERROR_FORMAT;
       
   210 		} else {
       
   211 			*outVar = val;
       
   212 		}
       
   213 	}
       
   214 	free(tmpValue);
       
   215 	return result;
       
   216 }
       
   217 
       
   218 int flib_ini_get_int_opt(flib_ini *ini, int *outVar, const char *key, int def) {
       
   219 	int tmpValue;
       
   220 	int result = flib_ini_get_int(ini, &tmpValue, key);
       
   221 	if(result == 0) {
       
   222 		*outVar = tmpValue;
       
   223 	} else if(result == INI_ERROR_NOTFOUND || result == INI_ERROR_FORMAT) {
       
   224 		*outVar = def;
       
   225 		result = 0;
       
   226 	}
       
   227 	return result;
       
   228 }
       
   229 
       
   230 int flib_ini_get_bool(flib_ini *ini, bool *outVar, const char *key) {
       
   231 	char *tmpValue = NULL;
       
   232 	int result = flib_ini_get_str(ini, &tmpValue, key);
       
   233 	if(result==0) {
       
   234 		bool trueval = strchr("1tTyY", tmpValue[0]);
       
   235 		bool falseval = strchr("0fFnN", tmpValue[0]);
       
   236 		if(!trueval && !falseval) {
       
   237 			flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", ini->currentSection, key, tmpValue);
       
   238 			result = INI_ERROR_FORMAT;
       
   239 		} else {
       
   240 			*outVar = trueval;
       
   241 		}
       
   242 	}
       
   243 	free(tmpValue);
       
   244 	return result;
       
   245 }
       
   246 
       
   247 int flib_ini_get_bool_opt(flib_ini *ini, bool *outVar, const char *key, bool def) {
       
   248 	bool tmpValue;
       
   249 	int result = flib_ini_get_bool(ini, &tmpValue, key);
       
   250 	if(result == 0) {
       
   251 		*outVar = tmpValue;
       
   252 	} else if(result == INI_ERROR_NOTFOUND || result == INI_ERROR_FORMAT) {
       
   253 		*outVar = def;
       
   254 		result = 0;
       
   255 	}
       
   256 	return result;
       
   257 }
       
   258 
       
   259 int flib_ini_set_str(flib_ini *ini, const char *key, const char *value) {
       
   260 	int result = INI_ERROR_OTHER;
       
   261 	if(!log_badargs_if4(ini==NULL, ini->currentSection==NULL, key==NULL, value==NULL)) {
       
   262 		char *dictKey = createDictKey(ini->currentSection, key);
       
   263 		if(dictKey) {
       
   264 			result = iniparser_set(ini->inidict, dictKey, value);
       
   265 			if(result) {
       
   266 				flib_log_e("Error setting ini entry %s to %s", dictKey, value);
       
   267 			}
       
   268 		}
       
   269 		free(dictKey);
       
   270 	}
       
   271 	return result;
       
   272 }
       
   273 
       
   274 int flib_ini_set_int(flib_ini *ini, const char *key, int value) {
       
   275 	int result = INI_ERROR_OTHER;
       
   276 	char *strvalue = flib_asprintf("%i", value);
       
   277 	if(strvalue) {
       
   278 		result = flib_ini_set_str(ini, key, strvalue);
       
   279 	}
       
   280 	free(strvalue);
       
   281 	return result;
       
   282 }
       
   283 
       
   284 int flib_ini_set_bool(flib_ini *ini, const char *key, bool value) {
       
   285 	return flib_ini_set_str(ini, key, value ? "true" : "false");
       
   286 }
       
   287 
       
   288 int flib_ini_get_sectioncount(flib_ini *ini) {
       
   289 	if(!log_badargs_if(ini==NULL)) {
       
   290 		return iniparser_getnsec(ini->inidict);
       
   291 	}
       
   292 	return INI_ERROR_OTHER;
       
   293 }
       
   294 
       
   295 char *flib_ini_get_sectionname(flib_ini *ini, int number) {
       
   296 	if(!log_badargs_if2(ini==NULL, number<0)) {
       
   297 		return flib_strdupnull(iniparser_getsecname(ini->inidict, number));
       
   298 	}
       
   299 	return NULL;
       
   300 }
       
   301 
       
   302 int flib_ini_get_keycount(flib_ini *ini) {
       
   303 	if(!log_badargs_if2(ini==NULL, ini->currentSection==NULL)) {
       
   304 		return iniparser_getsecnkeys(ini->inidict, ini->currentSection);
       
   305 	}
       
   306 	return INI_ERROR_OTHER;
       
   307 }
       
   308 
       
   309 char *flib_ini_get_keyname(flib_ini *ini, int number) {
       
   310 	char *result = NULL;
       
   311 	if(!log_badargs_if3(ini==NULL, ini->currentSection==NULL, number<0)) {
       
   312 		int keyCount = iniparser_getsecnkeys(ini->inidict, ini->currentSection);
       
   313 		char **keys = iniparser_getseckeys(ini->inidict, ini->currentSection);
       
   314 		if(keys && keyCount>number) {
       
   315 			// The keys are in the format section:key, so we have to skip the section and colon.
       
   316 			result = flib_strdupnull(keys[number]+strlen(ini->currentSection)+1);
       
   317 		}
       
   318 		free(keys);
       
   319 	}
       
   320 	return result;
       
   321 }