all repos — mgba @ 091e717133a10f785f02d1d4e880b8271fea8066

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