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 GBAConfig* config, int option, const char* arg);
42
43bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, 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 GBAConfigSetDefaultValue(config, "bios", 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 GBAConfigSetDefaultValue(config, "logLevel", optarg);
84 break;
85 case 'p':
86 opts->patch = strdup(optarg);
87 break;
88 case 's':
89 GBAConfigSetDefaultValue(config, "frameskip", optarg);
90 break;
91 default:
92 if (subparser) {
93 if (!subparser->parse(subparser, config, 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 freeArguments(struct GBAArguments* opts) {
110 free(opts->fname);
111 opts->fname = 0;
112
113 free(opts->patch);
114 opts->patch = 0;
115}
116
117void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
118 parser->usage = GRAPHICS_USAGE;
119 parser->opts = opts;
120 parser->parse = _parseGraphicsArg;
121 parser->extraOptions = GRAPHICS_OPTIONS;
122 opts->multiplier = 0;
123}
124
125bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) {
126 UNUSED(arg);
127 struct GraphicsOpts* graphicsOpts = parser->opts;
128 switch (option) {
129 case 'f':
130 GBAConfigSetDefaultIntValue(config, "fullscreen", 1);
131 return true;
132 case '1':
133 case '2':
134 case '3':
135 case '4':
136 if (graphicsOpts->multiplier) {
137 return false;
138 }
139 graphicsOpts->multiplier = option - '0';
140 GBAConfigSetDefaultIntValue(config, "width", VIDEO_HORIZONTAL_PIXELS * graphicsOpts->multiplier);
141 GBAConfigSetDefaultIntValue(config, "height", VIDEO_VERTICAL_PIXELS * graphicsOpts->multiplier);
142 return true;
143 default:
144 return false;
145 }
146}
147
148struct ARMDebugger* createDebugger(struct GBAArguments* opts) {
149 union DebugUnion {
150 struct ARMDebugger d;
151#ifdef USE_CLI_DEBUGGER
152 struct CLIDebugger cli;
153#endif
154#ifdef USE_GDB_STUB
155 struct GDBStub gdb;
156#endif
157 };
158
159 union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
160
161 switch (opts->debuggerType) {
162#ifdef USE_CLI_DEBUGGER
163 case DEBUGGER_CLI:
164 CLIDebuggerCreate(&debugger->cli);
165 break;
166#endif
167#ifdef USE_GDB_STUB
168 case DEBUGGER_GDB:
169 GDBStubCreate(&debugger->gdb);
170 GDBStubListen(&debugger->gdb, 2345, 0);
171 break;
172#endif
173 case DEBUGGER_NONE:
174 case DEBUGGER_MAX:
175 free(debugger);
176 return 0;
177 break;
178 }
179
180 return &debugger->d;
181}
182
183void usage(const char* arg0, const char* extraOptions) {
184 printf("usage: %s [option ...] file\n", arg0);
185 puts("\nGeneric options:");
186 puts(" -b, --bios FILE GBA BIOS file to use");
187#ifdef USE_CLI_DEBUGGER
188 puts(" -d, --debug Use command-line debugger");
189#endif
190#ifdef USE_GDB_STUB
191 puts(" -g, --gdb Start GDB session (default port 2345)");
192#endif
193 puts(" -p, --patch Apply a specified patch file when running");
194 puts(" -s, --frameskip N Skip every N frames");
195 if (extraOptions) {
196 puts(extraOptions);
197 }
198}