cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

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}