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