all repos — mgba @ 73425e80b51ffbb7f0553a7fa59455ad38890c7d

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