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