shithub: rgbds

Download patch

ref: cdabc057a0a1e307a13f78181c782a3194362fb5
parent: eb0d75711a93a6cdfd0bd612bf8e0c1f958d381b
author: ISSOtm <[email protected]>
date: Sun Feb 9 12:05:29 EST 2020

Allow unseekable files with `INCBIN`

Go figure the use case, but the feature is there now

--- a/src/asm/section.c
+++ b/src/asm/section.c
@@ -1,4 +1,5 @@
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -404,80 +405,117 @@
  */
 void out_BinaryFile(char const *s)
 {
-	FILE *f;
+	FILE *f = fstk_FindFile(s, NULL);
 
-	f = fstk_FindFile(s, NULL);
-	if (f == NULL) {
+	if (!f) {
 		if (oGeneratedMissingIncludes) {
 			oFailedOnMissingInclude = true;
 			return;
 		}
-		err(1, "Unable to open incbin file '%s'", s);
+		fatalerror("Error opening INCBIN file '%s': %s", s,
+			   strerror(errno));
 	}
 
-	int32_t fsize;
+	int32_t fsize = -1;
+	int byte;
 
-	fseek(f, 0, SEEK_END);
-	fsize = ftell(f);
-	fseek(f, 0, SEEK_SET);
-
 	checkcodesection();
-	checksectionoverflow(fsize);
+	if (fseek(f, 0, SEEK_END) != -1) {
+		fsize = ftell(f);
+		rewind(f);
 
-	int32_t todo = fsize;
+		checksectionoverflow(fsize);
+	} else if (errno != ESPIPE) {
+		yyerror("Error determining size of INCBIN file '%s': %s", s,
+			strerror(errno));
+	}
 
-	while (todo--)
-		pCurrentSection->tData[pCurrentSection->nPC++] = fgetc(f);
+	while ((byte = fgetc(f)) != EOF) {
+		if (fsize == -1)
+			checksectionoverflow(1);
+		pCurrentSection->tData[pCurrentSection->nPC++] = byte;
+		if (currentLoadSection)
+			currentLoadSection->nPC++;
+		nPC++;
+	}
 
-	if (currentLoadSection)
-		currentLoadSection->nPC += fsize;
-	nPC += fsize;
+	if (ferror(f))
+		yyerror("Error reading INCBIN file '%s': %s", s,
+			strerror(errno));
+
 	fclose(f);
 }
 
 void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
 {
-	FILE *f;
+	if (start_pos < 0) {
+		yyerror("Start position cannot be negative (%d)", start_pos);
+		start_pos = 0;
+	}
 
-	if (start_pos < 0)
-		fatalerror("Start position cannot be negative");
+	if (length < 0) {
+		yyerror("Number of bytes to read cannot be negative (%d)",
+			length);
+		length = 0;
+	}
+	if (length == 0) /* Don't even bother with 0-byte slices */
+		return;
 
-	if (length < 0)
-		fatalerror("Number of bytes to read must be greater than zero");
+	FILE *f = fstk_FindFile(s, NULL);
 
-	f = fstk_FindFile(s, NULL);
-	if (f == NULL) {
+	if (!f) {
 		if (oGeneratedMissingIncludes) {
 			oFailedOnMissingInclude = true;
 			return;
 		}
-		err(1, "Unable to open included file '%s'", s);
+		fatalerror("Error opening INCBIN file '%s': %s", s,
+			   strerror(errno));
 	}
 
+	checkcodesection();
+	checksectionoverflow(length);
+
 	int32_t fsize;
 
-	fseek(f, 0, SEEK_END);
-	fsize = ftell(f);
+	if (fseek(f, 0, SEEK_END) != -1) {
+		fsize = ftell(f);
 
-	if (start_pos >= fsize)
-		fatalerror("Specified start position is greater than length of file");
+		if (start_pos >= fsize) {
+			yyerror("Specified start position is greater than length of file");
+			return;
+		}
 
-	if ((start_pos + length) > fsize)
-		fatalerror("Specified range in INCBIN is out of bounds");
+		if ((start_pos + length) > fsize)
+			fatalerror("Specified range in INCBIN is out of bounds");
 
-	fseek(f, start_pos, SEEK_SET);
+		fseek(f, start_pos, SEEK_SET);
+	} else {
+		if (errno != ESPIPE)
+			yyerror("Error determining size of INCBIN file '%s': %s",
+				s, strerror(errno));
+		/* The file isn't seekable, so we'll just skip bytes */
+		while (start_pos--)
+			(void)fgetc(f);
+	}
 
-	checkcodesection();
-	checksectionoverflow(length);
-
 	int32_t todo = length;
 
-	while (todo--)
-		pCurrentSection->tData[pCurrentSection->nPC++] = fgetc(f);
+	while (todo--) {
+		int byte = fgetc(f);
 
-	if (currentLoadSection)
-		currentLoadSection->nPC += length;
-	nPC += length;
+		if (byte != EOF) {
+			pCurrentSection->tData[pCurrentSection->nPC++] = byte;
+			if (currentLoadSection)
+				currentLoadSection->nPC++;
+			nPC++;
+		} else if (ferror(f)) {
+			yyerror("Error reading INCBIN file '%s': %s", s,
+				strerror(errno));
+		} else {
+			yyerror("Premature end of file (%d bytes left to read)",
+				todo + 1);
+		}
+	}
 
 	fclose(f);
 }