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, struct GBAOptions* gbaOpts, int option, const char* arg);
42
43bool parseArguments(struct GBAArguments* opts, struct GBAOptions* gbaOpts, 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 if (gbaOpts->bios) {
62 free(gbaOpts->bios);
63 }
64 gbaOpts->bios = strdup(optarg);
65 break;
66 case 'D':
67 opts->dirmode = true;
68 break;
69#ifdef USE_CLI_DEBUGGER
70 case 'd':
71 if (opts->debuggerType != DEBUGGER_NONE) {
72 return false;
73 }
74 opts->debuggerType = DEBUGGER_CLI;
75 break;
76#endif
77#ifdef USE_GDB_STUB
78 case 'g':
79 if (opts->debuggerType != DEBUGGER_NONE) {
80 return false;
81 }
82 opts->debuggerType = DEBUGGER_GDB;
83 break;
84#endif
85 case 'l':
86 gbaOpts->logLevel = atoi(optarg);
87 break;
88 case 'p':
89 opts->patch = strdup(optarg);
90 break;
91 case 's':
92 gbaOpts->frameskip = atoi(optarg);
93 break;
94 default:
95 if (subparser) {
96 if (!subparser->parse(subparser, gbaOpts, ch, optarg)) {
97 return false;
98 }
99 }
100 break;
101 }
102 }
103 argc -= optind;
104 argv += optind;
105 if (argc != 1) {
106 return false;
107 }
108 opts->fname = strdup(argv[0]);
109 return true;
110}
111
112void freeArguments(struct GBAArguments* opts) {
113 free(opts->fname);
114 opts->fname = 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, struct GBAOptions* gbaOpts, int option, const char* arg) {
129 UNUSED(arg);
130 struct GraphicsOpts* graphicsOpts = parser->opts;
131 switch (option) {
132 case 'f':
133 gbaOpts->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 gbaOpts->width = VIDEO_HORIZONTAL_PIXELS * graphicsOpts->multiplier;
144 gbaOpts->height = VIDEO_VERTICAL_PIXELS * graphicsOpts->multiplier;
145 return true;
146 default:
147 return false;
148 }
149}
150
151struct ARMDebugger* createDebugger(struct GBAArguments* 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}