From 7cc94adb76fee4f94e82559fe9cbd98aecfa7310 Mon Sep 17 00:00:00 2001 From: n-a-c-h <> Date: Wed, 1 Jun 2005 00:00:58 +0000 Subject: [PATCH] Converted data config file to text, added new parser stuff. --- zsnes/src/Makefile.in | 15 +- zsnes/src/cfgparse.psr | 356 +++++++++++++++ zsnes/src/gui/guifuncs.c | 13 +- zsnes/src/makefile.ms | 14 +- zsnes/src/parsegen.cpp | 964 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 1348 insertions(+), 14 deletions(-) create mode 100644 zsnes/src/cfgparse.psr create mode 100644 zsnes/src/parsegen.cpp diff --git a/zsnes/src/Makefile.in b/zsnes/src/Makefile.in index 865fcc30..b823eaee 100644 --- a/zsnes/src/Makefile.in +++ b/zsnes/src/Makefile.in @@ -18,6 +18,8 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +PSR=parsegen + CHIPDIR=chips CPUDIR=cpu DOSDIR=dos @@ -73,11 +75,11 @@ ZIPOBJ=${ZIPDIR}/unzip.o ${ZIPDIR}/zpng.o EFFECTSOBJ=${EFFECTSDIR}/burn.o ${EFFECTSDIR}/water.o ${EFFECTSDIR}/smoke.o MAINOBJ=cfgload.o endmem.o init.o initc.o uic.o patch.o ui.o vcache.o version.o\ - zmovie.o zstate.o debug.o zloader.o + zmovie.o zstate.o debug.o zloader.o cfgparse.o OBJS=${CHIPSOBJ} ${CPUOBJ} ${WINOBJ} ${WINDOSOBJ} ${GUIOBJ} ${VIDEOBJ} ${MAINOBJ} ${NETOBJ} ${ZIPOBJ} ${EFFECTSOBJ} ${JMAOBJ} -.SUFFIXES: .cpp .c .asm +.SUFFIXES: .cpp .c .asm .psr %.o: %.cpp @CXX@ @CFLAGS@ -o $@ -c $< @@ -88,9 +90,12 @@ OBJS=${CHIPSOBJ} ${CPUOBJ} ${WINOBJ} ${WINDOSOBJ} ${GUIOBJ} ${VIDEOBJ} ${MAINOBJ %.o: %.asm @NASMPATH@ @NFLAGS@ -o $@ $< +%.c: %.psr + ${PSR} -D__LINUX__ $@ $< + ALL: @ZSNESEXE@ -@ZSNESEXE@: ${OBJS} +@ZSNESEXE@: ${PSR} ${OBJS} @CXX@ -o @ZSNESEXE@ ${OBJS} @CFLAGS@ @LDFLAGS@ ${ZIPDIR}/zpng.o: ${ZIPDIR}/zpng.c ${ZIPDIR}/zpng.h @@ -210,6 +215,10 @@ ${DOSDIR}/zsipx.o: ${DOSDIR}/zsipx.asm ${CHIPDIR}/sa1proc.o: ${CHIPDIR}/sa1proc.asm macros.mac endmem.o: endmem.asm macros.mac +${PSR}: $< +cfgparse.c: $< ${PSR} +cfgparse${OE}: $< + ${JMADIR}/7zlzma.o: ${JMADIR}/7zlzma.cpp ${JMADIR}/7z.h ${JMADIR}/iiostrm.h ${JMADIR}/crc32.o: ${JMADIR}/crc32.cpp ${JMADIR}/crc32.h ${JMADIR}/iiostrm.o: ${JMADIR}/iiostrm.cpp ${JMADIR}/iiostrm.h ${JMADIR}/crc32.h diff --git a/zsnes/src/cfgparse.psr b/zsnes/src/cfgparse.psr new file mode 100644 index 00000000..c8f22a39 --- /dev/null +++ b/zsnes/src/cfgparse.psr @@ -0,0 +1,356 @@ +GUIRAdd db 15 +GUIGAdd db 10 +GUIBAdd db 31 +mousewrap db 0 ; 0 = mouse boundries, 1 = mouse wrap +mouseshad db 1 ; 0 = no mouse shadow, 1 = mouse shadow +lastcursres db 0 ; 0 = go to load, 1 = go to previous menu, 2 = no menu +resetposn db 1 ; 0 = no window reset, 1 = window reset +NEWSYM GUIClick, db 0 ; 1 = mouse click enters/exits gui +GUIwinposx2 dd 0,5 ,60 ,30 ,55 ,50 ,65 ,5 ,30 ,20 ,10 ,80 ,65 ,20 ,70 ,50 ,3 ,0 +GUIwinposy2 dd 0,20 ,70 ,30 ,20 ,22 ,36 ,20 ,30 ,20 ,40 ,70 ,60 ,30 ,65 ,50 ,22,0 + +; Default keys +; Sound Channels 0 .. 7, Save/Select/Load States, Fast Forward +; Exit, Load, Reset, BG Disables, Reset, Windowing, New Gfx, OffsetMode +; State Selection 0 .. 9 + +NEWSYM KeyDisableSC0, dd 63 +NEWSYM KeyDisableSC1, dd 64 +NEWSYM KeyDisableSC2, dd 65 +NEWSYM KeyDisableSC3, dd 66 +NEWSYM KeyDisableSC4, dd 67 +NEWSYM KeyDisableSC5, dd 68 +NEWSYM KeyDisableSC6, dd 87 +NEWSYM KeyDisableSC7, dd 88 +NEWSYM KeySaveState, dd 60 +NEWSYM KeyStateSelct, dd 61 +NEWSYM KeyLoadState, dd 62 +NEWSYM KeyFastFrwrd, dd 41 +NEWSYM KeyQuickExit, dd 0 +NEWSYM KeyQuickLoad, dd 0 +NEWSYM KeyQuickRst, dd 0 +NEWSYM KeyBGDisble0, dd 2 +NEWSYM KeyBGDisble1, dd 3 +NEWSYM KeyBGDisble2, dd 4 +NEWSYM KeyBGDisble3, dd 5 +NEWSYM KeySprDisble, dd 6 +NEWSYM KeyResetAll, dd 7 +NEWSYM KeyExtraEnab, dd 8 +NEWSYM KeyNewGfxSwt, dd 9 +NEWSYM KeyWinDisble, dd 10 +NEWSYM KeyOffsetMSw, dd 11 +NEWSYM KeyStateSlc0, dd 0 +NEWSYM KeyStateSlc1, dd 0 +NEWSYM KeyStateSlc2, dd 0 +NEWSYM KeyStateSlc3, dd 0 +NEWSYM KeyStateSlc4, dd 0 +NEWSYM KeyStateSlc5, dd 0 +NEWSYM KeyStateSlc6, dd 0 +NEWSYM KeyStateSlc7, dd 0 +NEWSYM KeyStateSlc8, dd 0 +NEWSYM KeyStateSlc9, dd 0 + +GUIshowallext db 0 +GUIloadfntype db 0 + +NEWSYM pl3selk, dd 0 ; 3SELECT = SHIFT +NEWSYM pl3startk, dd 0 ; 3START = ENTER +NEWSYM pl3upk, dd 0 ; 3UP = up +NEWSYM pl3downk, dd 0 ; 3DOWN = down +NEWSYM pl3leftk, dd 0 ; 3LEFT = left +NEWSYM pl3rightk, dd 0 ; 3RIGHT = right +NEWSYM pl3Xk, dd 0 ; 3X = INS +NEWSYM pl3Ak, dd 0 ; 3A = HOME +NEWSYM pl3Lk, dd 0 ; 3L = PAGE UP +NEWSYM pl3Yk, dd 0 ; 3Y = DELETE +NEWSYM pl3Bk, dd 0 ; 3B = END +NEWSYM pl3Rk, dd 0 ; 3R = PAGE DOWN +NEWSYM pl4selk, dd 0 ; 4SELECT = SHIFT +NEWSYM pl4startk, dd 0 ; 4START = ENTER +NEWSYM pl4upk, dd 0 ; 4UP = up +NEWSYM pl4downk, dd 0 ; 4DOWN = down +NEWSYM pl4leftk, dd 0 ; 4LEFT = left +NEWSYM pl4rightk, dd 0 ; 4RIGHT = right +NEWSYM pl4Xk, dd 0 ; 4X = INS +NEWSYM pl4Ak, dd 0 ; 4A = HOME +NEWSYM pl4Lk, dd 0 ; 4L = PAGE UP +NEWSYM pl4Yk, dd 0 ; 4Y = DELETE +NEWSYM pl4Bk, dd 0 ; 4B = END +NEWSYM pl4Rk, dd 0 ; 4R = PAGE DOWN +NEWSYM TimeChecker, db 0 ; Future Reserved +GUISoundBuffer db 1 ; Sound Buffer Disabled +prevloadnames times 16*10 db 32 +prevloaddname times 128*10 db 0 +prevloadfname times 16*10 db 32 +prevlfreeze db 0 +GUIsmallscreenon db 0 +GUIScreenScale db 0 + +NEWSYM pl3contrl, db 0 +NEWSYM pl4contrl, db 0 +NEWSYM pl1p209b, db 0 +NEWSYM pl2p209b, db 0 +NEWSYM pl3p209b, db 0 +NEWSYM pl4p209b, db 0 +JoyPad1Move db 0 +NEWSYM FirstTimeData, db 0 +NEWSYM PrevSWFix, db 0 +NEWSYM CalibXmin, dd 0 +NEWSYM CalibYmin, dd 0 +NEWSYM CalibXmax, dd 0 +NEWSYM CalibYmax, dd 0 +NEWSYM CalibXmin209, dd 0 +NEWSYM CalibYmin209, dd 0 +NEWSYM CalibXmax209, dd 0 +NEWSYM CalibYmax209, dd 0 +NEWSYM maxskip, db 9 +NEWSYM FPSAtStart, db 0 +NEWSYM SidewinderFix, db 0 +GUIInitSt1 db 'ATZ' +GUIInitSt2 db 'AT S0=0' +GUIDialSt db 'ATDT ',0 +NEWSYM ComNum, db 2 +NEWSYM ComIRQ, db 3 +NEWSYM BaudRate, dd 3 +NEWSYM pl1Atk, dd 0 ; Turbo A +NEWSYM pl1Btk, dd 0 ; Turbo B +NEWSYM pl1Xtk, dd 0 ; Turbo X +NEWSYM pl1Ytk, dd 0 ; Turbo Y +NEWSYM pl2Atk, dd 0 ; Turbo A +NEWSYM pl2Btk, dd 0 ; Turbo B +NEWSYM pl2Xtk, dd 0 ; Turbo X +NEWSYM pl2Ytk, dd 0 ; Turbo Y +NEWSYM pl3Atk, dd 0 ; Turbo A +NEWSYM pl3Btk, dd 0 ; Turbo B +NEWSYM pl3Xtk, dd 0 ; Turbo X +NEWSYM pl3Ytk, dd 0 ; Turbo Y +NEWSYM pl4Atk, dd 0 ; Turbo A +NEWSYM pl4Btk, dd 0 ; Turbo B +NEWSYM pl4Xtk, dd 0 ; Turbo X +NEWSYM pl4Ytk, dd 0 ; Turbo Y +NEWSYM Turbo30hz, db 0 ; Turbo at 30hz instead of 60hz + +NEWSYM KeyVolUp, dd 0 +NEWSYM KeyVolDown, dd 0 +NEWSYM KeyFRateUp, dd 0 +NEWSYM KeyFRateDown, dd 0 + +NEWSYM KeyQuickChat, dd 20 +NEWSYM FossilUse, db 0 +NEWSYM TimerEnable, db 0 + +NEWSYM Surround, db 0 +NEWSYM InterSound, db 1 +NEWSYM FastFwdToggle, db 0 +NEWSYM En2xSaI, db 0 +NEWSYM AutoLoadCht, db 0 +NEWSYM KeyQuickSnapShot, dd 0 + +CheatSrcByteSize db 0 +CheatSrcByteBase db 0 +CheatSrcSearchType db 0 +CheatUpperByteOnly db 0 +NEWSYM SRAMSave5Sec, db 0 +NEWSYM ReInitSoundC, db 0 +NEWSYM OldGfxMode2 , db 0 +NEWSYM PitchModEn , db 0 +NEWSYM LatestSave , db 0 +NEWSYM AutoState , db 0 +NEWSYM OldVolume , db 1 +NEWSYM BlankVar , db 1 + +NEWSYM pl1ULk, dd 0 +NEWSYM pl1URk, dd 0 +NEWSYM pl1DLk, dd 0 +NEWSYM pl1DRk, dd 0 +NEWSYM pl2ULk, dd 0 +NEWSYM pl2URk, dd 0 +NEWSYM pl2DLk, dd 0 +NEWSYM pl2DRk, dd 0 +NEWSYM pl3ULk, dd 0 +NEWSYM pl3URk, dd 0 +NEWSYM pl3DLk, dd 0 +NEWSYM pl3DRk, dd 0 +NEWSYM pl4ULk, dd 0 +NEWSYM pl4URk, dd 0 +NEWSYM pl4DLk, dd 0 +NEWSYM pl4DRk, dd 0 + +NEWSYM LowPassFilterType, db 0 +NEWSYM DontSavePath, db 0 +NEWSYM ReCalib, db 1 +NEWSYM GUIComboGameSpec, db 0 +NEWSYM SoundNoiseDis, db 0 ; Disable Noise +NEWSYM Triplebufen, db 0 +NEWSYM SoundBufEn, db 0 +NEWSYM SPCDisable, db 0 +NEWSYM RaisePitch, db 0 + +prevloadl db 0 +prevloaddnamel times 512*10 db 0 +prevloadfnamel times 512*10 db 0 + +%ifdef __WIN32__ +NEWSYM PrevWinMode, db 2 +NEWSYM PrevFSMode, db 6 +%elifdef __LINUX__ +NEWSYM PrevWinMode, db 2 +NEWSYM PrevFSMode, db 3 +%elifdef __MSDOS__ +NEWSYM PrevWinMode, db 0 +NEWSYM PrevFSMode, db 0 +%endif + +; Window position index +; GAME 1 > Load +; 2 > Pick state +; 12 > Reset +; 14 > Save/Open state +; CONFIG 3 > Inputs +; 4 > Options +; 5 > Video +; 6 > Sound +; 17 > Add-ons +; 18 > Chip cfg +; 19 > Paths +; 20 > Saves +; 21 > Speed +; CHEAT 7 > Add/Browse +; 13 > Search +;(NETPLAY 8 > Internet) +; MISC 9 > Misc keys +; 10 > GUI opns +; 11 > About +; 15 > Movie opn +; 16 > Key comb. + +;# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 +OldWinPos db 0 +GUIwinposx dd 0, 5,60,30,55,50,65, 5,30,20,10,80,65,20,70,50, 3,50,50, 5,10,20 +GUIwinposxexp times 30 dd 0 +GUIwinposy dd 0,20,70,30,20,22,36,20,30,20,30,20,60,30,65,50,22,60,20,20,20,20 +GUIwinposyexp times 30 dd 0 + +NEWSYM GUIEffect, db 0 + +NEWSYM pl5selk, dd 0 ; 4SELECT = SHIFT +NEWSYM pl5startk, dd 0 ; 4START = ENTER +NEWSYM pl5upk, dd 0 ; 4UP = up +NEWSYM pl5downk, dd 0 ; 4DOWN = down +NEWSYM pl5leftk, dd 0 ; 4LEFT = left +NEWSYM pl5rightk, dd 0 ; 4RIGHT = right +NEWSYM pl5Xk, dd 0 ; 4X = INS +NEWSYM pl5Ak, dd 0 ; 4A = HOME +NEWSYM pl5Lk, dd 0 ; 4L = PAGE UP +NEWSYM pl5Yk, dd 0 ; 4Y = DELETE +NEWSYM pl5Bk, dd 0 ; 4B = END +NEWSYM pl5Rk, dd 0 ; 4R = PAGE DOWN +NEWSYM pl5ULk, dd 0 +NEWSYM pl5URk, dd 0 +NEWSYM pl5DLk, dd 0 +NEWSYM pl5DRk, dd 0 +NEWSYM pl5Atk, dd 0 ; Turbo A +NEWSYM pl5Btk, dd 0 ; Turbo B +NEWSYM pl5Xtk, dd 0 ; Turbo X +NEWSYM pl5Ytk, dd 0 ; Turbo Y +NEWSYM pl5contrl, db 0 +NEWSYM pl1p209, db 0 +NEWSYM pl2p209, db 0 +NEWSYM pl3p209, db 0 +NEWSYM pl4p209, db 0 +NEWSYM pl5p209, db 0 + +NEWSYM GUIEnableTransp, db 0 +NEWSYM Mode7HiRes16b, dd 0 +NEWSYM NewEngEnForce, db 1 +NEWSYM KeyRewind, dd 0 +NEWSYM ChatNick, times 16 db 0 +NEWSYM KeySlowDown, dd 0 + +NEWSYM UseCubicSpline, db 1 + +NEWSYM LargeSoundBuf, db 0 +NEWSYM HighPriority, db 0 +NEWSYM AlwaysOnTop, db 0 +NEWSYM SaveMainWindowPos, db 1 +NEWSYM MainWindowX, dw -1 +NEWSYM MainWindowY, dw -1 + +NEWSYM ScreenShotFormat, db 0 + +NEWSYM pl1Ltk, dd 0 ; Turbo L +NEWSYM pl1Rtk, dd 0 ; Turbo R +NEWSYM pl2Ltk, dd 0 ; Turbo L +NEWSYM pl2Rtk, dd 0 ; Turbo R +NEWSYM pl3Ltk, dd 0 ; Turbo L +NEWSYM pl3Rtk, dd 0 ; Turbo R +NEWSYM pl4Ltk, dd 0 ; Turbo L +NEWSYM pl4Rtk, dd 0 ; Turbo R +NEWSYM pl5Ltk, dd 0 ; Turbo L +NEWSYM pl5Rtk, dd 0 ; Turbo R + +NEWSYM GUITRAdd, db 0 +NEWSYM GUITGAdd, db 10 +NEWSYM GUITBAdd, db 31 + +NEWSYM GUIWRAdd, db 8 +NEWSYM GUIWGAdd, db 8 +NEWSYM GUIWBAdd, db 25 + +NEWSYM GrayscaleMode, db 0 +NEWSYM MouseWheel, db 1 +NEWSYM SmallMsgText, db 0 +NEWSYM AllowMultipleInst, db 0 +NEWSYM FilteredGUI, db 1 +NEWSYM BilinearFilter, db 0 +NEWSYM TripleBufferWin, db 0 + +NEWSYM ExclusiveSound, db 0 +NEWSYM DisableScreenSaver, db 0 +NEWSYM MMXSupport, db 1 +NEWSYM TrapMouseCursor, db 1 +NEWSYM KeyQuickClock, dd 0 +NEWSYM KeyQuickSaveSPC, dd 0 +NEWSYM AutoIncSaveSlot, db 0 +NEWSYM TCPIPAddress, times 29 db 0 +NEWSYM SoundInterpType, db 1 +NEWSYM KeyDisplayFPS, dd 0 +NEWSYM KeyIncStateSlot, dd 0 +NEWSYM KeyDecStateSlot, dd 0 +NEWSYM KeyUsePlayer1234, dd 0 +NEWSYM hqFilter, db 0 +NEWSYM reserved, db 0 ;old +NEWSYM scale2xFilter, db 0 +NEWSYM st010difficulty, db 0 ;old +NEWSYM SnapPath, times 1024 db "" +NEWSYM SPCPath, times 1024 db "" +NEWSYM BSXPath, times 1024 db "" +NEWSYM STPath, times 1024 db "" +NEWSYM GNextPath, times 1024 db "" +NEWSYM SGPath, times 1024 db "" +NEWSYM FEOEZPath, times 1024 db "" +NEWSYM SJNSPath, times 1024 db "" +NEWSYM MDHPath, times 1024 db "" +NEWSYM SPL4Path, times 1024 db "" +NEWSYM AutoPatch, db 1 +NEWSYM RomInfo, db 1 +NEWSYM SRAMState, db 0 +NEWSYM RewindStates, db 16 +NEWSYM PrimaryBuffer, db 0 +NEWSYM RewindFrames, db 15 +NEWSYM KeyInsrtChap, dd 0 +NEWSYM KeyNextChap, dd 0 +NEWSYM KeyPrevChap, dd 0 +NEWSYM MovieDisplayFrame, db 0 +NEWSYM MovieStartMethod, db 0 +NEWSYM EMUPauseKey, dd 0 +NEWSYM INCRFrameKey, dd 0 +NEWSYM PauseLoad, db 0 +NEWSYM PauseRewind, db 0 +NEWSYM KeyResetSpeed, dd 0 +NEWSYM EmuSpeed, db 29 ; 29 = 1x, 0 = /30 and 58 = 30x +NEWSYM FFRatio, db 9 ; 0 = 2x, 28 = 30x +NEWSYM SDRatio, db 0 ; 0 = /2, 28 = /30 +NEWSYM KeyEmuSpeedUp, dd 0 +NEWSYM KeyEmuSpeedDown, dd 0 +NEWSYM AllowUDLR, db 0 \ No newline at end of file diff --git a/zsnes/src/gui/guifuncs.c b/zsnes/src/gui/guifuncs.c index c391b06e..da70e971 100644 --- a/zsnes/src/gui/guifuncs.c +++ b/zsnes/src/gui/guifuncs.c @@ -63,13 +63,10 @@ unsigned char CalcCfgChecksum() void GUIRestoreVars() { + unsigned char read_cfg_vars(const char *); FILE *cfg_fp; - if ((cfg_fp = fopen(GUIFName, "rb"))) - { - fread(&GUIRAdd, 1, PHnumGUIsave, cfg_fp); - fclose(cfg_fp); - } + read_cfg_vars(GUIFName); smallscreenon = (unsigned int)GUIsmallscreenon; ScreenScale = GUIScreenScale; @@ -106,14 +103,14 @@ void GUIRestoreVars() void ExecGUISaveVars() { + unsigned char write_cfg_vars(const char *); FILE *cfg_fp; if (ShowTimer == 1) { TimeChecker = CalcCfgChecksum(); } - if (!cfgdontsave && (cfg_fp = fopen(GUIFName, "wb"))) + if (!cfgdontsave) { - fwrite(&GUIRAdd, 1, PHnumGUIsave, cfg_fp); - fclose(cfg_fp); + write_cfg_vars(GUIFName); } if (NumComboGlob && (cfg_fp = fopen(GUICName, "wb"))) diff --git a/zsnes/src/makefile.ms b/zsnes/src/makefile.ms index 9cbfc78d..cd06a6f0 100644 --- a/zsnes/src/makefile.ms +++ b/zsnes/src/makefile.ms @@ -50,6 +50,7 @@ JMADIR=jma DELETECOMMAND=rm -f TRUTH=;true SLASH=/ +PSR=parsegen ASM=nasm ASMOPT=-O1 ASMFLAGSORIG= @@ -110,6 +111,7 @@ ifeq (${CROSS},no) TRUTH= DELETECOMMAND=del SLASH=\${BLAHBLAHBLAH} + PSR=parsegen.exe endif ifeq (${OS},__MSDOS__) @@ -183,7 +185,7 @@ JMAOBJ=${JMADIR}/7zlzma${OE} ${JMADIR}/crc32${OE} ${JMADIR}/iiostrm${OE}\ ${JMADIR}/winout${OE} ${JMADIR}/zsnesjma${OE} MAINOBJ=cfgload${OE} endmem${OE} init${OE} initc${OE} uic${OE} patch${OE}\ - ui${OE} vcache${OE} version${OE} zmovie${OE} zstate${OE} zloader${OE} + ui${OE} vcache${OE} version${OE} zmovie${OE} zstate${OE} zloader${OE} cfgparse${OE} DOSOBJORIG=${DOSDIR}/debug${OE} ${DOSDIR}/joy${OE} ${DOSDIR}/vesa2${OE}\ ${DOSDIR}/initvid${OE} ${DOSDIR}/sw${OE} ${DOSDIR}/gppro${OE} ${DOSDIR}/vesa12${OE} @@ -203,7 +205,7 @@ DELETEOBJS=${OBJS} endif -.SUFFIXES: .c .cpp .asm +.SUFFIXES: .c .cpp .asm .psr ifneq (${ENV},msvc) %${OE}: %.c @@ -228,10 +230,13 @@ else ${ASM} ${ASMOPT} -f win32 -D__WIN32__ -o $@ $< endif +%.c: %.psr + ${PSR} -D${OS} $@ $< + ALL: zsnes ${DELETECOMMAND} version${OE} -zsnes: ${OBJFIX} ${OBJS} +zsnes: ${PSR} ${OBJFIX} ${OBJS} ifneq (${ENV},msvc) ${CPPC} ${STRIP} -o ${EXE} ${OBJS} ${LIBS} else @@ -362,6 +367,9 @@ ${WINDIR}/winlink${OE}: ${WINDIR}/winlink.cpp ${WINDIR}/resource.h ${OBJFIX}: $< gcc -O3 -o $@ objfix.c endif +${PSR}: $< +cfgparse.c: $< ${PSR} +cfgparse${OE}: $< clean: diff --git a/zsnes/src/parsegen.cpp b/zsnes/src/parsegen.cpp new file mode 100644 index 00000000..4f665ef4 --- /dev/null +++ b/zsnes/src/parsegen.cpp @@ -0,0 +1,964 @@ +/* +Config file handler creator by Nach (C) 2005 +*/ + +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include + +#if defined(__MSDOS__) || defined(__WIN32__) +#define SLASH_STR "\\" +#else +#define SLASH_STR "/" +#endif + +#define LINE_LENGTH 2048*10 +char line[LINE_LENGTH]; + +set defines; +stack ifs; + +typedef vector str_array; + +str_array memsets; + +enum cfg_value_type { single_value, quoted_value, parameterized_value }; +struct cfg_var_struct +{ + string name; + string object; + cfg_value_type type; + size_t size; +}; + +typedef vector cfg_var_array; + +cfg_var_array cfg_vars; + +size_t current_line_number = 0; +size_t current_column_number = 0; + +void show_error_loc(const char *str) +{ + cerr << "Error: parse problem occured at " << current_line_number << ":" << current_column_number << ". " << str << "." << endl; +} + +void check_existing_var(string& str) +{ + for (cfg_var_array::iterator i = cfg_vars.begin(); i != cfg_vars.end(); i++) + { + if (i->name == str) + { + cerr << "Duplicate definition of \"" << i->name << "\" found on line " << current_line_number << "." << endl; + break; + } + } +} + +void add_config_var(string& name, const char *object, cfg_value_type val, size_t size) +{ + check_existing_var(name); + cfg_var_struct cfg_var = {name, object, val, size}; + cfg_vars.push_back(cfg_var); + //cout << "Name: " << name << "; Value Type: " << val << "; Size: " << size << endl; +} + + +//Find next matching character which is not escaped +char *find_next_match(char *str, char match_char) +{ + char *pos = 0; + + while (*str) + { + if (*str == match_char) + { + pos = str; + } + if (*str == '\\') + { + if (str[1]) + { + str++; + } + else + { + break; + } + } + str++; + } + return(pos); +} + +//This is like strtok(), except this understands quoted characters and updates error locations +char *get_token(char *str, char *delim) +{ + static char *pos = 0; + char *token = 0; + + if (str) //Start a new string? + { + pos = str; + } + + if (pos) + { + //Skip delimiters + while (*pos && strchr(delim, *pos)) + { + pos++; + } + if (*pos) + { + token = pos; + + //Skip non-delimiters + while (*pos && !strchr(delim, *pos)) + { + //Skip quoted characters + if ((*pos == '\"') || (*pos == '\'')) + { + char *match_pos = 0; + if ((match_pos = find_next_match(pos+1, *pos))) + { + pos = match_pos; + } + } + pos++; + } + if (*pos) + { + *pos++ = '\0'; + } + } + } + + if (token) { current_column_number = token - line; } + return(token); +} + +//Like strchr() but understands quoted characters +char *find_chr(char *str, char match_char) +{ + char *pos = 0; + + while (*str) + { + if (*str == match_char) + { + pos = str; + break; + } + //Skip quoted characters + if ((*str == '\"') || (*str == '\'')) + { + char *match_pos = 0; + if ((match_pos = find_next_match(str+1, *str))) + { + str = match_pos; + } + } + str++; + } + return(pos); +} + + +//Convert $AB12 and 0AB12h style hex to 0xAB12 hex +string hex_convert(string str) +{ + size_t dollar_pos; + while ((dollar_pos = str.find("$")) != string::npos) + { + str.replace(dollar_pos, 1, "0x"); + } + + while (tolower(str[0]) == 'h') + { + str.erase(0, 1); + } + + size_t h_pos; + while ((h_pos = str.find_first_of("hH")) != string::npos) + { + size_t h_len = 1; + while ((h_pos-h_len) && isxdigit(str[h_pos-h_len])) + { + h_len++; + } + str.erase(h_pos, 1); + str.insert(h_pos-h_len+1, "0x"); + } + + return(str); +} + +//Ascii numbers to integer, with support for mathematics in the string +ssize_t enhanced_atoi(const char *str) +{ + ssize_t num = 0; + + //Make sure result file doesn't exist + if (remove("eatio.res") && (errno != ENOENT)) + { + cerr << "Error: Can not get accurate value information (eatio.res)." << endl; + } + + //Biggest cheat of all time + ofstream out_stream("eatio.c"); + if (out_stream) + { + out_stream << "#include \n" + << "int main()\n" + << "{\n" + << " FILE *fp = fopen(\"eatio.res\", \"w\");\n" + << " if (fp)\n" + << " {\n" + << " fprintf(fp, \"%d\", " << hex_convert(str) << ");\n" + << " fclose(fp);\n" + << " }\n" + << " return(0);\n" + << "}\n\n"; + out_stream.close(); + +#ifdef MSC_VER + system("cl /Foeatio.exe eatio.c"); +#else + system("gcc -o eatio.exe eatio.c -s"); +#endif + + system("."SLASH_STR"eatio.exe"); + + remove("eatio.c"); + remove("eatio.exe"); + + ifstream in_stream("eatio.res"); + if (in_stream) + { + in_stream >> num; + in_stream.close(); + } + else + { + cerr << "Error: Can not get accurate value information (eatio.res)." << endl; + } + + remove("eatio.res"); + } + + return(num); +} + +//Standard atoi(), but shows error if string isn't all a number +ssize_t safe_atoi(string& str) +{ + if (!str.length()) { str = "X"; } //Force error + + const char *p = str.c_str(); + for (p = ((*p == '-') ? p+1 : p); *p; p++) + { + if (!isdigit(*p)) + { + show_error_loc("Not a number"); + } + } + + return(atoi(str.c_str())); +} + +#define var_type_is_char(var_type) !strcmp(var_type+strlen(var_type)-strlen("char"), "char") +#define var_type_is_short(var_type) !strcmp(var_type+strlen(var_type)-strlen("short"), "short") +#define var_type_is_int(var_type) !strcmp(var_type+strlen(var_type)-strlen("int"), "int") + +#define short_scale "*sizeof(short)" +#define int_scale "*sizeof(int)" + +//Return the comment from global line variable +char *get_comment() +{ + char *comment = find_chr(line, ';'); + if (comment) + { + *comment = 0; + comment++; + if (isspace(comment[strlen(comment)-1])) + { + comment[strlen(comment)-1] = 0; + } + } + return(comment); +} + +void output_comment(ostream& c_stream, const char *comment) +{ + if (comment) + { + c_stream << " //" << comment; + } + c_stream << "\n"; +} + +bool all_spaces(const char *str) +{ + while (*str) + { + if (!isspace(*str)) { return(false); } + str++; + } + return(true); +} + +//Convert asm types to C types +char *convert_asm_type(const char *str, bool unsigned_var = true) +{ + char *var_type = 0; + if (!strcasecmp(str, "dd")) + { + var_type = "unsigned int"; + } + else if (!strcasecmp(str, "dw")) + { + var_type = "unsigned short"; + } + else if (!strcasecmp(str, "db")) + { + var_type = "unsigned char"; + } + else + { + show_error_loc("Not a valid type"); + } + + if (var_type && !unsigned_var) + { + var_type += strlen("unsigned "); + } + + return(var_type); +} + +void output_parser_start(ostream& c_stream) +{ + c_stream << "/*\n" + << "Config file handler generated by Nach's Config file handler creator.\n" + << "*/\n" + << "\n" + << "#include \n" + << "#include \n" + << "#include \n" + << "#include \n" + << "\n" + << "\n" + << "#define LINE_LENGTH " << LINE_LENGTH << "\n" + << "static char line[LINE_LENGTH];\n" + << "\n" + << "\n" + << "static char *encode_string(const char *str)\n" + << "{\n" + << " size_t i = 0;\n" + << " line[i++] = '\\\"';\n" + << " while (*str)\n" + << " {\n" + << " if ((*str == '\\\\') ||\n" + << " (*str == '\\\"') ||\n" + << " (*str == '\\\'') ||\n" + << " (*str == '\\n') ||\n" + << " (*str == '\\t'))\n" + << " {\n" + << " line[i++] = '\\\\';\n" + << " }\n" + << " line[i++] = *str++;\n" + << " }\n" + << " line[i++] = '\\\"';\n" + << " line[i] = 0;\n" + << " return(line);\n" + << "}\n" + << "\n" + << "static char *decode_string(char *str)\n" + << "{\n" + << " size_t str_len = strlen(str), i = 0;\n" + << " char *dest = str;\n" + << " \n" + << " if ((str_len > 1) && (*str == '\\\"') && (str[str_len-1] == '\\\"'))\n" + << " {\n" + << " memmove(str, str+1, str_len-2);\n" + << " str[str_len-2] = 0;\n" + << "\n" + << " while (*str)\n" + << " {\n" + << " if (*str == '\\\\')\n" + << " {\n" + << " str++;\n" + << " }\n" + << " dest[i++] = *str++;\n" + << " }\n" + << " }\n" + << " dest[i] = 0;\n" + << " return(dest);\n" + << "}\n" + << "\n" + << "static char *find_next_match(char *str, char match_char)\n" + << "{\n" + << " char *pos = 0;\n" + << "\n" + << " while (*str)\n" + << " {\n" + << " if (*str == match_char)\n" + << " {\n" + << " pos = str;\n" + << " }\n" + << " if (*str == '\\\\')\n" + << " {\n" + << " if (str[1])\n" + << " {\n" + << " str++;\n" + << " }\n" + << " else\n" + << " {\n" + << " break;\n" + << " }\n" + << " }\n" + << " str++;\n" + << " }\n" + << " return(pos);\n" + << "}\n" + << "\n" + << "static char *find_str(char *str, char *match_str)\n" + << "{\n" + << " char *pos = 0;\n" + << "\n" + << " while (*str)\n" + << " {\n" + << " if (strchr(match_str, *str))\n" + << " {\n" + << " pos = str;\n" + << " break;\n" + << " }\n" + << " if ((*str == '\\\"') || (*str == '\\\''))\n" + << " {\n" + << " char *match_pos = 0;\n" + << " if ((match_pos = find_next_match(str+1, *str)))\n" + << " {\n" + << " str = match_pos;\n" + << " }\n" + << " }\n" + << " str++;\n" + << " }\n" + << " return(pos); \n" + << "}\n" + << "\n" + << "\n"; +} + +void output_init_var(ostream& c_stream) +{ + c_stream << "\n" + << "static void init_cfg_vars()\n" + << "{\n" + << " static unsigned char init_done = 0;\n" + << " if (!init_done)\n" + << " {\n" + << " init_done = 1;\n" + << "\n"; + for (str_array::iterator i = memsets.begin(); i != memsets.end(); i++) + { + c_stream << " " << *i << "\n"; + } + c_stream << " }\n" + << "}\n"; +} + +void output_array_write(ostream& c_stream, const char *type) +{ + c_stream << "\n" + << "static void write_" << type << "_array(FILE *fp, const char *var_name, " << type << " *var, size_t size)\n" + << "{\n" + << " size_t i;\n" + << " fprintf(fp, \"%s=%d\", var_name, (int)*var);\n" + << " for (i = 1; i < size; i++)\n" + << " {\n" + << " fprintf(fp, \",%d\", (int)(var[i]));\n" + << " }\n" + << " fprintf(fp, \"\\n\");\n" + << "}\n"; +} + +void output_write_var(ostream& c_stream) +{ + output_array_write(c_stream, "char"); + output_array_write(c_stream, "short"); + output_array_write(c_stream, "int"); + + c_stream << "\n" + << "unsigned char write_cfg_vars(const char *file)\n" + << "{\n" + << " FILE *fp = 0;\n" + << "\n" + << " init_cfg_vars();\n" + << "\n" + << " if ((fp = fopen(file, \"w\")))\n" + << " {\n"; + for (cfg_var_array::iterator i = cfg_vars.begin(); i != cfg_vars.end(); i++) + { + if (i->type == parameterized_value) + { + c_stream << " write_" << convert_asm_type(i->object.c_str(), false) + << "_array(fp, \"" << i->name << "\", " << i->name << ", " << i->size << ");\n"; + } + else + { + c_stream << " fprintf(fp, \"" << i->name << "="; + if (i->type == single_value) + { + c_stream << "%d\\n\", " << i->name; + } + else + { + c_stream << "%s\\n\", encode_string(" << i->name << ")"; + } + c_stream << ");\n"; + } + } + c_stream << " fclose(fp);\n" + << "\n" + << " return(1);\n" + << " }\n" + << " return(0);\n" + << "}\n"; +} + +void output_array_read(ostream& c_stream, const char *type) +{ + c_stream << "\n" + << "static void read_" << type << "_array(char *line, " << type << " *var, size_t size)\n" + << "{\n" + << " size_t i;\n" + << " char *token;\n" + << " *var = atoi(strtok(line, \", \\t\\r\\n\"));\n" + << " for (i = 1; (i < size) && (token = strtok(0, \", \\t\\r\\n\")); i++)\n" + << " {\n" + << " var[i] = atoi(token);\n" + << " }\n" + << "}\n"; +} + +void output_read_var(ostream& c_stream) +{ + output_array_read(c_stream, "char"); + output_array_read(c_stream, "short"); + output_array_read(c_stream, "int"); + + c_stream << "\n" + << "unsigned char read_cfg_vars(const char *file)\n" + << "{\n" + << " FILE *fp = 0;\n" + << "\n" + << " init_cfg_vars();\n" + << "\n" + << " if (!(fp = fopen(file, \"r\")))\n" + << " {\n" + << " write_cfg_vars(file);\n" + << " return(0);\n" + << " }\n" + << "\n" + << " while (!feof(fp))\n" + << " {\n" + << " char *p, *var, *value;\n" + << "\n" + << " fgets(line, LINE_LENGTH, fp);\n" + << " if ((p = find_str(line, \";\"))) { *p = 0; }\n" + << " if ((p = strchr(line, '=')))\n" + << " {\n" + << " *p = 0;\n" + << " var = line;\n" + << " value = p+1;\n" + << " while (isspace(*var)) { var++; }\n" + << " while (isspace(*value)) { value++; }\n" + << " if ((p = find_str(var, \" \\t\\r\\n\"))) { *p = 0; }\n" + << " if ((p = find_str(value, \" \\t\\r\\n\"))) { *p = 0; }\n" + << " if (!*var || !*value) { continue; }\n" + << " }\n" + << " else\n" + << " {\n" + << " continue;\n" + << " }\n" + << "\n"; + for (cfg_var_array::iterator i = cfg_vars.begin(); i != cfg_vars.end(); i++) + { + c_stream << " if (!strcmp(var, \"" + i->name + "\")) { "; + if (i->type == single_value) + { + c_stream << i->name << " = atoi(value);"; + } + else if (i->type == parameterized_value) + { + c_stream << "read_" << convert_asm_type(i->object.c_str(), false) + << "_array(value, " << i->name << ", " << i->size << ");"; + } + else + { + c_stream << "*" << i->name << " = 0; " + << "strncat(" << i->name << ", decode_string(value), sizeof(" << i->name << ")-1);"; + } + c_stream << " }\n"; + } + c_stream << " }\n" + << "\n" + << " fclose(fp);\n" + << " write_cfg_vars(file);\n" + << " return(1);\n" + << "}\n"; +} + +void handle_directive(char *instruction, char *label) +{ + if (!strcasecmp(instruction, "define")) + { + if (label) + { + defines.insert(label); + } + else + { + show_error_loc("Could not get define label"); + } + } + else if (!strcasecmp(instruction, "undef")) + { + if (label) + { + defines.erase(label); + } + else + { + show_error_loc("Could not get undefine label"); + } + } + else if (!strcasecmp(instruction, "ifdef")) + { + if (label) + { + if (defines.find(label) != defines.end()) + { + ifs.push(true); + } + else + { + ifs.push(false); + } + } + else + { + show_error_loc("Could not get ifdef label"); + } + } + else if (!strcasecmp(instruction, "else")) + { + if (label) + { + show_error_loc("Processor directive else does not accept labels"); + } + else + { + if (ifs.empty()) + { + show_error_loc("Processor directive else without ifdef"); + } + else + { + bool process = !ifs.top(); + ifs.pop(); + ifs.push(process); + } + } + } + else if (!strcasecmp(instruction, "elifdef") || !strcasecmp(instruction, "elseifdef")) + { + if (label) + { + if (ifs.top()) + { + ifs.pop(); + ifs.push(false); + } + else if (defines.find(label) != defines.end()) + { + ifs.pop(); + ifs.push(true); + } + } + else + { + show_error_loc("Could not get elseifdef label"); + } + + } + else if (!strcasecmp(instruction, "endif")) + { + if (label) + { + show_error_loc("Processor directive endif does not accept labels"); + } + else + { + if (ifs.empty()) + { + show_error_loc("Processor directive endif without ifdef"); + } + else + { + ifs.pop(); + } + } + } + else + { + show_error_loc("Unknown processor directive"); + } +} + +void parser_generate(istream& psr_stream, ostream& c_stream) +{ + output_parser_start(c_stream); + + while (!psr_stream.eof()) + { + char *token; + char *comment; + + psr_stream.getline(line, LINE_LENGTH); + current_line_number++; + + comment = get_comment(); + + if (all_spaces(line)) + { + output_comment(c_stream, comment); + continue; + } + + if ((token = get_token(line, " ")) && + (strcasecmp(token, "NEWSYM") || (token = get_token(0, " ,")))) + { + if ((*token == '#') || (*token == '%')) + { + handle_directive(token+1, get_token(0, " ")); + continue; + } + + if (!ifs.empty() && !ifs.top()) + { + continue; + } + + string varname = token; + + if ((token = get_token(0, " ,"))) + { + size_t array = 0; + if (strcasecmp(token, "times") || + ((token = get_token(0, " ")) && (array = enhanced_atoi(token)) && (token = get_token(0, " ")))) + { + char *asm_type = token; + char *var_type = convert_asm_type(asm_type); + + if (var_type) + { + string initial_value = get_token(0, " ,\n"); + + if (((initial_value[0] == '\"') && (initial_value[initial_value.length()-1] == '\"')) || + ((initial_value[0] == '\'') && (initial_value[initial_value.length()-1] == '\''))) + { + //Make sure it's double quoted + initial_value[0] = '\"'; + initial_value[initial_value.length()-1] = '\"'; + + if (!array) + { + array = initial_value.length()-1; //Size minus quotes plus null + } + + c_stream << "char " << varname << "[" << array << "];"; + + ostringstream memset_line; + + if (initial_value.length()-2 < array) + { + memset_line << "strcpy(" << varname << ", " << initial_value << ");"; + } + else + { + memset_line << "strncpy(" << varname << ", " << initial_value << ", " << (array-1) << "); " + << varname << "[" << array << "] = 0;"; + } + memsets.push_back(memset_line.str()); + + add_config_var(varname, asm_type, quoted_value, 0); + } + else + { + ssize_t init_value_num = safe_atoi(initial_value); + + if (init_value_num < 0) + { + var_type += strlen("unsigned "); + } + + c_stream << var_type << " " << varname; + if (array) + { + if (var_type_is_char(var_type) || !init_value_num) + { + c_stream << "[" << array << "]"; + + ostringstream memset_line; + memset_line << "memset(" << varname << ", " << init_value_num << ", " << array; + + if (var_type_is_short(var_type)) + { + memset_line << short_scale; + } + else if (var_type_is_int(var_type)) + { + memset_line << int_scale; + } + + memset_line << ");"; + memsets.push_back(memset_line.str()); + } + else + { + c_stream << "[" << array << "] = {"; + for (size_t i = array; i > 1; i--) + { + c_stream << init_value_num << ","; + } + c_stream << init_value_num << "%d}"; + } + + add_config_var(varname, asm_type, parameterized_value, array); + } + else + { + if ((token = get_token(0, " ,\n"))) + { + array = 1; + c_stream << "[] = {" << init_value_num; + do + { + c_stream << "," << atoi(token); + array++; + } while((token = get_token(0, " ,\n"))); + c_stream << "}"; + + add_config_var(varname, asm_type, parameterized_value, array); + } + else + { + c_stream << " = " << init_value_num; + + add_config_var(varname, asm_type, single_value, 0); + } + } + c_stream << ";"; + } + } + //Else already handled + } + else + { + show_error_loc("Could not get array size"); + } + } + else + { + show_error_loc("Could not get type"); + } + } + else + { + show_error_loc("Could not get variable name"); + } + + output_comment(c_stream, comment); + } + + output_init_var(c_stream); + output_write_var(c_stream); + output_read_var(c_stream); + + c_stream << "\n"; + + if (!ifs.empty()) + { + cerr << "Error: " << ifs.size() << " ifdef segments have no endif." << endl; + } +} + +int main(size_t argc, const char **argv) +{ + size_t param_pos = 1; + for (; param_pos < argc; param_pos++) + { + if (!strncmp(argv[param_pos], "-D", 2)) + { + defines.insert(argv[param_pos]+2); + } + else + { + break; + } + } + + if ((argc-param_pos) != 2) + { + cout << "Config file handler creator by Nach (C) 2005\n" + << "\n" + << "Usage:\n" + << "parsegen [-Ddefine] \n" + << "\n" + << " -Ddefine Define a processor director. Example: -D__LINUX__\n" + << " Can specify multiple defines.\n" + << endl; + + return(1); + } + + const char *psr_file = argv[param_pos+1], *c_file = argv[param_pos]; + int ret_val = 0; + + ifstream psr_stream(psr_file); + if (psr_stream) + { + ofstream c_stream(c_file); + if (c_stream) + { + parser_generate(psr_stream, c_stream); + + c_stream.close(); + } + else + { + cerr << "Error opening " << c_file << " for writing." << endl; + ret_val |= 2; + } + + psr_stream.close(); + } + else + { + cerr << "Error opening " << psr_file << " for reading." << endl; + ret_val |= 4; + } + + return(0); +} +