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