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 Sart 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: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 's':
81 opts->frameskip = atoi(optarg);
82 break;
83 default:
84 if (subparser) {
85 if (!subparser->parse(subparser, ch, optarg)) {
86 return 0;
87 }
88 }
89 break;
90 }
91 }
92 argc -= optind;
93 argv += optind;
94 if (argc == 1) {
95 opts->fname = argv[0];
96 } else if (argc == 0) {
97 opts->fname = _defaultFilename;
98 } else {
99 return 0;
100 }
101 opts->fd = open(opts->fname, O_RDONLY);
102 return 1;
103}
104
105void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
106 parser->usage = GRAPHICS_USAGE;
107 parser->opts = opts;
108 parser->parse = _parseGraphicsArg;
109 parser->extraOptions = GRAPHICS_OPTIONS;
110 opts->multiplier = 1;
111 opts->fullscreen = 0;
112 opts->width = 240;
113 opts->height = 160;
114}
115
116int _parseGraphicsArg(struct SubParser* parser, int option, const char* arg) {
117 struct GraphicsOpts* graphicsOpts = parser->opts;
118 switch (option) {
119 case 'f':
120 graphicsOpts->fullscreen = 1;
121 return 1;
122 case '2':
123 if (graphicsOpts->multiplier != 1) {
124 return 0;
125 }
126 graphicsOpts->multiplier = 2;
127 graphicsOpts->width *= graphicsOpts->multiplier;
128 graphicsOpts->height *= graphicsOpts->multiplier;
129 return 1;
130 case '3':
131 if (graphicsOpts->multiplier != 1) {
132 return 0;
133 }
134 graphicsOpts->multiplier = 3;
135 graphicsOpts->width *= graphicsOpts->multiplier;
136 graphicsOpts->height *= graphicsOpts->multiplier;
137 return 1;
138 case '4':
139 if (graphicsOpts->multiplier != 1) {
140 return 0;
141 }
142 graphicsOpts->multiplier = 4;
143 graphicsOpts->width *= graphicsOpts->multiplier;
144 graphicsOpts->height *= graphicsOpts->multiplier;
145 return 1;
146 default:
147 return 0;
148 }
149}
150
151struct ARMDebugger* createDebugger(struct StartupOptions* opts) {
152 union DebugUnion {
153 struct ARMDebugger d;
154#ifdef USE_CLI_DEBUGGER
155 struct CLIDebugger cli;
156#endif
157#ifdef USE_GDB_STUB
158 struct GDBStub gdb;
159#endif
160 };
161
162 union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
163
164 switch (opts->debuggerType) {
165#ifdef USE_CLI_DEBUGGER
166 case DEBUGGER_CLI:
167 CLIDebuggerCreate(&debugger->cli);
168 break;
169#endif
170#ifdef USE_GDB_STUB
171 case DEBUGGER_GDB:
172 GDBStubCreate(&debugger->gdb);
173 GDBStubListen(&debugger->gdb, 2345, 0);
174 break;
175#endif
176 case DEBUGGER_NONE:
177 case DEBUGGER_MAX:
178 free(debugger);
179 return 0;
180 break;
181 }
182
183 return &debugger->d;
184}
185
186void usage(const char* arg0, const char* extraOptions) {
187 printf("usage: %s [option ...] file\n", arg0);
188 puts("\nGeneric options:");
189 puts(" -b, --bios FILE GBA BIOS file to use");
190#ifdef USE_CLI_DEBUGGER
191 puts(" -d, --debug Use command-line debugger");
192#endif
193#ifdef USE_GDB_STUB
194 puts(" -g, --gdb Start GDB session (default port 2345)");
195#endif
196 if (extraOptions) {
197 puts(extraOptions);
198 }
199}