diff options
author | Ludovic Pouzenc <lpouzenc@gmail.com> | 2013-07-16 21:11:55 +0200 |
---|---|---|
committer | Ludovic Pouzenc <lpouzenc@gmail.com> | 2013-07-16 21:11:55 +0200 |
commit | a3faaf6f1270e7af4789da1bda4e3e478ce33960 (patch) | |
tree | cab2c8c39d620612697c0cbd33b9ae0b33ca3092 /src/parser.c | |
parent | aebfa9ac4b9eea848ec40f62819ecf743a807b73 (diff) | |
download | mplemmings-a3faaf6f1270e7af4789da1bda4e3e478ce33960.tar.gz mplemmings-a3faaf6f1270e7af4789da1bda4e3e478ce33960.tar.bz2 mplemmings-a3faaf6f1270e7af4789da1bda4e3e478ce33960.zip |
Parseur de fichier INI fonctionnel. Il reste le misc.ini laissé de côté avec les nombre de frames par animations... A voir si on garde ça configurable (change le comportement du jeu)
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 346 |
1 files changed, 193 insertions, 153 deletions
diff --git a/src/parser.c b/src/parser.c index d139436..812b4c1 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,63 +1,186 @@ #include "parser.h" +#ifndef PARSER_H +#define PARSER_H + +#include "data_ini.h" +#ifndef DATA_INI_H +#define DATA_INI_H + +#include <SDL_stdinc.h> + +// Original game level size is fixed to 1664x160. We want to display all the game with a x2 zoom +#define LEVEL_WIDTH 1664*2 +#define LEVEL_HEIGHT 160*2 + +#define MAX_NAMELEN 64 + +#define MAX_PARTICLE_COLORS 16 +#define MAX_MUSICS_COUNT 32 +#define MAX_DIFFICULTY_COUNT 8 +#define MAX_OBJECTS_COUNT 256 +#define MAX_TERRAINS_COUNT 1024 +#define MAX_STEELS_COUNT 256 + +//////////////////////// LEVEL INI FILES //////////////////////// + +// Item should be an object, terrain or steel +struct levelItem { + int id, xpos, ypos; // Common to all types (but no id for steel) + int paintMode, ud; // Specific to objects + int modifier; // Specific to terrains + int width, height; // Specific to steels +}; + +struct levelIni { + int releaseRate, numLemmings, numToRescue, timeLimit; + int numClimbers, numFloaters, numBlockers, numBombers; + int numBuilders, numBashers, numMiners, numDiggers; + int xPos; // Initial camera position on level + char style[MAX_NAMELEN], name[MAX_NAMELEN]; + int superLemming; + int objectCount, terrainCount, steelCount; + struct levelItem objects[MAX_OBJECTS_COUNT]; + struct levelItem terrains[MAX_OBJECTS_COUNT]; + struct levelItem steels[MAX_OBJECTS_COUNT]; +}; + + +//////////////////////// LEVELPACK INI FILES //////////////////////// +struct levelPackIni { + char name[MAX_NAMELEN]; + int maxFallDistance; + char codeSeed[MAX_NAMELEN]; + int musicCount, levelDifficultyCount; + char music[MAX_MUSICS_COUNT][MAX_NAMELEN]; + char levelDifficulty[MAX_DIFFICULTY_COUNT][MAX_NAMELEN]; +}; + +//////////////////////// STYLE INI FILES //////////////////////// +struct styleIni { + char name[MAX_NAMELEN]; + uint32_t bgColor, debrisColor; + int tiles, particleColorCount; + uint32_t particleColor[MAX_PARTICLE_COLORS]; + int objectCount; + int frames[MAX_OBJECTS_COUNT]; + int anim[MAX_OBJECTS_COUNT]; + int type[MAX_OBJECTS_COUNT]; + int sound[MAX_OBJECTS_COUNT]; +}; + +/*////////////////////// MISC/LEMMING.INI FILE //////////////////////// +struct lemmingAnim { + int haveMask, haveImask; + + int lemmFrames, lemmDirs, lemmAnimType; + int maskFrames, maskDirs, maskStartFrame; + int imaskFrames, imaskDirs; + int xPos, yPos, posFlags; +}; + +struct miscIni { + int lemmingAnimCount; + struct lemmingAnim *lemmingAnims; +}; +*/ + +//////////////////////// GLOBAL INI FILES //////////////////////// +typedef struct { + struct styleIni style; + struct levelIni level; + struct levelPackIni levelPack; + //struct miscIni misc; +} gameIni_t; + + +#endif /*DATA_INI_H*/ + +//#define OUT_OF_BOUNDS "out of bounds" +//#define CANNOT_BE_NEGATIVE "cannot be negative" +//#define BAD_VALUE "bad value" + +//#define MAX_LEMMTYPES_COUNT 16 +//#define MAX_OBJECT_FRAMES 64 +//#define MAX_NUMLEMMINGS 100 +//#define STEEL_MAX_WIDTH 256 +//#define STEEL_MAX_HEIGHT 256 + +#define ERR_UNKNOWN_KEY 1 +#define ERR_NOT_YET_IMPLEMENTED 2 +#define ERR_KEY_OUT_OF_RANGE 3 +#define ERR_VAL_OUT_OF_RANGE 4 +#define ERR_STRING_TOO_LONG 5 + +enum ini_type { ini_style, ini_levelpack, ini_level }; + +int loadIni(enum ini_type type, const char *filepath, gameIni_t *ini); + +#endif /*PARSER_H*/ #include "minIni.h" -#define MATCH_INT(keysymbol) \ +#define _MATCH_SIMPLETYPE(keysymbol,parsefunc) \ do { \ if (SDL_strcasecmp(key,#keysymbol)==0) { \ - data->keysymbol = SDL_atoi(value); \ + data->keysymbol = parsefunc(value); \ return 1; \ } \ } while(0) -#define MATCH_HEXCOLOR(keysymbol) \ +#define MATCH_INT(keysymbol) _MATCH_SIMPLETYPE(keysymbol,SDL_atoi) +#define MATCH_HEXCOLOR(keysymbol) _MATCH_SIMPLETYPE(keysymbol,hextext2rgb) + +#define _SAFE_STRING_COPY(dst,src,maxlen) \ do { \ - if (SDL_strcasecmp(key,#keysymbol)==0) { \ - data->keysymbol = hextext2rgb(value); \ - return 1; \ + int srclen = SDL_strlcpy(dst,src,maxlen-1); \ + if (srclen > maxlen-1 ) { \ + *err=ERR_STRING_TOO_LONG; return 0; \ } \ } while(0) - -#define MATCH_STRING(keysymbol) \ +#define MATCH_STRING(keysymbol,valmaxlen) \ do { \ if (SDL_strcasecmp(key,#keysymbol)==0) { \ - data->keysymbol = SDL_strdup(value); \ + _SAFE_STRING_COPY(data->keysymbol,value,valmaxlen); \ return 1; \ } \ } while(0) -#define MATCH_STRING_ARRAY(keysymbol,keysymlen,keyidxmax,outofrangeerrnum) \ +#define MATCH_STRING_ARRAY(keysymbol,keyidxmax,countvar,arrayvar,valmaxlen) \ do { \ + int keysymlen=sizeof(#keysymbol)-1; \ if (SDL_strncasecmp(key,#keysymbol,keysymlen)==0 && key[keysymlen]=='_') { \ - int k = atoi(value+keysymlen+1); \ - if (k<0 || k>keyidxmax) { *err=outofrangeerrnum; return 0; } \ - if (data->keysymbol##Count < k) data->keysymbol##Count = k+1; \ - data->keysymbol##s[k] = SDL_strdup(value); \ - return 0; \ + int k = atoi(key+keysymlen+1); \ + if (k<0 || k>keyidxmax) { *err=ERR_KEY_OUT_OF_RANGE; return 0; } \ + if (countvar < k+1) countvar = k+1; \ + _SAFE_STRING_COPY(arrayvar[k],value,valmaxlen); \ + return 1; \ } \ } while(0) -#define MATCH_INT_ARRAY_MALLOC(keysymbol,keysymlen,outofrangeerrnum,minval,maxval,valoutofrangeerrnum) \ +#define MATCH_INT_ARRAY(keysymbol,keyidxmax,countvar,arrayvar,minval,maxval) \ do { \ + int keysymlen=sizeof(#keysymbol)-1; \ if (SDL_strncasecmp(key,#keysymbol,keysymlen)==0 && key[keysymlen]=='_') { \ - int k = atoi(value+keysymlen+1); \ - if ( k<0 || k > data->objectCount) { *err=outofrangeerrnum; return 0; } \ + int k = atoi(key+keysymlen+1); \ + if ( k<0 || k>keyidxmax) { *err=ERR_KEY_OUT_OF_RANGE; return 0; } \ + if (countvar < k+1) countvar = k+1; \ int v = atoi(value); \ - if ( v<minval || v>maxval) { *err=valoutofrangeerrnum; return 0; } \ - data->objects[k].keysymbol = v; \ + if ( v<minval || v>maxval) { *err=ERR_VAL_OUT_OF_RANGE; return 0; } \ + arrayvar[k] = v; \ + return 1; \ } \ - return 0; \ } while(0) int callback_ini_style (const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData); int callback_ini_levelpack (const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData); -int callback_ini_level_pass1(const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData); -int callback_ini_level_pass2(const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData); +int callback_ini_level(const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData); // struct for void *UserData pointer (app context passed to each callback func) +#define MAX_LINELEN 256 typedef struct { - int error_code; gameIni_t *ini; + int error_code; + char error_line_content[MAX_LINELEN]; } parserState_t; int loadIni(enum ini_type type, const char *filepath, gameIni_t *ini) { @@ -65,24 +188,34 @@ int loadIni(enum ini_type type, const char *filepath, gameIni_t *ini) { parserState_t state; const void *UserData=(void *)&state; - (void) SDL_memset(ini,0,sizeof(gameIni_t)); (void) SDL_memset(&state,0,sizeof(parserState_t)); state.ini=ini; switch (type) { case ini_style: + (void) SDL_memset(&ini->style,0,sizeof(struct styleIni)); res=ini_browse(callback_ini_style, UserData, filepath); - return (res!=0)?state.error_code:0; + break; case ini_levelpack: + (void) SDL_memset(&ini->levelPack,0,sizeof(struct levelPackIni)); res=ini_browse(callback_ini_levelpack, UserData, filepath); - return (res!=0)?state.error_code:0; + break; case ini_level: - res=ini_browse(callback_ini_level_pass1, UserData, filepath); - if (res!=0) return state.error_code; - res=ini_browse(callback_ini_level_pass2, UserData, filepath); - return state.error_code; + (void) SDL_memset(&ini->level,0,sizeof(struct levelIni)); + res=ini_browse(callback_ini_level, UserData, filepath); + break; + default: + return -1; //Should be unreachable + } + if (res!=1) { + res=state.error_code; + //FIXME : logging + printf("Parse error %i for this key/value pair : %s\n", state.error_code, state.error_line_content); + } else { + res=0; } - return -1; // should be unreachable + + return res; } uint32_t hextext2rgb(const char str[]) { @@ -94,99 +227,39 @@ uint32_t hextext2rgb(const char str[]) { } int callback_ini_style(const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData) { - gameIni_t *ini = ((parserState_t*) userData)->ini; struct styleIni *data = &( ((parserState_t*) userData)->ini->style ); int *err= &(((parserState_t*) userData)->error_code); + SDL_snprintf(((parserState_t*) userData)->error_line_content, MAX_LINELEN, "%s => %s", key, value); - MATCH_HEXCOLOR(bgColor); - MATCH_HEXCOLOR(debrisColor); -/* - if (SDL_strcasecmp(key,"bgColor")==0) - {ini->style.bgColor = hextext2rgb(value); return 1;} - if (SDL_strcasecmp(key,"debrisColor")==0) - {ini->style.debrisColor = hextext2rgb(value); return 1;} -*/ + // Special case for particleColor. No macros here if (SDL_strcasecmp(key,"particleColor")==0) { char *wordBoundary; int i=0; - //((parserState_t*) userData)->need_2pass=1; while ( SDL_strlen(value)>0 && (wordBoundary=SDL_strchr(value,','))!=NULL && i<MAX_PARTICLE_COLORS ) { *wordBoundary='\0'; - ini->style.particleColor[i++]=hextext2rgb(value); + data->particleColor[i++]=hextext2rgb(value); value = wordBoundary+1; } // Parse the last one - ini->style.particleColor[i++]=hextext2rgb(value); - ini->style.particleColorCount=i; + data->particleColor[i++]=hextext2rgb(value); + data->particleColorCount=i; - return 0; - } - if (SDL_strcasecmp(key,"tiles")==0) { - int v = atoi(value); - if ( v<0 || v>MAX_OBJECTS_COUNT) { *err=3; return 0; } - ini->style.objectCount = v; - return 0; + return 1; } - MATCH_INT_ARRAY_MALLOC(frames,6,4,0,MAX_OBJECT_FRAMES,5); -/* - if (SDL_strncasecmp(key,"frames_", 7) == 0) { - int i = atoi(value+7); - if ( i<0 || i>=ini->style.objectCount) { *err=4; return 0; } - - int v = atoi(value); - if ( v<0 || v>MAX_OBJECT_FRAMES) { *err=5; return 0; } - - ini->style.objects[i].frames = v; - return 0; - } -*/ - MATCH_INT_ARRAY_MALLOC(anim,5,6,0,3,7); -/* - if (SDL_strncasecmp(key,"anim_", 5) == 0) { - int i = atoi(value+5); - if ( i<0 || i>=ini->style.objectCount) { *err=6; return 0; } - - int v = atoi(value); - if ( v<0 || v>3) { *err=7; return 0; } - - ini->style.objects[i].anim = v; - return 0; - } -*/ - MATCH_INT_ARRAY_MALLOC(type,4,8,0,32,9); - // TODO : TEST outof range : if (! (v==0 || v==32 || (v>=3 && v<=8))) -/* - if (SDL_strncasecmp(key,"type_", 5) == 0) { - int i = atoi(value+5); - if ( i<0 || i>=ini->style.objectCount) { *err=8; return 0; } - - int v = atoi(value); - if (! (v==0 || v==32 || (v>=3 && v<=8))) { *err=9; return 0; } - - ini->style.objects[i].type = v; - return 0; - } -*/ - - MATCH_INT_ARRAY_MALLOC(sound,5,10,0,MAX_SOUNDS_COUNT,11); - /* - if (SDL_strncasecmp(key,"sound_", 6) == 0) { - int i = atoi(value+6); - if ( i<0 || i>=ini->style.objectCount) { *err=10; return 0; } - - int v = atoi(value); - if ( v<0 || v>MAX_SOUNDS_COUNT) { *err=11; return 0; } - - ini->style.objects[i].frames = v; - return 0; - } - */ + // Common cases, extensive use of macros + MATCH_HEXCOLOR(bgColor); + MATCH_HEXCOLOR(debrisColor); + MATCH_INT(tiles); + MATCH_INT_ARRAY(frames,MAX_OBJECTS_COUNT,data->objectCount,data->frames,0,32); + MATCH_INT_ARRAY(anim ,MAX_OBJECTS_COUNT,data->objectCount,data->anim ,0,3); + MATCH_INT_ARRAY(type ,MAX_OBJECTS_COUNT,data->objectCount,data->type ,0,32); + MATCH_INT_ARRAY(sound ,MAX_OBJECTS_COUNT,data->objectCount,data->sound ,-1,32); // No match is an error (unkown key) - *err=1; return -1; + *err=ERR_UNKNOWN_KEY; return 0; } int callback_ini_levelpack(const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData) { @@ -195,36 +268,12 @@ int callback_ini_levelpack(const mTCHAR *section, const mTCHAR *key, const mTCHA int *err= &(((parserState_t*) userData)->error_code); int i; - MATCH_STRING(name); + MATCH_STRING(name,MAX_NAMELEN); MATCH_INT(maxFallDistance); - MATCH_STRING(codeSeed); - - /* - if (SDL_strcasecmp(key,"name")==0) - { ini->levelPack.name = SDL_strdup(value); return 1;} - if (SDL_strcasecmp(key,"maxFallDistance")==0) - { ini->levelPack.maxFallDistance = SDL_atoi(value); return 1;} - if (SDL_strcasecmp(key,"codeSeed")==0) - { ini->levelPack.codeSeed = SDL_strdup(value); return 1;} - */ - - MATCH_STRING_ARRAY(music,5,MAX_MUSIC_COUNT,22); -/* - if (SDL_strncasecmp(key,"music_", 6) == 0) { - int k = atoi(value+6); - if (k<0 || k>MAX_MUSIC_COUNT) { *err=22; return 0; } - if (ini->levelPack.musicCount < k) ini->levelPack.musicCount=k+1; - ini->levelPack.musics[k] = SDL_strdup(value); - return 0; - } -*/ - if (SDL_strncasecmp(key,"level_", 6) == 0) { - int k = atoi(value+6); - if (k<0 || k>MAX_DIFFICULTY_COUNT) { *err=23; return 0; } - if (data->levelDifficultyCount < k) data->levelDifficultyCount=k+1; - data->levelDifficulty[k] = SDL_strdup(value); - return 0; - } + MATCH_STRING(codeSeed,MAX_NAMELEN); + + MATCH_STRING_ARRAY(music,MAX_MUSICS_COUNT,data->musicCount,data->music,MAX_NAMELEN); + MATCH_STRING_ARRAY(level,MAX_DIFFICULTY_COUNT,data->levelDifficultyCount,data->levelDifficulty,MAX_NAMELEN); // Parse all entries like <difficultyname>_<levelnumber> (ex: tame_0, havoc_5) for (i=0;i < data->levelDifficultyCount; i++ ) { @@ -234,18 +283,18 @@ int callback_ini_levelpack(const mTCHAR *section, const mTCHAR *key, const mTCHA if ( (len > 0) && (SDL_strncasecmp(key,diffname,len) == 0) && (key[len] == '_') ) { //FIXME : checher position de .ini : copier la chaine avant + 4 //FIXME : chercher , et sscandf de la suite - *err=1; return -1; + *err=ERR_NOT_YET_IMPLEMENTED; return 0; } } + // No match is an error (unkown key) - *err=1; return -1; + *err=ERR_UNKNOWN_KEY; return 0; } -int callback_ini_level_pass1(const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData) { - //gameIni_t *ini = ((parserState_t*) userData)->ini; +int callback_ini_level(const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData) { struct levelIni *data = &(((parserState_t*) userData)->ini->level); - int *err= &(((parserState_t*) userData)->error_code); + MATCH_INT(releaseRate); MATCH_INT(numLemmings); MATCH_INT(numToRescue); @@ -259,20 +308,11 @@ int callback_ini_level_pass1(const mTCHAR *section, const mTCHAR *key, const mTC MATCH_INT(numMiners); MATCH_INT(numDiggers); MATCH_INT(xPos); - MATCH_STRING(style); - MATCH_STRING(name); + MATCH_STRING(style,MAX_NAMELEN); + MATCH_STRING(name,MAX_NAMELEN); // TODO : object/terrain/steel à la main (car struct, et complications) // No match is an error (unkown key) - *err=1; return -1; -} - -int callback_ini_level_pass2(const mTCHAR *section, const mTCHAR *key, const mTCHAR *value, const void *userData) { - //gameIni_t *ini = ((parserState_t*) userData)->ini; - int *err= &(((parserState_t*) userData)->error_code); - - // No match is an error (unkown key) - *err=1; return -1; + *err=ERR_UNKNOWN_KEY; return 0; } - |