git.y1.nz

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.