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.