10017
+ − 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
}