summaryrefslogtreecommitdiff
path: root/readall.c
diff options
context:
space:
mode:
Diffstat (limited to 'readall.c')
-rw-r--r--readall.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/readall.c b/readall.c
new file mode 100644
index 0000000..9f55697
--- /dev/null
+++ b/readall.c
@@ -0,0 +1,82 @@
+/* by Nominal Animal, 2017: https://stackoverflow.com/a/44894946 */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "readall.h"
+
+/* Size of each input chunk to be
+ read and allocate for. */
+#ifndef READALL_CHUNK
+#define READALL_CHUNK 262144
+#endif
+
+/* This function returns one of the READALL_ constants above.
+ If the return value is zero == READALL_OK, then:
+ (*dataptr) points to a dynamically allocated buffer, with
+ (*sizeptr) chars read from the file.
+ The buffer is allocated for one extra char, which is NUL,
+ and automatically appended after the data.
+ Initial values of (*dataptr) and (*sizeptr) are ignored.
+*/
+int readall(FILE *in, char **dataptr, size_t *sizeptr)
+{
+ char *data = NULL, *temp;
+ size_t size = 0;
+ size_t used = 0;
+ size_t n;
+
+ /* None of the parameters can be NULL. */
+ if (in == NULL || dataptr == NULL || sizeptr == NULL)
+ return READALL_INVALID;
+
+ /* A read error already occurred? */
+ if (ferror(in))
+ return READALL_ERROR;
+
+ while (1) {
+
+ if (used + READALL_CHUNK + 1 > size) {
+ size = used + READALL_CHUNK + 1;
+
+ /* Overflow check. Some ANSI C compilers
+ may optimize this away, though. */
+ if (size <= used) {
+ free(data);
+ return READALL_TOOMUCH;
+ }
+
+ temp = realloc(data, size);
+ if (temp == NULL) {
+ free(data);
+ return READALL_NOMEM;
+ }
+ data = temp;
+ }
+
+ n = fread(data + used, 1, READALL_CHUNK, in);
+ if (n == 0)
+ break;
+
+ used += n;
+ }
+
+ if (ferror(in)) {
+ free(data);
+ return READALL_ERROR;
+ }
+
+ temp = realloc(data, used + 1);
+ if (temp == NULL) {
+ free(data);
+ return READALL_NOMEM;
+ }
+ data = temp;
+ data[used] = '\0';
+
+ *dataptr = data;
+ *sizeptr = used;
+
+ return READALL_OK;
+}