Use subparsers instead of stuffing everything into one parser

This commit is contained in:
Jeffrey Pfau 2014-04-26 16:05:09 -07:00
parent 6ca25e44aa
commit 12e5425b9b
5 changed files with 130 additions and 66 deletions

View File

@ -13,6 +13,14 @@
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h> #include <getopt.h>
#define GRAPHICS_OPTIONS "234f"
#define GRAPHICS_USAGE \
"\nGraphics options:\n" \
" -2 2x viewport\n" \
" -3 3x viewport\n" \
" -4 4x viewport\n" \
" -f Sart full-screen"
static const char* _defaultFilename = "test.rom"; static const char* _defaultFilename = "test.rom";
static const struct option _options[] = { static const struct option _options[] = {
@ -27,14 +35,13 @@ static const struct option _options[] = {
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, const char* extraOptions) { int _parseGraphicsArg(struct SubParser* parser, int option, const char* arg);
int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, struct SubParser* subparser) {
memset(opts, 0, sizeof(*opts)); memset(opts, 0, sizeof(*opts));
opts->fd = -1; opts->fd = -1;
opts->biosFd = -1; opts->biosFd = -1;
opts->width = 240;
opts->height = 160;
int multiplier = 1;
int ch; int ch;
char options[64] = char options[64] =
"b:s:" "b:s:"
@ -45,9 +52,9 @@ int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, c
"g" "g"
#endif #endif
; ;
if (extraOptions) { if (subparser->extraOptions) {
// TODO: modularize options to subparsers // TODO: modularize options to subparsers
strncat(options, extraOptions, sizeof(options) - strlen(options) - 1); strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
} }
while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) { while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) {
switch (ch) { switch (ch) {
@ -62,9 +69,6 @@ int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, c
opts->debuggerType = DEBUGGER_CLI; opts->debuggerType = DEBUGGER_CLI;
break; break;
#endif #endif
case 'f':
opts->fullscreen = 1;
break;
#ifdef USE_GDB_STUB #ifdef USE_GDB_STUB
case 'g': case 'g':
if (opts->debuggerType != DEBUGGER_NONE) { if (opts->debuggerType != DEBUGGER_NONE) {
@ -76,29 +80,13 @@ int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, c
case 's': case 's':
opts->frameskip = atoi(optarg); opts->frameskip = atoi(optarg);
break; break;
case 'S':
opts->perfDuration = atoi(optarg);
break;
case '2':
if (multiplier != 1) {
return 0;
}
multiplier = 2;
break;
case '3':
if (multiplier != 1) {
return 0;
}
multiplier = 3;
break;
case '4':
if (multiplier != 1) {
return 0;
}
multiplier = 4;
break;
default: default:
return 0; if (subparser) {
if (!subparser->parse(subparser, ch, optarg)) {
return 0;
}
}
break;
} }
} }
argc -= optind; argc -= optind;
@ -111,11 +99,55 @@ int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, c
return 0; return 0;
} }
opts->fd = open(opts->fname, O_RDONLY); opts->fd = open(opts->fname, O_RDONLY);
opts->width *= multiplier;
opts->height *= multiplier;
return 1; return 1;
} }
void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
parser->usage = GRAPHICS_USAGE;
parser->opts = opts;
parser->parse = _parseGraphicsArg;
parser->extraOptions = GRAPHICS_OPTIONS;
opts->multiplier = 1;
opts->fullscreen = 0;
opts->width = 240;
opts->height = 160;
}
int _parseGraphicsArg(struct SubParser* parser, int option, const char* arg) {
struct GraphicsOpts* graphicsOpts = parser->opts;
switch (option) {
case 'f':
graphicsOpts->fullscreen = 1;
return 1;
case '2':
if (graphicsOpts->multiplier != 1) {
return 0;
}
graphicsOpts->multiplier = 2;
graphicsOpts->width *= graphicsOpts->multiplier;
graphicsOpts->height *= graphicsOpts->multiplier;
return 1;
case '3':
if (graphicsOpts->multiplier != 1) {
return 0;
}
graphicsOpts->multiplier = 3;
graphicsOpts->width *= graphicsOpts->multiplier;
graphicsOpts->height *= graphicsOpts->multiplier;
return 1;
case '4':
if (graphicsOpts->multiplier != 1) {
return 0;
}
graphicsOpts->multiplier = 4;
graphicsOpts->width *= graphicsOpts->multiplier;
graphicsOpts->height *= graphicsOpts->multiplier;
return 1;
default:
return 0;
}
}
struct ARMDebugger* createDebugger(struct StartupOptions* opts) { struct ARMDebugger* createDebugger(struct StartupOptions* opts) {
union DebugUnion { union DebugUnion {
struct ARMDebugger d; struct ARMDebugger d;

View File

@ -14,19 +14,6 @@ enum DebuggerType {
DEBUGGER_MAX DEBUGGER_MAX
}; };
#define GRAPHICS_OPTIONS "234f"
#define GRAPHICS_USAGE \
"\nGraphics options:\n" \
" -2 2x viewport\n" \
" -3 3x viewport\n" \
" -4 4x viewport\n" \
" -f Sart full-screen"
#define PERF_OPTIONS "S:"
#define PERF_USAGE \
"\nBenchmark options:\n" \
" -S SEC Run for SEC in-game seconds before exiting"
struct StartupOptions { struct StartupOptions {
int fd; int fd;
const char* fname; const char* fname;
@ -35,19 +22,28 @@ struct StartupOptions {
int rewindBufferCapacity; int rewindBufferCapacity;
int rewindBufferInterval; int rewindBufferInterval;
int width;
int height;
int fullscreen;
int perfDuration;
enum DebuggerType debuggerType; enum DebuggerType debuggerType;
int debugAtStart; int debugAtStart;
}; };
int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, const char* extraOptions); struct SubParser {
const char* usage;
int (*parse)(struct SubParser* parser, int option, const char* arg);
const char* extraOptions;
void* opts;
};
struct GraphicsOpts {
int multiplier;
int fullscreen;
int width;
int height;
};
int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, struct SubParser* subparser);
void usage(const char* arg0, const char* extraOptions); void usage(const char* arg0, const char* extraOptions);
void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts);
struct ARMDebugger* createDebugger(struct StartupOptions* opts); struct ARMDebugger* createDebugger(struct StartupOptions* opts);
#endif #endif

View File

@ -2,12 +2,23 @@
#include "gba.h" #include "gba.h"
#include "renderers/video-software.h" #include "renderers/video-software.h"
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <sys/time.h> #include <sys/time.h>
#define PERF_OPTIONS "S:"
#define PERF_USAGE \
"\nBenchmark options:\n" \
" -S SEC Run for SEC in-game seconds before exiting"
struct PerfOpts {
int duration;
};
static void _GBAPerfRunloop(struct GBAThread* context, int* frames); static void _GBAPerfRunloop(struct GBAThread* context, int* frames);
static void _GBAPerfShutdown(int signal); static void _GBAPerfShutdown(int signal);
static int _parsePerfOpts(struct SubParser* parser, int option, const char* arg);
static struct GBAThread* _thread; static struct GBAThread* _thread;
@ -17,8 +28,16 @@ int main(int argc, char** argv) {
struct GBAVideoSoftwareRenderer renderer; struct GBAVideoSoftwareRenderer renderer;
GBAVideoSoftwareRendererCreate(&renderer); GBAVideoSoftwareRendererCreate(&renderer);
struct PerfOpts perfOpts = {};
struct SubParser subparser = {
.usage = PERF_USAGE,
.parse = _parsePerfOpts,
.extraOptions = PERF_OPTIONS,
.opts = &perfOpts
};
struct StartupOptions opts; struct StartupOptions opts;
if (!parseCommandArgs(&opts, argc, argv, PERF_OPTIONS)) { if (!parseCommandArgs(&opts, argc, argv, &subparser)) {
usage(argv[0], PERF_USAGE); usage(argv[0], PERF_USAGE);
return 1; return 1;
} }
@ -39,7 +58,7 @@ int main(int argc, char** argv) {
GBAThreadStart(&context); GBAThreadStart(&context);
int frames = opts.perfDuration; int frames = perfOpts.duration;
time_t start = time(0); time_t start = time(0);
_GBAPerfRunloop(&context, &frames); _GBAPerfRunloop(&context, &frames);
time_t end = time(0); time_t end = time(0);
@ -96,3 +115,14 @@ static void _GBAPerfShutdown(int signal) {
_thread->state = THREAD_EXITING; _thread->state = THREAD_EXITING;
pthread_mutex_unlock(&_thread->stateMutex); pthread_mutex_unlock(&_thread->stateMutex);
} }
static int _parsePerfOpts(struct SubParser* parser, int option, const char* arg) {
struct PerfOpts* opts = parser->opts;
switch (option) {
case 'S':
opts->duration = strtol(arg, 0, 10);
return !errno;
default:
return 0;
}
}

View File

@ -62,15 +62,18 @@ int main(int argc, char** argv) {
GBAVideoSoftwareRendererCreate(&renderer.d); GBAVideoSoftwareRendererCreate(&renderer.d);
struct StartupOptions opts; struct StartupOptions opts;
if (!parseCommandArgs(&opts, argc, argv, GRAPHICS_OPTIONS)) { struct SubParser subparser;
usage(argv[0], GRAPHICS_USAGE); struct GraphicsOpts graphicsOpts;
initParserForGraphics(&subparser, &graphicsOpts);
if (!parseCommandArgs(&opts, argc, argv, &subparser)) {
usage(argv[0], subparser.usage);
return 1; return 1;
} }
renderer.viewportWidth = opts.width; renderer.viewportWidth = graphicsOpts.width;
renderer.viewportHeight = opts.height; renderer.viewportHeight = graphicsOpts.height;
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
renderer.events.fullscreen = opts.fullscreen; renderer.events.fullscreen = graphicsOpts.fullscreen;
#endif #endif
if (!_GBASDLInit(&renderer)) { if (!_GBASDLInit(&renderer)) {

View File

@ -49,13 +49,16 @@ int main(int argc, char** argv) {
GBAVideoSoftwareRendererCreate(&renderer.d); GBAVideoSoftwareRendererCreate(&renderer.d);
struct StartupOptions opts; struct StartupOptions opts;
if (!parseCommandArgs(&opts, argc, argv, GRAPHICS_OPTIONS)) { struct SubParser subparser;
usage(argv[0], GRAPHICS_USAGE); struct GraphicsOpts graphicsOpts;
initParserForGraphics(&subparser, &graphicsOpts);
if (!parseCommandArgs(&opts, argc, argv, &subparser)) {
usage(argv[0], subparser.usage);
return 1; return 1;
} }
renderer.viewportWidth = opts.width; renderer.viewportWidth = graphicsOpts.width;
renderer.viewportHeight = opts.height; renderer.viewportHeight = graphicsOpts.height;
if (!_GBASDLInit(&renderer)) { if (!_GBASDLInit(&renderer)) {
return 1; return 1;
@ -75,7 +78,7 @@ int main(int argc, char** argv) {
GBAMapOptionsToContext(&opts, &context); GBAMapOptionsToContext(&opts, &context);
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
renderer.events.fullscreen = opts.fullscreen; renderer.events.fullscreen = graphicsOpts.fullscreen;
renderer.window = SDL_CreateWindow("GBAc", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer.viewportWidth, renderer.viewportHeight, SDL_WINDOW_OPENGL | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer.events.fullscreen)); renderer.window = SDL_CreateWindow("GBAc", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer.viewportWidth, renderer.viewportHeight, SDL_WINDOW_OPENGL | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer.events.fullscreen));
SDL_GetWindowSize(renderer.window, &renderer.viewportWidth, &renderer.viewportHeight); SDL_GetWindowSize(renderer.window, &renderer.viewportWidth, &renderer.viewportHeight);
renderer.events.window = renderer.window; renderer.events.window = renderer.window;
@ -100,7 +103,7 @@ int main(int argc, char** argv) {
SDL_Surface* surface = SDL_GetVideoSurface(); SDL_Surface* surface = SDL_GetVideoSurface();
SDL_LockSurface(surface); SDL_LockSurface(surface);
renderer.ratio = renderer.viewportWidth / VIDEO_HORIZONTAL_PIXELS; renderer.ratio = graphicsOpts.multiplier;
if (renderer.ratio == 1) { if (renderer.ratio == 1) {
renderer.d.outputBuffer = surface->pixels; renderer.d.outputBuffer = surface->pixels;
#ifdef COLOR_16_BIT #ifdef COLOR_16_BIT