all repos — mgba @ 629196e7a10942046455347c7469d6d42ea82dc9

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