cscg22-gearboy

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

files.c (8535B)


      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 <unistd.h>
     10#include <stdint.h>
     11
     12#include "common.h"
     13#include "path_ops.h"
     14#include "list.h"
     15#include "files.h"
     16#include "obj_data.h"
     17
     18static void files_set_output_name(void);
     19static char * file_read_to_buffer(char *);
     20
     21list_type filelist;
     22
     23char g_out_ext[MAX_FILE_STR];
     24char g_out_path[MAX_FILE_STR];
     25char g_out_linkerfile_name[MAX_FILE_STR] = {'\0'};
     26
     27void files_set_out_ext(char * ext_str) {
     28    if (snprintf(g_out_ext, sizeof(g_out_ext), "%s", ext_str) > sizeof(g_out_ext))
     29        printf("Bankpack: Warning: truncated output extension to:%s\n",g_out_ext);
     30}
     31
     32void files_set_out_path(char * path_str) {
     33    if (snprintf(g_out_path, sizeof(g_out_path), "%s", path_str) > sizeof(g_out_path))
     34        printf("Bankpack: Warning: truncated output path to:%s\n",g_out_path);
     35}
     36
     37
     38void files_init(void) {
     39    list_init(&filelist, sizeof(file_item));
     40    g_out_ext[0]  = '\0';
     41    g_out_path[0] = '\0';
     42}
     43
     44void files_cleanup(void) {
     45    list_cleanup(&filelist);
     46}
     47
     48
     49// Reads a list of object files from a linkerfile
     50// (one filename per line) and adds them
     51void files_read_linkerfile(char * filename_in) {
     52    char strline_in[MAX_FILE_STR] = "";
     53
     54    FILE * in_file;
     55
     56    // Open each object file and try to process all the lines
     57    in_file = fopen(filename_in, "r");
     58    if (in_file) {
     59
     60        // Read one line at a time into \0 terminated string
     61        // Skip empty lines
     62        // Strip newlines and carraige returns from end of filename
     63        while ( fgets(strline_in, sizeof(strline_in), in_file) != NULL) {
     64            if ((strline_in[0] != '\n') || (strline_in[0] != '\r')) {
     65                strline_in[strcspn(strline_in, "\r\n")] = '\0';
     66                files_add(strline_in);
     67            }
     68        }
     69        fclose(in_file);
     70
     71    } // end: if valid file
     72    else {
     73        printf("BankPack: ERROR: failed to open input linkerfile: %s\n", filename_in);
     74        exit(EXIT_FAILURE);
     75    }
     76}
     77
     78
     79void files_set_linkerfile_outname(char * filename) {
     80
     81    if (snprintf(g_out_linkerfile_name, sizeof(g_out_linkerfile_name), "%s", filename) > sizeof(g_out_linkerfile_name))
     82        printf("Warning: truncated output linkerfile name to:%s\n",g_out_linkerfile_name);
     83}
     84
     85
     86// Writes a list of loaded object filenames to
     87// a linkerfile (one filename per line)
     88void files_write_linkerfile(void) {
     89    uint32_t c;
     90    file_item * files = (file_item *)filelist.p_array;
     91    FILE * out_file;
     92
     93    // Open the linkerfile output and write all object filenames
     94    out_file = fopen(g_out_linkerfile_name, "w");
     95    if (out_file) {
     96
     97        // Process stored file names
     98        for (c = 0; c < filelist.count; c++)
     99            fprintf(out_file, "%s\n", files[c].name_out);
    100
    101        fclose(out_file);
    102
    103    } // end: if valid file
    104    else {
    105        printf("BankPack: ERROR: failed to open output linkerfile: %s\n", g_out_linkerfile_name);
    106        exit(EXIT_FAILURE);
    107    }
    108}
    109
    110
    111void files_add(char * filename) {
    112
    113    file_item newfile;
    114
    115    if (snprintf(newfile.name_in, sizeof(newfile.name_in), "%s", filename) > sizeof(newfile.name_in))
    116        printf("Warning: truncated input filename to:%s\n",newfile.name_in);
    117
    118    newfile.name_out[0] = '\0';
    119    newfile.rewrite_needed = false;
    120    newfile.bank_num = BANK_NUM_UNASSIGNED;
    121
    122    list_additem(&filelist, &newfile);
    123}
    124
    125
    126char * file_get_name_in_by_id(uint32_t file_id) {
    127
    128    file_item * files = (file_item *)filelist.p_array;
    129
    130    if ((file_id >= 0) && (file_id < filelist.count))
    131        return files[file_id].name_in;
    132    else
    133        return (char *)"\0";
    134}
    135
    136
    137char * file_get_name_out_by_id(uint32_t file_id) {
    138
    139    file_item * files = (file_item *)filelist.p_array;
    140
    141    if ((file_id >= 0) && (file_id < filelist.count))
    142        return files[file_id].name_out;
    143    else
    144        return (char *)"\0";
    145}
    146
    147
    148// Update output names based on -path= and -ext= option params
    149static void files_set_output_name(void) {
    150
    151    uint32_t c;
    152    file_item * files = (file_item *)filelist.p_array;
    153
    154    // Process stored file names
    155    for (c = 0; c < filelist.count; c++) {
    156
    157        snprintf(files[c].name_out, sizeof(files[c].name_out), "%s", files[c].name_in);
    158
    159        if (g_out_ext[0])
    160            filename_replace_extension(files[c].name_out, g_out_ext, sizeof(files[c].name_out));
    161        if (g_out_path[0])
    162            filename_replace_path(files[c].name_out, g_out_path, sizeof(files[c].name_out));
    163    }
    164}
    165
    166
    167// Read from a file into a buffer (will allocate needed memory)
    168// Returns NULL if reading file didn't succeed
    169static char * file_read_to_buffer(char * filename) {
    170
    171    long fsize;
    172    FILE * file_in = fopen(filename, "rb");
    173    char * filedata = NULL;
    174
    175    if (file_in) {
    176        // Get file size
    177        fseek(file_in, 0, SEEK_END);
    178        fsize = ftell(file_in);
    179        if (fsize != -1L) {
    180            fseek(file_in, 0, SEEK_SET);
    181
    182            filedata = malloc(fsize + 1); // One extra byte to add string null terminator
    183            if (filedata) {
    184                if (fsize != fread(filedata, 1, fsize, file_in))
    185                    printf("BankPack: Warning: File read size didn't match expected for %s\n", filename);
    186                filedata[fsize] = '\0'; // Add null string terminator at end
    187            } else printf("BankPack: ERROR: Failed to allocate memory to read file %s\n", filename);
    188
    189        } else printf("BankPack: ERROR: Failed to read size of file %s\n", filename);
    190
    191        fclose(file_in);
    192    } else printf("BankPack: ERROR: Failed to open input file %s\n", filename);
    193
    194    return filedata;
    195}
    196
    197
    198// Extract areas from files, then collected assign them to banks
    199void files_extract(void) {
    200    uint32_t c;
    201    char strline_in[OBJ_NAME_MAX_STR_LEN] = "";
    202    file_item * files = (file_item *)filelist.p_array;
    203    FILE * obj_file;
    204
    205    // Process stored file names
    206    for (c = 0; c < filelist.count; c++) {
    207
    208        // Open each object file and try to process all the lines
    209        obj_file = fopen(files[c].name_in, "r");
    210        if (obj_file) {
    211
    212            // Read one line at a time into \0 terminated string
    213            while ( fgets(strline_in, sizeof(strline_in), obj_file) != NULL) {
    214                if (strline_in[0] == 'A')
    215                    areas_add(strline_in, c);
    216                else if (strline_in[0] == 'S')
    217                    symbols_add(strline_in, c);
    218            }
    219            fclose(obj_file);
    220
    221        } // end: if valid file
    222        else {
    223            printf("BankPack: ERROR: failed to open file %s\n", files[c].name_in);
    224            exit(EXIT_FAILURE);
    225        }
    226    }
    227
    228    obj_data_process(&filelist);
    229    files_set_output_name();
    230}
    231
    232
    233void files_rewrite(void) {
    234
    235    uint32_t c;
    236    char * in_file_buf = NULL;
    237    char * strline_in  = NULL;
    238    FILE * out_file    = NULL;
    239    file_item * files  = (file_item *)filelist.p_array;
    240
    241    // If linkerfile output is enabled, write it
    242    if (g_out_linkerfile_name[0] != '\0')
    243        files_write_linkerfile();
    244
    245    // Process stored file names - (including unchanged ones since output may get new extensions or path)
    246    for (c = 0; c < filelist.count; c++) {
    247
    248        in_file_buf = file_read_to_buffer(files[c].name_in);
    249        if (!in_file_buf)
    250            exit(EXIT_FAILURE);
    251
    252        out_file = fopen(files[c].name_out, "w");
    253        if (!out_file) {
    254            printf("BankPack: ERROR: failed to open output file %s\n", files[c].name_out);
    255            exit(EXIT_FAILURE);
    256        }
    257
    258        // Read one line at a time from a string buffer
    259        // Note: strtok will replace the \n chars with \0 on each split, so be sure to add those back
    260        strline_in = strtok(in_file_buf,"\n");
    261        while (strline_in != NULL) {
    262
    263            // Only modify lines in flagged files
    264            if (files[c].rewrite_needed) {
    265
    266                if (!area_modify_and_write_to_file(strline_in, out_file, files[c].bank_num)) {
    267                    if (!symbol_modify_and_write_to_file(strline_in, out_file, files[c].bank_num, c)) {
    268                        // Default is to write line with no changes
    269                        fprintf(out_file, "%s\n", strline_in);
    270                    }
    271                }
    272            } else
    273                fprintf(out_file, "%s\n", strline_in);
    274
    275            // Read next line
    276            strline_in = strtok(NULL,"\n");
    277        }
    278
    279        if (in_file_buf)
    280            free(in_file_buf);
    281        fclose(out_file);
    282    }
    283
    284}