Converted the config parser into reusable utility functions

This commit is contained in:
Andrei "Akari" Alexeyev 2017-03-11 23:10:05 +02:00
parent c82928a8da
commit cceb1aa20d
3 changed files with 118 additions and 62 deletions

View file

@ -269,8 +269,12 @@ static void config_delete_unknown_entries(void) {
delete_all_elements((void**)&unknowndefs, config_delete_unknown_entry); delete_all_elements((void**)&unknowndefs, config_delete_unknown_entry);
} }
static char* config_path(const char *filename) {
return strjoin(get_config_path(), "/", filename, NULL);
}
static FILE* config_open(const char *filename, const char *mode) { static FILE* config_open(const char *filename, const char *mode) {
char *buf = strjoin(get_config_path(), "/", filename, NULL); char *buf = config_path(filename);
FILE *out = fopen(buf, mode); FILE *out = fopen(buf, mode);
free(buf); free(buf);
@ -327,7 +331,7 @@ void config_save(const char *filename) {
#define INTOF(s) ((int)strtol(s, NULL, 10)) #define INTOF(s) ((int)strtol(s, NULL, 10))
#define FLOATOF(s) ((float)strtod(s, NULL)) #define FLOATOF(s) ((float)strtod(s, NULL))
static void config_set(const char *key, const char *val) { static void config_set(const char *key, const char *val, void *data) {
ConfigEntry *e = config_find_entry(key); ConfigEntry *e = config_find_entry(key);
if(!e) { if(!e) {
@ -367,67 +371,10 @@ static void config_set(const char *key, const char *val) {
#undef FLOATOF #undef FLOATOF
void config_load(const char *filename) { void config_load(const char *filename) {
FILE *in = config_open(filename, "r"); char *path = config_path(filename);
int c, i = 0, found, line = 0;
char buf[CONFIG_LOAD_BUFSIZE];
char key[CONFIG_LOAD_BUFSIZE];
char val[CONFIG_LOAD_BUFSIZE];
config_init(); config_init();
parse_keyvalue_file_cb(path, config_set, NULL);
if(!in) { free(path);
return;
}
while((c = fgetc(in)) != EOF) {
if(c == '#' && !i) {
i = 0;
while(fgetc(in) != '\n');
} else if(c == ' ') {
if(!i) SYNTAXERROR
buf[i] = 0;
i = 0;
strcpy(key, buf);
found = 0;
while((c = fgetc(in)) != EOF) {
if(c == '=') {
if(++found > 1) SYNTAXERROR
} else if(c != ' ') {
if(!found || c == '\n') SYNTAXERROR
do {
if(c == '\n') {
if(!i) SYNTAXERROR
buf[i] = 0;
i = 0;
strcpy(val, buf);
found = 0;
++line;
config_set(key, val);
break;
} else {
buf[i++] = c;
if(i == CONFIG_LOAD_BUFSIZE)
BUFFERERROR
}
} while((c = fgetc(in)) != EOF);
break;
}
} if(found) SYNTAXERROR
} else {
buf[i++] = c;
if(i == CONFIG_LOAD_BUFSIZE)
BUFFERERROR
}
}
end:
fclose(in);
} }
#undef SYNTAXERROR #undef SYNTAXERROR

View file

@ -252,6 +252,107 @@ char* read_all(const char *filename, int *outsize) {
return text; return text;
} }
bool parse_keyvalue_stream_cb(SDL_RWops *strm, KVCallback callback, void *data) {
const size_t bufsize = 128;
#define SYNTAXERROR { warnx("%s(): syntax error on line %i, aborted! [%s:%i]\n", __func__, line, __FILE__, __LINE__); return false; }
#define BUFFERERROR { warnx("%s(): string exceed the limit of %i, aborted! [%s:%i]", __func__, bufsize, __FILE__, __LINE__); return false; }
int i = 0, found, line = 0;
char c, buf[bufsize], key[bufsize], val[bufsize];
while(c = (char)SDL_ReadU8(strm)) {
if(c == '#' && !i) {
i = 0;
while((char)SDL_ReadU8(strm) != '\n');
} else if(c == ' ') {
if(!i) SYNTAXERROR
buf[i] = 0;
i = 0;
strcpy(key, buf);
found = 0;
while(c = (char)SDL_ReadU8(strm)) {
if(c == '=') {
if(++found > 1) SYNTAXERROR
} else if(c != ' ') {
if(!found || c == '\n') SYNTAXERROR
do {
if(c == '\n') {
if(!i) SYNTAXERROR
buf[i] = 0;
i = 0;
strcpy(val, buf);
found = 0;
++line;
callback(key, val, data);
break;
} else {
buf[i++] = c;
if(i == bufsize)
BUFFERERROR
}
} while(c = (char)SDL_ReadU8(strm));
break;
}
} if(found) SYNTAXERROR
} else {
buf[i++] = c;
if(i == bufsize)
BUFFERERROR
}
}
return true;
#undef SYNTAXERROR
#undef BUFFERERROR
}
bool parse_keyvalue_file_cb(const char *filename, KVCallback callback, void *data) {
SDL_RWops *strm = SDL_RWFromFile(filename, "r");
if(!strm) {
warnx("parse_keyvalue_file_cb(): SDL_RWFromFile() failed: %s", SDL_GetError());
return false;
}
bool status = parse_keyvalue_stream_cb(strm, callback, data);
SDL_RWclose(strm);
return status;
}
static void kvcallback_hashtable(const char *key, const char *val, Hashtable *ht) {
hashtable_set_string(ht, key, (void*)val);
}
Hashtable* parse_keyvalue_stream(SDL_RWops *strm) {
Hashtable *ht = hashtable_new_stringkeys(37);
if(!parse_keyvalue_stream_cb(strm, (KVCallback)kvcallback_hashtable, ht)) {
free(ht);
ht = NULL;
}
return ht;
}
Hashtable* parse_keyvalue_file(const char *filename) {
Hashtable *ht = hashtable_new_stringkeys(37);
if(!parse_keyvalue_file_cb(filename, (KVCallback)kvcallback_hashtable, ht)) {
free(ht);
ht = NULL;
}
return ht;
}
// //
// misc utils // misc utils
// //

View file

@ -6,6 +6,8 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <zlib.h> // compiling under mingw may fail without this... #include <zlib.h> // compiling under mingw may fail without this...
#include <SDL.h>
#include "hashtable.h"
// //
// compatibility // compatibility
@ -92,7 +94,13 @@ void fade_out(float f);
// i/o utils // i/o utils
// //
typedef void (*KVCallback)(const char *key, const char *value, void *data);
char* read_all(const char *filename, int *size); char* read_all(const char *filename, int *size);
bool parse_keyvalue_stream_cb(SDL_RWops *strm, KVCallback callback, void *data);
bool parse_keyvalue_file_cb(const char *filename, KVCallback callback, void *data);
Hashtable* parse_keyvalue_stream(SDL_RWops *strm);
Hashtable* parse_keyvalue_file(const char *filename);
// //
// misc utils // misc utils