56 lines
1.8 KiB
C
56 lines
1.8 KiB
C
/** Dynamic contiguous string that is used to load files into a
|
|
`struct char_array`. */
|
|
|
|
#include "text.h"
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
|
|
#define ARRAY_NAME char
|
|
#define ARRAY_TYPE char
|
|
#define ARRAY_BODY
|
|
#include "../src/array.h"
|
|
|
|
/** @return Idle. */
|
|
struct char_array text(void) { return char_array(); }
|
|
|
|
/** Destroys `text`. */
|
|
void text_(struct char_array *const text) { char_array_(text); }
|
|
|
|
/** Append a text file, `fn`, to `text`, and add a '\0'.
|
|
@return The start of the appended file or null on error. A partial read is a
|
|
failure. @throws[fopen, fread, realloc]
|
|
@throws[EISEQ] The text file has embedded nulls. */
|
|
char *text_append_file(struct char_array *text, const char *const fn) {
|
|
FILE *fp = 0;
|
|
const size_t granularity = 1024;
|
|
size_t nread, start;
|
|
char *cursor;
|
|
int success = 1;
|
|
assert(text && fn);
|
|
start = text->size;
|
|
if(!(fp = fopen(fn, "r"))) goto catch;
|
|
/* Read entire file in chunks. We don't allow any text file to go over
|
|
`INT_MAX` and `UINT32_MAX` because `printf("%.*s", int, char *)` is used
|
|
and we store it in an `uint32_t`. */
|
|
do if(!(cursor = char_array_buffer(text, granularity))
|
|
|| (nread = fread(cursor, 1, granularity, fp), ferror(fp))
|
|
|| !char_array_append(text, nread)
|
|
|| text->size - start >= (INT_MAX < UINT32_MAX ? INT_MAX : UINT32_MAX))
|
|
goto catch;
|
|
while(nread == granularity);
|
|
/* File to `C` string. */
|
|
if(!(cursor = char_array_new(text))) goto catch;
|
|
*cursor = '\0';
|
|
/* Binary files with embedded '\0' are not allowed; check just this read. */
|
|
if(strchr(text->data + start, '\0') != cursor)
|
|
{ errno = EILSEQ; goto catch; }
|
|
goto finally;
|
|
catch:
|
|
if(!errno) errno = EILSEQ; /* Will never be true on POSIX. */
|
|
success = 0;
|
|
finally:
|
|
if(fp) fclose(fp);
|
|
return success ? text->data + start : 0;
|
|
}
|