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