src/platform/commandline.c (view raw)
1#include "commandline.h"
2
3#include "debugger/debugger.h"
4
5#ifdef USE_CLI_DEBUGGER
6#include "debugger/cli-debugger.h"
7#endif
8
9#ifdef USE_GDB_STUB
10#include "debugger/gdb-stub.h"
11#endif
12
13#include <fcntl.h>
14#include <getopt.h>
15
16#define GRAPHICS_OPTIONS "234f"
17#define GRAPHICS_USAGE \
18 "\nGraphics options:\n" \
19 " -2 2x viewport\n" \
20 " -3 3x viewport\n" \
21 " -4 4x viewport\n" \
22 " -f Start full-screen"
23
24static const struct option _options[] = {
25 { "bios", required_argument, 0, 'b' },
26 { "dirmode", required_argument, 0, 'D' },
27 { "frameskip", required_argument, 0, 's' },
28#ifdef USE_CLI_DEBUGGER
29 { "debug", no_argument, 0, 'd' },
30#endif
31#ifdef USE_GDB_STUB
32 { "gdb", no_argument, 0, 'g' },
33#endif
34 { "patch", required_argument, 0, 'p' },
35 { 0, 0, 0, 0 }
36};
37
38bool _parseGraphicsArg(struct SubParser* parser, int option, const char* arg);
39
40bool parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, struct SubParser* subparser) {
41 memset(opts, 0, sizeof(*opts));
42
43 int ch;
44 char options[64] =
45 "b:Dl:p:s:"
46#ifdef USE_CLI_DEBUGGER
47 "d"
48#endif
49#ifdef USE_GDB_STUB
50 "g"
51#endif
52 ;
53 if (subparser->extraOptions) {
54 // TODO: modularize options to subparsers
55 strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
56 }
57 while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) {
58 switch (ch) {
59 case 'b':
60 opts->bios = strdup(optarg);
61 break;
62 case 'D':
63 opts->dirmode = true;
64 break;
65#ifdef USE_CLI_DEBUGGER
66 case 'd':
67 if (opts->debuggerType != DEBUGGER_NONE) {
68 return false;
69 }
70 opts->debuggerType = DEBUGGER_CLI;
71 break;
72#endif
73#ifdef USE_GDB_STUB
74 case 'g':
75 if (opts->debuggerType != DEBUGGER_NONE) {
76 return false;
77 }
78 opts->debuggerType = DEBUGGER_GDB;
79 break;
80#endif
81 case 'l':
82 opts->logLevel = atoi(optarg);
83 break;
84 case 'p':
85 opts->patch = strdup(optarg);
86 break;
87 case 's':
88 opts->frameskip = atoi(optarg);
89 break;
90 default:
91 if (subparser) {
92 if (!subparser->parse(subparser, ch, optarg)) {
93 return false;
94 }
95 }
96 break;
97 }
98 }
99 argc -= optind;
100 argv += optind;
101 if (argc != 1) {
102 return false;
103 }
104 opts->fname = strdup(argv[0]);
105 return true;
106}
107
108void freeOptions(struct StartupOptions* opts) {
109 free(opts->fname);
110 opts->fname = 0;
111
112 free(opts->bios);
113 opts->bios = 0;
114
115 free(opts->patch);
116 opts->patch = 0;
117}
118
119void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
120 parser->usage = GRAPHICS_USAGE;
121 parser->opts = opts;
122 parser->parse = _parseGraphicsArg;
123 parser->extraOptions = GRAPHICS_OPTIONS;
124 opts->multiplier = 1;
125 opts->fullscreen = 0;
126 opts->width = 240;
127 opts->height = 160;
128}
129
130bool _parseGraphicsArg(struct SubParser* parser, int option, const char* arg) {
131 UNUSED(arg);
132 struct GraphicsOpts* graphicsOpts = parser->opts;
133 switch (option) {
134 case 'f':
135 graphicsOpts->fullscreen = 1;
136 return true;
137 case '2':
138 if (graphicsOpts->multiplier != 1) {
139 return false;
140 }
141 graphicsOpts->multiplier = 2;
142 graphicsOpts->width *= graphicsOpts->multiplier;
143 graphicsOpts->height *= graphicsOpts->multiplier;
144 return true;
145 case '3':
146 if (graphicsOpts->multiplier != 1) {
147 return false;
148 }
149 graphicsOpts->multiplier = 3;
150 graphicsOpts->width *= graphicsOpts->multiplier;
151 graphicsOpts->height *= graphicsOpts->multiplier;
152 return true;
153 case '4':
154 if (graphicsOpts->multiplier != 1) {
155 return false;
156 }
157 graphicsOpts->multiplier = 4;
158 graphicsOpts->width *= graphicsOpts->multiplier;
159 graphicsOpts->height *= graphicsOpts->multiplier;
160 return true;
161 default:
162 return false;
163 }
164}
165
166struct ARMDebugger* createDebugger(struct StartupOptions* opts) {
167 union DebugUnion {
168 struct ARMDebugger d;
169#ifdef USE_CLI_DEBUGGER
170 struct CLIDebugger cli;
171#endif
172#ifdef USE_GDB_STUB
173 struct GDBStub gdb;
174#endif
175 };
176
177 union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
178
179 switch (opts->debuggerType) {
180#ifdef USE_CLI_DEBUGGER
181 case DEBUGGER_CLI:
182 CLIDebuggerCreate(&debugger->cli);
183 break;
184#endif
185#ifdef USE_GDB_STUB
186 case DEBUGGER_GDB:
187 GDBStubCreate(&debugger->gdb);
188 GDBStubListen(&debugger->gdb, 2345, 0);
189 break;
190#endif
191 case DEBUGGER_NONE:
192 case DEBUGGER_MAX:
193 free(debugger);
194 return 0;
195 break;
196 }
197
198 return &debugger->d;
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#ifdef USE_CLI_DEBUGGER
206 puts(" -d, --debug Use command-line debugger");
207#endif
208#ifdef USE_GDB_STUB
209 puts(" -g, --gdb Start GDB session (default port 2345)");
210#endif
211 if (extraOptions) {
212 puts(extraOptions);
213 }
214}