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 { "movie", required_argument, 0, 'v' },
47 { "patch", required_argument, 0, 'p' },
48 { 0, 0, 0, 0 }
49};
50
51bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg);
52
53bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser) {
54 int ch;
55 char options[64] =
56 "b:c:Dl:p:s:v:"
57#ifdef USE_CLI_DEBUGGER
58 "d"
59#endif
60#ifdef USE_GDB_STUB
61 "g"
62#endif
63 ;
64 memset(opts, 0, sizeof(*opts));
65 if (subparser && subparser->extraOptions) {
66 // TODO: modularize options to subparsers
67 strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
68 }
69 while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) {
70 switch (ch) {
71 case 'b':
72 GBAConfigSetDefaultValue(config, "bios", optarg);
73 break;
74 case 'c':
75 opts->cheatsFile = strdup(optarg);
76 break;
77 case 'D':
78 opts->dirmode = true;
79 break;
80#ifdef USE_CLI_DEBUGGER
81 case 'd':
82 if (opts->debuggerType != DEBUGGER_NONE) {
83 return false;
84 }
85 opts->debuggerType = DEBUGGER_CLI;
86 break;
87#endif
88#ifdef USE_GDB_STUB
89 case 'g':
90 if (opts->debuggerType != DEBUGGER_NONE) {
91 return false;
92 }
93 opts->debuggerType = DEBUGGER_GDB;
94 break;
95#endif
96 case 'l':
97 GBAConfigSetDefaultValue(config, "logLevel", optarg);
98 break;
99 case 'p':
100 opts->patch = strdup(optarg);
101 break;
102 case 's':
103 GBAConfigSetDefaultValue(config, "frameskip", optarg);
104 break;
105 case 'v':
106 opts->movie = strdup(optarg);
107 break;
108 default:
109 if (subparser) {
110 if (!subparser->parse(subparser, config, ch, optarg)) {
111 return false;
112 }
113 }
114 break;
115 }
116 }
117 argc -= optind;
118 argv += optind;
119 if (argc != 1) {
120 return false;
121 }
122 opts->fname = strdup(argv[0]);
123 return true;
124}
125
126void freeArguments(struct GBAArguments* opts) {
127 free(opts->fname);
128 opts->fname = 0;
129
130 free(opts->patch);
131 opts->patch = 0;
132
133 free(opts->movie);
134 opts->movie = 0;
135}
136
137void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
138 parser->usage = GRAPHICS_USAGE;
139 parser->opts = opts;
140 parser->parse = _parseGraphicsArg;
141 parser->extraOptions = GRAPHICS_OPTIONS;
142 opts->multiplier = 0;
143}
144
145bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) {
146 UNUSED(arg);
147 struct GraphicsOpts* graphicsOpts = parser->opts;
148 switch (option) {
149 case 'f':
150 GBAConfigSetDefaultIntValue(config, "fullscreen", 1);
151 return true;
152 case '1':
153 case '2':
154 case '3':
155 case '4':
156 case '5':
157 case '6':
158 if (graphicsOpts->multiplier) {
159 return false;
160 }
161 graphicsOpts->multiplier = option - '0';
162 GBAConfigSetDefaultIntValue(config, "width", VIDEO_HORIZONTAL_PIXELS * graphicsOpts->multiplier);
163 GBAConfigSetDefaultIntValue(config, "height", VIDEO_VERTICAL_PIXELS * graphicsOpts->multiplier);
164 return true;
165 default:
166 return false;
167 }
168}
169
170struct ARMDebugger* createDebugger(struct GBAArguments* opts, struct GBAThread* context) {
171#ifndef USE_CLI_DEBUGGER
172 UNUSED(context);
173#endif
174 union DebugUnion {
175 struct ARMDebugger d;
176#ifdef USE_CLI_DEBUGGER
177 struct CLIDebugger cli;
178#endif
179#ifdef USE_GDB_STUB
180 struct GDBStub gdb;
181#endif
182 };
183
184 union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
185
186 switch (opts->debuggerType) {
187#ifdef USE_CLI_DEBUGGER
188 case DEBUGGER_CLI:
189 CLIDebuggerCreate(&debugger->cli);
190 struct GBACLIDebugger* gbaDebugger = GBACLIDebuggerCreate(context);
191 CLIDebuggerAttachSystem(&debugger->cli, &gbaDebugger->d);
192 break;
193#endif
194#ifdef USE_GDB_STUB
195 case DEBUGGER_GDB:
196 GDBStubCreate(&debugger->gdb);
197 GDBStubListen(&debugger->gdb, 2345, 0);
198 break;
199#endif
200 case DEBUGGER_NONE:
201 case DEBUGGER_MAX:
202 free(debugger);
203 return 0;
204 break;
205 }
206
207 return &debugger->d;
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_CLI_DEBUGGER
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(" -v, --movie FILE Play back a movie of recorded input");
222 puts(" -p, --patch FILE Apply a specified patch file when running");
223 puts(" -s, --frameskip N Skip every N frames");
224 if (extraOptions) {
225 puts(extraOptions);
226 }
227}