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