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