all repos — mgba @ 618092a5f6b5ed1501e361b4c7c2f390f4967d66

mGBA Game Boy Advance Emulator

src/platform/commandline.c (view raw)

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