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 struct GraphicsOpts* graphicsOpts = parser->opts;
121 switch (option) {
122 case 'f':
123 graphicsOpts->fullscreen = 1;
124 return 1;
125 case '2':
126 if (graphicsOpts->multiplier != 1) {
127 return 0;
128 }
129 graphicsOpts->multiplier = 2;
130 graphicsOpts->width *= graphicsOpts->multiplier;
131 graphicsOpts->height *= graphicsOpts->multiplier;
132 return 1;
133 case '3':
134 if (graphicsOpts->multiplier != 1) {
135 return 0;
136 }
137 graphicsOpts->multiplier = 3;
138 graphicsOpts->width *= graphicsOpts->multiplier;
139 graphicsOpts->height *= graphicsOpts->multiplier;
140 return 1;
141 case '4':
142 if (graphicsOpts->multiplier != 1) {
143 return 0;
144 }
145 graphicsOpts->multiplier = 4;
146 graphicsOpts->width *= graphicsOpts->multiplier;
147 graphicsOpts->height *= graphicsOpts->multiplier;
148 return 1;
149 default:
150 return 0;
151 }
152}
153
154struct ARMDebugger* createDebugger(struct StartupOptions* opts) {
155 union DebugUnion {
156 struct ARMDebugger d;
157#ifdef USE_CLI_DEBUGGER
158 struct CLIDebugger cli;
159#endif
160#ifdef USE_GDB_STUB
161 struct GDBStub gdb;
162#endif
163 };
164
165 union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
166
167 switch (opts->debuggerType) {
168#ifdef USE_CLI_DEBUGGER
169 case DEBUGGER_CLI:
170 CLIDebuggerCreate(&debugger->cli);
171 break;
172#endif
173#ifdef USE_GDB_STUB
174 case DEBUGGER_GDB:
175 GDBStubCreate(&debugger->gdb);
176 GDBStubListen(&debugger->gdb, 2345, 0);
177 break;
178#endif
179 case DEBUGGER_NONE:
180 case DEBUGGER_MAX:
181 free(debugger);
182 return 0;
183 break;
184 }
185
186 return &debugger->d;
187}
188
189void usage(const char* arg0, const char* extraOptions) {
190 printf("usage: %s [option ...] file\n", arg0);
191 puts("\nGeneric options:");
192 puts(" -b, --bios FILE GBA BIOS file to use");
193#ifdef USE_CLI_DEBUGGER
194 puts(" -d, --debug Use command-line debugger");
195#endif
196#ifdef USE_GDB_STUB
197 puts(" -g, --gdb Start GDB session (default port 2345)");
198#endif
199 if (extraOptions) {
200 puts(extraOptions);
201 }
202}