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}