noi_file.c (5430B)
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/* 18DEF s__CODE 0x200 19DEF l__BASE 0x2A3 20DEF __shadow_OAM_OFF 0x455 21DEF .mode 0x456 22*/ 23 24const char * known_section_names[] = 25 {"_CODE","_HOME","_BASE","_CODE_0","_INITIALIZER","_LIT","_GSINIT","_GSFINAL"}; 26 27 28list_type symbol_list; 29uint32_t overlay_count_addr = SYM_VAL_UNSET; 30uint32_t overlay_name_addr = SYM_VAL_UNSET; 31 32 33// Initialize the symbol list 34void noi_init(void) { 35 36 list_init(&symbol_list, sizeof(symbol_item)); 37} 38 39 40// Free the symbol list 41void 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 48static 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 70static 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 104int 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}