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}