/** Dynamic contiguous string that is used to load files. */ #define ARRAY_NAME char #define ARRAY_TYPE char #include "../src/array.h" #define HAVE_CHAR_ARRAY #include "text.h" #include /** Append a text file, `fn`, to `c`, and add a '\0'. @return The start of the appended file or null on error. A partial read is a failure. @throws[fopen, fread, malloc] @throws[EISEQ] The text file has embedded nulls. @throws[ERANGE] If the standard library does not follow POSIX. */ static char *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. */ do if(!(cursor = char_array_buffer(text, granularity)) || (nread = fread(cursor, 1, granularity, fp), ferror(fp)) || !char_array_append(text, nread)) 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; } struct text text(void) { struct text text; text.a = char_array(); return text; } void text_(struct text *const text) { char_array_(&text->a); } char *text_append_file(struct text *text, const char *const fn) { return append_file(&text->a, fn); }