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