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/banks_print.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 2020
      4 
      5 #include <stdio.h>
      6 #include <string.h>
      7 #include <stdlib.h>
      8 #include <stdbool.h>
      9 #include <stdint.h>
     10 
     11 #include "common.h"
     12 #include "logging.h"
     13 #include "list.h"
     14 #include "banks.h"
     15 #include "banks_print.h"
     16 #include "banks_color.h"
     17 
     18 
     19 #ifdef _WIN32
     20   #ifndef _WIN32
     21      #define __WIN32__
     22   #endif
     23 #endif
     24 
     25 
     26 
     27 // Ascii art style characters
     28 // Print a block character to stdout based on the percentage used (int 0 - 100)
     29 static void print_graph_char_asciistyle(uint32_t perc_used) {
     30 
     31     #ifdef __WIN32__
     32         // https://en.wikipedia.org/wiki/Code_page_437
     33         // https://sourceforge.net/p/mingw/mailman/message/14065664/
     34         // Code Page 437 (appears to be default for windows console,
     35         if      (perc_used >= 95) fprintf(stdout, "%c", 219u); // Full  Shade Block
     36         else if (perc_used >= 75) fprintf(stdout, "%c", 178u); // Dark  Shade Block
     37         else if (perc_used >= 50) fprintf(stdout, "%c", 177u); // Med   Shade Block
     38         else if (perc_used >= 25) fprintf(stdout, "%c", 176u); // Light Shade Block
     39         else                      fprintf(stdout, "_"); // ".");
     40 
     41         // All Block characters
     42         // if      (perc_used >= 99) fprintf(stdout, "%c", 219u); // Full  Shade Block
     43         // else if (perc_used >= 75) fprintf(stdout, "%c", 178u); // Dark  Shade Block
     44         // else if (perc_used >= 25) fprintf(stdout, "%c", 177u); // Med   Shade Block
     45         // else                      fprintf(stdout, "%c", 176u); // Light Shade Block
     46 
     47 
     48     #else // Non-Windows
     49         // https://www.fileformat.info/info/unicode/block/block_elements/utf8test.htm
     50         // https://www.fileformat.info/info/unicode/char/2588/index.htm
     51         if      (perc_used >= 95) fprintf(stdout, "%s", u8"\xE2\x96\x88"); // Full         Block in UTF-8 0xE2 0x96 0x88 (e29688)
     52         else if (perc_used >= 75) fprintf(stdout, "%s", u8"\xE2\x96\x93"); // Dark Shade   Block in UTF-8 0xE2 0x96 0x93 (e29693)
     53         else if (perc_used >= 50) fprintf(stdout, "%s", u8"\xE2\x96\x92"); // Med Shade    Block in UTF-8 0xE2 0x96 0x92 (e29692)
     54         else if (perc_used >= 25) fprintf(stdout, "%s", u8"\xE2\x96\x91"); // Light Shade  Block in UTF-8 0xE2 0x96 0x91 (e29691)
     55         else                      fprintf(stdout, "%s", u8"_"); // u8".");
     56 
     57         // All Blocks characters
     58         // if      (perc_used >= 95) fprintf(stdout, "%s", u8"\xE2\x96\x88"); // Full         Block in UTF-8 0xE2 0x96 0x88 (e29688)
     59         // else if (perc_used >= 75) fprintf(stdout, "%s", u8"\xE2\x96\x93"); // Dark Shade   Block in UTF-8 0xE2 0x96 0x93 (e29693)
     60         // else if (perc_used >= 25) fprintf(stdout, "%s", u8"\xE2\x96\x92"); // Med Shade    Block in UTF-8 0xE2 0x96 0x92 (e29692)
     61         // else                      fprintf(stdout, "%s", u8"\xE2\x96\x91"); // Light Shade  Block in UTF-8 0xE2 0x96 0x91 (e29691)
     62     #endif
     63 }
     64 
     65 
     66 // Standard character style
     67 // Print a block character to stdout based on the percentage used (int 0 - 100)
     68 static void print_graph_char_standard(uint32_t perc_used) {
     69 
     70     char ch;
     71 
     72     if (perc_used > 95)      ch = '#';
     73     else if (perc_used > 25) ch = '-';
     74     else                     ch = '.';
     75     fprintf(stdout, "%c", ch);
     76 }
     77 
     78 
     79 // Prints a graph for the bank
     80 // Each character represents an arbitrary amount based on the bank size
     81 static void bank_print_graph(bank_item * p_bank, uint32_t num_chars) {
     82 
     83     float bytes_per_char = p_bank->size_total / num_chars;
     84     unsigned int perc_used;
     85     uint32_t bucket_start, bucket_end;
     86     uint32_t bucket_id;
     87     uint32_t bucket_buf_size = num_chars * sizeof(uint32_t);
     88 
     89     uint32_t * p_buckets = (uint32_t *)malloc(bucket_buf_size);
     90     if (p_buckets == NULL) {
     91         log_error("Error: Failed to allocate buffer for graph!\n");
     92         return;
     93     }
     94     memset(p_buckets, 0, bucket_buf_size);
     95 
     96     bank_areas_split_to_buckets(p_bank, p_bank->start, p_bank->size_total, num_chars, p_buckets);
     97 
     98     for (bucket_id = 0; bucket_id <= (num_chars - 1); bucket_id++) {
     99 
    100         // Calculate range size this way so it matches the slightly variable bucket size.
    101         // See bank_areas_split_to_buckets() for details
    102         bucket_start = (uint32_t)(bytes_per_char * (float)bucket_id) + p_bank->start;
    103         bucket_end   = (uint32_t)((bytes_per_char * ((float)bucket_id + 1.0)) - 1.0) + p_bank->start;
    104 
    105         perc_used = (uint32_t)((float)p_buckets[bucket_id] * 100.0) / ((bucket_end - bucket_start) + 1);
    106 
    107         // Non-ascii style output
    108         if (!get_option_display_asciistyle())
    109             print_graph_char_standard(perc_used);
    110         else
    111             print_graph_char_asciistyle(perc_used);
    112 
    113         // Periodic line break if needed (for multi-line large graphs)
    114         if (((bucket_id + 1) % 64) == 0)
    115             fprintf(stdout, "\n");
    116     }
    117 
    118     if (p_buckets)
    119         free(p_buckets);
    120 }
    121 
    122 
    123 // Show a large usage graph for each bank
    124 // Currently 16 bytes per character
    125 static void banklist_print_large_graph(list_type * p_bank_list) {
    126 
    127     bank_item * banks = (bank_item *)p_bank_list->p_array;
    128     int c;
    129 
    130         for (c = 0; c < p_bank_list->count; c++) {
    131 
    132             fprintf(stdout,"\n\nStart: %s  ",banks[c].name); // Name
    133             fprintf(stdout,"0x%04X -> 0x%04X",banks[c].start,
    134                                               banks[c].end); // Address Start -> End
    135             fprintf(stdout,"\n"); // Name
    136 
    137             uint32_t bytes_per_char = LARGEGRAPH_BYTES_PER_CHAR;
    138 
    139             // Scale large graph unit size by number of banks it uses for banked items
    140             // (factoring in whether bank start is 0 or 1 based)
    141             if (option_summarized_mode)
    142                 bytes_per_char *= ((banks[c].bank_num - banks[c].base_bank_num) + 1);
    143 
    144             bank_print_graph(&banks[c], banks[c].size_total / bytes_per_char);
    145 
    146             fprintf(stdout,"End: %s\n",banks[c].name); // Name
    147         }
    148 }
    149 
    150 
    151 // Display all areas for a bank
    152 static void bank_print_area(bank_item *p_bank) {
    153 
    154     area_item * areas;
    155     int b;
    156     int hidden_count = 0;
    157     uint32_t hidden_total = 0;
    158 
    159     for(b = 0; b < p_bank->area_list.count; b++) {
    160 
    161         // Load the area list for the bank
    162         areas = (area_item *)p_bank->area_list.p_array;
    163 
    164         if (b == 0) {
    165             fprintf(stdout,"|\n");
    166 
    167             // Only show sub column headers for CDB output since there are a lot more areas
    168             if (get_option_input_source() == OPT_INPUT_SRC_CDB)
    169                 fprintf(stdout,
    170                            "| Name                            Start  -> End      Size \n"
    171                            "| ---------------------           ----------------   -----\n");
    172         }
    173 
    174         // Don't display headers unless requested
    175         if ((banks_display_headers) || !(strstr(areas[b].name,"HEADER"))) {
    176 
    177             // Optionally hide areas below a given size
    178             if (areas[b].length >= get_option_area_hide_size()) {
    179 
    180                 fprintf(stdout,"+ %-32s", areas[b].name);           // Name
    181                 fprintf(stdout,"0x%04X -> 0x%04X",areas[b].start,
    182                                                   areas[b].end); // Address Start -> End
    183                 fprintf(stdout,"%8d", areas[b].length);
    184                 fprintf(stdout,"\n");
    185             } else {
    186                 hidden_count++;
    187                 hidden_total += areas[b].length;
    188             }
    189         }
    190     }
    191     if (hidden_count > 0)
    192         fprintf(stdout,"+ (%d items < %d hidden = %d total bytes)\n",
    193                         hidden_count, get_option_area_hide_size(), hidden_total);
    194 
    195     fprintf(stdout,"\n");
    196 }
    197 
    198 
    199 static void bank_print_info(bank_item *p_bank) {
    200 
    201     bank_render_color(p_bank, PRINT_REGION_ROW_START);
    202     fprintf(stdout,"%-13s",p_bank->name); // Name
    203 
    204     bank_render_color(p_bank, PRINT_REGION_ROW_MIDDLE_START);
    205     // Skip some info if compact mode is enabled.
    206     if (!option_compact_mode) {
    207         fprintf(stdout,"0x%04X -> 0x%04X",p_bank->start, p_bank->end); // Address Start -> End
    208         fprintf(stdout,"%9d", p_bank->size_total);      // Total size
    209     }
    210     fprintf(stdout,"%9d", p_bank->size_used); // Used
    211 
    212     if (!option_compact_mode) {
    213         fprintf(stdout,"  %4d%%", bank_calc_percent_used(p_bank)); // Percent Used
    214     }
    215 
    216     bank_render_color(p_bank, PRINT_REGION_ROW_MIDDLE_END);
    217     fprintf(stdout,"%9d", (int32_t)p_bank->size_total - (int32_t)p_bank->size_used); // Free
    218     fprintf(stdout,"   %3d%%", bank_calc_percent_free(p_bank)); // Percent Free
    219 
    220     // Print a small bar graph if requested
    221     if (banks_display_minigraph) {
    222         fprintf(stdout, " |");
    223         bank_print_graph(p_bank, MINIGRAPH_SIZE);
    224         fprintf(stdout, "|");
    225     }
    226 
    227     bank_render_color(p_bank, PRINT_REGION_ROW_END);
    228 }
    229 
    230 
    231 // Display all banks along with space used.
    232 // Optionally show areas.
    233 void banklist_printall(list_type * p_bank_list) {
    234 
    235     bank_item * banks = (bank_item *)p_bank_list->p_array;
    236     int c;
    237     int b;
    238 
    239     #ifdef __WIN32__
    240         if (get_option_color_mode() != OPT_PRINT_COLOR_OFF)
    241             if (!colors_try_windows_enable_virtual_term_for_vt_codes())
    242                 log_warning("Warning: Failed to enable Windows virtual terminal sequences for color!\n");
    243     #endif
    244 
    245     fprintf(stdout, "\n");
    246     if (option_compact_mode) {
    247         fprintf(stdout,"Bank              Used     Free  Free%% \n"
    248                        "--------       -------  -------  -----\n");
    249     } else {
    250         fprintf(stdout,"Bank         Range                Size     Used  Used%%     Free  Free%% \n"
    251                        "--------     ----------------  -------  -------  -----  -------  -----\n");
    252     }
    253 
    254     // Print all banks
    255     for (c = 0; c < p_bank_list->count; c++) {
    256 
    257         if (!banks[c].hidden) {
    258             bank_print_info(&banks[c]);
    259             fprintf(stdout,"\n");
    260 
    261             if (get_option_area_sort() != OPT_AREA_SORT_HIDE) { // This is a hack-workaround, TODO:fixme
    262                 if (banks_display_areas)
    263                     bank_print_area(&banks[c]);
    264             }
    265         }
    266 
    267     } // End: Print all banks loop
    268 
    269         // Print a large graph per-bank if requested
    270     if (banks_display_largegraph)
    271         banklist_print_large_graph(p_bank_list);
    272 }
    273 
    274 
    275 // ====== JSON OUTPUT ======
    276 
    277 static void bank_print_info_json(bank_item *p_bank) {
    278 
    279     fprintf(stdout,"    {\n");
    280     fprintf(stdout,"    \"name\":         \"%s\",\n",p_bank->name);
    281 
    282     fprintf(stdout,"    \"type\":         \"%d\",\n",p_bank->bank_mem_type);
    283     fprintf(stdout,"    \"baseBankNum\":  \"%d\",\n",p_bank->base_bank_num);
    284     fprintf(stdout,"    \"isBanked\":     \"%d\",\n",p_bank->is_banked);
    285     fprintf(stdout,"    \"isMergedBank\": \"%d\",\n",p_bank->is_merged_bank);
    286 
    287     fprintf(stdout,"    \"rangeStart\":   \"%d\",\n",p_bank->start);
    288     fprintf(stdout,"    \"rangeEnd\":     \"%d\",\n",p_bank->end);
    289     fprintf(stdout,"    \"size\":         \"%d\",\n",p_bank->size_total);
    290     fprintf(stdout,"    \"used\":         \"%d\",\n",p_bank->size_used);
    291     fprintf(stdout,"    \"free\":         \"%d\",\n",(int32_t)p_bank->size_total - (int32_t)p_bank->size_used);
    292     fprintf(stdout,"    \"usedPercent\":  \"%d\",\n",bank_calc_percent_used(p_bank));
    293     fprintf(stdout,"    \"freePercent\":  \"%d\",\n",bank_calc_percent_free(p_bank));
    294 
    295     fprintf(stdout,"    \"miniGraph\":    \"");
    296         bank_print_graph(p_bank, MINIGRAPH_SIZE);
    297     fprintf(stdout,"\"\n");
    298 
    299     fprintf(stdout,"    }\n");
    300 }
    301 
    302 
    303 // Render all banks and space used as json format
    304 // Example:
    305 //
    306 // {"banks":
    307 //   [
    308 //     {
    309 //     "name":         "ROM_2/3",
    310 //     "type":         "0",
    311 //     "baseBankNum":  "0",
    312 //     "isBanked":     "1",
    313 //     "isMergedBank": "1",
    314 //     "rangeStart":   "0",
    315 //     "rangeEnd":     "32767",
    316 //     "size":         "65536",
    317 //     "used":         "24740",
    318 //     "free":         "40796",
    319 //     "usedPercent":  "38",
    320 //     "freePercent":  "62",
    321 //     "miniGraph":    "-##-...#######.............."
    322 //     }
    323 //     ,
    324 //     ...
    325 //   ]
    326 // }
    327 void banklist_printall_json(list_type * p_bank_list) {
    328 
    329     bank_item * banks = (bank_item *)p_bank_list->p_array;
    330     int c;
    331     int b;
    332 
    333     // JSON array header
    334     fprintf(stdout,"{\"banks\":\n"
    335                    "  [\n");
    336 
    337     // Print each bank as an array object item
    338     for (c = 0; c < p_bank_list->count; c++) {
    339         if (!banks[c].hidden) {
    340             // Comma separator between array items
    341             if (c > 0) fprintf(stdout,"    ,\n");
    342 
    343             bank_print_info_json(&banks[c]);
    344         }
    345     }
    346 
    347     // JSON array footer
    348     fprintf(stdout,"  ]\n"
    349                    "}\n");
    350 }

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.