all repos — mgba @ e2927ebcea5025bd426b0721fac671e4f4d216cc

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