/** Dynamic contiguous string that is used to load files. */ #include "text.h" #include #define ARRAY_NAME char #define ARRAY_TYPE char #define ARRAY_BODY #include "../src/array.h" struct char_array text(void) { return char_array(); } void text_(struct char_array *const text) { char_array_(text); } /** 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? */ 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. */ 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; }