project_files/frontlib/util/inihelper.c
changeset 7227 1c859f572d72
parent 7224 5143861c83bd
child 7230 240620f46dd7
equal deleted inserted replaced
7224:5143861c83bd 7227:1c859f572d72
     1 #include "inihelper.h"
     1 #include "inihelper.h"
       
     2 #include "../iniparser/dictionary.h"
       
     3 #include "../iniparser/iniparser.h"
       
     4 
     2 #include "logging.h"
     5 #include "logging.h"
     3 #include "util.h"
     6 #include "util.h"
     4 
     7 
     5 #include <string.h>
     8 #include <string.h>
     6 #include <stdlib.h>
     9 #include <stdlib.h>
     7 #include <ctype.h>
    10 #include <ctype.h>
     8 #include <limits.h>
    11 #include <limits.h>
     9 #include <errno.h>
    12 #include <errno.h>
    10 #include <stdarg.h>
    13 #include <stdarg.h>
    11 
    14 
    12 static bool keychar_needs_urlencoding(char c) {
    15 struct _flib_ini {
    13 	return !isalnum(c);
    16 	dictionary *inidict;
    14 }
    17 	char *currentSection;
    15 
    18 };
    16 char *inihelper_urlencode(const char *inbuf) {
    19 
    17 	if(!inbuf) {
    20 static char *createDictKey(const char *sectionName, const char *keyName) {
    18 		return NULL;
       
    19 	}
       
    20 	size_t insize = strlen(inbuf);
       
    21 	if(insize > SIZE_MAX/4) {
       
    22 		return NULL;
       
    23 	}
       
    24 
       
    25 	char *outbuf = flib_malloc(insize*3+1);
       
    26 	if(!outbuf) {
       
    27 		return NULL;
       
    28 	}
       
    29 
       
    30     size_t inpos = 0, outpos = 0;
       
    31     while(inbuf[inpos]) {
       
    32         if(!keychar_needs_urlencoding(inbuf[inpos])) {
       
    33         	outbuf[outpos++] = inbuf[inpos++];
       
    34         } else {
       
    35             if(snprintf(outbuf+outpos, 4, "%%%02X", (unsigned)((uint8_t*)inbuf)[inpos])<0) {
       
    36             	free(outbuf);
       
    37             	return NULL;
       
    38             }
       
    39             inpos++;
       
    40             outpos += 3;
       
    41         }
       
    42     }
       
    43     outbuf[outpos] = 0;
       
    44     char *shrunk = realloc(outbuf, outpos+1);
       
    45     return shrunk ? shrunk : outbuf;
       
    46 }
       
    47 
       
    48 char *inihelper_urldecode(const char *inbuf) {
       
    49 	char *outbuf = flib_malloc(strlen(inbuf)+1);
       
    50 	if(!outbuf) {
       
    51 		return NULL;
       
    52 	}
       
    53 
       
    54     size_t inpos = 0, outpos = 0;
       
    55     while(inbuf[inpos]) {
       
    56         if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) {
       
    57             char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0};
       
    58             outbuf[outpos++] = strtol(temp, NULL, 16);
       
    59             inpos += 3;
       
    60         } else {
       
    61         	outbuf[outpos++] = inbuf[inpos++];
       
    62         }
       
    63     }
       
    64     outbuf[outpos] = 0;
       
    65     char *shrunk = realloc(outbuf, outpos+1);
       
    66     return shrunk ? shrunk : outbuf;
       
    67 }
       
    68 
       
    69 char *inihelper_createDictKey(const char *sectionName, const char *keyName) {
       
    70 	if(!sectionName || !keyName) {
       
    71 		flib_log_e("null parameter in inihelper_createDictKey");
       
    72 		return NULL;
       
    73 	}
       
    74 	return flib_asprintf("%s:%s", sectionName, keyName);
    21 	return flib_asprintf("%s:%s", sectionName, keyName);
    75 }
    22 }
    76 
    23 
    77 char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) {
    24 /**
    78 	if(!inifile || !sectionName || !keyName) {
    25  * Turns a string into a lowercase string, in-place.
    79 		flib_log_e("null parameter in inihelper_getstring");
    26  */
    80 		*error = true;
    27 static void strToLower(char *str) {
    81 		return NULL;
    28 	if(str) {
    82 	}
    29 		while(*str) {
    83 	char *extendedkey = inihelper_createDictKey(sectionName, keyName);
    30 			*str = tolower(*str);
    84 	if(!extendedkey) {
    31 			str++;
    85 		*error = true;
    32 		}
    86 		return NULL;
    33 	}
    87 	}
    34 }
    88 	char *result = iniparser_getstring(inifile, extendedkey, NULL);
    35 
    89 	free(extendedkey);
    36 flib_ini *flib_ini_create(const char *filename) {
    90 	if(!result) {
    37 	flib_ini *result = NULL;
    91 		flib_log_d("Missing ini setting: %s/%s", sectionName, keyName);
    38 	flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini));
    92 		*error = true;
    39 	if(tmpIni) {
    93 	}
    40 		if(filename) {
    94 	return result;
    41 			tmpIni->inidict = iniparser_load(filename);
    95 }
    42 		}
    96 
    43 		if(!tmpIni->inidict) {
    97 char *inihelper_getstringdup(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) {
    44 			tmpIni->inidict = dictionary_new(0);
    98 	return flib_strdupnull(inihelper_getstring(inifile, error, sectionName, keyName));
    45 		}
    99 }
    46 		if(tmpIni->inidict) {
   100 
    47 			result = tmpIni;
   101 int inihelper_getint(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) {
    48 			tmpIni = NULL;
   102 	char *value = inihelper_getstring(inifile, error, sectionName, keyName);
    49 		}
   103 	if(!value) {
    50 	}
   104 		return 0;
    51 	flib_ini_destroy(tmpIni);
   105 	} else {
    52 	return result;
       
    53 }
       
    54 
       
    55 flib_ini *flib_ini_load(const char *filename) {
       
    56 	flib_ini *result = NULL;
       
    57 	if(!filename) {
       
    58 		flib_log_e("null parameter in flib_ini_load");
       
    59 	} else {
       
    60 		flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini));
       
    61 		if(tmpIni) {
       
    62 			tmpIni->inidict = iniparser_load(filename);
       
    63 			if(tmpIni->inidict) {
       
    64 				result = tmpIni;
       
    65 				tmpIni = NULL;
       
    66 			}
       
    67 		}
       
    68 		flib_ini_destroy(tmpIni);
       
    69 	}
       
    70 	return result;
       
    71 }
       
    72 
       
    73 int flib_ini_save(flib_ini *ini, const char *filename) {
       
    74 	int result = INI_ERROR_OTHER;
       
    75 	if(!ini || !filename) {
       
    76 		flib_log_e("null parameter in flib_ini_save");
       
    77 	} else {
       
    78 		FILE *file = fopen(filename, "wb");
       
    79 		if(!file) {
       
    80 			flib_log_e("Error opening file \"%s\" for writing.", filename);
       
    81 		} else {
       
    82 			iniparser_dump_ini(ini->inidict, file);
       
    83 			if(fclose(file)) {
       
    84 				flib_log_e("Write error on ini file \"%s\"", filename);
       
    85 			} else {
       
    86 				result = 0;
       
    87 			}
       
    88 		}
       
    89 	}
       
    90 	return result;
       
    91 }
       
    92 
       
    93 void flib_ini_destroy(flib_ini *ini) {
       
    94 	if(ini) {
       
    95 		if(ini->inidict) {
       
    96 			iniparser_freedict(ini->inidict);
       
    97 		}
       
    98 		free(ini->currentSection);
       
    99 		free(ini);
       
   100 	}
       
   101 }
       
   102 
       
   103 int flib_ini_enter_section(flib_ini *ini, const char *section) {
       
   104 	int result = INI_ERROR_OTHER;
       
   105 	if(ini) {
       
   106 		free(ini->currentSection);
       
   107 		ini->currentSection = NULL;
       
   108 	}
       
   109 	if(!ini || !section) {
       
   110 		flib_log_e("null parameter in flib_ini_enter_section");
       
   111 	} else {
       
   112 		if(!iniparser_find_entry(ini->inidict, section)) {
       
   113 			result = INI_ERROR_NOTFOUND;
       
   114 		} else {
       
   115 			ini->currentSection = flib_strdupnull(section);
       
   116 			if(ini->currentSection) {
       
   117 				// Usually iniparser ignores case, but some section-handling functions don't,
       
   118 				// so we set it to lowercase manually
       
   119 				strToLower(ini->currentSection);
       
   120 				result = 0;
       
   121 			}
       
   122 		}
       
   123 	}
       
   124 	return result;
       
   125 }
       
   126 
       
   127 int flib_ini_create_section(flib_ini *ini, const char *section) {
       
   128 	int result = INI_ERROR_OTHER;
       
   129 	if(!ini || !section) {
       
   130 		flib_log_e("null parameter in flib_ini_create_section");
       
   131 	} else {
       
   132 		result = flib_ini_enter_section(ini, section);
       
   133 		if(result == INI_ERROR_NOTFOUND) {
       
   134 			if(iniparser_set(ini->inidict, section, NULL)) {
       
   135 				result = INI_ERROR_OTHER;
       
   136 			} else {
       
   137 				result = flib_ini_enter_section(ini, section);
       
   138 			}
       
   139 		}
       
   140 	}
       
   141 	return result;
       
   142 }
       
   143 
       
   144 /**
       
   145  * The result is an internal string of the iniparser, don't free it.
       
   146  */
       
   147 static char *findValue(dictionary *dict, const char *section, const char *key) {
       
   148 	char *result = NULL;
       
   149 	char *dictKey = createDictKey(section, key);
       
   150 	if(dictKey) {
       
   151 		result = iniparser_getstring(dict, dictKey, NULL);
       
   152 	}
       
   153 	free(dictKey);
       
   154 	return result;
       
   155 }
       
   156 
       
   157 int flib_ini_get_str(flib_ini *ini, char **outVar, const char *key) {
       
   158 	char *tmpValue = NULL;
       
   159 	int result = flib_ini_get_str_opt(ini, &tmpValue, key, NULL);
       
   160 	if(result==0) {
       
   161 		if(tmpValue == NULL) {
       
   162 			result = INI_ERROR_NOTFOUND;
       
   163 		} else {
       
   164 			*outVar = tmpValue;
       
   165 			tmpValue = NULL;
       
   166 		}
       
   167 	}
       
   168 	free(tmpValue);
       
   169 	return result;
       
   170 }
       
   171 
       
   172 int flib_ini_get_str_opt(flib_ini *ini, char **outVar, const char *key, const char *def) {
       
   173 	int result = INI_ERROR_OTHER;
       
   174 	if(!ini || !outVar || !key || !ini->currentSection) {
       
   175 		flib_log_e("null parameter or no current section in flib_ini_get_str_opt");
       
   176 	} else {
       
   177 		const char *value = findValue(ini->inidict, ini->currentSection, key);
       
   178 		if(!value) {
       
   179 			value = def;
       
   180 		}
       
   181 		char *valueDup = flib_strdupnull(value);
       
   182 		if(valueDup) {
       
   183 			*outVar = valueDup;
       
   184 			result = 0;
       
   185 		}
       
   186 	}
       
   187 	return result;
       
   188 }
       
   189 
       
   190 int flib_ini_get_int(flib_ini *ini, int *outVar, const char *key) {
       
   191 	char *tmpValue = NULL;
       
   192 	int result = flib_ini_get_str(ini, &tmpValue, key);
       
   193 	if(result==0) {
   106 		errno = 0;
   194 		errno = 0;
   107 		long val = strtol(value, NULL, 10);
   195 		long val = strtol(tmpValue, NULL, 10);
   108 		if(errno!=0) {
   196 		if(errno!=0 || val<INT_MIN || val>INT_MAX) {
   109 			flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", sectionName, keyName, value);
   197 			flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", ini->currentSection, key, tmpValue);
   110 			*error = true;
   198 			result = INI_ERROR_FORMAT;
   111 			return 0;
   199 		} else {
   112 		}
   200 			*outVar = val;
   113 		if(val<INT_MIN || val>INT_MAX) {
   201 		}
   114 			flib_log_w("ini setting %s/%s = \"%s\" is too large or too small.", sectionName, keyName, value);
   202 	}
   115 			*error = true;
   203 	free(tmpValue);
   116 			return 0;
   204 	return result;
   117 		}
   205 }
   118 		return (int)val;
   206 
   119 	}
   207 int flib_ini_get_int_opt(flib_ini *ini, int *outVar, const char *key, int def) {
   120 }
   208 	int tmpValue;
   121 
   209 	int result = flib_ini_get_int(ini, &tmpValue, key);
   122 bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) {
   210 	if(result == 0) {
   123 	char *value = inihelper_getstring(inifile, error, sectionName, keyName);
   211 		*outVar = tmpValue;
   124 	if(!value) {
   212 	} else if(result == INI_ERROR_NOTFOUND) {
   125 		return false;
   213 		*outVar = def;
   126 	} else {
   214 		result = 0;
   127 		bool trueval = strchr("1tTyY", value[0]);
   215 	}
   128 		bool falseval = strchr("0fFnN", value[0]);
   216 	return result;
       
   217 }
       
   218 
       
   219 int flib_ini_get_bool(flib_ini *ini, bool *outVar, const char *key) {
       
   220 	char *tmpValue = NULL;
       
   221 	int result = flib_ini_get_str(ini, &tmpValue, key);
       
   222 	if(result==0) {
       
   223 		bool trueval = strchr("1tTyY", tmpValue[0]);
       
   224 		bool falseval = strchr("0fFnN", tmpValue[0]);
   129 		if(!trueval && !falseval) {
   225 		if(!trueval && !falseval) {
   130 			flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", sectionName, keyName, value);
   226 			flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", ini->currentSection, key, tmpValue);
   131 			*error = true;
   227 			result = INI_ERROR_FORMAT;
   132 			return false;
   228 		} else {
   133 		} else {
   229 			*outVar = trueval;
   134 			return trueval;
   230 		}
   135 		}
   231 	}
   136 	}
   232 	free(tmpValue);
   137 }
   233 	return result;
   138 
   234 }
   139 int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value) {
   235 
   140 	int result = -1;
   236 int flib_ini_get_bool_opt(flib_ini *ini, bool *outVar, const char *key, bool def) {
   141 	if(!dict || !sectionName || !keyName || !value) {
   237 	bool tmpValue;
   142 		flib_log_e("null parameter in inihelper_setstr");
   238 	int result = flib_ini_get_bool(ini, &tmpValue, key);
   143 	} else {
   239 	if(result == 0) {
   144 		char *extendedkey = inihelper_createDictKey(sectionName, keyName);
   240 		*outVar = tmpValue;
   145 		if(extendedkey) {
   241 	} else if(result == INI_ERROR_NOTFOUND) {
   146 			result = iniparser_set(dict, extendedkey, value);
   242 		*outVar = def;
   147 		}
   243 		result = 0;
   148 		free(extendedkey);
   244 	}
   149 	}
   245 	return result;
   150 	return result;
   246 }
   151 }
   247 
   152 
   248 int flib_ini_set_str(flib_ini *ini, const char *key, const char *value) {
   153 int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value) {
   249 	int result = INI_ERROR_OTHER;
   154 	int result = -1;
   250 	if(!ini || !key || !value || !ini->currentSection) {
   155 	if(!dict || !sectionName || !keyName) {
   251 		flib_log_e("null parameter or no current section in flib_ini_set_str");
   156 		flib_log_e("null parameter in inihelper_setint");
   252 	} else {
   157 	} else {
   253 		char *dictKey = createDictKey(ini->currentSection, key);
   158 		char *strvalue = flib_asprintf("%i", value);
   254 		if(dictKey) {
   159 		if(strvalue) {
   255 			result = iniparser_set(ini->inidict, dictKey, value);
   160 			result = inihelper_setstr(dict, sectionName, keyName, strvalue);
   256 		}
   161 			free(strvalue);
   257 		free(dictKey);
   162 		}
   258 	}
   163 	}
   259 	return result;
   164 	return result;
   260 }
   165 }
   261 
   166 
   262 int flib_ini_set_int(flib_ini *ini, const char *key, int value) {
   167 int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value) {
   263 	int result = INI_ERROR_OTHER;
   168 	int result = -1;
   264 	char *strvalue = flib_asprintf("%i", value);
   169 	if(!dict || !sectionName || !keyName) {
   265 	if(strvalue) {
   170 		flib_log_e("null parameter in inihelper_setbool");
   266 		result = flib_ini_set_str(ini, key, strvalue);
   171 	} else {
   267 	}
   172 		result = inihelper_setstr(dict, sectionName, keyName, value ? "true" : "false");
   268 	free(strvalue);
   173 	}
   269 	return result;
   174 	return result;
   270 }
   175 }
   271 
       
   272 int flib_ini_set_bool(flib_ini *ini, const char *key, bool value) {
       
   273 	return flib_ini_set_str(ini, key, value ? "true" : "false");
       
   274 }
       
   275 
       
   276 int flib_ini_get_sectioncount(flib_ini *ini) {
       
   277 	int result = INI_ERROR_OTHER;
       
   278 	if(!ini) {
       
   279 		flib_log_e("null parameter in flib_ini_get_sectioncount");
       
   280 	} else {
       
   281 		result = iniparser_getnsec(ini->inidict);
       
   282 	}
       
   283 	return result;
       
   284 }
       
   285 
       
   286 char *flib_ini_get_sectionname(flib_ini *ini, int number) {
       
   287 	char *result = NULL;
       
   288 	if(!ini || number<0) {
       
   289 		flib_log_e("bad parameter in flib_ini_get_sectionname");
       
   290 	} else {
       
   291 		result = flib_strdupnull(iniparser_getsecname(ini->inidict, number));
       
   292 	}
       
   293 	return result;
       
   294 }
       
   295 
       
   296 int flib_ini_get_keycount(flib_ini *ini) {
       
   297 	int result = INI_ERROR_OTHER;
       
   298 	if(!ini || !ini->currentSection) {
       
   299 		flib_log_e("null parameter or no current section in flib_ini_get_keycount");
       
   300 	} else {
       
   301 		result = iniparser_getsecnkeys(ini->inidict, ini->currentSection);
       
   302 	}
       
   303 	return result;
       
   304 }
       
   305 
       
   306 char *flib_ini_get_keyname(flib_ini *ini, int number) {
       
   307 	char *result = NULL;
       
   308 	if(!ini || number<0 || !ini->currentSection) {
       
   309 		flib_log_e("bad parameter or no current section in flib_ini_get_keyname");
       
   310 	} else {
       
   311 		int keyCount = iniparser_getsecnkeys(ini->inidict, ini->currentSection);
       
   312 		char **keys = iniparser_getseckeys(ini->inidict, ini->currentSection);
       
   313 		if(keys && keyCount>number) {
       
   314 			// The keys are in the format section:key, so we have to skip the section and colon.
       
   315 			result = flib_strdupnull(keys[number]+strlen(ini->currentSection)+1);
       
   316 		}
       
   317 		free(keys);
       
   318 	}
       
   319 	return result;
       
   320 }