From 92952054193297e7171634bc7142a05ab83e7e38 Mon Sep 17 00:00:00 2001 From: "Andrew \"Akari\" Alexeyew" Date: Fri, 3 Aug 2012 08:06:19 +0300 Subject: [PATCH] New config parser. bison and flex, please gtfo, thanks. --- README | 1 - src/CMakeLists.txt | 10 +- src/config.c | 251 +++++++++++++++++++++++++++++++++++++++++++++ src/config.h | 33 +++++- src/config.l | 83 --------------- src/config.y | 186 --------------------------------- src/main.c | 3 +- src/menu/options.c | 63 +----------- 8 files changed, 287 insertions(+), 343 deletions(-) create mode 100644 src/config.c delete mode 100644 src/config.l delete mode 100644 src/config.y diff --git a/README b/README index 90b919b7..c8b48dba 100644 --- a/README +++ b/README @@ -12,7 +12,6 @@ Dependencies: - libpng - OpenGL - OpenAL, ALUT - - flex/bison - CMake (build system) To build and install Taisei just follow these steps. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2771381f..2d2e2e36 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,19 +6,14 @@ find_package(OpenAL REQUIRED) find_package(ALUT REQUIRED) find_package(PNG REQUIRED) find_package(SDL_ttf REQUIRED) -find_package(BISON REQUIRED) -find_package(FLEX REQUIRED) find_package(Freetype) find_package(ZLIB) -BISON_TARGET(cfgparser config.y ${CMAKE_CURRENT_SOURCE_DIR}/parser.c) -FLEX_TARGET(cfgscanner config.l ${CMAKE_CURRENT_SOURCE_DIR}/lexer.c) -ADD_FLEX_BISON_DEPENDENCY(cfgscanner cfgparser) - set(SRCs main.c taiseigl.c random.c + config.c stage.c replay.c global.c @@ -62,8 +57,7 @@ set(SRCs resource/shader.c resource/audio.c resource/model.c - ${BISON_cfgparser_OUTPUTS} - ${FLEX_cfgscanner_OUTPUTS}) +) if(RELATIVE) set(SRCs ${SRCs} paths/relative.c) diff --git a/src/config.c b/src/config.c new file mode 100644 index 00000000..7e92d8c4 --- /dev/null +++ b/src/config.c @@ -0,0 +1,251 @@ +/* + * This software is licensed under the terms of the MIT-License + * See COPYING for further information. + * --- + * Copyright (C) 2011, Lukas Weber + * Copyright (C) 2012, Alexeyew Andrew + */ + +#include + +#include "config.h" +#include "global.h" +#include "paths/native.h" +#include "taisei_err.h" + +ConfigEntry configdefs[] = { + {CFGT_KEYBINDING, KEY_UP, "key_up"}, + {CFGT_KEYBINDING, KEY_DOWN, "key_down"}, + {CFGT_KEYBINDING, KEY_LEFT, "key_left"}, + {CFGT_KEYBINDING, KEY_RIGHT, "key_right"}, + + {CFGT_KEYBINDING, KEY_FOCUS, "key_focus"}, + {CFGT_KEYBINDING, KEY_SHOT, "key_shot"}, + {CFGT_KEYBINDING, KEY_BOMB, "key_bomb"}, + + {CFGT_KEYBINDING, KEY_FULLSCREEN, "key_fullscreen"}, + {CFGT_KEYBINDING, KEY_SCREENSHOT, "key_screenshot"}, + {CFGT_KEYBINDING, KEY_SKIP, "key_skip"}, + + {CFGT_INT, FULLSCREEN, "fullscreen"}, + {CFGT_INT, NO_SHADER, "disable_shader"}, + {CFGT_INT, NO_AUDIO, "disable_audio"}, + {CFGT_INT, NO_STAGEBG, "disable_stagebg"}, + {CFGT_INT, NO_STAGEBG_FPSLIMIT, "disable_stagebg_auto_fpslimit"}, + {CFGT_INT, SAVE_RPY, "save_rpy"}, + {CFGT_INT, VID_WIDTH, "vid_width"}, + {CFGT_INT, VID_HEIGHT, "vid_height"}, + {CFGT_STRING, PLAYERNAME, "playername"}, + + {0, 0, 0} +}; + +ConfigEntry* config_findentry(char *name) { + ConfigEntry *e = configdefs; + do if(!strcmp(e->name, name)) return e; while((++e)->name); + return NULL; +} + +void config_preset() { + memset(tconfig.strval, 0, sizeof(tconfig.strval)); + + tconfig.intval[KEY_UP] = SDLK_UP; + tconfig.intval[KEY_DOWN] = SDLK_DOWN; + tconfig.intval[KEY_LEFT] = SDLK_LEFT; + tconfig.intval[KEY_RIGHT] = SDLK_RIGHT; + + tconfig.intval[KEY_FOCUS] = SDLK_LSHIFT; + tconfig.intval[KEY_SHOT] = SDLK_z; + tconfig.intval[KEY_BOMB] = SDLK_x; + + tconfig.intval[KEY_FULLSCREEN] = SDLK_F11; + tconfig.intval[KEY_SCREENSHOT] = SDLK_p; + tconfig.intval[KEY_SKIP] = SDLK_LCTRL; + + tconfig.intval[FULLSCREEN] = 0; + + tconfig.intval[NO_SHADER] = 0; + tconfig.intval[NO_AUDIO] = 0; + + tconfig.intval[NO_STAGEBG] = 0; + tconfig.intval[NO_STAGEBG_FPSLIMIT] = 40; + + tconfig.intval[SAVE_RPY] = 2; + + tconfig.intval[VID_WIDTH] = RESX; + tconfig.intval[VID_HEIGHT] = RESY; + + char *name = "Player"; + tconfig.strval[PLAYERNAME] = malloc(strlen(name)+1); + strcpy(tconfig.strval[PLAYERNAME], name); +} + +int config_sym2key(int sym) { + int i; + for(i = CONFIG_KEY_FIRST; i <= CONFIG_KEY_LAST; ++i) + if(sym == tconfig.intval[i]) + return i; + return -1; +} + +FILE* config_open(char *filename, char *mode) { + char *buf; + FILE *out; + + buf = malloc(strlen(filename) + strlen(get_config_path()) + 2); + strcpy(buf, get_config_path()); + strcat(buf, "/"); + strcat(buf, filename); + + out = fopen(buf, mode); + free(buf); + + if(!out) { + warnx("config_open(): couldn't open '%s'", filename); + return NULL; + } + + return out; +} + +inline int config_intval_p(ConfigEntry *e) { + return tconfig.intval[e->key]; +} + +inline char* config_strval_p(ConfigEntry *e) { + return tconfig.strval[e->key]; +} + +inline int config_intval(char *key) { + return config_intval_p(config_findentry(key)); +} + +inline char* config_strval(char *key) { + return config_strval_p(config_findentry(key)); +} + +void config_save(char *filename) { + FILE *out = config_open(filename, "w"); + ConfigEntry *e = configdefs; + + if(!out) + return; + + fputs("# Generated by taisei\n", out); + + do switch(e->type) { + case CFGT_INT: + fprintf(out, "%s = %i\n", e->name, config_intval_p(e)); + break; + + case CFGT_KEYBINDING: + fprintf(out, "%s = K%i\n", e->name, config_intval_p(e)); + break; + + case CFGT_STRING: + fprintf(out, "%s = %s\n", e->name, config_strval_p(e)); + break; + } while((++e)->name); + + fclose(out); + printf("Saved config '%s'\n", filename); +} + +#define SYNTAXERROR { warnx("config_load(): syntax error on line %i, aborted! [%s:%i]\n", line, __FILE__, __LINE__); goto end; } +#define BUFFERERROR { warnx("config_load(): string exceed the limit of %i, aborted! [%s:%i]", line, __FILE__, __LINE__); goto end; } +#define INTOF(s) ((int)strtol(s, NULL, 10)) + +void config_set(char *key, char *val) { + ConfigEntry *e = config_findentry(key); + + if(!e) { + warnx("config_set(): unknown key '%s'", key); + return; + } + + switch(e->type) { + case CFGT_INT: + tconfig.intval[e->key] = INTOF(val); + break; + + case CFGT_KEYBINDING: + tconfig.intval[e->key] = INTOF(val+1); + break; + + case CFGT_STRING: + stralloc(&(tconfig.strval[e->key]), val); + break; + } +} + +#undef INTOF + +void config_load(char *filename) { + FILE *in = config_open(filename, "r"); + int c, i = 0, found, line; + char buf[CONFIG_LOAD_BUFSIZE]; + char key[CONFIG_LOAD_BUFSIZE]; + char val[CONFIG_LOAD_BUFSIZE]; + + config_preset(); + if(!in) + 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); + printf("config_load(): key = %s\n", key); + + 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); + printf("config_load(): val = %s\n", val); + 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); + + ConfigEntry *e = configdefs; + do printf("%s = %i [%s]\n", e->name, config_intval_p(e), config_strval_p(e)); while((++e)->name); +} + +#undef SYNTAXERROR +#undef BUFFERERROR diff --git a/src/config.h b/src/config.h index e556b71f..5287731c 100644 --- a/src/config.h +++ b/src/config.h @@ -3,8 +3,9 @@ * See COPYING for further information. * --- * Copyright (C) 2011, Lukas Weber + * Copyright (C) 2012, Alexeyew Andrew */ - + #ifndef CONFIG_H #define CONFIG_H @@ -23,7 +24,7 @@ extern Config tconfig; * Not doing so will likely break replays! And don't forget to update CONFIG_KEY_LAST below. */ -enum { +typedef enum ConfigKey { KEY_UP = 0, KEY_DOWN, KEY_LEFT, @@ -50,14 +51,36 @@ enum { VID_HEIGHT, PLAYERNAME -}; +} ConfigKey; -void parse_config(char *filename); -void config_preset(); +typedef enum ConfigKeyType { + CFGT_INT, + CFGT_STRING, + CFGT_KEYBINDING +} ConfigKeyType; + +typedef struct ConfigEntry { + ConfigKeyType type; + ConfigKey key; + char *name; +} ConfigEntry; + +extern ConfigEntry configdefs[]; +Config tconfig; #define CONFIG_KEY_FIRST KEY_UP #define CONFIG_KEY_LAST KEY_SKIP +#define CONFIG_LOAD_BUFSIZE 256 int config_sym2key(int sym); +void config_preset(); +void config_load(char *filename); +void config_save(char *filename); +ConfigEntry* config_findentry(char *name); + +inline int config_intval(char*); +inline int config_intval_p(ConfigEntry*); +inline int config_strval(char*); +inline int config_strval_p(ConfigEntry*) #endif diff --git a/src/config.l b/src/config.l deleted file mode 100644 index 9ba0b8bf..00000000 --- a/src/config.l +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This software is licensed under the terms of the MIT-License - * See COPYING for further information. - * --- - * Copyright (C) 2011, Lukas Weber - */ - -%{ - #include "parser.h" - #include "config.h" - #include - - #define YY_NO_INPUT -%} - -%% - -= return EQ; - -#.+ ; - -"key_up" { yylval = KEY_UP; return tKEY_UP; } -"key_down" { yylval = KEY_DOWN; return tKEY_DOWN; } -"key_left" { yylval = KEY_LEFT; return tKEY_LEFT; } -"key_right" { yylval = KEY_RIGHT; return tKEY_RIGHT; } - -"key_focus" { yylval = KEY_FOCUS; return tKEY_FOCUS; } - -"key_shot" { yylval = KEY_SHOT; return tKEY_SHOT; } -"key_bomb" { yylval = KEY_BOMB; return tKEY_BOMB; } - -"key_fullscreen" { yylval = KEY_FULLSCREEN; return tKEY_FULLSCREEN; } -"key_screenshot" { yylval = KEY_SCREENSHOT; return tKEY_SCREENSHOT; } -"key_skip" { yylval = KEY_SKIP; return tKEY_SKIP; } - -"fullscreen" { yylval = FULLSCREEN; return tFULLSCREEN; } - -"disable_shader" { yylval = NO_SHADER; return tNO_SHADER; } -"disable_audio" {yylval = NO_AUDIO; return tNO_AUDIO; } -"disable_stagebg" { yylval = NO_STAGEBG; return tNO_STAGEBG; } -"disable_stagebg_auto_fpslimit" { yylval = NO_STAGEBG_FPSLIMIT; return tNO_STAGEBG_FPSLIMIT; } - -"save_rpy" { yylval = SAVE_RPY; return tSAVE_RPY; } - -"vid_width" { yylval = VID_WIDTH; return tVID_WIDTH; } -"vid_height" { yylval = VID_HEIGHT; return tVID_HEIGHT; } - -"playername" { yylval = PLAYERNAME; return tPLAYERNAME; } - -"shift" { yylval = SDLK_LSHIFT; return SKEY; } -"ctrl" { yylval = SDLK_LCTRL; return SKEY; } -"return" { yylval = SDLK_RETURN; return SKEY; } -"alt" { yylval = SDLK_LALT; return SKEY; } - -"up" { yylval = SDLK_UP; return SKEY; } -"down" { yylval = SDLK_DOWN; return SKEY; } -"right" { yylval = SDLK_RIGHT; return SKEY; } -"left" { yylval = SDLK_LEFT; return SKEY; } - -[0-9]+ { yylval = atoi(yytext); return NUMBER; } -[a-zA-Z] { yylval = yytext[0]; return tCHAR; } - -ä { yylval = SDLK_WORLD_68; return tCHAR; } -ü { yylval = SDLK_WORLD_92; return tCHAR; } -ö { yylval = SDLK_WORLD_86; return tCHAR; } -ß { yylval = SDLK_WORLD_63; return tCHAR; } - -K[0-9]+ { yylval = atoi(yytext + 1); return tCHAR; } - -\"[^\"\n\r]+\" { - int l = strlen(yytext); - char *s = malloc(l); - strcpy(s, yytext + 1); - s[l-2] = 0; - - yylval = (int)s; - return tSTRING; -} - -\n return LB; -[ \t] ; - -%% diff --git a/src/config.y b/src/config.y deleted file mode 100644 index 711b79c4..00000000 --- a/src/config.y +++ /dev/null @@ -1,186 +0,0 @@ -/* - * This software is licensed under the terms of the MIT-License - * See COPYING for further information. - * --- - * Copyright (C) 2011, Lukas Weber - */ - -%{ - #include "config.h" - #include "global.h" - #include - #include - #include - - #include "paths/native.h" - #include "taisei_err.h" - - Config tconfig; - int lineno; - - int yywrap() { - return 1; - } - - int yyerror(char *s) { - errx(-1, "!- %d: %s", lineno, s); - return 1; - } - - extern int yylex(void); - extern FILE *yyin; -%} - -%token tKEY_UP -%token tKEY_DOWN -%token tKEY_LEFT -%token tKEY_RIGHT - -%token tKEY_FOCUS - -%token tKEY_SHOT -%token tKEY_BOMB - -%token tKEY_FULLSCREEN -%token tKEY_SCREENSHOT -%token tKEY_SKIP - -%token tFULLSCREEN - -%token tNO_SHADER -%token tNO_AUDIO -%token tNO_STAGEBG -%token tNO_STAGEBG_FPSLIMIT -%token tSAVE_RPY - -%token tVID_WIDTH -%token tVID_HEIGHT - -%token tPLAYERNAME - -%token SKEY - -%token NUMBER -%token tCHAR -%token tSTRING - -%token SEMI -%token EQ -%token LB - -%% - -file : line nl file - | nl file - | ; - -line : key_key EQ key_val { - if($1 > sizeof(tconfig.intval)/sizeof(int)) - errx(-1, "config index out of range"); // should not happen - tconfig.intval[$1] = $3; - } - | key_strkey EQ tSTRING { - if($1 > sizeof(tconfig.strval)/sizeof(char*)) - errx(-1, "config index out of range"); // should not happen - - if(tconfig.strval[$1]) - free(tconfig.strval[$1]); - tconfig.strval[$1] = $3; - }; - -key_val : SKEY - | NUMBER - | tCHAR; - -key_key : tKEY_UP - | tKEY_DOWN - | tKEY_LEFT - | tKEY_RIGHT - | tKEY_FOCUS - | tKEY_SHOT - | tKEY_BOMB - | tKEY_FULLSCREEN - | tKEY_SCREENSHOT - | tKEY_SKIP - | tNO_SHADER - | tNO_AUDIO - | tFULLSCREEN - | tNO_STAGEBG - | tNO_STAGEBG_FPSLIMIT - | tVID_WIDTH - | tVID_HEIGHT - | tSAVE_RPY; - -key_strkey : tPLAYERNAME; - - -nl : LB { lineno++; }; -%% - -void parse_config(char *filename) { - config_preset(); - - lineno = 1; - - char *buf; - - buf = malloc(strlen(filename)+strlen(get_config_path())+3); - strcpy(buf, get_config_path()); - - strcat(buf, "/"); - strcat(buf, filename); - yyin = fopen(buf, "r"); - - printf("parse_config():\n"); - if(yyin) { - yyparse(); - printf("-- parsing complete\n"); - fclose(yyin); - } else { - printf("-- parsing incomplete; falling back to built-in preset\n"); - warnx("problems with parsing %s", buf); - } - free(buf); -} - -void config_preset() { - memset(tconfig.strval, 0, sizeof(tconfig.strval)); - - tconfig.intval[KEY_UP] = SDLK_UP; - tconfig.intval[KEY_DOWN] = SDLK_DOWN; - tconfig.intval[KEY_LEFT] = SDLK_LEFT; - tconfig.intval[KEY_RIGHT] = SDLK_RIGHT; - - tconfig.intval[KEY_FOCUS] = SDLK_LSHIFT; - tconfig.intval[KEY_SHOT] = SDLK_z; - tconfig.intval[KEY_BOMB] = SDLK_x; - - tconfig.intval[KEY_FULLSCREEN] = SDLK_F11; - tconfig.intval[KEY_SCREENSHOT] = SDLK_p; - tconfig.intval[KEY_SKIP] = SDLK_LCTRL; - - tconfig.intval[FULLSCREEN] = 0; - - tconfig.intval[NO_SHADER] = 0; - tconfig.intval[NO_AUDIO] = 0; - - tconfig.intval[NO_STAGEBG] = 0; - tconfig.intval[NO_STAGEBG_FPSLIMIT] = 40; - - tconfig.intval[SAVE_RPY] = 2; - - tconfig.intval[VID_WIDTH] = RESX; - tconfig.intval[VID_HEIGHT] = RESY; - - char *name = "Player"; - tconfig.strval[PLAYERNAME] = malloc(strlen(name)+1); - strcpy(tconfig.strval[PLAYERNAME], name); -} - -int config_sym2key(int sym) { - int i; - for(i = CONFIG_KEY_FIRST; i <= CONFIG_KEY_LAST; ++i) - if(sym == tconfig.intval[i]) - return i; - return -1; -} diff --git a/src/main.c b/src/main.c index dfe0bf83..835b82e5 100644 --- a/src/main.c +++ b/src/main.c @@ -32,6 +32,7 @@ void init_gl() { void taisei_shutdown() { + config_save(CONFIG_FILE); printf("\nshutdown:\n"); free_resources(); @@ -55,7 +56,7 @@ int main(int argc, char** argv) { MKDIR(get_screenshots_path()); MKDIR(get_replays_path()); - parse_config(CONFIG_FILE); + config_load(CONFIG_FILE); printf("initialize:\n"); if(SDL_Init(SDL_INIT_VIDEO) < 0) diff --git a/src/menu/options.c b/src/menu/options.c index 2bb0e88b..f45521dd 100644 --- a/src/menu/options.c +++ b/src/menu/options.c @@ -317,64 +317,6 @@ int bind_saverpy_set(void *b, int v) return !(tconfig.intval[((OptionBinding*)b)->configentry] = !v); } -// --- Config saving --- // - -void menu_save_config(MenuData *m, char *filename) -{ - char *buf; - buf = malloc(strlen(filename) + strlen(get_config_path()) + 2); - strcpy(buf, get_config_path()); - strcat(buf, "/"); - strcat(buf, filename); - - FILE *out = fopen(buf, "w"); - free(buf); - - if(!out) - { - perror("fopen"); - return; - } - - fputs("# Generated by taisei\n", out); - - int i; - for(i = 0; i < m->ecount; ++i) - { - OptionBinding *binds = (OptionBinding*)m->context; - OptionBinding *bind = &(binds[i]); - - if(!bind->enabled) - continue; - - switch(bind->type) - { - case BT_IntValue: - fprintf(out, "%s = %i\n", bind->optname, tconfig.intval[bind->configentry]); - break; - - case BT_KeyBinding: - fprintf(out, "%s = K%i\n", bind->optname, tconfig.intval[bind->configentry]); - break; - - case BT_StrValue: - fprintf(out, "%s = \"%s\"\n", bind->optname, tconfig.strval[bind->configentry]); - break; - - case BT_Resolution: - // at this point, the intended resolution is what the user has picked - fprintf(out, "vid_width = %i\nvid_height = %i\n", video.intended.width, video.intended.height); - break; - - default: - printf("FIXME: unhandled BindingType %i, option '%s' will NOT be saved!\n", bind->type, bind->optname); - } - } - - fclose(out); - printf("Saved config '%s'\n", filename); -} - // --- Creating, destroying, filling the menu --- // void destroy_options_menu(void *menu) @@ -388,12 +330,15 @@ void destroy_options_menu(void *menu) if(binds[i].selected != -1) { VideoMode *m = &(video.modes[binds[i].selected]); video_setmode(m->width, m->height, tconfig.intval[FULLSCREEN]); + + tconfig.intval[VID_WIDTH] = video.intended.width; + tconfig.intval[VID_HEIGHT] = video.intended.height; } break; } } - menu_save_config(m, CONFIG_FILE); + config_save(CONFIG_FILE); free_bindings(menu); }