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#include "gba/gba-cli.h"
8#endif
9
10#ifdef USE_GDB_STUB
11#include "debugger/gdb-stub.h"
12#endif
13
14#include "gba/gba-video.h"
15
16#include <fcntl.h>
17#include <getopt.h>
18
19#define GRAPHICS_OPTIONS "1234f"
20#define GRAPHICS_USAGE \
21 "\nGraphics options:\n" \
22 " -1 1x viewport\n" \
23 " -2 2x viewport\n" \
24 " -3 3x viewport\n" \
25 " -4 4x viewport\n" \
26 " -f Start full-screen"
27
28static const struct option _options[] = {
29 { "bios", required_argument, 0, 'b' },
30 { "dirmode", required_argument, 0, 'D' },
31 { "frameskip", required_argument, 0, 's' },
32#ifdef USE_CLI_DEBUGGER
33 { "debug", no_argument, 0, 'd' },
34#endif
35#ifdef USE_GDB_STUB
36 { "gdb", no_argument, 0, 'g' },
37#endif
38 { "patch", required_argument, 0, 'p' },
39 { 0, 0, 0, 0 }
40};
41
42bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg);
43
44bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser) {
45 int ch;
46 char options[64] =
47 "b:Dl:p:s:"
48#ifdef USE_CLI_DEBUGGER
49 "d"
50#endif
51#ifdef USE_GDB_STUB
52 "g"
53#endif
54 ;
55 if (subparser && 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 GBAConfigSetDefaultValue(config, "bios", optarg);
63 break;
64 case 'D':
65 opts->dirmode = true;
66 break;
67#ifdef USE_CLI_DEBUGGER
68 case 'd':
69 if (opts->debuggerType != DEBUGGER_NONE) {
70 return false;
71 }
72 opts->debuggerType = DEBUGGER_CLI;
73 break;
74#endif
75#ifdef USE_GDB_STUB
76 case 'g':
77 if (opts->debuggerType != DEBUGGER_NONE) {
78 return false;
79 }
80 opts->debuggerType = DEBUGGER_GDB;
81 break;
82#endif
83 case 'l':
84 GBAConfigSetDefaultValue(config, "logLevel", optarg);
85 break;
86 case 'p':
87 opts->patch = strdup(optarg);
88 break;
89 case 's':
90 GBAConfigSetDefaultValue(config, "frameskip", optarg);
91 break;
92 default:
93 if (subparser) {
94 if (!subparser->parse(subparser, config, ch, optarg)) {
95 return false;
96 }
97 }
98 break;
99 }
100 }
101 argc -= optind;
102 argv += optind;
103 if (argc != 1) {
104 return false;
105 }
106 opts->fname = strdup(argv[0]);
107 return true;
108}
109
110void freeArguments(struct GBAArguments* opts) {
111 free(opts->fname);
112 opts->fname = 0;
113
114 free(opts->patch);
115 opts->patch = 0;
116}
117
118void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
119 parser->usage = GRAPHICS_USAGE;
120 parser->opts = opts;
121 parser->parse = _parseGraphicsArg;
122 parser->extraOptions = GRAPHICS_OPTIONS;
123 opts->multiplier = 0;
124}
125
126bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) {
127 UNUSED(arg);
128 struct GraphicsOpts* graphicsOpts = parser->opts;
129 switch (option) {
130 case 'f':
131 GBAConfigSetDefaultIntValue(config, "fullscreen", 1);
132 return true;
133 case '1':
134 case '2':
135 case '3':
136 case '4':
137 if (graphicsOpts->multiplier) {
138 return false;
139 }
140 graphicsOpts->multiplier = option - '0';
141 GBAConfigSetDefaultIntValue(config, "width", VIDEO_HORIZONTAL_PIXELS * graphicsOpts->multiplier);
142 GBAConfigSetDefaultIntValue(config, "height", VIDEO_VERTICAL_PIXELS * graphicsOpts->multiplier);
143 return true;
144 default:
145 return false;
146 }
147}
148
149struct ARMDebugger* createDebugger(struct GBAArguments* opts, struct GBAThread* context) {
150#ifndef USE_CLI_DEBUGGER
151 UNUSED(context);
152#endif
153 union DebugUnion {
154 struct ARMDebugger d;
155#ifdef USE_CLI_DEBUGGER
156 struct CLIDebugger cli;
157#endif
158#ifdef USE_GDB_STUB
159 struct GDBStub gdb;
160#endif
161 };
162
163 union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
164
165 switch (opts->debuggerType) {
166#ifdef USE_CLI_DEBUGGER
167 case DEBUGGER_CLI:
168 CLIDebuggerCreate(&debugger->cli);
169 struct GBACLIDebugger* gbaDebugger = GBACLIDebuggerCreate(context);
170 CLIDebuggerAttachSystem(&debugger->cli, &gbaDebugger->d);
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 puts(" -p, --patch Apply a specified patch file when running");
200 puts(" -s, --frameskip N Skip every N frames");
201 if (extraOptions) {
202 puts(extraOptions);
203 }
204}