Rewrote the key=value parser into something more sensible
Also updated the readme
This commit is contained in:
parent
455039edb4
commit
52286cac7f
3 changed files with 56 additions and 67 deletions
19
README.md
19
README.md
|
@ -52,21 +52,18 @@ BGM (as well as SFX) may be in `.wav`, `.flac`, or `.ogg` format; additionally
|
|||
you may try another formats such as `.mp3`, `.aiff`, `.mod`, `.xm`, etc. if
|
||||
your build of SDL2_mixer supports these formats.
|
||||
|
||||
Complete music pack consists of 16 bgm\_\*.(ogg/wav/flac) files, where ‘\*’ mean:
|
||||
Complete music pack consists of 16 bgm\_\*.(ogg/wav/flac) files, where ‘\*’ means:
|
||||
```
|
||||
credits BGM for credits screen
|
||||
ending BGM for ending
|
||||
gameover BGM for game over screen
|
||||
menu BGM for menus (excluding in-game menu which pauses BGM)
|
||||
stageN N=1..6, standard stage theme
|
||||
stageNboss N=1..6, boss theme for a stage
|
||||
credits BGM for credits screen
|
||||
ending BGM for ending
|
||||
gameover BGM for game over screen
|
||||
menu BGM for menus (excluding in-game menu which pauses BGM)
|
||||
stageN N=1..6, standard stage theme
|
||||
stageNboss N=1..6, boss theme for a stage
|
||||
```
|
||||
|
||||
If you want to specify stage/boss theme names to be shown during gameplay, you
|
||||
may do it in `bgm/bgm.conf` file. This file contains some lines, each of which
|
||||
consists of bgm filename (without extension), space of tab, and theme name.
|
||||
No space/tab allowed either in beginning of line or BGM filenames listed in
|
||||
this file; theme names may contain them.
|
||||
may do it by editing the [`bgm/bgm.conf`](bgm/bgm.conf) file.
|
||||
|
||||
## Sound problems
|
||||
|
||||
|
|
|
@ -365,9 +365,8 @@ static void config_set(const char *key, const char *val, void *data) {
|
|||
void config_load(const char *filename) {
|
||||
char *path = config_path(filename);
|
||||
config_init();
|
||||
parse_keyvalue_file_cb(path, config_set, NULL);
|
||||
if(!parse_keyvalue_file_cb(path, config_set, NULL)) {
|
||||
log_warn("Errors occured while parsing the configuration file");
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
|
||||
#undef SYNTAXERROR
|
||||
#undef BUFFERERROR
|
||||
|
|
97
src/util.c
97
src/util.c
|
@ -258,65 +258,58 @@ char* read_all(const char *filename, int *outsize) {
|
|||
}
|
||||
|
||||
bool parse_keyvalue_stream_cb(SDL_RWops *strm, KVCallback callback, void *data) {
|
||||
const size_t bufsize = 128;
|
||||
static const size_t bufsize = 256;
|
||||
static const char separator[] = "= ";
|
||||
|
||||
#define SYNTAXERROR { log_warn("Syntax error on line %i, aborted! [%s:%i]", line, __FILE__, __LINE__); return false; }
|
||||
#define BUFFERERROR { log_warn("String exceed the limit of %li, aborted! [%s:%i]", (long int)bufsize, __FILE__, __LINE__); return false; }
|
||||
char buffer[bufsize];
|
||||
int lineno = 0;
|
||||
int errors = 0;
|
||||
|
||||
int i = 0, found, line = 0;
|
||||
char c, buf[bufsize], key[bufsize], val[bufsize];
|
||||
loopstart: while(SDL_RWgets(strm, buffer, bufsize)) {
|
||||
char *ptr = buffer;
|
||||
char *sep, *key, *val;
|
||||
|
||||
while(c = (char)SDL_ReadU8(strm)) {
|
||||
if(c == '#' && !i) {
|
||||
i = 0;
|
||||
while((char)SDL_ReadU8(strm) != '\n');
|
||||
} else if(c == ' ') {
|
||||
if(!i) SYNTAXERROR
|
||||
++lineno;
|
||||
|
||||
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 if(c != '\r') {
|
||||
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
|
||||
while(isspace(*ptr)) {
|
||||
if(!*(++ptr)) {
|
||||
// blank line
|
||||
goto loopstart;
|
||||
}
|
||||
}
|
||||
|
||||
if(*ptr == '#') {
|
||||
// comment
|
||||
continue;
|
||||
}
|
||||
|
||||
sep = strstr(ptr, separator);
|
||||
|
||||
if(!sep) {
|
||||
++errors;
|
||||
log_warn("Syntax error on line %i: missing separator", lineno);
|
||||
continue;
|
||||
}
|
||||
|
||||
// split it up
|
||||
*sep = 0;
|
||||
key = ptr;
|
||||
val = sep + sizeof(separator) - 1;
|
||||
|
||||
// the separator may be preceeded by any kind of whitespace, so strip it from the key
|
||||
while(isspace(*(ptr = strchr(key, 0) - 1))) {
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
// strip any kind of line endings from the value
|
||||
while(strchr("\r\n", *(ptr = strchr(val, 0) - 1))) {
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
callback(key, val, data);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
#undef SYNTAXERROR
|
||||
#undef BUFFERERROR
|
||||
return !errors;
|
||||
}
|
||||
|
||||
bool parse_keyvalue_file_cb(const char *filename, KVCallback callback, void *data) {
|
||||
|
|
Loading…
Reference in a new issue