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