all repos — mgba @ 6ca25e44aa55b8930d14ad313fa1ad5c94c4f8bf

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#endif
  8
  9#ifdef USE_GDB_STUB
 10#include "debugger/gdb-stub.h"
 11#endif
 12
 13#include <fcntl.h>
 14#include <getopt.h>
 15
 16static const char* _defaultFilename = "test.rom";
 17
 18static const struct option _options[] = {
 19	{ "bios", 1, 0, 'b' },
 20	{ "frameskip", 1, 0, 's' },
 21#ifdef USE_CLI_DEBUGGER
 22	{ "debug", 1, 0, 'd' },
 23#endif
 24#ifdef USE_GDB_STUB
 25	{ "gdb", 1, 0, 'g' },
 26#endif
 27	{ 0, 0, 0, 0 }
 28};
 29
 30int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, const char* extraOptions) {
 31	memset(opts, 0, sizeof(*opts));
 32	opts->fd = -1;
 33	opts->biosFd = -1;
 34	opts->width = 240;
 35	opts->height = 160;
 36
 37	int multiplier = 1;
 38	int ch;
 39	char options[64] =
 40		"b:s:"
 41#ifdef USE_CLI_DEBUGGER
 42		"d"
 43#endif
 44#ifdef USE_GDB_STUB
 45		"g"
 46#endif
 47	;
 48	if (extraOptions) {
 49		// TODO: modularize options to subparsers
 50		strncat(options, extraOptions, sizeof(options) - strlen(options) - 1);
 51	}
 52	while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) {
 53		switch (ch) {
 54		case 'b':
 55			opts->biosFd = open(optarg, O_RDONLY);
 56			break;
 57#ifdef USE_CLI_DEBUGGER
 58		case 'd':
 59			if (opts->debuggerType != DEBUGGER_NONE) {
 60				return 0;
 61			}
 62			opts->debuggerType = DEBUGGER_CLI;
 63			break;
 64#endif
 65		case 'f':
 66			opts->fullscreen = 1;
 67			break;
 68#ifdef USE_GDB_STUB
 69		case 'g':
 70			if (opts->debuggerType != DEBUGGER_NONE) {
 71				return 0;
 72			}
 73			opts->debuggerType = DEBUGGER_GDB;
 74			break;
 75#endif
 76		case 's':
 77			opts->frameskip = atoi(optarg);
 78			break;
 79		case 'S':
 80			opts->perfDuration = atoi(optarg);
 81			break;
 82		case '2':
 83			if (multiplier != 1) {
 84				return 0;
 85			}
 86			multiplier = 2;
 87			break;
 88		case '3':
 89			if (multiplier != 1) {
 90				return 0;
 91			}
 92			multiplier = 3;
 93			break;
 94		case '4':
 95			if (multiplier != 1) {
 96				return 0;
 97			}
 98			multiplier = 4;
 99			break;
100		default:
101			return 0;
102		}
103	}
104	argc -= optind;
105	argv += optind;
106	if (argc == 1) {
107		opts->fname = argv[0];
108	} else if (argc == 0) {
109		opts->fname = _defaultFilename;
110	} else {
111		return 0;
112	}
113	opts->fd = open(opts->fname, O_RDONLY);
114	opts->width *= multiplier;
115	opts->height *= multiplier;
116	return 1;
117}
118
119struct ARMDebugger* createDebugger(struct StartupOptions* opts) {
120	union DebugUnion {
121		struct ARMDebugger d;
122#ifdef USE_CLI_DEBUGGER
123		struct CLIDebugger cli;
124#endif
125#ifdef USE_GDB_STUB
126		struct GDBStub gdb;
127#endif
128	};
129
130	union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
131
132	switch (opts->debuggerType) {
133#ifdef USE_CLI_DEBUGGER
134	case DEBUGGER_CLI:
135		CLIDebuggerCreate(&debugger->cli);
136		break;
137#endif
138#ifdef USE_GDB_STUB
139	case DEBUGGER_GDB:
140		GDBStubCreate(&debugger->gdb);
141		GDBStubListen(&debugger->gdb, 2345, 0);
142		break;
143#endif
144	case DEBUGGER_NONE:
145	case DEBUGGER_MAX:
146		free(debugger);
147		return 0;
148		break;
149	}
150
151	return &debugger->d;
152}
153
154void usage(const char* arg0, const char* extraOptions) {
155	printf("usage: %s [option ...] file\n", arg0);
156	puts("\nGeneric options:");
157	puts("  -b, --bios FILE  GBA BIOS file to use");
158#ifdef USE_CLI_DEBUGGER
159	puts("  -d, --debug      Use command-line debugger");
160#endif
161#ifdef USE_GDB_STUB
162	puts("  -g, --gdb        Start GDB session (default port 2345)");
163#endif
164	if (extraOptions) {
165		puts(extraOptions);
166	}
167}