src/platform/commandline.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "commandline.h"
7
8#include "debugger/debugger.h"
9
10#ifdef USE_CLI_DEBUGGER
11#include "debugger/cli-debugger.h"
12#include "gba/gba-cli.h"
13#endif
14
15#ifdef USE_GDB_STUB
16#include "debugger/gdb-stub.h"
17#endif
18
19#include "gba/gba-video.h"
20
21#include <fcntl.h>
22#include <getopt.h>
23
24#define GRAPHICS_OPTIONS "1234f"
25#define GRAPHICS_USAGE \
26 "\nGraphics options:\n" \
27 " -1 1x viewport\n" \
28 " -2 2x viewport\n" \
29 " -3 3x viewport\n" \
30 " -4 4x viewport\n" \
31 " -f Start full-screen"
32
33static const struct option _options[] = {
34 { "bios", required_argument, 0, 'b' },
35 { "dirmode", required_argument, 0, 'D' },
36 { "frameskip", required_argument, 0, 's' },
37#ifdef USE_CLI_DEBUGGER
38 { "debug", no_argument, 0, 'd' },
39#endif
40#ifdef USE_GDB_STUB
41 { "gdb", no_argument, 0, 'g' },
42#endif
43 { "patch", required_argument, 0, 'p' },
44 { 0, 0, 0, 0 }
45};
46
47bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg);
48
49bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser) {
50 int ch;
51 char options[64] =
52 "b:Dl:p:s:"
53#ifdef USE_CLI_DEBUGGER
54 "d"
55#endif
56#ifdef USE_GDB_STUB
57 "g"
58#endif
59 ;
60 if (subparser && subparser->extraOptions) {
61 // TODO: modularize options to subparsers
62 strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
63 }
64 while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) {
65 switch (ch) {
66 case 'b':
67 GBAConfigSetDefaultValue(config, "bios", optarg);
68 break;
69 case 'D':
70 opts->dirmode = true;
71 break;
72#ifdef USE_CLI_DEBUGGER
73 case 'd':
74 if (opts->debuggerType != DEBUGGER_NONE) {
75 return false;
76 }
77 opts->debuggerType = DEBUGGER_CLI;
78 break;
79#endif
80#ifdef USE_GDB_STUB
81 case 'g':
82 if (opts->debuggerType != DEBUGGER_NONE) {
83 return false;
84 }
85 opts->debuggerType = DEBUGGER_GDB;
86 break;
87#endif
88 case 'l':
89 GBAConfigSetDefaultValue(config, "logLevel", optarg);
90 break;
91 case 'p':
92 opts->patch = strdup(optarg);
93 break;
94 case 's':
95 GBAConfigSetDefaultValue(config, "frameskip", optarg);
96 break;
97 default:
98 if (subparser) {
99 if (!subparser->parse(subparser, config, ch, optarg)) {
100 return false;
101 }
102 }
103 break;
104 }
105 }
106 argc -= optind;
107 argv += optind;
108 if (argc != 1) {
109 return false;
110 }
111 opts->fname = strdup(argv[0]);
112 return true;
113}
114
115void freeArguments(struct GBAArguments* opts) {
116 free(opts->fname);
117 opts->fname = 0;
118
119 free(opts->patch);
120 opts->patch = 0;
121}
122
123void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {
124 parser->usage = GRAPHICS_USAGE;
125 parser->opts = opts;
126 parser->parse = _parseGraphicsArg;
127 parser->extraOptions = GRAPHICS_OPTIONS;
128 opts->multiplier = 0;
129}
130
131bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) {
132 UNUSED(arg);
133 struct GraphicsOpts* graphicsOpts = parser->opts;
134 switch (option) {
135 case 'f':
136 GBAConfigSetDefaultIntValue(config, "fullscreen", 1);
137 return true;
138 case '1':
139 case '2':
140 case '3':
141 case '4':
142 if (graphicsOpts->multiplier) {
143 return false;
144 }
145 graphicsOpts->multiplier = option - '0';
146 GBAConfigSetDefaultIntValue(config, "width", VIDEO_HORIZONTAL_PIXELS * graphicsOpts->multiplier);
147 GBAConfigSetDefaultIntValue(config, "height", VIDEO_VERTICAL_PIXELS * graphicsOpts->multiplier);
148 return true;
149 default:
150 return false;
151 }
152}
153
154struct ARMDebugger* createDebugger(struct GBAArguments* opts, struct GBAThread* context) {
155#ifndef USE_CLI_DEBUGGER
156 UNUSED(context);
157#endif
158 union DebugUnion {
159 struct ARMDebugger d;
160#ifdef USE_CLI_DEBUGGER
161 struct CLIDebugger cli;
162#endif
163#ifdef USE_GDB_STUB
164 struct GDBStub gdb;
165#endif
166 };
167
168 union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
169
170 switch (opts->debuggerType) {
171#ifdef USE_CLI_DEBUGGER
172 case DEBUGGER_CLI:
173 CLIDebuggerCreate(&debugger->cli);
174 struct GBACLIDebugger* gbaDebugger = GBACLIDebuggerCreate(context);
175 CLIDebuggerAttachSystem(&debugger->cli, &gbaDebugger->d);
176 break;
177#endif
178#ifdef USE_GDB_STUB
179 case DEBUGGER_GDB:
180 GDBStubCreate(&debugger->gdb);
181 GDBStubListen(&debugger->gdb, 2345, 0);
182 break;
183#endif
184 case DEBUGGER_NONE:
185 case DEBUGGER_MAX:
186 free(debugger);
187 return 0;
188 break;
189 }
190
191 return &debugger->d;
192}
193
194void usage(const char* arg0, const char* extraOptions) {
195 printf("usage: %s [option ...] file\n", arg0);
196 puts("\nGeneric options:");
197 puts(" -b, --bios FILE GBA BIOS file to use");
198#ifdef USE_CLI_DEBUGGER
199 puts(" -d, --debug Use command-line debugger");
200#endif
201#ifdef USE_GDB_STUB
202 puts(" -g, --gdb Start GDB session (default port 2345)");
203#endif
204 puts(" -p, --patch Apply a specified patch file when running");
205 puts(" -s, --frameskip N Skip every N frames");
206 if (extraOptions) {
207 puts(extraOptions);
208 }
209}