From 64f1ba20b9be23e189ee301cfd47c1edafcc2f1c Mon Sep 17 00:00:00 2001 From: sinamas Date: Tue, 28 Aug 2007 22:16:53 +0000 Subject: [PATCH] Support command line arguments. git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@44 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24 --- gambatte_sdl/SConstruct | 8 +- gambatte_sdl/{ => src}/gambatte_sdl.cpp | 209 +++++++++++++++--------- gambatte_sdl/src/parser.cpp | 115 +++++++++++++ gambatte_sdl/src/parser.h | 56 +++++++ gambatte_sdl/src/syncfunc.cpp | 90 ++++++++++ gambatte_sdl/src/syncfunc.h | 24 +++ 6 files changed, 425 insertions(+), 77 deletions(-) rename gambatte_sdl/{ => src}/gambatte_sdl.cpp (63%) create mode 100644 gambatte_sdl/src/parser.cpp create mode 100644 gambatte_sdl/src/parser.h create mode 100644 gambatte_sdl/src/syncfunc.cpp create mode 100644 gambatte_sdl/src/syncfunc.h diff --git a/gambatte_sdl/SConstruct b/gambatte_sdl/SConstruct index 67ebb9f..8bcac47 100644 --- a/gambatte_sdl/SConstruct +++ b/gambatte_sdl/SConstruct @@ -1,4 +1,4 @@ -env = Environment(CPPPATH = ['.', '../libgambatte/include'], +env = Environment(CPPPATH = ['src', '../libgambatte/include'], LIBS = ['gambatte'], LIBPATH = '../libgambatte', CPPFLAGS = ARGUMENTS.get('CPPFLAGS', '-Wall -O2 -fno-exceptions -fno-rtti -fomit-frame-pointer')) @@ -6,7 +6,9 @@ env = Environment(CPPPATH = ['.', '../libgambatte/include'], env.ParseConfig('sdl-config --cflags --libs') sourceFiles = Split(''' - gambatte_sdl.cpp + src/gambatte_sdl.cpp + src/parser.cpp + src/syncfunc.cpp ''') -env.Program(sourceFiles) +env.Program('gambatte_sdl', sourceFiles) diff --git a/gambatte_sdl/gambatte_sdl.cpp b/gambatte_sdl/src/gambatte_sdl.cpp similarity index 63% rename from gambatte_sdl/gambatte_sdl.cpp rename to gambatte_sdl/src/gambatte_sdl.cpp index f5f2fef..8809d45 100644 --- a/gambatte_sdl/gambatte_sdl.cpp +++ b/gambatte_sdl/src/gambatte_sdl.cpp @@ -18,84 +18,27 @@ ***************************************************************************/ #include #include +#include +#include -namespace { -struct timeval { - long tv_sec; - long tv_usec; -}; - -void gettimeofday(timeval *const t, void *) { - const unsigned long tv_msec = SDL_GetTicks(); - - t->tv_sec = tv_msec / 1000; - t->tv_usec = (tv_msec % 1000) * 1000; -} - -void syncFunc() { - timeval t; - gettimeofday(&t, NULL); - static timeval time = t; - static long late = 0; - static unsigned noSleep = 60; - - if (time.tv_sec > t.tv_sec || (time.tv_sec == t.tv_sec && time.tv_usec > t.tv_usec)) { - timeval tmp; - tmp.tv_sec = 0; - tmp.tv_usec = time.tv_usec - t.tv_usec; - if (time.tv_sec != t.tv_sec) - tmp.tv_usec += 1000000; - - if (tmp.tv_usec > late) { - tmp.tv_usec -= late; - - if (tmp.tv_usec >= 1000000) { - tmp.tv_usec -= 1000000; - ++tmp.tv_sec; - } - - SDL_Delay(tmp.tv_sec * 1000 + (tmp.tv_usec + 500) / 1000); - - gettimeofday(&t, NULL); - late -= (time.tv_sec - t.tv_sec) * 1000000 + time.tv_usec - t.tv_usec >> 1; -// printf("late: %d\n", late); - - if (late < 0) - late = 0; - - noSleep = 60; - } else if (noSleep-- == 0) { - noSleep = 60; - late = 0; - } - - while (time.tv_sec > t.tv_sec || (time.tv_sec == t.tv_sec && time.tv_usec > t.tv_usec)) { - gettimeofday(&t, NULL); - } - - } else - time = t; - - time.tv_usec += 16743; - - if (time.tv_usec >= 1000000) { - time.tv_usec -= 1000000; - ++time.tv_sec; - } -} -} +#include "syncfunc.h" +#include "parser.h" class SdlBlitter : public VideoBlitter { SDL_Surface *screen; + unsigned startFlags; + public: + SdlBlitter() : screen(NULL), startFlags(SDL_SWSURFACE) {} void setBufferDimensions(unsigned int width, unsigned int height); const PixelBuffer inBuffer(); void blit(); void toggleFullScreen(); + void setStartFull() { startFlags |= SDL_FULLSCREEN; } }; void SdlBlitter::setBufferDimensions(const unsigned int width, const unsigned int height) { - screen = SDL_SetVideoMode(width, height, SDL_GetVideoInfo()->vfmt->BitsPerPixel == 16 ? 16 : 32, SDL_SWSURFACE/*|SDL_FULLSCREEN*/); + screen = SDL_SetVideoMode(width, height, SDL_GetVideoInfo()->vfmt->BitsPerPixel == 16 ? 16 : 32, startFlags); } const PixelBuffer SdlBlitter::inBuffer() { @@ -118,6 +61,86 @@ static Gambatte gambatte; static SdlBlitter blitter; static InputState is; +struct FatOption { + virtual Parser::Option* getShort() { return NULL; }; + virtual Parser::Option* getLong() = 0; + virtual const char* getDesc() const = 0; + virtual ~FatOption() {} +}; + +class FsOption : public FatOption { + class Main : public Parser::Option { + protected: + Main(const char *const s) : Option(s) {} + public: + void exec(const char *const */*argv*/, int /*index*/) { + blitter.setStartFull(); + } + }; + + struct Short : Main { + Short() : Main("-f") {} + }; + + struct Long : Main { + Long() : Main("--full-screen") {} + }; + + Short sOpt; + Long lOpt; + static const char *const desc; + +public: + Parser::Option* getShort() { return &sOpt; } + Parser::Option* getLong() { return &lOpt; } + const char* getDesc() const { return desc; } +}; + +const char *const FsOption::desc = "\t\tStart in full screen mode\n"; + +class VfOption : public FatOption { + class Main : public Parser::Option { + protected: + Main(const char *const s) : Option(s, 1) {} + public: + void exec(const char *const *argv, int index) { + gambatte.setVideoFilter(atoi(argv[index + 1])); + } + }; + + struct Short : Main { + Short() : Main("-v") {} + }; + + struct Long : Main { + Long() : Main("--video-filter") {} + }; + + Short sOpt; + Long lOpt; + std::string s; + +public: + VfOption(); + Parser::Option* getShort() { return &sOpt; } + Parser::Option* getLong() { return &lOpt; } + const char* getDesc() const { return s.c_str(); } +}; + +VfOption::VfOption() { + const std::vector &finfo = gambatte.filterInfo(); + std::stringstream ss; + ss << " N\t\tUse video filter number N\n"; + + for (std::size_t i = 0; i < finfo.size(); ++i) { + ss << "\t\t\t\t " << i << " = " << finfo[i]->handle << "\n"; + } + + s = ss.str(); +} + + + static void fill_buffer(void *buffer, Uint8 *stream, int len); // static unsigned bufPos = 0; @@ -137,17 +160,55 @@ static InputGetter inputGetter; static const unsigned SND_BUF_SZ = 4096; +static const char *const usage = "Usage: gambatte_sdl romfile\n"; + +static void printUsage(std::vector &v) { + printf("Usage: gambatte_sdl [OPTION]... romfile\n\n"); + + for (unsigned i = 0; i < v.size(); ++i) { + printf(" %s, %s%s\n", v[i]->getShort()->getStr(), v[i]->getLong()->getStr(), v[i]->getDesc()); + } +} + int main(int argc, char **argv) { printf("Gambatte SDL svn\n"); - if (argc < 2) { - printf("Usage: gambatte_sdl romfile\n"); - return 1; - } + Parser parser; - if (gambatte.load(argv[1])) { - printf("failed to load rom %s\n", argv[1]); - return 1; + { + static std::vector v; + static FsOption fsOption; + v.push_back(&fsOption); + static VfOption vfOption; + v.push_back(&vfOption); + + for (unsigned i = 0; i < v.size(); ++i) { + parser.add(v[i]->getShort()); + parser.add(v[i]->getLong()); + } + + unsigned loadIndex = 0; + + for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (!(i = parser.parse(argc, argv, i))) { + printUsage(v); + return 1; + } + } else if (!loadIndex) { + loadIndex = i; + } + } + + if (!loadIndex) { + printUsage(v); + return 1; + } + + if (gambatte.load(argv[loadIndex])) { + printf("failed to load ROM %s\n", argv[loadIndex]); + return 1; + } } gambatte.setInputStateGetter(&inputGetter); @@ -165,6 +226,7 @@ int main(int argc, char **argv) { SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO); SDL_ShowCursor(SDL_DISABLE); + SDL_WM_SetCaption("Gambatte SDL", NULL); SDL_OpenAudio(&spec, NULL); SDL_PauseAudio(0); @@ -174,7 +236,6 @@ int main(int argc, char **argv) { Uint8 *keys = SDL_GetKeyState(NULL); -// gambatte.setVideoFilter(4); gambatte.setVideoBlitter(&blitter); for (;;) { diff --git a/gambatte_sdl/src/parser.cpp b/gambatte_sdl/src/parser.cpp new file mode 100644 index 0000000..ca6b2b3 --- /dev/null +++ b/gambatte_sdl/src/parser.cpp @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (C) 2007 by Sindre Aamås * + * aamas@stud.ntnu.no * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License version 2 as * + * published by the Free Software Foundation. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License version 2 for more details. * + * * + * You should have received a copy of the GNU General Public License * + * version 2 along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ +#include "parser.h" + +#include + +struct OptionLess { + bool operator()(const Parser::Option *const l, const Parser::Option *const r) const { + return l->getHash() < r->getHash(); + } +}; + +static unsigned computeHash(const char *s) { + unsigned hash = 0; + + while (*s) { + hash += *s++; + hash += hash << 10; + hash ^= hash >> 6; + } + + hash += hash << 3; + hash ^= hash >> 11; + hash += hash << 15; + + return hash; +} + +Parser::Option::Option(const char *const s, int nArgs) : s(s), hash(computeHash(s)), nArgs(nArgs) {} + +Parser::Parser() : sorted(false) { + memset(t, 0, sizeof(t)); +} + +void Parser::addLong(Option *const o) { + v.push_back(o); + sorted = false; +} + +int Parser::parseLong(const int argc, const char *const *const argv, const int index) { + if (!sorted) + std::sort(v.begin(), v.end(), OptionLess()); + + sorted = true; + + Option o(argv[index]); + std::vector::iterator it = lower_bound(v.begin(), v.end(), &o, OptionLess()); + + while (it != v.end() && (*it)->getHash() == o.getHash()) { + if (!strcmp((*it)->getStr(), o.getStr())) { + if ((*it)->neededArgs() >= argc - index) + return 0; + + (*it)->exec(argv, index); + return index + (*it)->neededArgs(); + } + } + + return 0; +} + +void Parser::addShort(Option *const o) { + t[static_cast(o->getStr()[1])] = o; +} + +int Parser::parseShort(const int argc, const char *const *const argv, const int index) { + const char *s = argv[index]; + ++s; + + if (!(*s)) + return 0; + + do { + Option *const o = t[static_cast(*s)]; + + if (!o) + return 0; + + if (o->neededArgs()) { + if (s[1] || o->neededArgs() >= argc - index) + return 0; + + o->exec(argv, index); + return index + o->neededArgs(); + } + + o->exec(argv, index); + } while (*++s); + + return index; +} + +void Parser::add(Option *const o) { + (o->getStr()[1] == '-') ? addLong(o) : addShort(o); +} + +int Parser::parse(const int argc, const char *const *const argv, const int index) { + return (argv[index][1] == '-') ? parseLong(argc, argv, index) : parseShort(argc, argv, index); +} diff --git a/gambatte_sdl/src/parser.h b/gambatte_sdl/src/parser.h new file mode 100644 index 0000000..7f8cf45 --- /dev/null +++ b/gambatte_sdl/src/parser.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2007 by Sindre Aamås * + * aamas@stud.ntnu.no * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License version 2 as * + * published by the Free Software Foundation. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License version 2 for more details. * + * * + * You should have received a copy of the GNU General Public License * + * version 2 along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ +#ifndef PARSER_H +#define PARSER_H + +#include + +class Parser { +public: + class Option { + const char *const s; + const unsigned hash; + const int nArgs; + + public: + Option(const char *s, int nArgs = 0); + virtual ~Option() {} + unsigned getHash() const { return hash; } + const char* getStr() const { return s; } + int neededArgs() const { return nArgs; } + virtual void exec(const char *const */*argv*/, int /*index*/) {} + }; + +private: + Option *t[256]; + std::vector v; + bool sorted; + + void addLong(Option *o); + void addShort(Option *o); + int parseLong(int argc, const char *const *argv, int index); + int parseShort(int argc, const char *const *argv, int index); + +public: + Parser(); + void add(Option *o); + int parse(int argc,const char *const *argv, int index); +}; + +#endif diff --git a/gambatte_sdl/src/syncfunc.cpp b/gambatte_sdl/src/syncfunc.cpp new file mode 100644 index 0000000..5e43d44 --- /dev/null +++ b/gambatte_sdl/src/syncfunc.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2007 by Sindre Aamås * + * aamas@stud.ntnu.no * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License version 2 as * + * published by the Free Software Foundation. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License version 2 for more details. * + * * + * You should have received a copy of the GNU General Public License * + * version 2 along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ +#include "syncfunc.h" + +#include + +namespace SyncFunc { +struct timeval { + long tv_sec; + long tv_usec; +}; + +void gettimeofday(timeval *const t, void *) { + const unsigned long tv_msec = SDL_GetTicks(); + + t->tv_sec = tv_msec / 1000; + t->tv_usec = (tv_msec % 1000) * 1000; +} +} + +void syncFunc() { + using SyncFunc::timeval; + using SyncFunc::gettimeofday; + + timeval t; + gettimeofday(&t, NULL); + static timeval time = t; + static long late = 0; + static unsigned noSleep = 60; + + if (time.tv_sec > t.tv_sec || (time.tv_sec == t.tv_sec && time.tv_usec > t.tv_usec)) { + timeval tmp; + tmp.tv_sec = 0; + tmp.tv_usec = time.tv_usec - t.tv_usec; + if (time.tv_sec != t.tv_sec) + tmp.tv_usec += 1000000; + + if (tmp.tv_usec > late) { + tmp.tv_usec -= late; + + if (tmp.tv_usec >= 1000000) { + tmp.tv_usec -= 1000000; + ++tmp.tv_sec; + } + + SDL_Delay(tmp.tv_sec * 1000 + (tmp.tv_usec + 500) / 1000); + + gettimeofday(&t, NULL); + late -= (time.tv_sec - t.tv_sec) * 1000000 + time.tv_usec - t.tv_usec >> 1; +// printf("late: %d\n", late); + + if (late < 0) + late = 0; + + noSleep = 60; + } else if (noSleep-- == 0) { + noSleep = 60; + late = 0; + } + + while (time.tv_sec > t.tv_sec || (time.tv_sec == t.tv_sec && time.tv_usec > t.tv_usec)) { + gettimeofday(&t, NULL); + } + + } else + time = t; + + time.tv_usec += 16743; + + if (time.tv_usec >= 1000000) { + time.tv_usec -= 1000000; + ++time.tv_sec; + } +} diff --git a/gambatte_sdl/src/syncfunc.h b/gambatte_sdl/src/syncfunc.h new file mode 100644 index 0000000..f95305a --- /dev/null +++ b/gambatte_sdl/src/syncfunc.h @@ -0,0 +1,24 @@ +/*************************************************************************** + * Copyright (C) 2007 by Sindre Aamås * + * aamas@stud.ntnu.no * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License version 2 as * + * published by the Free Software Foundation. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License version 2 for more details. * + * * + * You should have received a copy of the GNU General Public License * + * version 2 along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ +#ifndef SYNCFUNC_H +#define SYNCFUNC_H + +void syncFunc(); + +#endif