all repos — mgba @ ee5c918ff24e6f5f23864518d9bdd64309115919

mGBA Game Boy Advance Emulator

src/platform/commandline.c (view raw)

  1#include "commandline.h"
  2
  3#include "debugger/debugger.h"
  4
  5#ifdef USE_CLI_DEBUGGER
  6#include "debugger/cli-debugger.h"
  7#endif
  8
  9#ifdef USE_GDB_STUB
 10#include "debugger/gdb-stub.h"
 11#endif
 12
 13#include <fcntl.h>
 14#include <getopt.h>
 15
 16#define GRAPHICS_OPTIONS "234f"
 17#define GRAPHICS_USAGE \
 18	"\nGraphics options:\n" \
 19	"  -2               2x viewport\n" \
 20	"  -3               3x viewport\n" \
 21	"  -4               4x viewport\n" \
 22	"  -f               Start full-screen"
 23
 24static const struct option _options[] = {
 25	{ "bios",      required_argument, 0, 'b' },
 26	{ "dirmode",      required_argument, 0, 'D' },
 27	{ "frameskip", required_argument, 0, 's' },
 28#ifdef USE_CLI_DEBUGGER
 29	{ "debug",     no_argument, 0, 'd' },
 30#endif
 31#ifdef USE_GDB_STUB
 32	{ "gdb",       no_argument, 0, 'g' },
 33#endif
 34	{ "patch",     required_argument, 0, 'p' },
 35	{ 0, 0, 0, 0 }
 36};
 37
 38bool _parseGraphicsArg(struct SubParser* parser, int option, const char* arg);
 39
 40bool parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, struct SubParser* subparser) {
 41	memset(opts, 0, sizeof(*opts));
 42
 43	int ch;
 44	char options[64] =
 45		"b:Dl:p:s:"
 46#ifdef USE_CLI_DEBUGGER
 47		"d"
 48#endif
 49#ifdef USE_GDB_STUB
 50		"g"
 51#endif
 52	;
 53	if (subparser->extraOptions) {
 54		// TODO: modularize options to subparsers
 55		strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
 56	}
 57	while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) {
 58		switch (ch) {
 59		case 'b':
 60			opts->bios = strdup(optarg);
 61			break;
 62		case 'D':
 63			opts->dirmode = true;
 64			break;
 65#ifdef USE_CLI_DEBUGGER
 66		case 'd':
 67			if (opts->debuggerType != DEBUGGER_NONE) {
 68				return false;
 69			}
 70			opts->debuggerType = DEBUGGER_CLI;
 71			break;
 72#endif
 73#ifdef USE_GDB_STUB
 74		case 'g':
 75			if (opts->debuggerType != DEBUGGER_NONE) {
 76				return false;
 77			}
 78			opts->debuggerType = DEBUGGER_GDB;
 79			break;
 80#endif
 81		case 'l':
 82			opts->logLevel = atoi(optarg);
 83			break;
 84		case 'p':
 85			opts->patch = strdup(optarg);
 86			break;
 87		case 's':
 88			opts->frameskip = atoi(optarg);
 89			break;
 90		default:
 91			if (subparser) {
 92				if (!subparser->parse(subparser, ch, optarg)) {
 93					return false;
 94				}
 95			}
 96			break;
 97		}
 98	}
 99	argc -= optind;
100	argv += optind;
101	if (argc != 1) {
102		return false;
103	}
104	opts->fname = strdup(argv[0]);
105	return true;
106}
107
108void freeOptions(struct StartupOptions* opts) {
109	free(opts->fname);
110	opts->fname = 0;
111
112	free(opts->bios);
113	opts->bios = 0;
114
115	free(opts->patch);
116	opts->patch = 0;
117}
118
119void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
120	parser->usage = GRAPHICS_USAGE;
121	parser->opts = opts;
122	parser->parse = _parseGraphicsArg;
123	parser->extraOptions = GRAPHICS_OPTIONS;
124	opts->multiplier = 1;
125	opts->fullscreen = 0;
126	opts->width = 240;
127	opts->height = 160;
128}
129
130bool _parseGraphicsArg(struct SubParser* parser, int option, const char* arg) {
131	UNUSED(arg);
132	struct GraphicsOpts* graphicsOpts = parser->opts;
133	switch (option) {
134	case 'f':
135		graphicsOpts->fullscreen = 1;
136		return true;
137	case '2':
138		if (graphicsOpts->multiplier != 1) {
139			return false;
140		}
141		graphicsOpts->multiplier = 2;
142		graphicsOpts->width *= graphicsOpts->multiplier;
143		graphicsOpts->height *= graphicsOpts->multiplier;
144		return true;
145	case '3':
146		if (graphicsOpts->multiplier != 1) {
147			return false;
148		}
149		graphicsOpts->multiplier = 3;
150		graphicsOpts->width *= graphicsOpts->multiplier;
151		graphicsOpts->height *= graphicsOpts->multiplier;
152		return true;
153	case '4':
154		if (graphicsOpts->multiplier != 1) {
155			return false;
156		}
157		graphicsOpts->multiplier = 4;
158		graphicsOpts->width *= graphicsOpts->multiplier;
159		graphicsOpts->height *= graphicsOpts->multiplier;
160		return true;
161	default:
162		return false;
163	}
164}
165
166struct ARMDebugger* createDebugger(struct StartupOptions* opts) {
167	union DebugUnion {
168		struct ARMDebugger d;
169#ifdef USE_CLI_DEBUGGER
170		struct CLIDebugger cli;
171#endif
172#ifdef USE_GDB_STUB
173		struct GDBStub gdb;
174#endif
175	};
176
177	union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
178
179	switch (opts->debuggerType) {
180#ifdef USE_CLI_DEBUGGER
181	case DEBUGGER_CLI:
182		CLIDebuggerCreate(&debugger->cli);
183		break;
184#endif
185#ifdef USE_GDB_STUB
186	case DEBUGGER_GDB:
187		GDBStubCreate(&debugger->gdb);
188		GDBStubListen(&debugger->gdb, 2345, 0);
189		break;
190#endif
191	case DEBUGGER_NONE:
192	case DEBUGGER_MAX:
193		free(debugger);
194		return 0;
195		break;
196	}
197
198	return &debugger->d;
199}
200
201void usage(const char* arg0, const char* extraOptions) {
202	printf("usage: %s [option ...] file\n", arg0);
203	puts("\nGeneric options:");
204	puts("  -b, --bios FILE  GBA BIOS file to use");
205#ifdef USE_CLI_DEBUGGER
206	puts("  -d, --debug      Use command-line debugger");
207#endif
208#ifdef USE_GDB_STUB
209	puts("  -g, --gdb        Start GDB session (default port 2345)");
210#endif
211	if (extraOptions) {
212		puts(extraOptions);
213	}
214}