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