git.y1.nz

gbdk-2020

GameBoy Development Kit
download: https://git.y1.nz/archives/gbdk.tar.gz
README | Files | Log | Refs | LICENSE

gbdk-support/bankpack/obj_data.c

      1 
      2 // This is free and unencumbered software released into the public domain.
      3 // For more information, please refer to <https://unlicense.org>
      4 // bbbbbr 2020
      5 
      6 #include <stdio.h>
      7 #include <string.h>
      8 #include <stdlib.h>
      9 #include <unistd.h>
     10 #include <stdbool.h>
     11 #include <stdint.h>
     12 
     13 #include "common.h"
     14 #include "list.h"
     15 #include "files.h"
     16 #include "options.h"
     17 #include "obj_data.h"
     18 
     19 
     20 static bool bank_check_mbc1_ok(uint32_t bank_num);
     21 static void bank_update_assigned_minmax(uint16_t bank_num);
     22 static void bank_update_all_max(uint16_t bank_num);
     23 static void bank_add_area(bank_item * p_bank, uint16_t bank_num, area_item * p_area);
     24 static void bank_check_area_size(area_item * p_area);
     25 static void banks_assign_area(area_item * p_area);
     26 static int area_item_compare(const void* a, const void* b);
     27 static void areas_sort(void);
     28 static bool symbol_banked_check_rewrite_ok(char *, uint32_t);
     29 
     30 
     31 
     32 list_type banklist;
     33 list_type arealist;
     34 list_type symbollist;
     35 list_type symbol_matchlist;
     36 
     37 uint16_t bank_limit_rom_min = BANK_NUM_ROM_DEFAULT;
     38 uint16_t bank_limit_rom_max = BANK_NUM_ROM_MAX;
     39 
     40 
     41 uint16_t bank_assigned_rom_min = BANK_NUM_ROM_MAX;
     42 uint16_t bank_assigned_rom_max = 0;
     43 uint16_t bank_assigned_rom_max_alltypes = 0;
     44 
     45 
     46 void obj_data_init(void) {
     47     int c;
     48     bank_item newbank;
     49 
     50     list_init(&banklist,      sizeof(bank_item));
     51     list_init(&arealist,      sizeof(area_item));
     52     list_init(&symbollist,    sizeof(symbol_item));
     53     list_init(&symbol_matchlist, sizeof(symbol_match_item));
     54 
     55     // Pre-populate bank list with max number of banks
     56     // to allow handling fixed-bank (non-autobank) areas
     57     newbank.size = newbank.free = BANK_SIZE_ROM;
     58     newbank.reserved = 0;
     59     newbank.type = BANK_TYPE_UNSET;
     60     newbank.item_count = 0;
     61     for (c=0; c < BANK_ROM_TOTAL; c++)
     62         list_additem(&banklist, &newbank);
     63 
     64     // Add default symbol match and replace
     65     symbol_match_add("___bank_");
     66 }
     67 
     68 
     69 void obj_data_cleanup(void) {
     70     list_cleanup(&banklist);
     71     list_cleanup(&arealist);
     72     list_cleanup(&symbollist);
     73     list_cleanup(&symbol_matchlist);
     74 }
     75 
     76 
     77 // Add a symbol to the match and replace list
     78 void symbol_match_add(char * symbol_str) {
     79 
     80     symbol_match_item newmatch;
     81 
     82     if (snprintf(newmatch.name, sizeof(newmatch.name), "%s", symbol_str) > sizeof(newmatch.name))
     83         printf("BankPack: Warning: truncated symbol match string to:%s\n",newmatch.name);
     84 
     85     list_additem(&symbol_matchlist, &newmatch);
     86 }
     87 
     88 
     89 
     90 // Add an area into the pool of areas to assign (if it's banked CODE)
     91 int areas_add(char * area_str, uint32_t file_id) {
     92 
     93     area_item newarea;
     94 
     95     // Only match areas which are banked ("_CODE_" vs "_CODE") and ("_LIT_")
     96     if (AREA_LINE_RECORDS == sscanf(area_str,"A _CODE _%3d size %4x flags %*4x addr %*4x",
     97                                     &newarea.bank_num_in, &newarea.size)) {
     98         newarea.type = BANK_TYPE_CODE;
     99     }
    100     else if (AREA_LINE_RECORDS == sscanf(area_str,"A _LIT_%3d size %4x flags %*4x addr %*4x",
    101                                         &newarea.bank_num_in, &newarea.size)) {
    102         newarea.type = BANK_TYPE_LIT_EXCLUSIVE;
    103     }
    104     else
    105         return false;
    106 
    107     // Only process areas with (size > 0)
    108     if (newarea.size > 0) {
    109         if (newarea.type == BANK_TYPE_LIT_EXCLUSIVE)
    110             sprintf(newarea.name, "_LIT_");  // Hardwired to _LIT_ for now
    111         else
    112             sprintf(newarea.name, "_CODE_"); // Hardwired to _CODE_ for now
    113         newarea.file_id = file_id;
    114         newarea.bank_num_out = BANK_NUM_UNASSIGNED;
    115         list_additem(&arealist, &newarea);
    116         return true;
    117     } else
    118         return false;
    119 }
    120 
    121 
    122 // Check and add a symbol record (if it's banked CODE)
    123 int symbols_add(char * symbol_str, uint32_t file_id, unsigned int obj_file_format) {
    124 
    125     symbol_item newsymbol;
    126 
    127     const char * s_def_matches[] = {[OBJ_FILE_XL3_24BIT_ADDR] = "S %" TOSTR(OBJ_NAME_MAX_STR_LEN) "s Def00%4x",
    128                                     [OBJ_FILE_XL4_32BIT_ADDR] = "S %" TOSTR(OBJ_NAME_MAX_STR_LEN) "s Def0000%4x"};
    129     if (obj_file_format >= OBJ_FILE_UNKNOWN) return false;
    130 
    131     if (SYMBOL_LINE_RECORDS == sscanf(symbol_str, s_def_matches[obj_file_format], newsymbol.name, &newsymbol.bank_num_in)) {
    132 
    133         // Symbols that start with b_ store the bank num for the matching symbol without 'b'
    134         newsymbol.is_banked_def          = (newsymbol.name[0] == 'b');
    135         newsymbol.file_id                = file_id;
    136         newsymbol.found_matching_symbol  = false;
    137 
    138         // Don't add banked symbols if they're not set to the autobank bank #
    139         if ((newsymbol.is_banked_def) && (newsymbol.bank_num_in != BANK_NUM_AUTO))
    140             return false;
    141 
    142         list_additem(&symbollist, &newsymbol);
    143         return true;
    144     }
    145     return false;
    146 }
    147 
    148 
    149 // Track Min/Max assigned banks used
    150 static void bank_update_assigned_minmax(uint16_t bank_num) {
    151 
    152     if (bank_num > bank_assigned_rom_max)
    153         bank_assigned_rom_max = bank_num;
    154 
    155     if (bank_num < bank_assigned_rom_min)
    156         bank_assigned_rom_min = bank_num;
    157 
    158     bank_update_all_max(bank_num);
    159 }
    160 
    161 
    162 // Tracks Max bank for *all* banks used, including fixed banks outside max limits
    163 static void bank_update_all_max(uint16_t bank_num) {
    164 
    165     if (bank_num > bank_assigned_rom_max_alltypes)
    166         bank_assigned_rom_max_alltypes = bank_num;
    167 }
    168 
    169 
    170 // Add an area to a bank.
    171 // It should only error out when there isn't enough
    172 // room with a fixed-bank area (non-autobank)
    173 static void bank_add_area(bank_item * p_bank, uint16_t bank_num, area_item * p_area) {
    174 
    175     // Make sure there is room and then update free space
    176     if (p_area->size > p_bank->free) {
    177 
    178         // Trying to add an auto-bank area to a full bank should be prevented by previous tests, but just in case
    179         if (p_area->bank_num_in == BANK_NUM_AUTO) {
    180             printf("BankPack: ERROR! Auto-banked Area %s, bank %d, size %d won't fit in assigned bank %d (%d bytes free, %d bytes reserved)\n",
    181                     p_area->name, p_area->bank_num_in, p_area->size, bank_num, p_bank->free, p_bank->reserved);
    182             exit(EXIT_FAILURE);
    183         } else {
    184             // Only warn for fixed bank areas. Don't exit and add the area anyway
    185             printf("BankPack: Warning: Fixed-bank Area %s, bank %d, size %d won't fit in assigned bank %d (%d bytes free, %d bytes reserved)\n",
    186                     p_area->name, p_area->bank_num_in, p_area->size, bank_num, p_bank->free, p_bank->reserved);
    187         }
    188 
    189         // Force bank space to zero, subtracting at this point would overflow
    190         p_bank->free = 0;
    191     } else
    192         p_bank->free -= p_area->size;
    193 
    194     // Copy bank type from area: some platforms (sms) don't allow mixing of area types in the same bank
    195     // Assign outbound bank number for the area
    196     p_bank->type = p_area->type;
    197     p_bank->item_count++;
    198     p_area->bank_num_out = bank_num;
    199     bank_update_assigned_minmax(bank_num);
    200 }
    201 
    202 
    203 // Check to see if the specified bank is allowed with MBC1
    204 static bool bank_check_mbc1_ok(uint32_t bank_num) {
    205 
    206     if ((bank_num == 0x20U) || (bank_num == 0x40U) || (bank_num == 0x60U))
    207         return false;
    208     else
    209         return true;
    210 }
    211 
    212 
    213 // Checks to make sure area size is not larger than an entire bank
    214 static void bank_check_area_size(area_item * p_area) {
    215     if (p_area->size > BANK_SIZE_ROM) {
    216         printf("BankPack: ERROR! Area %s, bank %d, size %d is too large for bank size %d (file %s)\n",
    217                 p_area->name, p_area->bank_num_in, p_area->size, BANK_SIZE_ROM, file_get_name_in_by_id(p_area->file_id));
    218         exit(EXIT_FAILURE);
    219     }
    220 }
    221 
    222 
    223 // Display a error message about bank mixing
    224 static void bank_report_mixed_area_error(bank_item * p_bank, uint16_t bank_num, area_item * p_area) {
    225 
    226     printf("BankPack: ERROR! Bank %d already assigned different area type.\n"
    227            "  Can't mix _CODE_ and _LIT_ areas in the same bank for this platform.\n"
    228            "  Rejecting: Area %s, bank %d, file:%s\n",
    229            p_area->bank_num_in, p_area->name, bank_num, file_get_name_in_by_id(p_area->file_id));
    230 
    231     if (option_get_verbose())
    232         banks_show();
    233 }
    234 
    235 
    236 // Checks whether mixing area types in the same bank should be rejected
    237 static bool bank_check_mixed_area_types_ok(bank_item * p_bank, uint16_t bank_num, area_item * p_area) {
    238 
    239     // Don't allow mixing of _CODE_ and _LIT_ for sms/gg ports
    240     // If one type has already been assigned to the bank, lock others out
    241     if ((option_get_platform() == PLATFORM_SMS) &&
    242         (p_bank->type != BANK_TYPE_UNSET) &&
    243         (p_area->type != p_bank->type))
    244         return false;
    245     else
    246         return true;
    247 }
    248 
    249 
    250 // Verify that a bank is available for an area
    251 // Checks: Size, MBC Availability, Mixed area restrictions
    252 static bool bank_check_ok_for_area(uint16_t bank_num, area_item * p_area, bank_item * banks) {
    253 
    254     // Check for MBC bank restrictions
    255     if ((option_get_mbc_type() != MBC_TYPE_MBC1) || (bank_check_mbc1_ok(bank_num))) {
    256         // Check for allowed area mixing if needed
    257         if (bank_check_mixed_area_types_ok(&banks[bank_num], bank_num, p_area)) {
    258             // Make sure there is enough space for the area
    259             if (p_area->size <= banks[bank_num].free) {
    260                 return true;
    261             }
    262         }
    263     }
    264 
    265     return false;
    266 }
    267 
    268 
    269 // Assign areas randomly and distributed as sparsely as possible
    270 static bool banks_assign_area_random(area_item * p_area, bank_item * banks) {
    271 
    272     uint16_t bank_num;
    273     uint16_t item_count_min = BANK_ITEM_COUNT_MAX;
    274     uint16_t list_of_banks[BANK_ROM_TOTAL];
    275     uint16_t list_count = 0;
    276 
    277     // Find lowest number of areas per bank among banks which have sufficient space for the area
    278     for (bank_num = bank_limit_rom_min; bank_num <= bank_limit_rom_max; bank_num++)
    279         if ((banks[bank_num].item_count < item_count_min) && bank_check_ok_for_area(bank_num, p_area, banks))
    280             item_count_min = banks[bank_num].item_count;
    281 
    282     // Now make a list of suitable banks below that threshold
    283     for (bank_num = bank_limit_rom_min; bank_num <= bank_limit_rom_max; bank_num++)
    284         if ((banks[bank_num].item_count <= item_count_min) && bank_check_ok_for_area(bank_num, p_area, banks))
    285             list_of_banks[list_count++] = bank_num;
    286 
    287     if (list_count > 0) {
    288         // Choose a random bank from the selected banks and add the area to it
    289         bank_num = list_of_banks[ rand() % list_count ];
    290         bank_add_area(&banks[bank_num], bank_num, p_area);
    291 
    292         return true;
    293     } else
    294         return false; // Fail if no banks were available
    295 }
    296 
    297 
    298 // Assign areas linearly, trying to fill up lowest banks first
    299 static bool banks_assign_area_linear(area_item * p_area, bank_item * banks) {
    300 
    301     uint16_t bank_num;
    302 
    303     // Try to assign area to first allowed bank with enough free space
    304     // Bank array index maps directly to bank numbers, so [2] will be _CODE_2
    305     for (bank_num = bank_limit_rom_min; bank_num <= bank_limit_rom_max; bank_num++) {
    306         if (bank_check_ok_for_area(bank_num, p_area, banks)) {
    307             bank_add_area(&banks[bank_num], bank_num, p_area);
    308             return true;
    309         }
    310     }
    311     return false; // Fail if no banks were available
    312 }
    313 
    314 
    315 // Find a bank for a given area using First Fit Decreasing (FFD)
    316 // All possible banks (0-255) were pre-created and initialized [in obj_data_init()],
    317 // so there is no need to add when using a fresh bank
    318 static void banks_assign_area(area_item * p_area) {
    319 
    320     uint16_t bank_num;
    321     bank_item * banks = (bank_item *)banklist.p_array;
    322     bool result;
    323 
    324     bank_check_area_size(p_area);
    325 
    326     // Try to assign fixed bank areas to their expected bank.
    327     // (ignore the area if it's outside the processing range)
    328     if (p_area->bank_num_in != BANK_NUM_AUTO) {
    329 
    330         bank_num = p_area->bank_num_in;
    331 
    332         // Update max bank var that tracks regardless of limits
    333         // For auto banks this will get updated via bank_add_area()
    334         bank_update_all_max(bank_num);
    335 
    336         if ((bank_num >= bank_limit_rom_min) &&
    337             (bank_num <= bank_limit_rom_max)) {
    338 
    339             if ((option_get_mbc_type() == MBC_TYPE_MBC1) && (!bank_check_mbc1_ok(bank_num)))
    340                 printf("BankPack: Warning: Area in fixed bank assigned to MBC1 excluded bank: %d, file: %s\n", bank_num, file_get_name_in_by_id(p_area->file_id));
    341 
    342             if (!bank_check_mixed_area_types_ok(&banks[bank_num], bank_num, p_area)) {
    343                 bank_report_mixed_area_error(&banks[bank_num], bank_num, p_area);
    344                 exit(EXIT_FAILURE);
    345             }
    346 
    347             bank_add_area(&banks[bank_num], bank_num, p_area);
    348         }
    349         //else
    350         //    printf("BankPack: Notice: Ignoring Area in fixed bank %d outside specified range %d - %d, file: %s\n", bank_num, bank_limit_rom_min, bank_limit_rom_max, file_get_name_in_by_id(p_area->file_id));
    351 
    352         return;
    353     }
    354     else if (p_area->bank_num_in == BANK_NUM_AUTO) {
    355 
    356         if (option_get_random_assign())
    357             result = banks_assign_area_random(p_area, banks);
    358         else
    359             result = banks_assign_area_linear(p_area, banks);
    360 
    361         if (result) // Success
    362             return;
    363     }
    364 
    365     if (option_get_verbose())
    366         banks_show();
    367     printf("BankPack: ERROR! Failed to assign bank for Area %s, bank %d, size %d. Out of banks!\n",
    368             p_area->name, p_area->bank_num_in, p_area->size);
    369     exit(EXIT_FAILURE);
    370 }
    371 
    372 
    373 // qsort compare rule function for sorting areas
    374 static int area_item_compare(const void* a, const void* b) {
    375 
    376     // Sort:
    377     // - First by bank num [asc] (implied fixed first, since fixed [0..254] < auto [255])
    378     // - Then by size [desc]
    379     //
    380     // This assumes the autobank indicator (255) is larger than all fixed bank numbers (< 255)
    381     if (((area_item *)a)->bank_num_in != ((area_item *)b)->bank_num_in)
    382         return  (((area_item *)a)->bank_num_in < ((area_item *)b)->bank_num_in) ? QSORT_A_FIRST : QSORT_A_AFTER;
    383     else if (((area_item *)a)->size != ((area_item *)b)->size)
    384         return (((area_item *)a)->size > ((area_item *)b)->size) ? QSORT_A_FIRST : QSORT_A_AFTER;
    385     else
    386         return QSORT_A_SAME;
    387 }
    388 
    389 static void areas_sort(void) {
    390     // Sort banks by name
    391     qsort (arealist.p_array, arealist.count, sizeof(area_item), area_item_compare);
    392 }
    393 
    394 
    395 // Assigns all areas -> banks, and bank numbers -> files
    396 // Fixed bank areas are placed first, then auto-banks fill the rest in
    397 // Only call after all areas have been collected from object files
    398 void obj_data_process(list_type * p_filelist) {
    399     uint32_t c, s;
    400     area_item   * areas   = (area_item *)arealist.p_array;
    401     symbol_item * symbols = (symbol_item *)symbollist.p_array;
    402     file_item   * files   = (file_item *)(p_filelist->p_array);
    403 
    404     // Sort all areas (see function for sort order)
    405     areas_sort();
    406 
    407     // Assign areas to banks
    408     for (c = 0; c < arealist.count; c++) {
    409         banks_assign_area(&(areas[c]));
    410         // Set linkerfile order based on sort order above
    411         //
    412         // All files get processed here, including Fixed bank files.
    413         // The Fixed vs Auto sorting guarantees Fixed are always before Auto,
    414         // they are then sub-sorted by size
    415         //
    416         // The + 1 differentiates it from the default LINKERFILE_ORDER_FIRST
    417         files[ areas[c].file_id ].linkerfile_order = c + 1;
    418 
    419         // If area was auto-banked then set bank number in associated file 
    420         if ((areas[c].bank_num_in == BANK_NUM_AUTO) &&
    421             (areas[c].bank_num_out != BANK_NUM_UNASSIGNED)) {
    422 
    423             if (files[ areas[c].file_id ].bank_num != BANK_NUM_UNASSIGNED) {
    424                 printf("BankPack: ERROR! Can't assign bank number to a file more than once! Already %d, new is %d\n",
    425                         files[ areas[c].file_id ].bank_num, areas[c].bank_num_out);
    426                 exit(EXIT_FAILURE);
    427             }
    428 
    429             files[ areas[c].file_id ].bank_num = areas[c].bank_num_out;
    430             files[ areas[c].file_id ].rewrite_needed = true;
    431         }
    432     }
    433 
    434     // Check all symbols for matching banked entries ("b<symbol>"), flag if match found
    435     // TODO: inefficient to loop over symbols for all files
    436     for (c = 0; c < symbollist.count; c++) {
    437         if (symbols[c].is_banked_def) {
    438             for (s = 0; s < symbollist.count; s++) {
    439                 if (symbols[c].file_id == symbols[s].file_id) {
    440                     // offset +1 past the "b" char at start of banked symbol entry name
    441                     if (strcmp(symbols[c].name + 1, symbols[s].name) == 0) {
    442                         symbols[c].found_matching_symbol = true;
    443                         break;
    444                     } else if (s == symbollist.count -1)
    445                         printf("  -> NO MATCH FOUND%s\n", symbols[c].name);
    446                 }
    447             }
    448         }
    449     }
    450 
    451 }
    452 
    453 
    454 // Display file/area/bank assignment
    455 // Should be called after obj_data_process()
    456 void banks_show(void) {
    457 
    458     uint32_t c;
    459     uint32_t a;
    460 
    461     printf("\n== Banks assigned: %d -> %d (allowed %d -> %d). Max including fixed: %d) ==\n",
    462             bank_assigned_rom_min, bank_assigned_rom_max,
    463             bank_limit_rom_min,  bank_limit_rom_max,
    464             bank_assigned_rom_max_alltypes);
    465 
    466     bank_item * banks = (bank_item *)banklist.p_array;
    467     area_item * areas = (area_item *)arealist.p_array;
    468     for (c = 0; c < banklist.count; c++) {
    469         if (banks[c].free != BANK_SIZE_ROM) {
    470             printf("Bank %d: Size=%5d, Free=%5d, Reserved=%5d\n", c, banks[c].size, banks[c].free, banks[c].reserved);
    471             printf("     Area  Size  Bank in->out  File in->out\n");
    472             for (a = 0; a < arealist.count; a++) {
    473                 if (areas[a].bank_num_out == c) {
    474                     printf(" %8s %5d    %3d -> %3d  ",
    475                         areas[a].name,
    476                         areas[a].size,
    477                         areas[a].bank_num_in,
    478                         areas[a].bank_num_out);
    479 
    480                     // Split in/out files to separate lines if output would extend
    481                     // beyond 80 chars (28 leading chars from print above, 4 for " -> ")
    482                     bool no_line_break = ((strlen(file_get_name_in_by_id(areas[a].file_id)) +
    483                                            strlen(file_get_name_out_by_id(areas[a].file_id)) + 4 + 28) <= 80);
    484                     printf("%s%s-> %s\n",
    485                         file_get_name_in_by_id(areas[a].file_id), 
    486                         (no_line_break) ? " " : "\n                               ",
    487                         file_get_name_out_by_id(areas[a].file_id));
    488                 }
    489             }
    490             // End of bank line break
    491             printf("\n");
    492         }
    493     }
    494 }
    495 
    496 
    497 // Accepts an input string line and writes it
    498 // out with an **updated bank num** to a file
    499 // * Adds trailing \n if missing
    500 bool area_modify_and_write_to_file(char * strline_in, FILE * out_file, uint16_t bank_num) {
    501 
    502     // Only rewrite area bank number for unset banked CODE
    503     if (strline_in[0] == 'A') {
    504         // For lines: A _CODE_255 ...
    505         if (strstr(strline_in, "A _CODE_255")) {
    506             fprintf(out_file, "A _CODE_%d %s", bank_num, strstr(strline_in, "size"));
    507             // Add trailing \n if missing (may be, due to using strtok() to split the string)
    508             if (strline_in[(strlen(strline_in)-1)] != '\n')
    509                 fprintf(out_file, "\n");
    510             return true;
    511         }
    512         else if (strstr(strline_in, "A _LIT_255")) {
    513             fprintf(out_file, "A _LIT_%d %s", bank_num, strstr(strline_in, "size"));
    514             // Add trailing \n if missing (may be, due to using strtok() to split the string)
    515             if (strline_in[(strlen(strline_in)-1)] != '\n')
    516                 fprintf(out_file, "\n");
    517             return true;
    518         }
    519     }
    520     return false;
    521 }
    522 
    523 
    524 // Check to make sure a banked symbol has a matching symbol in the same file
    525 // This prevents mistakenly rewriting symbol b_<something> entries from asm files
    526 bool symbol_banked_check_rewrite_ok(char * symbol_name, uint32_t file_id) {
    527 
    528     uint32_t c;
    529     symbol_item * symbols = (symbol_item *)symbollist.p_array;
    530 
    531     for (c = 0; c < symbollist.count; c++) {
    532         if ((symbols[c].file_id == file_id) &&
    533             (symbols[c].is_banked_def) &&
    534             (symbols[c].found_matching_symbol)) {
    535             // Make sure b_<name> matches
    536             if (strcmp(symbols[c].name + 2, symbol_name) == 0)
    537                 return true;
    538         }
    539     }
    540     return false;
    541 }
    542 
    543 
    544 // Accepts an input string line
    545 // and writes it out with an updated bank to a file
    546 // * Adds trailing \n if missing
    547 bool symbol_modify_and_write_to_file(char * strline_in, FILE * out_file, uint16_t bank_num, uint32_t file_id, unsigned int obj_file_format) {
    548 
    549     uint32_t c;
    550     uint32_t bank_in = 0;
    551     char strmatch[OBJ_NAME_MAX_STR_LEN];
    552     char symbol_name[OBJ_NAME_MAX_STR_LEN];
    553     symbol_match_item * sym_match = (symbol_match_item *)symbol_matchlist.p_array;
    554 
    555     const char * s_def_b_matches[] = {[OBJ_FILE_XL3_24BIT_ADDR] = "S b_%" TOSTR(OBJ_NAME_MAX_STR_LEN) "s Def%06x",
    556                                       [OBJ_FILE_XL4_32BIT_ADDR] = "S b_%" TOSTR(OBJ_NAME_MAX_STR_LEN) "s Def%08x"};
    557     const char * s_def_b_rewrite[] = {[OBJ_FILE_XL3_24BIT_ADDR] = "S b_%s Def0000%02x",
    558                                       [OBJ_FILE_XL4_32BIT_ADDR] = "S b_%s Def0000%04x"};
    559 
    560     const char * s_def_matches[] = {[OBJ_FILE_XL3_24BIT_ADDR] = "S %s%%" TOSTR(OBJ_NAME_MAX_STR_LEN) "s Def%%06x",
    561                                     [OBJ_FILE_XL4_32BIT_ADDR] = "S %s%%" TOSTR(OBJ_NAME_MAX_STR_LEN) "s Def%%08x"};
    562     const char * s_def_rewrite[] = {[OBJ_FILE_XL3_24BIT_ADDR] = "S %s%s Def0000%02x",
    563                                     [OBJ_FILE_XL4_32BIT_ADDR] = "S %s%s Def0000%04x"};
    564 
    565     if (obj_file_format >= OBJ_FILE_UNKNOWN) return false;
    566 
    567     // Only rewrite banked symbol entries
    568     if (strline_in[0] == 'S') {
    569         // For lines: S b_<symbol name>... Def0000FF   (XL3 version)
    570         // For lines: S b_<symbol name>... Def000000FF (XL4 version)
    571         if (SYMBOL_REWRITE_RECORDS == sscanf(strline_in, s_def_b_matches[obj_file_format], symbol_name, &bank_in)) {
    572             if (bank_in == BANK_NUM_AUTO) {
    573                 if (symbol_banked_check_rewrite_ok(symbol_name, file_id))  {
    574                     fprintf(out_file, s_def_b_rewrite[obj_file_format], symbol_name, bank_num);
    575                     if (strline_in[(strlen(strline_in)-1)] != '\n')
    576                         fprintf(out_file, "\n");
    577                     return true;
    578                 }
    579             }
    580         } // For lines: S ___bank_<trailing symbol name>... Def0000FF
    581         else {
    582             for (c = 0; c < symbol_matchlist.count; c++) {
    583                 // Prepare a sscanf match test string for the current symbol name
    584                 if (snprintf(strmatch, sizeof(strmatch), s_def_matches[obj_file_format], sym_match[c].name) > sizeof(strmatch))
    585                     printf("BankPack: Warning: truncated symbol match string to:%s\n",strmatch);
    586 
    587                 if (SYMBOL_REWRITE_RECORDS == sscanf(strline_in, strmatch, symbol_name, &bank_in)) {
    588                     if (bank_in == BANK_NUM_AUTO) {
    589                         fprintf(out_file, s_def_rewrite[obj_file_format], sym_match[c].name, symbol_name, bank_num);
    590                         if (strline_in[(strlen(strline_in)-1)] != '\n')
    591                             fprintf(out_file, "\n");
    592                         return true;
    593                     }
    594                 }
    595             }
    596         }
    597     }
    598     return false;
    599 }

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