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