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