all repos — mgba @ 28ba251cfbb4396f9501b5404c0a4a5afcf43211

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