src/platform/commandline.c (view raw)
1#include "commandline.h"
2
3#include "debugger/debugger.h"
4
5#ifdef USE_CLI_DEBUGGER
6#include "debugger/cli-debugger.h"
7#endif
8
9#ifdef USE_GDB_STUB
10#include "debugger/gdb-stub.h"
11#endif
12
13#include <fcntl.h>
14#include <getopt.h>
15
16static const char* _defaultFilename = "test.rom";
17
18static const struct option _options[] = {
19 { "bios", 1, 0, 'b' },
20 { "frameskip", 1, 0, 's' },
21#ifdef USE_CLI_DEBUGGER
22 { "debug", 1, 0, 'd' },
23#endif
24#ifdef USE_GDB_STUB
25 { "gdb", 1, 0, 'g' },
26#endif
27 { 0, 0, 0, 0 }
28};
29
30int parseCommandArgs(struct StartupOptions* opts, int argc, char* const* argv, const char* extraOptions) {
31 memset(opts, 0, sizeof(*opts));
32 opts->fd = -1;
33 opts->biosFd = -1;
34 opts->width = 240;
35 opts->height = 160;
36
37 int multiplier = 1;
38 int ch;
39 char options[64] =
40 "b:s:"
41#ifdef USE_CLI_DEBUGGER
42 "d"
43#endif
44#ifdef USE_GDB_STUB
45 "g"
46#endif
47 ;
48 if (extraOptions) {
49 // TODO: modularize options to subparsers
50 strncat(options, extraOptions, sizeof(options) - strlen(options) - 1);
51 }
52 while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) {
53 switch (ch) {
54 case 'b':
55 opts->biosFd = open(optarg, O_RDONLY);
56 break;
57#ifdef USE_CLI_DEBUGGER
58 case 'd':
59 if (opts->debuggerType != DEBUGGER_NONE) {
60 return 0;
61 }
62 opts->debuggerType = DEBUGGER_CLI;
63 break;
64#endif
65 case 'f':
66 opts->fullscreen = 1;
67 break;
68#ifdef USE_GDB_STUB
69 case 'g':
70 if (opts->debuggerType != DEBUGGER_NONE) {
71 return 0;
72 }
73 opts->debuggerType = DEBUGGER_GDB;
74 break;
75#endif
76 case 's':
77 opts->frameskip = atoi(optarg);
78 break;
79 case 'S':
80 opts->perfDuration = atoi(optarg);
81 break;
82 case '2':
83 if (multiplier != 1) {
84 return 0;
85 }
86 multiplier = 2;
87 break;
88 case '3':
89 if (multiplier != 1) {
90 return 0;
91 }
92 multiplier = 3;
93 break;
94 case '4':
95 if (multiplier != 1) {
96 return 0;
97 }
98 multiplier = 4;
99 break;
100 default:
101 return 0;
102 }
103 }
104 argc -= optind;
105 argv += optind;
106 if (argc == 1) {
107 opts->fname = argv[0];
108 } else if (argc == 0) {
109 opts->fname = _defaultFilename;
110 } else {
111 return 0;
112 }
113 opts->fd = open(opts->fname, O_RDONLY);
114 opts->width *= multiplier;
115 opts->height *= multiplier;
116 return 1;
117}
118
119struct ARMDebugger* createDebugger(struct StartupOptions* opts) {
120 union DebugUnion {
121 struct ARMDebugger d;
122#ifdef USE_CLI_DEBUGGER
123 struct CLIDebugger cli;
124#endif
125#ifdef USE_GDB_STUB
126 struct GDBStub gdb;
127#endif
128 };
129
130 union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
131
132 switch (opts->debuggerType) {
133#ifdef USE_CLI_DEBUGGER
134 case DEBUGGER_CLI:
135 CLIDebuggerCreate(&debugger->cli);
136 break;
137#endif
138#ifdef USE_GDB_STUB
139 case DEBUGGER_GDB:
140 GDBStubCreate(&debugger->gdb);
141 GDBStubListen(&debugger->gdb, 2345, 0);
142 break;
143#endif
144 case DEBUGGER_NONE:
145 case DEBUGGER_MAX:
146 free(debugger);
147 return 0;
148 break;
149 }
150
151 return &debugger->d;
152}
153
154void usage(const char* arg0, const char* extraOptions) {
155 printf("usage: %s [option ...] file\n", arg0);
156 puts("\nGeneric options:");
157 puts(" -b, --bios FILE GBA BIOS file to use");
158#ifdef USE_CLI_DEBUGGER
159 puts(" -d, --debug Use command-line debugger");
160#endif
161#ifdef USE_GDB_STUB
162 puts(" -g, --gdb Start GDB session (default port 2345)");
163#endif
164 if (extraOptions) {
165 puts(extraOptions);
166 }
167}