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 "gba/gba-video.h"
14
15#include <fcntl.h>
16#include <getopt.h>
17
18#define GRAPHICS_OPTIONS "1234f"
19#define GRAPHICS_USAGE \
20 "\nGraphics options:\n" \
21 " -1 1x viewport\n" \
22 " -2 2x viewport\n" \
23 " -3 3x viewport\n" \
24 " -4 4x viewport\n" \
25 " -f Start full-screen"
26
27static const struct option _options[] = {
28 { "bios", required_argument, 0, 'b' },
29 { "dirmode", required_argument, 0, 'D' },
30 { "frameskip", required_argument, 0, 's' },
31#ifdef USE_CLI_DEBUGGER
32 { "debug", no_argument, 0, 'd' },
33#endif
34#ifdef USE_GDB_STUB
35 { "gdb", no_argument, 0, 'g' },
36#endif
37 { "patch", required_argument, 0, 'p' },
38 { 0, 0, 0, 0 }
39};
40
41bool _parseGraphicsArg(struct SubParser* parser, int option, const char* arg);
42
43bool parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, struct SubParser* subparser) {
44 int ch;
45 char options[64] =
46 "b:Dl:p:s:"
47#ifdef USE_CLI_DEBUGGER
48 "d"
49#endif
50#ifdef USE_GDB_STUB
51 "g"
52#endif
53 ;
54 if (subparser && subparser->extraOptions) {
55 // TODO: modularize options to subparsers
56 strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
57 }
58 while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) {
59 switch (ch) {
60 case 'b':
61 opts->bios = strdup(optarg);
62 break;
63 case 'D':
64 opts->dirmode = true;
65 break;
66#ifdef USE_CLI_DEBUGGER
67 case 'd':
68 if (opts->debuggerType != DEBUGGER_NONE) {
69 return false;
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 false;
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->patch = strdup(optarg);
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 false;
95 }
96 }
97 break;
98 }
99 }
100 argc -= optind;
101 argv += optind;
102 if (argc != 1) {
103 return false;
104 }
105 opts->fname = strdup(argv[0]);
106 return true;
107}
108
109void freeOptions(struct StartupOptions* opts) {
110 free(opts->fname);
111 opts->fname = 0;
112
113 free(opts->bios);
114 opts->bios = 0;
115
116 free(opts->patch);
117 opts->patch = 0;
118}
119
120void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
121 parser->usage = GRAPHICS_USAGE;
122 parser->opts = opts;
123 parser->parse = _parseGraphicsArg;
124 parser->extraOptions = GRAPHICS_OPTIONS;
125 opts->multiplier = 0;
126}
127
128bool _parseGraphicsArg(struct SubParser* parser, int option, const char* arg) {
129 UNUSED(arg);
130 struct GraphicsOpts* graphicsOpts = parser->opts;
131 switch (option) {
132 case 'f':
133 graphicsOpts->fullscreen = 1;
134 return true;
135 case '1':
136 case '2':
137 case '3':
138 case '4':
139 if (graphicsOpts->multiplier) {
140 return false;
141 }
142 graphicsOpts->multiplier = option - '0';
143 graphicsOpts->width = VIDEO_HORIZONTAL_PIXELS * graphicsOpts->multiplier;
144 graphicsOpts->height = VIDEO_VERTICAL_PIXELS * graphicsOpts->multiplier;
145 return true;
146 default:
147 return false;
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 puts(" -p, --patch Apply a specified patch file when running");
197 puts(" -s, --frameskip N Skip every N frames");
198 if (extraOptions) {
199 puts(extraOptions);
200 }
201}