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