all repos — mgba @ d53e479fede3df65a3c5375d72240b0327a2c0f1

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#include "util/string.h"
 21
 22#include <fcntl.h>
 23#include <getopt.h>
 24
 25#define GRAPHICS_OPTIONS "123456f"
 26#define GRAPHICS_USAGE \
 27	"\nGraphics options:\n" \
 28	"  -1               1x viewport\n" \
 29	"  -2               2x viewport\n" \
 30	"  -3               3x viewport\n" \
 31	"  -4               4x viewport\n" \
 32	"  -5               5x viewport\n" \
 33	"  -6               6x viewport\n" \
 34	"  -f               Start full-screen"
 35
 36static const struct option _options[] = {
 37	{ "bios",      required_argument, 0, 'b' },
 38	{ "cheats",    required_argument, 0, 'c' },
 39	{ "dirmode",   required_argument, 0, 'D' },
 40	{ "frameskip", required_argument, 0, 's' },
 41#ifdef USE_CLI_DEBUGGER
 42	{ "debug",     no_argument, 0, 'd' },
 43#endif
 44#ifdef USE_GDB_STUB
 45	{ "gdb",       no_argument, 0, 'g' },
 46#endif
 47	{ "help",      no_argument, 0, 'h' },
 48	{ "movie",     required_argument, 0, 'v' },
 49	{ "patch",     required_argument, 0, 'p' },
 50	{ "version",   no_argument, 0, '\0' },
 51	{ 0, 0, 0, 0 }
 52};
 53
 54static bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg);
 55
 56bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser) {
 57	int ch;
 58	char options[64] =
 59		"b:c:Dhl:p:s:v:"
 60#ifdef USE_CLI_DEBUGGER
 61		"d"
 62#endif
 63#ifdef USE_GDB_STUB
 64		"g"
 65#endif
 66	;
 67	memset(opts, 0, sizeof(*opts));
 68	if (subparser && subparser->extraOptions) {
 69		// TODO: modularize options to subparsers
 70		strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
 71	}
 72	int index = 0;
 73	while ((ch = getopt_long(argc, argv, options, _options, &index)) != -1) {
 74		const struct option* opt = &_options[index];
 75		switch (ch) {
 76		case '\0':
 77			if (strcmp(opt->name, "version") == 0) {
 78				opts->showVersion = true;
 79			} else {
 80				return false;
 81			}
 82			break;
 83		case 'b':
 84			GBAConfigSetOverrideValue(config, "bios", optarg);
 85			break;
 86		case 'c':
 87			opts->cheatsFile = strdup(optarg);
 88			break;
 89		case 'D':
 90			opts->dirmode = true;
 91			break;
 92#ifdef USE_CLI_DEBUGGER
 93		case 'd':
 94			if (opts->debuggerType != DEBUGGER_NONE) {
 95				return false;
 96			}
 97			opts->debuggerType = DEBUGGER_CLI;
 98			break;
 99#endif
100#ifdef USE_GDB_STUB
101		case 'g':
102			if (opts->debuggerType != DEBUGGER_NONE) {
103				return false;
104			}
105			opts->debuggerType = DEBUGGER_GDB;
106			break;
107#endif
108		case 'h':
109			opts->showHelp = true;
110			break;
111		case 'l':
112			GBAConfigSetOverrideValue(config, "logLevel", optarg);
113			break;
114		case 'p':
115			opts->patch = strdup(optarg);
116			break;
117		case 's':
118			GBAConfigSetOverrideValue(config, "frameskip", optarg);
119			break;
120		case 'v':
121			opts->movie = strdup(optarg);
122			break;
123		default:
124			if (subparser) {
125				if (!subparser->parse(subparser, config, ch, optarg)) {
126					return false;
127				}
128			}
129			break;
130		}
131	}
132	argc -= optind;
133	argv += optind;
134	if (argc != 1) {
135		return opts->showHelp || opts->showVersion;
136	}
137	opts->fname = strdup(argv[0]);
138	return true;
139}
140
141void freeArguments(struct GBAArguments* opts) {
142	free(opts->fname);
143	opts->fname = 0;
144
145	free(opts->patch);
146	opts->patch = 0;
147
148	free(opts->movie);
149	opts->movie = 0;
150}
151
152void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
153	parser->usage = GRAPHICS_USAGE;
154	parser->opts = opts;
155	parser->parse = _parseGraphicsArg;
156	parser->extraOptions = GRAPHICS_OPTIONS;
157	opts->multiplier = 0;
158	opts->fullscreen = false;
159}
160
161bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) {
162	UNUSED(arg);
163	struct GraphicsOpts* graphicsOpts = parser->opts;
164	switch (option) {
165	case 'f':
166		graphicsOpts->fullscreen = true;
167		GBAConfigSetOverrideIntValue(config, "fullscreen", 1);
168		return true;
169	case '1':
170	case '2':
171	case '3':
172	case '4':
173	case '5':
174	case '6':
175		if (graphicsOpts->multiplier) {
176			return false;
177		}
178		graphicsOpts->multiplier = option - '0';
179		GBAConfigSetOverrideIntValue(config, "width", VIDEO_HORIZONTAL_PIXELS * graphicsOpts->multiplier);
180		GBAConfigSetOverrideIntValue(config, "height", VIDEO_VERTICAL_PIXELS * graphicsOpts->multiplier);
181		return true;
182	default:
183		return false;
184	}
185}
186
187struct ARMDebugger* createDebugger(struct GBAArguments* opts, struct GBAThread* context) {
188#ifndef USE_CLI_DEBUGGER
189	UNUSED(context);
190#endif
191	union DebugUnion {
192		struct ARMDebugger d;
193#ifdef USE_CLI_DEBUGGER
194		struct CLIDebugger cli;
195#endif
196#ifdef USE_GDB_STUB
197		struct GDBStub gdb;
198#endif
199	};
200
201	union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
202
203	switch (opts->debuggerType) {
204#ifdef USE_CLI_DEBUGGER
205	case DEBUGGER_CLI:
206		CLIDebuggerCreate(&debugger->cli);
207		struct GBACLIDebugger* gbaDebugger = GBACLIDebuggerCreate(context);
208		CLIDebuggerAttachSystem(&debugger->cli, &gbaDebugger->d);
209		break;
210#endif
211#ifdef USE_GDB_STUB
212	case DEBUGGER_GDB:
213		GDBStubCreate(&debugger->gdb);
214		GDBStubListen(&debugger->gdb, 2345, 0);
215		break;
216#endif
217	case DEBUGGER_NONE:
218	case DEBUGGER_MAX:
219		free(debugger);
220		return 0;
221		break;
222	}
223
224	return &debugger->d;
225}
226
227void usage(const char* arg0, const char* extraOptions) {
228	printf("usage: %s [option ...] file\n", arg0);
229	puts("\nGeneric options:");
230	puts("  -b, --bios FILE     GBA BIOS file to use");
231	puts("  -c, --cheats FILE   Apply cheat codes from a file");
232#ifdef USE_CLI_DEBUGGER
233	puts("  -d, --debug         Use command-line debugger");
234#endif
235#ifdef USE_GDB_STUB
236	puts("  -g, --gdb           Start GDB session (default port 2345)");
237#endif
238	puts("  -v, --movie FILE    Play back a movie of recorded input");
239	puts("  -p, --patch FILE    Apply a specified patch file when running");
240	puts("  -s, --frameskip N   Skip every N frames");
241	puts("  --version           Print version and exit");
242	if (extraOptions) {
243		puts(extraOptions);
244	}
245}
246
247void version(const char* arg0) {
248	printf("%s %s (%s)\n", arg0, projectVersion, gitCommit);
249}