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