diff --git a/include/link/main.h b/include/link/main.h index e6ad30ab..ebc24f02 100644 --- a/include/link/main.h +++ b/include/link/main.h @@ -16,11 +16,11 @@ /* Variables related to CLI options */ extern bool isDmgMode; -extern FILE *linkerScript; -extern FILE *mapFile; -extern FILE *symFile; -extern FILE *overlayFile; -extern FILE *outputFile; +extern char const *linkerScriptName; +extern char const *mapFileName; +extern char const *symFileName; +extern char const *overlayFileName; +extern char const *outputFileName; extern uint8_t padValue; extern bool is32kMode; extern bool beVerbose; @@ -32,4 +32,18 @@ extern bool isWRA0Mode; fprintf(stderr, __VA_ARGS__); \ } while (0) +/** + * Opens a file if specified, and aborts on error. + * @param fileName The name of the file to open; if NULL, no file will be opened + * @param mode The mode to open the file with + * @return A pointer to a valid FILE structure, or NULL if fileName was NULL + */ +FILE *openFile(char const *fileName, char const *mode); + +#define closeFile(file) do { \ + FILE *tmp = file; \ + if (tmp) \ + fclose(tmp); \ + } while (0) + #endif /* RGBDS_LINK_MAIN_H */ diff --git a/include/link/script.h b/include/link/script.h index 412ccee8..93cf44c8 100644 --- a/include/link/script.h +++ b/include/link/script.h @@ -12,6 +12,8 @@ #include +extern FILE *linkerScript; + struct SectionPlacement { struct Section *section; uint16_t org; diff --git a/src/link/assign.c b/src/link/assign.c index 4780e120..b300e9c6 100644 --- a/src/link/assign.c +++ b/src/link/assign.c @@ -58,10 +58,12 @@ static void initFreeSpace(void) */ static void processLinkerScript(void) { - if (!linkerScript) + if (!linkerScriptName) return; verbosePrint("Reading linker script...\n"); + linkerScript = openFile(linkerScriptName, "r"); + /* Modify all sections according to the linker script */ struct SectionPlacement *placement; @@ -86,6 +88,8 @@ static void processLinkerScript(void) section->bank = placement->bank; section->isAlignFixed = false; /* The alignment is satisfied */ } + + fclose(linkerScript); } /** @@ -385,7 +389,7 @@ void assign_AssignSections(void) /* Overlaying requires only fully-constrained sections */ verbosePrint("Assigning other sections...\n"); - if (overlayFile) + if (overlayFileName) errx(1, "All sections must be fixed when using an overlay file; %u, %sn't", nbSectionsToAssign, nbSectionsToAssign == 1 ? "is" : "are"); diff --git a/src/link/main.c b/src/link/main.c index c2c8b2f5..3649f90c 100644 --- a/src/link/main.c +++ b/src/link/main.c @@ -6,6 +6,8 @@ * SPDX-License-Identifier: MIT */ +#include +#include #include #include #include @@ -22,16 +24,29 @@ #include "extern/err.h" #include "version.h" -bool isDmgMode; /* -d */ -FILE *linkerScript; /* -l */ -FILE *mapFile; /* -m */ -FILE *symFile; /* -n */ -FILE *overlayFile; /* -O */ -FILE *outputFile; /* -o */ -uint8_t padValue; /* -p */ -bool is32kMode; /* -t */ -bool beVerbose; /* -v */ -bool isWRA0Mode; /* -w */ +bool isDmgMode; /* -d */ +char const *linkerScriptName; /* -l */ +char const *mapFileName; /* -m */ +char const *symFileName; /* -n */ +char const *overlayFileName; /* -O */ +char const *outputFileName; /* -o */ +uint8_t padValue; /* -p */ +bool is32kMode; /* -t */ +bool beVerbose; /* -v */ +bool isWRA0Mode; /* -w */ + +FILE *openFile(char const *fileName, char const *mode) +{ + if (!fileName) + return NULL; + + FILE *file = fopen(fileName, mode); + + if (!file) + err(1, "Could not open file \"%s\"", fileName); + + return file; +} /** * Prints the program's usage to stdout. @@ -42,42 +57,12 @@ static void printUsage(void) " [-o outfile] [-p pad_value] [-s symbol] file [...]"); } -/** - * Helper function for `main`'s argument parsing. - * For use with options which take a file name to operate on - * If the file fails to be opened, an error message will be printed, - * and the function `exit`s. - * @param mode The mode to open the file in - * @param failureMessage A format string that will be printed on failure. - * A single (string) argument is given, the file name. - * @return What `fopen` returned; this cannot be NULL. - */ -static FILE *openArgFile(char const *mode, char const *failureMessage) -{ - FILE *file = fopen(optarg, mode); - - if (!file) - err(1, failureMessage, optarg); - return file; -} - /** * Cleans up what has been done * Mostly here to please tools such as `valgrind` so actual errors can be seen */ static void cleanup(void) { - if (linkerScript) - fclose(linkerScript); - if (mapFile) - fclose(mapFile); - if (symFile) - fclose(symFile); - if (overlayFile) - fclose(overlayFile); - if (outputFile) - fclose(outputFile); - obj_Cleanup(); } @@ -95,19 +80,19 @@ int main(int argc, char *argv[]) isWRA0Mode = true; break; case 'l': - linkerScript = openArgFile("r", "Could not open linker script file \"%s\""); + linkerScriptName = optarg; break; case 'm': - mapFile = openArgFile("w", "Could not open map file \"%s\""); + mapFileName = optarg; break; case 'n': - symFile = openArgFile("w", "Could not open sym file \"%s\""); + symFileName = optarg; break; case 'O': - overlayFile = openArgFile("r+b", "Could not open overlay file \"%s\""); + overlayFileName = optarg; break; case 'o': - outputFile = openArgFile("wb", "Could not open output file \"%s\""); + outputFileName = optarg; break; case 'p': value = strtoul(optarg, &endptr, 0); diff --git a/src/link/output.c b/src/link/output.c index 6c2e17d5..805d0bb1 100644 --- a/src/link/output.c +++ b/src/link/output.c @@ -9,6 +9,11 @@ #include "extern/err.h" +FILE *outputFile; +FILE *overlayFile; +FILE *symFile; +FILE *mapFile; + struct SortedSection { struct Section const *section; struct SortedSection *next; @@ -158,6 +163,9 @@ static void writeBank(struct SortedSection *bankSections, uint16_t baseOffset, */ static void writeROM(void) { + outputFile = openFile(outputFileName, "wb"); + overlayFile = openFile(overlayFileName, "rb"); + checkOverlay(); if (outputFile) { @@ -177,6 +185,9 @@ static void writeROM(void) funlockfile(overlayFile); funlockfile(outputFile); } + + closeFile(outputFile); + closeFile(overlayFile); } /** @@ -310,7 +321,7 @@ static void writeMapBank(struct SortedSections const *sectList, */ static void writeSymAndMap(void) { - if (!symFile && !mapFile) + if (!symFileName && !mapFileName) return; enum SectionType typeMap[SECTTYPE_INVALID] = { @@ -324,8 +335,12 @@ static void writeSymAndMap(void) SECTTYPE_HRAM }; - if (symFile) + symFile = openFile(symFileName, "w"); + mapFile = openFile(mapFileName, "w"); + + if (symFileName) { fputs("; File generated by rgblink\n", symFile); + } for (uint8_t i = 0; i < SECTTYPE_INVALID; i++) { enum SectionType type = typeMap[i]; @@ -339,6 +354,9 @@ static void writeSymAndMap(void) } } } + + closeFile(symFile); + closeFile(mapFile); } static void cleanupSections(struct SortedSection *section) diff --git a/src/link/script.c b/src/link/script.c index 1f5880ad..4187d4b0 100644 --- a/src/link/script.c +++ b/src/link/script.c @@ -11,6 +11,8 @@ #include "extern/err.h" +FILE *linkerScript; + static inline bool isWhiteSpace(int c) { return c == ' ' || c == '\t';