# HG changeset patch # User Medo # Date 1339528211 -7200 # Node ID 1c859f572d72c341a4c02aa21e15572cb5c9e6df # Parent 5143861c83bd9c9143a4e5564d5710378bf35b77 frontlib: Rewrote the ini helper code, finished ini reading/writing support for all relevant file types diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/ipc/ipcconn.c --- a/project_files/frontlib/ipc/ipcconn.c Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/ipc/ipcconn.c Tue Jun 12 21:10:11 2012 +0200 @@ -15,7 +15,7 @@ * * We don't need to worry about wasting a few kb though, and I like powers of two... */ -typedef struct _flib_ipcconn { +struct _flib_ipcconn { uint8_t readBuffer[8192]; int readBufferSize; @@ -23,10 +23,10 @@ uint16_t port; flib_tcpsocket *sock; -} _flib_ipcconn; +}; flib_ipcconn *flib_ipcconn_create() { - flib_ipcconn *result = flib_malloc(sizeof(_flib_ipcconn)); + flib_ipcconn *result = flib_malloc(sizeof(flib_ipcconn)); flib_acceptor *acceptor = flib_acceptor_create(0); if(!result || !acceptor) { diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/model/cfg.c --- a/project_files/frontlib/model/cfg.c Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/model/cfg.c Tue Jun 12 21:10:11 2012 +0200 @@ -1,17 +1,16 @@ #include "cfg.h" -#include "../iniparser/iniparser.h" -#include "../iniparser/dictionary.h" #include "../util/inihelper.h" #include "../util/logging.h" #include "../util/util.h" #include +#include -static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, dictionary *settingfile, dictionary *modfile) { +static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, flib_ini *settingfile, flib_ini *modfile) { flib_cfg_meta_destroy(result); - iniparser_freedict(settingfile); - iniparser_freedict(modfile); + flib_ini_destroy(settingfile); + flib_ini_destroy(modfile); return NULL; } @@ -21,15 +20,15 @@ return NULL; } flib_cfg_meta *result = flib_calloc(1, sizeof(flib_cfg_meta)); - dictionary *settingfile = iniparser_load(settingpath); - dictionary *modfile = iniparser_load(modpath); + flib_ini *settingfile = flib_ini_load(settingpath); + flib_ini *modfile = flib_ini_load(modpath); if(!result || !settingfile || !modfile) { return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); } - result->settingCount = iniparser_getnsec(settingfile); - result->modCount = iniparser_getnsec(modfile); + result->settingCount = flib_ini_get_sectioncount(settingfile); + result->modCount = flib_ini_get_sectioncount(modfile); result->settings = flib_calloc(result->settingCount, sizeof(flib_cfg_setting_meta)); result->mods = flib_calloc(result->modCount, sizeof(flib_cfg_mod_meta)); @@ -38,44 +37,45 @@ } for(int i=0; isettingCount; i++) { - char *sectionName = iniparser_getsecname(settingfile, i); - if(!sectionName) { + result->settings[i].iniName = flib_ini_get_sectionname(settingfile, i); + if(!result->settings[i].iniName) { return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); } bool error = false; - result->settings[i].iniName = flib_strdupnull(sectionName); - result->settings[i].title = inihelper_getstringdup(settingfile, &error, sectionName, "title"); - result->settings[i].engineCommand = inihelper_getstringdup(settingfile, &error, sectionName, "command"); - result->settings[i].image = inihelper_getstringdup(settingfile, &error, sectionName, "image"); - result->settings[i].checkOverMax = inihelper_getbool(settingfile, &error, sectionName, "checkOverMax"); - result->settings[i].times1000 = inihelper_getbool(settingfile, &error, sectionName, "times1000"); - result->settings[i].min = inihelper_getint(settingfile, &error, sectionName, "min"); - result->settings[i].max = inihelper_getint(settingfile, &error, sectionName, "max"); - result->settings[i].def = inihelper_getint(settingfile, &error, sectionName, "default"); + error |= flib_ini_enter_section(settingfile, result->settings[i].iniName); + error |= flib_ini_get_str(settingfile, &result->settings[i].title, "title"); + error |= flib_ini_get_str(settingfile, &result->settings[i].engineCommand, "command"); + error |= flib_ini_get_str(settingfile, &result->settings[i].image, "image"); + error |= flib_ini_get_bool(settingfile, &result->settings[i].checkOverMax, "checkOverMax"); + error |= flib_ini_get_bool(settingfile, &result->settings[i].times1000, "times1000"); + error |= flib_ini_get_int(settingfile, &result->settings[i].min, "min"); + error |= flib_ini_get_int(settingfile, &result->settings[i].max, "max"); + error |= flib_ini_get_int(settingfile, &result->settings[i].def, "default"); + if(error) { - flib_log_e("Missing or malformed ini parameter in file %s, section %s", settingpath, sectionName); + flib_log_e("Missing or malformed ini parameter in file %s, section %s", settingpath, result->settings[i].iniName); return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); } } for(int i=0; imodCount; i++) { - char *sectionName = iniparser_getsecname(modfile, i); - if(!sectionName) { + result->mods[i].iniName = flib_ini_get_sectionname(modfile, i); + if(!result->mods[i].iniName) { return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); } bool error = false; - result->mods[i].iniName = flib_strdupnull(sectionName); - result->mods[i].bitmaskIndex = inihelper_getint(modfile, &error, sectionName, "bitmaskIndex"); + error |= flib_ini_enter_section(modfile, result->mods[i].iniName); + error |= flib_ini_get_int(modfile, &result->mods[i].bitmaskIndex, "bitmaskIndex"); if(error) { - flib_log_e("Missing or malformed ini parameter in file %s, section %s", modpath, sectionName); + flib_log_e("Missing or malformed ini parameter in file %s, section %s", modpath, result->mods[i].iniName); return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); } } - iniparser_freedict(settingfile); - iniparser_freedict(modfile); + flib_ini_destroy(settingfile); + flib_ini_destroy(modfile); return result; } @@ -124,8 +124,8 @@ return result; } -flib_cfg *flib_cfg_from_ini_handleError(flib_cfg *result, dictionary *settingfile) { - iniparser_freedict(settingfile); +flib_cfg *flib_cfg_from_ini_handleError(flib_cfg *result, flib_ini *settingfile) { + flib_ini_destroy(settingfile); flib_cfg_destroy(result); return NULL; } @@ -135,36 +135,45 @@ flib_log_e("null parameter in flib_cfg_from_ini"); return NULL; } - dictionary *settingfile = iniparser_load(filename); + flib_ini *settingfile = flib_ini_load(filename); if(!settingfile) { return NULL; } - bool error = false; - char *schemename = inihelper_getstring(settingfile, &error, "Scheme", "name"); - if(!schemename) { + char *schemename = NULL; + if(flib_ini_enter_section(settingfile, "Scheme")) { + flib_log_e("Missing section \"Scheme\" in config file %s.", filename); + return flib_cfg_from_ini_handleError(NULL, settingfile); + } + if(flib_ini_get_str(settingfile, &schemename, "name")) { + flib_log_e("Missing scheme name in config file %s.", filename); return flib_cfg_from_ini_handleError(NULL, settingfile); } flib_cfg *result = flib_cfg_create(meta, schemename); - for(int i=0; isettingCount; i++) { - char *key = inihelper_createDictKey("BasicSettings", meta->settings[i].iniName); - if(!key) { - return flib_cfg_from_ini_handleError(result, settingfile); + if(flib_ini_enter_section(settingfile, "BasicSettings")) { + flib_log_w("Missing section \"BasicSettings\" in config file %s, using defaults.", filename); + } else { + for(int i=0; isettingCount; i++) { + if(flib_ini_get_int_opt(settingfile, &result->settings[i], meta->settings[i].iniName, meta->settings[i].def)) { + flib_log_e("Error reading BasicSetting %s in config file %s.", meta->settings[i].iniName, filename); + return flib_cfg_from_ini_handleError(result, settingfile); + } } - result->settings[i] = iniparser_getint(settingfile, key, meta->settings[i].def); - free(key); } - for(int i=0; imodCount; i++) { - char *key = inihelper_createDictKey("GameMods", meta->mods[i].iniName); - if(!key) { - return flib_cfg_from_ini_handleError(result, settingfile); + + if(flib_ini_enter_section(settingfile, "GameMods")) { + flib_log_w("Missing section \"GameMods\" in config file %s, using defaults.", filename); + } else { + for(int i=0; imodCount; i++) { + if(flib_ini_get_bool_opt(settingfile, &result->mods[i], meta->mods[i].iniName, false)) { + flib_log_e("Error reading GameMod %s in config file %s.", meta->mods[i].iniName, filename); + return flib_cfg_from_ini_handleError(result, settingfile); + } } - result->mods[i] = iniparser_getboolean(settingfile, key, false); - free(key); } - iniparser_freedict(settingfile); + flib_ini_destroy(settingfile); return result; } @@ -173,35 +182,36 @@ if(!meta || !filename || !config || config->modCount!=meta->modCount || config->settingCount!=meta->settingCount) { flib_log_e("Invalid parameter in flib_cfg_to_ini"); } else { - dictionary *dict = iniparser_load(filename); - if(!dict) { - dict = dictionary_new(0); - } - if(dict) { + flib_ini *ini = flib_ini_create(filename); + if(ini) { bool error = false; - // Add the sections - error |= iniparser_set(dict, "Scheme", NULL); - error |= iniparser_set(dict, "BasicSettings", NULL); - error |= iniparser_set(dict, "GameMods", NULL); // Add the values - error |= inihelper_setstr(dict, "Scheme", "name", config->schemeName); - for(int i=0; isettingCount; i++) { - error |= inihelper_setint(dict, "BasicSettings", meta->settings[i].iniName, config->settings[i]); - } - for(int i=0; imodCount; i++) { - error |= inihelper_setbool(dict, "GameMods", meta->mods[i].iniName, config->mods[i]); + error |= flib_ini_create_section(ini, "Scheme"); + if(!error) { + error |= flib_ini_set_str(ini, "name", config->schemeName); } + + + error |= flib_ini_create_section(ini, "BasicSettings"); if(!error) { - FILE *inifile = fopen(filename, "wb"); - if(inifile) { - iniparser_dump_ini(dict, inifile); - fclose(inifile); - result = 0; + for(int i=0; isettingCount; i++) { + error |= flib_ini_set_int(ini, meta->settings[i].iniName, config->settings[i]); } } - dictionary_del(dict); + + error |= flib_ini_create_section(ini, "GameMods"); + if(!error) { + for(int i=0; imodCount; i++) { + error |= flib_ini_set_bool(ini, meta->mods[i].iniName, config->mods[i]); + } + } + + if(!error) { + result = flib_ini_save(ini, filename); + } } + flib_ini_destroy(ini); } return result; } diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/model/team.c --- a/project_files/frontlib/model/team.c Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/model/team.c Tue Jun 12 21:10:11 2012 +0200 @@ -3,84 +3,189 @@ #include "../util/inihelper.h" #include "../util/util.h" #include "../util/logging.h" +#include +#include -static flib_team *from_ini_handleError(flib_team *result, dictionary *settingfile, char **bindingKeys) { - if(settingfile) { - iniparser_freedict(settingfile); - } +static flib_team *from_ini_handleError(flib_team *result, flib_ini *settingfile) { + flib_ini_destroy(settingfile); flib_team_destroy(result); - free(bindingKeys); return NULL; } flib_team *flib_team_from_ini(const char *filename) { flib_team *result = flib_calloc(1, sizeof(flib_team)); - dictionary *settingfile = NULL; - char **bindingKeys = NULL; + flib_ini *ini = NULL; if(!filename) { flib_log_e("null parameter in flib_team_from_ini"); - return from_ini_handleError(result, settingfile, bindingKeys); + return from_ini_handleError(result, ini); } if(!result) { - return from_ini_handleError(result, settingfile, bindingKeys); + return from_ini_handleError(result, ini); + } + + ini = flib_ini_load(filename); + if(!ini) { + flib_log_e("Error loading team file %s", filename); + return from_ini_handleError(result, ini); } - settingfile = iniparser_load(filename); - if(!settingfile) { - flib_log_e("Error loading team file %s", filename); - return from_ini_handleError(result, settingfile, bindingKeys); + if(flib_ini_enter_section(ini, "team")) { + flib_log_e("Missing section \"Team\" in team file %s", filename); + return from_ini_handleError(result, ini); + } + bool error = false; + error |= flib_ini_get_str(ini, &result->name, "name"); + error |= flib_ini_get_str(ini, &result->grave, "grave"); + error |= flib_ini_get_str(ini, &result->fort, "fort"); + error |= flib_ini_get_str(ini, &result->voicepack, "voicepack"); + error |= flib_ini_get_str(ini, &result->flag, "flag"); + error |= flib_ini_get_int(ini, &result->rounds, "rounds"); + error |= flib_ini_get_int(ini, &result->wins, "wins"); + error |= flib_ini_get_int(ini, &result->campaignProgress, "campaignprogress"); + + int difficulty = 0; + error |= flib_ini_get_int(ini, &difficulty, "difficulty"); + + if(error) { + flib_log_e("Missing or malformed entry in section \"Team\" in file %s", filename); + return from_ini_handleError(result, ini); } - bool error = false; - result->name = inihelper_getstringdup(settingfile, &error, "team", "name"); - result->grave = inihelper_getstringdup(settingfile, &error, "team", "grave"); - result->fort = inihelper_getstringdup(settingfile, &error, "team", "fort"); - result->voicepack = inihelper_getstringdup(settingfile, &error, "team", "voicepack"); - result->flag = inihelper_getstringdup(settingfile, &error, "team", "flag"); - result->rounds = inihelper_getint(settingfile, &error, "team", "rounds"); - result->wins = inihelper_getint(settingfile, &error, "team", "wins"); - result->campaignProgress = inihelper_getint(settingfile, &error, "team", "campaignprogress"); - int difficulty = inihelper_getint(settingfile, &error, "team", "difficulty"); - - char sectionName[10]; - strcpy(sectionName, "hedgehog0"); for(int i=0; ihogs[i].name = inihelper_getstringdup(settingfile, &error, sectionName, "name"); - result->hogs[i].hat = inihelper_getstringdup(settingfile, &error, sectionName, "hat"); - result->hogs[i].rounds = inihelper_getint(settingfile, &error, sectionName, "rounds"); - result->hogs[i].kills = inihelper_getint(settingfile, &error, sectionName, "kills"); - result->hogs[i].deaths = inihelper_getint(settingfile, &error, sectionName, "deaths"); - result->hogs[i].suicides = inihelper_getint(settingfile, &error, sectionName, "suicides"); + char sectionName[32]; + if(snprintf(sectionName, sizeof(sectionName), "hedgehog%i", i) <= 0) { + return from_ini_handleError(result, ini); + } + if(flib_ini_enter_section(ini, sectionName)) { + flib_log_e("Missing section \"%s\" in team file %s", sectionName, filename); + return from_ini_handleError(result, ini); + } + flib_hog *hog = &result->hogs[i]; + error |= flib_ini_get_str(ini, &hog->name, "name"); + error |= flib_ini_get_str(ini, &hog->hat, "hat"); + error |= flib_ini_get_int(ini, &hog->rounds, "rounds"); + error |= flib_ini_get_int(ini, &hog->kills, "kills"); + error |= flib_ini_get_int(ini, &hog->deaths, "deaths"); + error |= flib_ini_get_int(ini, &hog->suicides, "suicides"); result->hogs[i].difficulty = difficulty; result->hogs[i].initialHealth = TEAM_DEFAULT_HEALTH; + + if(error) { + flib_log_e("Missing or malformed entry in section \"%s\" in file %s", sectionName, filename); + return from_ini_handleError(result, ini); + } } - result->bindingCount = iniparser_getsecnkeys(settingfile, "binds"); - result->bindings = flib_calloc(result->bindingCount, sizeof(flib_binding)); - bindingKeys = iniparser_getseckeys(settingfile, "binds"); - if(!result->bindings || !bindingKeys) { - return from_ini_handleError(result, settingfile, bindingKeys); - } - - for(int i=0; ibindingCount; i++) { - result->bindings[i].binding = flib_strdupnull(iniparser_getstring(settingfile, bindingKeys[i], NULL)); - // The key names all start with "binds:", so we skip that. - result->bindings[i].action = inihelper_urldecode(bindingKeys[i]+strlen("binds:")); - if(!result->bindings[i].action || !result->bindings[i].binding) { - error = true; + if(!flib_ini_enter_section(ini, "binds")) { + result->bindingCount = flib_ini_get_keycount(ini); + if(result->bindingCount<0) { + flib_log_e("Error reading bindings from file %s", filename); + result->bindingCount = 0; + } + result->bindings = flib_calloc(result->bindingCount, sizeof(flib_binding)); + if(!result->bindings) { + return from_ini_handleError(result, ini); + } + for(int i=0; ibindingCount; i++) { + char *keyname = flib_ini_get_keyname(ini, i); + if(!keyname) { + error = true; + } else { + result->bindings[i].action = flib_urldecode(keyname); + error |= !result->bindings[i].action; + error |= flib_ini_get_str(ini, &result->bindings[i].binding, keyname); + } + free(keyname); } } if(error) { flib_log_e("Error reading team file %s", filename); - return from_ini_handleError(result, settingfile, bindingKeys); + return from_ini_handleError(result, ini); } - iniparser_freedict(settingfile); - free(bindingKeys); + flib_ini_destroy(ini); + return result; +} + +static int writeTeamSection(const flib_team *team, flib_ini *ini) { + if(flib_ini_create_section(ini, "team")) { + return -1; + } + bool error = false; + error |= flib_ini_set_str(ini, "name", team->name); + error |= flib_ini_set_str(ini, "grave", team->grave); + error |= flib_ini_set_str(ini, "fort", team->fort); + error |= flib_ini_set_str(ini, "voicepack", team->voicepack); + error |= flib_ini_set_str(ini, "flag", team->flag); + error |= flib_ini_set_int(ini, "rounds", team->rounds); + error |= flib_ini_set_int(ini, "wins", team->wins); + error |= flib_ini_set_int(ini, "campaignprogress", team->campaignProgress); + error |= flib_ini_set_int(ini, "difficulty", team->hogs[0].difficulty); + return error; +} + +static int writeHogSections(const flib_team *team, flib_ini *ini) { + for(int i=0; ihogs[i]; + char sectionName[32]; + if(snprintf(sectionName, sizeof(sectionName), "hedgehog%i", i) <= 0) { + return -1; + } + if(flib_ini_create_section(ini, sectionName)) { + return -1; + } + bool error = false; + error |= flib_ini_set_str(ini, "name", hog->name); + error |= flib_ini_set_str(ini, "hat", hog->hat); + error |= flib_ini_set_int(ini, "rounds", hog->rounds); + error |= flib_ini_set_int(ini, "kills", hog->kills); + error |= flib_ini_set_int(ini, "deaths", hog->deaths); + error |= flib_ini_set_int(ini, "suicides", hog->suicides); + if(error) { + return error; + } + } + return 0; +} + +static int writeBindingSection(const flib_team *team, flib_ini *ini) { + if(flib_ini_create_section(ini, "binds")) { + return -1; + } + for(int i=0; ibindingCount; i++) { + bool error = false; + char *action = flib_urlencode(team->bindings[i].action); + if(action) { + error |= flib_ini_set_str(ini, action, team->bindings[i].binding); + free(action); + } else { + error = true; + } + if(error) { + return error; + } + } + return 0; +} + +int flib_team_to_ini(const char *filename, const flib_team *team) { + int result = -1; + if(!filename || !team) { + flib_log_e("null parameter in flib_team_to_ini"); + } else { + flib_ini *ini = flib_ini_create(filename); + bool error = false; + error |= writeTeamSection(team, ini); + error |= writeHogSections(team, ini); + error |= writeBindingSection(team, ini); + if(!error) { + result = flib_ini_save(ini, filename); + } + flib_ini_destroy(ini); + } return result; } diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/model/team.h --- a/project_files/frontlib/model/team.h Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/model/team.h Tue Jun 12 21:10:11 2012 +0200 @@ -79,6 +79,10 @@ * that were already present. Note that not all fields of a team struct * are stored in the ini, some are only used intermittently to store * information about a team in the context of a game. + * + * The flib_team can handle "difficulty" on a per-hog basis, but it + * is only written per-team in the team file. The difficulty of the + * first hog is used for the entire team when writing. */ int flib_team_to_ini(const char *filename, const flib_team *team); void flib_team_destroy(flib_team *team); diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/model/weapon.c --- a/project_files/frontlib/model/weapon.c Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/model/weapon.c Tue Jun 12 21:10:11 2012 +0200 @@ -1,6 +1,5 @@ #include "weapon.h" -#include "../iniparser/iniparser.h" #include "../util/inihelper.h" #include "../util/logging.h" #include "../util/util.h" @@ -75,23 +74,30 @@ if(!filename) { flib_log_e("null parameter in flib_weaponset_from_ini"); } else { - dictionary *settingfile = iniparser_load(filename); - if(!settingfile) { + flib_ini *ini = flib_ini_load(filename); + if(!ini) { flib_log_e("Error loading weapon scheme file %s", filename); - } else { + } else if(!flib_ini_enter_section(ini, "weaponset")) { bool error = false; - char *name = inihelper_getstring(settingfile, &error, "weaponset", "name"); - char *loadout = inihelper_getstring(settingfile, &error, "weaponset", "loadout"); - char *crateprob = inihelper_getstring(settingfile, &error, "weaponset", "crateprob"); - char *crateammo = inihelper_getstring(settingfile, &error, "weaponset", "crateammo"); - char *delay = inihelper_getstring(settingfile, &error, "weaponset", "delay"); + char *name = NULL, *loadout = NULL, *crateprob = NULL, *crateammo = NULL, *delay = NULL; + error |= flib_ini_get_str(ini, &name, "name"); + error |= flib_ini_get_str(ini, &loadout, "loadout"); + error |= flib_ini_get_str(ini, &crateprob, "crateprob"); + error |= flib_ini_get_str(ini, &crateammo, "crateammo"); + error |= flib_ini_get_str(ini, &delay, "delay"); + if(error) { flib_log_e("Missing key in weapon scheme file %s", filename); } else { result = flib_weaponset_create_str(name, loadout, crateprob, crateammo, delay); } + free(name); + free(loadout); + free(crateprob); + free(crateammo); + free(delay); } - iniparser_freedict(settingfile); + flib_ini_destroy(ini); } return result; } @@ -101,31 +107,19 @@ if(!filename || !set) { flib_log_e("null parameter in flib_weaponset_to_ini"); } else { - dictionary *dict = iniparser_load(filename); - if(!dict) { - dict = dictionary_new(0); - } - if(dict) { + flib_ini *ini = flib_ini_create(filename); + if(!flib_ini_create_section(ini, "weaponset")) { bool error = false; - // Add the sections - error |= iniparser_set(dict, "weaponset", NULL); - - // Add the values - error |= inihelper_setstr(dict, "weaponset", "name", set->name); - error |= inihelper_setstr(dict, "weaponset", "loadout", set->loadout); - error |= inihelper_setstr(dict, "weaponset", "crateprob", set->crateprob); - error |= inihelper_setstr(dict, "weaponset", "crateammo", set->crateammo); - error |= inihelper_setstr(dict, "weaponset", "delay", set->delay); + error |= flib_ini_set_str(ini, "name", set->name); + error |= flib_ini_set_str(ini, "loadout", set->loadout); + error |= flib_ini_set_str(ini, "crateprob", set->crateprob); + error |= flib_ini_set_str(ini, "crateammo", set->crateammo); + error |= flib_ini_set_str(ini, "delay", set->delay); if(!error) { - FILE *inifile = fopen(filename, "wb"); - if(inifile) { - iniparser_dump_ini(dict, inifile); - fclose(inifile); - result = 0; - } + result = flib_ini_save(ini, filename); } - dictionary_del(dict); } + flib_ini_destroy(ini); } return result; } diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/test.c --- a/project_files/frontlib/test.c Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/test.c Tue Jun 12 21:10:11 2012 +0200 @@ -104,7 +104,7 @@ flib_gamesetup setup; setup.gamescheme = flib_cfg_from_ini(metaconf, "scheme_shoppa.ini"); setup.map = flib_map_create_maze("Jungle", MAZE_SIZE_MEDIUM_TUNNELS); - setup.seed = "apsfooasdgnds"; + setup.seed = "asparagus"; setup.script = NULL; setup.teamcount = 2; setup.teams = calloc(2, sizeof(flib_team*)); @@ -166,12 +166,37 @@ } } +void testSave() { + FILE *demofile = fopen("testsave.42.hws", "rb"); + assert(demofile); + flib_vector *vec = flib_vector_create(); + uint8_t demobuf[512]; + int len; + while((len=fread(demobuf, 1, 512, demofile))>0) { + flib_vector_append(vec, demobuf, len); + } + fclose(demofile); + flib_constbuffer constbuf = flib_vector_as_constbuffer(vec); + flib_gameconn *gameconn = flib_gameconn_create_loadgame("Medo42", constbuf.data, constbuf.size); + flib_vector_destroy(vec); + assert(gameconn); + flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn); + flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn); + startEngineGame(flib_gameconn_getport(gameconn)); + + while(gameconn) { + flib_gameconn_tick(gameconn); + } +} + int main(int argc, char *argv[]) { flib_init(0); flib_log_setLevel(FLIB_LOGLEVEL_ALL); //testMapPreview(); - testDemo(); + //testDemo(); + //testSave(); + testGame(); flib_quit(); return 0; diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/util/inihelper.c --- a/project_files/frontlib/util/inihelper.c Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/util/inihelper.c Tue Jun 12 21:10:11 2012 +0200 @@ -1,4 +1,7 @@ #include "inihelper.h" +#include "../iniparser/dictionary.h" +#include "../iniparser/iniparser.h" + #include "logging.h" #include "util.h" @@ -9,167 +12,309 @@ #include #include -static bool keychar_needs_urlencoding(char c) { - return !isalnum(c); -} - -char *inihelper_urlencode(const char *inbuf) { - if(!inbuf) { - return NULL; - } - size_t insize = strlen(inbuf); - if(insize > SIZE_MAX/4) { - return NULL; - } - - char *outbuf = flib_malloc(insize*3+1); - if(!outbuf) { - return NULL; - } +struct _flib_ini { + dictionary *inidict; + char *currentSection; +}; - size_t inpos = 0, outpos = 0; - while(inbuf[inpos]) { - if(!keychar_needs_urlencoding(inbuf[inpos])) { - outbuf[outpos++] = inbuf[inpos++]; - } else { - if(snprintf(outbuf+outpos, 4, "%%%02X", (unsigned)((uint8_t*)inbuf)[inpos])<0) { - free(outbuf); - return NULL; - } - inpos++; - outpos += 3; - } - } - outbuf[outpos] = 0; - char *shrunk = realloc(outbuf, outpos+1); - return shrunk ? shrunk : outbuf; -} - -char *inihelper_urldecode(const char *inbuf) { - char *outbuf = flib_malloc(strlen(inbuf)+1); - if(!outbuf) { - return NULL; - } - - size_t inpos = 0, outpos = 0; - while(inbuf[inpos]) { - if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) { - char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0}; - outbuf[outpos++] = strtol(temp, NULL, 16); - inpos += 3; - } else { - outbuf[outpos++] = inbuf[inpos++]; - } - } - outbuf[outpos] = 0; - char *shrunk = realloc(outbuf, outpos+1); - return shrunk ? shrunk : outbuf; -} - -char *inihelper_createDictKey(const char *sectionName, const char *keyName) { - if(!sectionName || !keyName) { - flib_log_e("null parameter in inihelper_createDictKey"); - return NULL; - } +static char *createDictKey(const char *sectionName, const char *keyName) { return flib_asprintf("%s:%s", sectionName, keyName); } -char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - if(!inifile || !sectionName || !keyName) { - flib_log_e("null parameter in inihelper_getstring"); - *error = true; - return NULL; +/** + * Turns a string into a lowercase string, in-place. + */ +static void strToLower(char *str) { + if(str) { + while(*str) { + *str = tolower(*str); + str++; + } } - char *extendedkey = inihelper_createDictKey(sectionName, keyName); - if(!extendedkey) { - *error = true; - return NULL; +} + +flib_ini *flib_ini_create(const char *filename) { + flib_ini *result = NULL; + flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini)); + if(tmpIni) { + if(filename) { + tmpIni->inidict = iniparser_load(filename); + } + if(!tmpIni->inidict) { + tmpIni->inidict = dictionary_new(0); + } + if(tmpIni->inidict) { + result = tmpIni; + tmpIni = NULL; + } } - char *result = iniparser_getstring(inifile, extendedkey, NULL); - free(extendedkey); - if(!result) { - flib_log_d("Missing ini setting: %s/%s", sectionName, keyName); - *error = true; + flib_ini_destroy(tmpIni); + return result; +} + +flib_ini *flib_ini_load(const char *filename) { + flib_ini *result = NULL; + if(!filename) { + flib_log_e("null parameter in flib_ini_load"); + } else { + flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini)); + if(tmpIni) { + tmpIni->inidict = iniparser_load(filename); + if(tmpIni->inidict) { + result = tmpIni; + tmpIni = NULL; + } + } + flib_ini_destroy(tmpIni); } return result; } -char *inihelper_getstringdup(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - return flib_strdupnull(inihelper_getstring(inifile, error, sectionName, keyName)); -} - -int inihelper_getint(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - char *value = inihelper_getstring(inifile, error, sectionName, keyName); - if(!value) { - return 0; +int flib_ini_save(flib_ini *ini, const char *filename) { + int result = INI_ERROR_OTHER; + if(!ini || !filename) { + flib_log_e("null parameter in flib_ini_save"); } else { - errno = 0; - long val = strtol(value, NULL, 10); - if(errno!=0) { - flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", sectionName, keyName, value); - *error = true; - return 0; - } - if(valINT_MAX) { - flib_log_w("ini setting %s/%s = \"%s\" is too large or too small.", sectionName, keyName, value); - *error = true; - return 0; + FILE *file = fopen(filename, "wb"); + if(!file) { + flib_log_e("Error opening file \"%s\" for writing.", filename); + } else { + iniparser_dump_ini(ini->inidict, file); + if(fclose(file)) { + flib_log_e("Write error on ini file \"%s\"", filename); + } else { + result = 0; + } } - return (int)val; - } -} - -bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - char *value = inihelper_getstring(inifile, error, sectionName, keyName); - if(!value) { - return false; - } else { - bool trueval = strchr("1tTyY", value[0]); - bool falseval = strchr("0fFnN", value[0]); - if(!trueval && !falseval) { - flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", sectionName, keyName, value); - *error = true; - return false; - } else { - return trueval; - } - } -} - -int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value) { - int result = -1; - if(!dict || !sectionName || !keyName || !value) { - flib_log_e("null parameter in inihelper_setstr"); - } else { - char *extendedkey = inihelper_createDictKey(sectionName, keyName); - if(extendedkey) { - result = iniparser_set(dict, extendedkey, value); - } - free(extendedkey); } return result; } -int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value) { - int result = -1; - if(!dict || !sectionName || !keyName) { - flib_log_e("null parameter in inihelper_setint"); +void flib_ini_destroy(flib_ini *ini) { + if(ini) { + if(ini->inidict) { + iniparser_freedict(ini->inidict); + } + free(ini->currentSection); + free(ini); + } +} + +int flib_ini_enter_section(flib_ini *ini, const char *section) { + int result = INI_ERROR_OTHER; + if(ini) { + free(ini->currentSection); + ini->currentSection = NULL; + } + if(!ini || !section) { + flib_log_e("null parameter in flib_ini_enter_section"); } else { - char *strvalue = flib_asprintf("%i", value); - if(strvalue) { - result = inihelper_setstr(dict, sectionName, keyName, strvalue); - free(strvalue); + if(!iniparser_find_entry(ini->inidict, section)) { + result = INI_ERROR_NOTFOUND; + } else { + ini->currentSection = flib_strdupnull(section); + if(ini->currentSection) { + // Usually iniparser ignores case, but some section-handling functions don't, + // so we set it to lowercase manually + strToLower(ini->currentSection); + result = 0; + } + } + } + return result; +} + +int flib_ini_create_section(flib_ini *ini, const char *section) { + int result = INI_ERROR_OTHER; + if(!ini || !section) { + flib_log_e("null parameter in flib_ini_create_section"); + } else { + result = flib_ini_enter_section(ini, section); + if(result == INI_ERROR_NOTFOUND) { + if(iniparser_set(ini->inidict, section, NULL)) { + result = INI_ERROR_OTHER; + } else { + result = flib_ini_enter_section(ini, section); + } } } return result; } -int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value) { - int result = -1; - if(!dict || !sectionName || !keyName) { - flib_log_e("null parameter in inihelper_setbool"); +/** + * The result is an internal string of the iniparser, don't free it. + */ +static char *findValue(dictionary *dict, const char *section, const char *key) { + char *result = NULL; + char *dictKey = createDictKey(section, key); + if(dictKey) { + result = iniparser_getstring(dict, dictKey, NULL); + } + free(dictKey); + return result; +} + +int flib_ini_get_str(flib_ini *ini, char **outVar, const char *key) { + char *tmpValue = NULL; + int result = flib_ini_get_str_opt(ini, &tmpValue, key, NULL); + if(result==0) { + if(tmpValue == NULL) { + result = INI_ERROR_NOTFOUND; + } else { + *outVar = tmpValue; + tmpValue = NULL; + } + } + free(tmpValue); + return result; +} + +int flib_ini_get_str_opt(flib_ini *ini, char **outVar, const char *key, const char *def) { + int result = INI_ERROR_OTHER; + if(!ini || !outVar || !key || !ini->currentSection) { + flib_log_e("null parameter or no current section in flib_ini_get_str_opt"); } else { - result = inihelper_setstr(dict, sectionName, keyName, value ? "true" : "false"); + const char *value = findValue(ini->inidict, ini->currentSection, key); + if(!value) { + value = def; + } + char *valueDup = flib_strdupnull(value); + if(valueDup) { + *outVar = valueDup; + result = 0; + } + } + return result; +} + +int flib_ini_get_int(flib_ini *ini, int *outVar, const char *key) { + char *tmpValue = NULL; + int result = flib_ini_get_str(ini, &tmpValue, key); + if(result==0) { + errno = 0; + long val = strtol(tmpValue, NULL, 10); + if(errno!=0 || valINT_MAX) { + flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", ini->currentSection, key, tmpValue); + result = INI_ERROR_FORMAT; + } else { + *outVar = val; + } + } + free(tmpValue); + return result; +} + +int flib_ini_get_int_opt(flib_ini *ini, int *outVar, const char *key, int def) { + int tmpValue; + int result = flib_ini_get_int(ini, &tmpValue, key); + if(result == 0) { + *outVar = tmpValue; + } else if(result == INI_ERROR_NOTFOUND) { + *outVar = def; + result = 0; } return result; } + +int flib_ini_get_bool(flib_ini *ini, bool *outVar, const char *key) { + char *tmpValue = NULL; + int result = flib_ini_get_str(ini, &tmpValue, key); + if(result==0) { + bool trueval = strchr("1tTyY", tmpValue[0]); + bool falseval = strchr("0fFnN", tmpValue[0]); + if(!trueval && !falseval) { + flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", ini->currentSection, key, tmpValue); + result = INI_ERROR_FORMAT; + } else { + *outVar = trueval; + } + } + free(tmpValue); + return result; +} + +int flib_ini_get_bool_opt(flib_ini *ini, bool *outVar, const char *key, bool def) { + bool tmpValue; + int result = flib_ini_get_bool(ini, &tmpValue, key); + if(result == 0) { + *outVar = tmpValue; + } else if(result == INI_ERROR_NOTFOUND) { + *outVar = def; + result = 0; + } + return result; +} + +int flib_ini_set_str(flib_ini *ini, const char *key, const char *value) { + int result = INI_ERROR_OTHER; + if(!ini || !key || !value || !ini->currentSection) { + flib_log_e("null parameter or no current section in flib_ini_set_str"); + } else { + char *dictKey = createDictKey(ini->currentSection, key); + if(dictKey) { + result = iniparser_set(ini->inidict, dictKey, value); + } + free(dictKey); + } + return result; +} + +int flib_ini_set_int(flib_ini *ini, const char *key, int value) { + int result = INI_ERROR_OTHER; + char *strvalue = flib_asprintf("%i", value); + if(strvalue) { + result = flib_ini_set_str(ini, key, strvalue); + } + free(strvalue); + return result; +} + +int flib_ini_set_bool(flib_ini *ini, const char *key, bool value) { + return flib_ini_set_str(ini, key, value ? "true" : "false"); +} + +int flib_ini_get_sectioncount(flib_ini *ini) { + int result = INI_ERROR_OTHER; + if(!ini) { + flib_log_e("null parameter in flib_ini_get_sectioncount"); + } else { + result = iniparser_getnsec(ini->inidict); + } + return result; +} + +char *flib_ini_get_sectionname(flib_ini *ini, int number) { + char *result = NULL; + if(!ini || number<0) { + flib_log_e("bad parameter in flib_ini_get_sectionname"); + } else { + result = flib_strdupnull(iniparser_getsecname(ini->inidict, number)); + } + return result; +} + +int flib_ini_get_keycount(flib_ini *ini) { + int result = INI_ERROR_OTHER; + if(!ini || !ini->currentSection) { + flib_log_e("null parameter or no current section in flib_ini_get_keycount"); + } else { + result = iniparser_getsecnkeys(ini->inidict, ini->currentSection); + } + return result; +} + +char *flib_ini_get_keyname(flib_ini *ini, int number) { + char *result = NULL; + if(!ini || number<0 || !ini->currentSection) { + flib_log_e("bad parameter or no current section in flib_ini_get_keyname"); + } else { + int keyCount = iniparser_getsecnkeys(ini->inidict, ini->currentSection); + char **keys = iniparser_getseckeys(ini->inidict, ini->currentSection); + if(keys && keyCount>number) { + // The keys are in the format section:key, so we have to skip the section and colon. + result = flib_strdupnull(keys[number]+strlen(ini->currentSection)+1); + } + free(keys); + } + return result; +} diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/util/inihelper.h --- a/project_files/frontlib/util/inihelper.h Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/util/inihelper.h Tue Jun 12 21:10:11 2012 +0200 @@ -9,65 +9,152 @@ #ifndef INIHELPER_H_ #define INIHELPER_H_ -#include "../iniparser/iniparser.h" +#include -#include +#define INI_ERROR_NOTFOUND -1 +#define INI_ERROR_FORMAT -2 +#define INI_ERROR_OTHER -100 struct _flib_ini; -typedef struct _flib_inihelper flib_ini; +typedef struct _flib_ini flib_ini; /** - * Returned buffer must be free()d + * Create a new ini data structure, pre-filled with the contents of + * the file "filename" if it exists. If filename is null, or the file + * is not found, an empty ini will be created. However, if an error + * occurs while reading the ini file (or any other error), null + * is returned. + * + * This behavior is useful for modifying an existing ini file without + * discarding unknown keys. */ -char *inihelper_urlencode(const char *inbuf); +flib_ini *flib_ini_create(const char *filename); + +/** + * Similar to flib_ini_create, but fails if the file is not found + * or if filename is null. + */ +flib_ini *flib_ini_load(const char *filename); /** - * Returned buffer must be free()d + * Store the ini to the file "filename", overwriting + * the previous contents. Returns 0 on success. */ -char *inihelper_urldecode(const char *inbuf); +int flib_ini_save(flib_ini *ini, const char *filename); + +void flib_ini_destroy(flib_ini *ini); + +/** + * Enter the section with the specified name. Returns 0 on + * success, INI_ERROR_NOTFOUND if the section does not exist + * and a different value if another error occurs. + * If an error occurs, there is no current section. + * + * The section name should only consist of letters and + * numbers. + */ +int flib_ini_enter_section(flib_ini *ini, const char *section); /** - * Create a key in the format "sectionName:keyName" - * Returned buffer must be free()d + * Creates and enters the section with the specified name. Simply + * enters the section if it exists already. Returns 0 on success + * and a different value if another error occurs. + * If an error occurs, there is no current section. */ -char *inihelper_createDictKey(const char *sectionName, const char *keyName); +int flib_ini_create_section(flib_ini *ini, const char *section); /** - * Returns an internal buffer, don't modify or free - * Sets error to true if something goes wrong, leaves it unchanged otherwise. + * Find a key in the current section and store the value in outVar + * as a newly allocated string. Returns 0 on success, INI_ERROR_NOTFOUND + * if the key was not found and a different value for other errors, + * e.g. if there is no current section. */ -char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); +int flib_ini_get_str(flib_ini *ini, char **outVar, const char *key); + +/** + * Find a key in the current section and store the value in outVar + * as a newly allocated string. If the key is not found, the default + * value will be used instead. Returns 0 on success. + */ +int flib_ini_get_str_opt(flib_ini *ini, char **outVar, const char *key, const char *def); /** - * Returned buffer must be free()d - * Sets error to true if something goes wrong, leaves it unchanged otherwise. + * Find a key in the current section and store the value in outVar + * as an int. Returns 0 on success, INI_ERROR_NOTFOUND + * if the key was not found, INI_ERROR_FORMAT if it was found but + * could not be converted to an int, and a different value for other + * errors, e.g. if there is no current section. */ -char *inihelper_getstringdup(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); +int flib_ini_get_int(flib_ini *ini, int *outVar, const char *key); + +/** + * Find a key in the current section and store the value in outVar + * as an int. If the key is not found, the default value will be used instead. + * Returns 0 on success, INI_ERROR_FORMAT if the value was found but + * could not be converted to int, and another value otherwise. + */ +int flib_ini_get_int_opt(flib_ini *ini, int *outVar, const char *key, int def); /** - * Sets error to true if something goes wrong, leaves it unchanged otherwise. + * Find a key in the current section and store the value in outVar + * as a bool. Treats everything beginning with "Y", "T" or "1" as true, + * everything starting with "N", "F" or "1" as false. + * + * Returns 0 on success, INI_ERROR_NOTFOUND if the key was not found, + * INI_ERROR_FORMAT if the value could not be interpreted as boolean, + * and another value otherwise. */ -int inihelper_getint(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); +int flib_ini_get_bool(flib_ini *ini, bool *outVar, const char *key); /** - * Sets error to true if something goes wrong, leaves it unchanged otherwise. + * Find a key in the current section and store the value in outVar + * as a bool. If the key is not found, the default value will be + * used instead. Returns 0 on success, INI_ERROR_FORMAT if the + * value could not be interpreted as boolean, and another value otherwise. */ -bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); +int flib_ini_get_bool_opt(flib_ini *ini, bool *outVar, const char *key, bool def); /** - * Returns a nonzero value on error. + * In the current section, associate key with value. Returns 0 on success. + */ +int flib_ini_set_str(flib_ini *ini, const char *key, const char *value); + +/** + * In the current section, associate key with value. Returns 0 on success. */ -int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value); +int flib_ini_set_int(flib_ini *ini, const char *key, int value); + +/** + * In the current section, associate key with value. Returns 0 on success. + */ +int flib_ini_set_bool(flib_ini *ini, const char *key, bool value); + +/** + * Returns the number of sections in the ini file, or a negative value on error. + */ +int flib_ini_get_sectioncount(flib_ini *ini); /** - * Returns a nonzero value on error. + * Returns the name of the section, or NULL on error. The returned string must + * be free()d. + * + * Note: There is no guarantee that the order of the sections + * will remain stable if the ini is modified. */ -int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value); +char *flib_ini_get_sectionname(flib_ini *ini, int number); /** - * Set an ini setting to "true" or "false". - * Returns a nonzero value on error. + * Returns the number of keys in the current section, or -1 on error. */ -int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value); +int flib_ini_get_keycount(flib_ini *ini); + +/** + * Returns the name of the key in the current section, or NULL on error. + * The returned string must be free()d. + * + * Note: There is no guarantee that the order of the keys in a section + * will remain stable if the ini is modified. + */ +char *flib_ini_get_keyname(flib_ini *ini, int number); #endif /* INIHELPER_H_ */ diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/util/util.c --- a/project_files/frontlib/util/util.c Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/util/util.c Tue Jun 12 21:10:11 2012 +0200 @@ -6,6 +6,7 @@ #include #include #include +#include char *flib_asprintf(const char *fmt, ...) { va_list argp; @@ -68,3 +69,62 @@ } return result; } + +static bool isAsciiAlnum(char c) { + return (c>='0' && c<='9') || (c>='a' && c <='z') || (c>='A' && c <='Z'); +} + +char *flib_urlencode(const char *inbuf) { + if(!inbuf) { + return NULL; + } + size_t insize = strlen(inbuf); + if(insize > SIZE_MAX/4) { + flib_log_e("String too long in flib_urlencode: %zu bytes.", insize); + return NULL; + } + + char *outbuf = flib_malloc(insize*3+1); + if(!outbuf) { + return NULL; + } + + size_t inpos = 0, outpos = 0; + while(inbuf[inpos]) { + if(isAsciiAlnum(inbuf[inpos])) { + outbuf[outpos++] = inbuf[inpos++]; + } else { + if(snprintf(outbuf+outpos, 4, "%%%02X", (unsigned)((uint8_t*)inbuf)[inpos])<0) { + flib_log_e("printf error in flib_urlencode"); + free(outbuf); + return NULL; + } + inpos++; + outpos += 3; + } + } + outbuf[outpos] = 0; + char *shrunk = realloc(outbuf, outpos+1); + return shrunk ? shrunk : outbuf; +} + +char *flib_urldecode(const char *inbuf) { + char *outbuf = flib_malloc(strlen(inbuf)+1); + if(!outbuf) { + return NULL; + } + + size_t inpos = 0, outpos = 0; + while(inbuf[inpos]) { + if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) { + char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0}; + outbuf[outpos++] = strtol(temp, NULL, 16); + inpos += 3; + } else { + outbuf[outpos++] = inbuf[inpos++]; + } + } + outbuf[outpos] = 0; + char *shrunk = realloc(outbuf, outpos+1); + return shrunk ? shrunk : outbuf; +} diff -r 5143861c83bd -r 1c859f572d72 project_files/frontlib/util/util.h --- a/project_files/frontlib/util/util.h Tue Jun 12 11:25:05 2012 +0200 +++ b/project_files/frontlib/util/util.h Tue Jun 12 21:10:11 2012 +0200 @@ -45,4 +45,22 @@ */ void *flib_calloc(size_t count, size_t elementsize); +/** + * Replace all non-alphanumeric and non-ascii bytes with escape + * sequences in the form %XX. Does not modify the original string, + * but returns a newly allocated one that must be free()d. Returns + * null on failure or if null was passed as argument. + * + * This should work fine with all ASCII-based charsets including UTF-8. + */ +char *flib_urlencode(const char *str); + +/** + * Replace escape sequences of the form %XX with their byte values. + * Does not modify the original string, but returns a newly allocated + * one that must be free()d. Returns null on failure or if null was + * passed as argument. + */ +char *flib_urldecode(const char *str); + #endif