-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathromusage.c
More file actions
372 lines (311 loc) · 14.2 KB
/
Copy pathromusage.c
File metadata and controls
372 lines (311 loc) · 14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
// This is free and unencumbered software released into the public domain.
// For more information, please refer to <https://unlicense.org>
// bbbbbr 2024
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdint.h>
#include "common.h"
#include "logging.h"
#include "banks.h"
#include "banks_color.h"
#include "map_file.h"
#include "noi_file.h"
#include "ihx_file.h"
#include "cdb_file.h"
#include "rom_file.h"
#define VERSION "version 1.3.2"
enum {
HELP_FULL = 0,
HELP_BRIEF
};
void static display_cdb_warning(void);
void static display_help(int mode);
int handle_args(int argc, char * argv[]);
static bool matches_extension(char *, char *);
static void init(void);
void cleanup(void);
char filename_in[MAX_STR_LEN] = {'\0'};
int show_help_and_exit = false;
static void main_init(void) {
show_help_and_exit = false;
}
static void display_cdb_warning() {
printf("\n"
" ************************ NOTICE ************************ \n"
" .cdb output ONLY counts (most) data from C sources. \n"
" It cannot count functions and data from ASM and LIBs. \n"
" Bank totals may be incorrect/missing. (-nB to hide this) \n"
" ************************ NOTICE ************************ \n");
}
static void display_help(int mode) {
fprintf(stdout,
"romusage input_file.[map|noi|ihx|cdb|.gb[c]|.pocket|.duck|.gg|.sms] [options]\n"
VERSION", by bbbbbr\n"
"\n"
"Options\n"
"-h : Show this help\n"
"-p : Set platform (GBDK specific), \"-p:SMS_GG\" for SMS/Game Gear, \"-p:NES1\" for NES\n"
"\n"
"-a : Show Areas in each Bank. Optional sort by, address:\"-aA\" or size:\"-aS\" \n"
"-g : Show a small usage graph per bank (-gA for ascii style)\n"
"-G : Show a large usage graph per bank (-GA for ascii style)\n"
"-B : Brief (summarized) output for banked regions. Auto scales max bank\n"
" shows [Region]_[Max Used Bank] / [auto-sized Max Bank Num]\n"
"-F : Force Max ROM and SRAM bank num for -B. (0 based) -F:ROM:SRAM (ex: -F:255:15)\n"
"\n"
"-m : Manually specify an Area -m:NAME:HEXADDR:HEXLENGTH\n"
"-e : Manually specify an Area that should not overlap -e:NAME:HEXADDR:HEXLENGTH\n"
"-b : Set hex bytes treated as Empty in ROM files (.gb/etc) -b:HEXVAL[...] (default FF)\n"
"-E : All areas are exclusive (except HEADERs), warn for any overlaps\n"
"-q : Quiet, no output except warnings and errors\n"
"-Q : Suppress output of warnings and errors\n"
"-R : Return error code for Area warnings and errors\n"
"\n"
"-sR : [Rainbow] Color output (-sRe for Row Ends, -sRd for Center Dimmed, -sRp %% based)\n"
"-sP : Custom Color Palette. Colon separated entries are decimal VT100 color codes\n"
" -sP:DEFAULT:ROM:VRAM:SRAM:WRAM:HRAM (section based color only)\n"
"-sC : Show Compact Output, hide non-essential columns\n"
"-sH : Show HEADER Areas (normally hidden)\n"
"-smROM : Show Merged ROM_0 and ROM_1 output (i.e. bare 32K ROM)\n"
"-smWRAM : Show Merged WRAM_0 and WRAM_1 output (i.e DMG/MGB not CGB)\n"
" -sm* compatible with banked ROM_x or WRAM_x when used with -B\n"
"-sJ : Show JSON output. Some options not applicable. When used, -Q recommended\n"
"-nB : Hide warning banner (for .cdb output)\n"
"-nA : Hide areas (shown by default in .cdb output)\n"
"-z : Hide areas smaller than SIZE -z:DECSIZE\n"
"-nMEM : Hide banks matching case sensitive substring (ex hide all RAM: -nMEM:RAM)\n"
"\n");
if (mode == HELP_FULL) {
fprintf(stdout,
"Use: Read a .map, .noi, .cdb or .ihx file to display area sizes\n"
"Example 1: \"romusage build/MyProject.map\"\n"
"Example 2: \"romusage build/MyProject.noi -a -e:STACK:DEFF:100 -e:SHADOW_OAM:C000:A0\"\n"
"Example 3: \"romusage build/MyProject.ihx -g\"\n"
"Example 4: \"romusage build/MyProject.map -q -R\"\n"
"Example 5: \"romusage build/MyProject.noi -sR -sP:90:32:90:35:33:36\"\n"
"Example 6: \"romusage build/MyProject.map -sRp -g -B -F:255:15 -smROM -smWRAM\"\n"
"Example 7: \"romusage build/MyProject.gb -g -b:FF:00\"\n"
"\n"
"Notes:\n"
" * GBDK / RGBDS map file format detection is automatic.\n"
" * Estimates are as close as possible, but may not be complete.\n"
" Unless specified with -m/-e they *do not* factor regions lacking\n"
" complete ranges in the Map/Noi/Ihx file, for example Shadow OAM and Stack.\n"
" * IHX files can only detect overlaps, not detect memory region overflows.\n"
" * CDB file output ONLY counts (most) data from C sources.\n"
" It cannot count functions and data from ASM and LIBs,\n"
" so bank totals may be incorrect/missing.\n"
" * GB/GBC/ROM files are just guessing, no promises.\n"
);
}
}
// Default options for Windows Drag and Drop recipient mode
void set_drag_and_drop_mode_defaults(void) {
set_option_color_mode(OPT_PRINT_COLOR_ROW_ENDS);
banks_output_show_minigraph(true);
set_option_summarized(true);
}
int handle_args(int argc, char * argv[]) {
int i;
bool filename_present = false;
if( argc < 2 ) {
display_help(HELP_FULL);
return false;
}
// Start at first optional argument ([0] is executable)
for (i = 1; i < argc; i++ ) {
if (strstr(argv[i], "-h") == argv[i]) {
display_help(HELP_FULL);
show_help_and_exit = true;
return true; // Don't parse further input when -h is used
} else if (strstr(argv[i], "-a") == argv[i]) {
banks_output_show_areas(true);
if (argv[i][2] == 'S') set_option_area_sort(OPT_AREA_SORT_SIZE_DESC);
else if (argv[i][2] == 'A') set_option_area_sort(OPT_AREA_SORT_ADDR_ASC);
} else if (strstr(argv[i], "-sR") == argv[i]) {
switch (argv[i][ + strlen("-sR")]) {
case 'p': set_option_percentage_based_color(true); break; // Turns on default color mode if not set
case 'e': set_option_color_mode(OPT_PRINT_COLOR_ROW_ENDS); break;
case 'd': set_option_color_mode(OPT_PRINT_COLOR_WHOLE_ROW_DIMMED); break;
case 'w': set_option_color_mode(OPT_PRINT_COLOR_WHOLE_ROW); break;
default: set_option_color_mode(OPT_PRINT_COLOR_DEFAULT); break;
}
} else if (strstr(argv[i], "-sP") == argv[i]) {
if (!set_option_custom_bank_colors(argv[i])) {
log_error("Malformed -sP custom color palette: %s\n\n", argv[i]);
// display_help();
return false;
}
} else if (strstr(argv[i], "-sH") == argv[i]) {
banks_output_show_headers(true);
} else if (strstr(argv[i], "-sC") == argv[i]) {
set_option_show_compact(true);
} else if (strstr(argv[i], "-sJ") == argv[i]) {
set_option_show_json(true);
} else if (strstr(argv[i], "-nB") == argv[i]) {
set_option_hide_banners(true);
} else if (strstr(argv[i], "-nA")) {
set_option_area_sort(OPT_AREA_SORT_HIDE);
} else if (strstr(argv[i], "-p:SMS_GG") == argv[i]) {
set_option_platform(OPT_PLAT_SMS_GG_GBDK);
} else if (strstr(argv[i], "-p:NES1") == argv[i]) {
set_option_platform(OPT_PLAT_NES_GBDK_1);
} else if (strstr(argv[i], "-g") == argv[i]) {
banks_output_show_minigraph(true);
if (argv[i][2] == 'A') set_option_display_asciistyle(true);
} else if (strstr(argv[i], "-G") == argv[i]) {
banks_output_show_largegraph(true);
if (argv[i][2] == 'A') set_option_display_asciistyle(true);
} else if (strstr(argv[i], "-E") == argv[i]) {
set_option_all_areas_exclusive(true);
} else if (strstr(argv[i], "-B") == argv[i]) {
set_option_summarized(true);
} else if (strstr(argv[i], "-F") == argv[i]) {
if (!set_option_displayed_bank_range(argv[i])) {
log_error("Malformed -F forced display max bank range\n\n");
// display_help();
return false;
}
} else if (strstr(argv[i], "-b") == argv[i]) {
if (!set_option_binary_rom_empty_values(argv[i] + strlen("-b"))) {
log_error("Malformed or no entries found -b set hex values treated as empty for ROM files: %s\n\n", argv[i]);
return false;
}
} else if (strstr(argv[i], "-smWRAM") == argv[i]) {
set_option_merged_banks(OPT_MERGED_BANKS_WRAM);
} else if (strstr(argv[i], "-smROM") == argv[i]) {
set_option_merged_banks(OPT_MERGED_BANKS_ROM);
} else if (strstr(argv[i], "-q") == argv[i]) {
set_option_quiet_mode(true);
} else if (strstr(argv[i], "-Q") == argv[i]) {
log_set_level(OUTPUT_LEVEL_QUIET);
} else if (strstr(argv[i], "-R") == argv[i]) {
set_option_error_on_warning(true);
} else if (strstr(argv[i], "-z:") == argv[i]) {
set_option_area_hide_size( strtol(argv[i] + 3, NULL, 10));
} else if (strstr(argv[i], "-nMEM:") == argv[i]) {
if (!set_option_banks_hide_add(argv[i] + strlen("-nMEM:"))) {
log_error("Adding memory region to hide failed: %s\n\n", argv[i]);
// display_help();
return false;
}
} else if ((strstr(argv[i], "-m") == argv[i]) ||
(strstr(argv[i], "-e") == argv[i])) {
if (!area_manual_queue(argv[i])) {
log_error("Malformed -m or -e manual area argument: %s\n\n", argv[i]);
// display_help();
return false;
}
} else if (argv[i][0] == '-') {
log_error("Error: Unknown argument: %s\n\n", argv[i]);
display_help(HELP_BRIEF);
return false;
}
// Copy input filename (if not preceded with option dash)
else if (argv[i][0] != '-') {
snprintf(filename_in, sizeof(filename_in), "%s", argv[i]);
filename_present = true;
}
}
if (filename_present) {
return true;
} else {
display_help(HELP_FULL);
show_help_and_exit = true;
return false;
}
}
// Case insensitive
static bool matches_extension(char * filename, char * extension) {
if (strlen(filename) >= strlen(extension)) {
char * str_ext = filename + (strlen(filename) - strlen(extension));
return (strncasecmp(str_ext, extension, strlen(extension)) == 0);
}
else
return false;
}
static void init(void) {
// The first two are for web mode which needs a reset between runs
main_init();
options_reset_all();
cdb_init();
noi_init();
banks_init();
romfile_init_defaults();
}
// Register as an exit handler
void cleanup(void) {
cdb_cleanup();
noi_cleanup();
banks_cleanup();
}
int main( int argc, char *argv[] ) {
int ret = EXIT_FAILURE; // Default to failure on exit
// Register cleanup with exit handler
atexit(cleanup);
init();
#ifdef DRAG_AND_DROP_MODE
// Non-interactive mode, set some reasonable default
set_drag_and_drop_mode_defaults();
#endif
if (handle_args(argc, argv)) {
banks_init_templates();
area_manual_apply_queued();
if (show_help_and_exit) {
ret = EXIT_SUCCESS;
}
else {
// detect file extension
if (matches_extension(filename_in, (char *)".noi")) {
if (noi_file_process_areas(filename_in)) {
banklist_finalize_and_show();
ret = EXIT_SUCCESS; // Exit with success
}
} else if (matches_extension(filename_in, (char *)".map")) {
if (map_file_process_areas(filename_in)) {
banklist_finalize_and_show();
ret = EXIT_SUCCESS; // Exit with success
}
} else if (matches_extension(filename_in, (char *)".ihx")) {
if (ihx_file_process_areas(filename_in)) {
banklist_finalize_and_show();
ret = EXIT_SUCCESS; // Exit with success
}
} else if (matches_extension(filename_in, (char *)".gb" ) ||
matches_extension(filename_in, (char *)".gbc" ) ||
matches_extension(filename_in, (char *)".sms" ) ||
matches_extension(filename_in, (char *)".gg" ) ||
matches_extension(filename_in, (char *)".pocket") ||
matches_extension(filename_in, (char *)".duck") ) {
// printf("ROM FILE\n");
if (rom_file_process(filename_in)) {
banklist_finalize_and_show();
ret = EXIT_SUCCESS; // Exit with success
}
} else if (matches_extension(filename_in, (char *)".cdb")) {
if (cdb_file_process_symbols(filename_in)) {
if (!get_option_hide_banners()) display_cdb_warning();
banklist_finalize_and_show();
if (!get_option_hide_banners()) display_cdb_warning();
ret = EXIT_SUCCESS; // Exit with success
}
} else {
log_error("Error: Incompatible file extension\n");
}
}
}
// if (ret == EXIT_FAILURE)
// printf("Problem with filename or unable to open file! %s\n", filename_in);
// Override exit code if was set during processing
if (get_exit_error())
ret = EXIT_FAILURE;
#ifdef DRAG_AND_DROP_MODE
// Wait for input to keep the console window open after processing
printf("\n\nPress Any Key to Continue\n");
getchar();
#endif
return ret;
}