New config parser. bison and flex, please gtfo, thanks.

This commit is contained in:
Andrew "Akari" Alexeyew 2012-08-03 08:06:19 +03:00
parent 5cbac0a8d5
commit 9295205419
8 changed files with 287 additions and 343 deletions

1
README
View file

@ -12,7 +12,6 @@ Dependencies:
- libpng
- OpenGL
- OpenAL, ALUT
- flex/bison
- CMake (build system)
To build and install Taisei just follow these steps.

View file

@ -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)

251
src/config.c Normal file
View file

@ -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 <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#include <string.h>
#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

View file

@ -3,8 +3,9 @@
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#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

View file

@ -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 <laochailan@web.de>
*/
%{
#include "parser.h"
#include "config.h"
#include <SDL/SDL_keysym.h>
#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] ;
%%

View file

@ -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 <laochailan@web.de>
*/
%{
#include "config.h"
#include "global.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#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;
}

View file

@ -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)

View file

@ -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);
}