all repos — mgba @ fce2fb925284a8c021406dbc4e394de972c0c763

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