git.y1.nz

gbdk-2020

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

gbdk-support/makecom/noi_file.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 <unistd.h>
      9 #include <stdbool.h>
     10 #include <stdint.h>
     11 
     12 #include "common.h"
     13 #include "noi_file.h"
     14 #include "bin_to_com.h"
     15 
     16 // Example data to parse from a .noi file:
     17 /*
     18 DEF s__CODE 0x200
     19 DEF l__BASE 0x2A3
     20 DEF __shadow_OAM_OFF 0x455
     21 DEF .mode 0x456
     22 */
     23 
     24 const char * known_section_names[] =
     25         {"_CODE","_HOME","_BASE","_CODE_0","_INITIALIZER","_LIT","_GSINIT","_GSFINAL"};
     26 
     27 
     28 list_type symbol_list;
     29 uint32_t overlay_count_addr = SYM_VAL_UNSET;
     30 uint32_t overlay_name_addr = SYM_VAL_UNSET;
     31 
     32 
     33 // Initialize the symbol list
     34 void noi_init(void) {
     35 
     36     list_init(&symbol_list, sizeof(symbol_item));
     37 }
     38 
     39 
     40 // Free the symbol list
     41 void noi_cleanup(void) {
     42 
     43     list_cleanup(&symbol_list);
     44 }
     45 
     46 
     47 // Find a matching symbol, if none matches a new one is added and returned
     48 static int symbollist_get_id_by_name(char * symbol_name) {
     49 
     50     symbol_item * symbols = (symbol_item *)symbol_list.p_array;
     51 
     52     // Check for matching symbol name
     53     for(int c = 0;c < symbol_list.count; c++) {
     54         // Return matching symbol index if present
     55         if (strcmp(symbol_name, symbols[c].name) == 0) {
     56             return c;
     57         }
     58     }
     59 
     60     // no match was found, add symbol
     61     symbol_item new_symbol = {.name = "", .addr_start = SYM_VAL_UNSET, .length = SYM_VAL_UNSET, .bank_num = 0x00, .src_rom_addr = SYM_VAL_UNSET};
     62     snprintf(new_symbol.name, sizeof(new_symbol.name), "%s", symbol_name);
     63     list_additem(&symbol_list, &new_symbol);
     64 
     65     return (symbol_list.count - 1);
     66 }
     67 
     68 
     69 // Add the start address or length for a s_ or l_ symbol record
     70 static void noi_symbollist_add(char rec_type, char * name, char * value) {
     71 
     72     // Only add symbols if they're in the known section name list
     73     for (int c = 0; c < ARRAY_LEN(known_section_names); c++) {
     74 
     75         if ((strcmp(name, known_section_names[c]) == 0) ||
     76             (strncmp(name, "_CODE_", (sizeof("_CODE_") - 1)) == 0)) {
     77 
     78             symbol_item * symbols = (symbol_item *)symbol_list.p_array;
     79 
     80             // Check to see if there is an existing record to update
     81             // If one isn't found a new record will have been created automatically
     82             int symbol_id = symbollist_get_id_by_name(name);
     83             if (symbol_id != ERR_NO_SYMBOLS_LEFT) {
     84 
     85                 // Handle whether it's a start-of-address or a length record for the given symbol
     86                 if (rec_type == NOI_REC_START) {
     87                     symbols[symbol_id].addr_start   = strtol(value, NULL, 16);
     88                     symbols[symbol_id].bank_num     = BANK_GET_NUM(symbols[symbol_id].addr_start);
     89                     symbols[symbol_id].src_rom_addr = BANK_GET_ROM_ADDR(symbols[symbol_id].addr_start);
     90                 }
     91                 else if (rec_type == NOI_REC_LENGTH) {
     92                     symbols[symbol_id].length = strtol(value, NULL, 16);
     93                 }
     94             }
     95 
     96             return;
     97         }
     98     }
     99 }
    100 
    101 
    102 // Load symbols from a .noi file and create paired records for start & length entries
    103 // Plus, look for and store for overlay symbol information
    104 int noi_file_load_symbols(char * filename_in) {
    105 
    106     char cols;
    107     char * p_str;
    108     char * p_words[MAX_SPLIT_WORDS];
    109     char strline_in[MAX_STR_LEN] = "";
    110     FILE * noi_file = fopen(filename_in, "r");
    111     symbol_item symbol;
    112     int symbol_id;
    113 
    114     noi_init();
    115 
    116     if (noi_file) {
    117 
    118         // Read one line at a time into \0 terminated string
    119         while ( fgets(strline_in, sizeof(strline_in), noi_file) != NULL) {
    120 
    121             // Require minimum length to match
    122             if (strlen(strline_in) >= NOI_REC_START_LEN) {
    123 
    124                 // Split string into words separated by spaces
    125                 cols = 0;
    126                 p_str = strtok(strline_in," ");
    127                 while (p_str != NULL)
    128                 {
    129                     p_words[cols++] = p_str;
    130                     // Only split on underscore for the second match
    131                     p_str = strtok(NULL, " ");
    132                     if (cols >= MAX_SPLIT_WORDS) break;
    133                 }
    134 
    135                 // [0] = "DEF"
    136                 // [1] = symbol name
    137                 // [2] = symbol value
    138                 if (cols >= NOI_REC_COUNT_MATCH) {
    139 
    140                     // If it matches either _s_egment or _l_ength records (first two chars)
    141                     // then add a record for it with the first two chars truncated
    142                     if ((strncmp(p_words[1], "l_", NOI_REC_S_L_CHK) == 0) ||
    143                         (strncmp(p_words[1], "s_", NOI_REC_S_L_CHK) == 0)) {
    144                         noi_symbollist_add(p_words[1][0], p_words[1] + NOI_REC_S_L_CHK, p_words[2]);
    145                     }
    146                     // Otherwise check for records of interest and store them
    147                     else if (strcmp(p_words[1], "___overlay_count") == 0) {
    148                         overlay_count_addr = strtol(p_words[2], NULL, 16);
    149                     }
    150                     else if (strcmp(p_words[1], "___overlay_name") == 0) {
    151                         overlay_name_addr = strtol(p_words[2], NULL, 16);
    152                     }
    153                 }
    154             } // end: valid min chars to process line
    155 
    156         } // end: while still lines to process
    157 
    158         fclose(noi_file);
    159 
    160     } // end: if valid file
    161     else return (false);
    162 
    163    return true;
    164 }

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