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