all repos — mgba @ 7dc9eb4d5641d5980a2cc0eb8f1e459b4bfdfb4a

mGBA Game Boy Advance Emulator

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