From f6cee05cf1132209612989f7c30b2752b366e4e6 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 25 Oct 2010 11:35:45 +0100 Subject: Implement dynstr_fread and dynstr_read. --- dynstr.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dynstr.h | 8 +++----- unittests.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 5 deletions(-) diff --git a/dynstr.c b/dynstr.c index 99ef2ab..246c16f 100644 --- a/dynstr.c +++ b/dynstr.c @@ -9,6 +9,9 @@ #include "dynstr.h" +#define DYNSTR_ERROR ((size_t) -1) + + struct Dynstr { const unsigned char *mem; size_t size; @@ -301,3 +304,68 @@ ssize_t dynstr_write(int fd, Dynstr *dynstr) return write(fd, dynstr->mem, dynstr->size); } + +static Dynstr *read_helper(size_t (*callback)(FILE *f, int fd, unsigned char *buf, + size_t size), + FILE *f, int fd, size_t size) +{ + unsigned char *buf; + unsigned char *p; + Dynstr *dynstr; + size_t n; + + buf = alloc(size); + if (buf == NULL) + return NULL; + + n = callback(f, fd, buf, size); + if (n == DYNSTR_ERROR) { + free(buf); + return NULL; + } + + if (n < size) { + p = realloc(buf, n); + if (p != NULL) + buf = p; + } + + dynstr = new(buf, n, false); + dynstr->dynamic = true; + return dynstr; +} + + +static size_t fread_callback(FILE *f, int fd, unsigned char *buf, size_t size) +{ + size_t n; + + n = fread(buf, 1, size, f); + if (n == 0 && ferror(f)) + return DYNSTR_ERROR; + return n; +} + + +static size_t read_callback(FILE *f, int fd, unsigned char *buf, size_t size) +{ + ssize_t n; + + n = read(fd, buf, size); + if (n == -1) + return DYNSTR_ERROR; + return n; +} + + +Dynstr *dynstr_fread(FILE *file, size_t size) +{ + return read_helper(fread_callback, file, -1, size); +} + + +Dynstr *dynstr_read(int file, size_t size) +{ + return read_helper(read_callback, NULL, file, size); +} + diff --git a/dynstr.h b/dynstr.h index 95f7f4e..5c5bc86 100644 --- a/dynstr.h +++ b/dynstr.h @@ -147,12 +147,10 @@ size_t dynstr_fwrite(FILE *file, Dynstr *dynstr); ssize_t dynstr_write(int file, Dynstr *dynstr); /* Read a number of bytes from an open file, either FILE or a Unix file - * handle. Return value is number of bytes read, just like for fread(3). - * A value less than the requested may indicate an error or end-of-file. - * Use ferror(3) and feof(3) to determine which. If it was an error, errno - * has been set by fread(3). */ -Dynstr *dynstr_read(int file, size_t size); + * handle. Return value is the string that was read. The string is empty + * to indicate EOF, or NULL for error. */ Dynstr *dynstr_fread(FILE *file, size_t size); +Dynstr *dynstr_read(int file, size_t size); /* Read a line from an open file, either a FILE or a Unix file handle. * The line ends with the first newline byte, or at the end of the file. diff --git a/unittests.c b/unittests.c index f888f94..b4ad978 100644 --- a/unittests.c +++ b/unittests.c @@ -1031,6 +1031,71 @@ static int test_write_writes_string(void) } +static int read_test(Dynstr *(*callback)(char *filename, size_t size)) +{ + char tempname[] = "unittest.XXXXXX"; + int fd; + Dynstr *dynstr; + Dynstr *dynstr2; + const char canonical[] = "life is too short for str* and mem* in apps"; + + fd = mkstemp(tempname); + if (fd == -1) + abort(); + if (write(fd, canonical, sizeof(canonical)) == -1) + abort(); + close(fd); + + dynstr = callback(tempname, sizeof(canonical) * 2); + FAIL_UNLESS(dynstr != NULL); + FAIL_UNLESS_EQUAL(dynstr_len(dynstr), sizeof(canonical)); + + dynstr2 = dynstr_new_from_memory(canonical, sizeof(canonical)); + FAIL_UNLESS_EQUAL(dynstr_cmp(dynstr, dynstr2), 0); + + dynstr_free(dynstr); + dynstr_free(dynstr2); + + return true; +} + + +static Dynstr *fread_callback(char *filename, size_t size) +{ + FILE *f; + Dynstr *dynstr; + + f = fopen(filename, "r"); + dynstr = dynstr_fread(f, size); + fclose(f); + return dynstr; +} + + +static int test_fread_reads_string(void) +{ + return read_test(fread_callback); +} + + +static Dynstr *read_callback(char *filename, size_t size) +{ + int fd; + Dynstr *dynstr; + + fd = open(filename, O_RDONLY, 0); + dynstr = dynstr_read(fd, size); + close(fd); + return dynstr; +} + + +static int test_read_reads_string(void) +{ + return read_test(read_callback); +} + + static void setup(void) { dynstr_init(); @@ -1119,6 +1184,8 @@ static const struct test tests[] = { TEST(test_cmp_returns_positive_if_second_string_comes_first), TEST(test_fwrite_writes_string), TEST(test_write_writes_string), + TEST(test_fread_reads_string), + TEST(test_read_reads_string), }; static const int num_tests = sizeof(tests) / sizeof(tests[0]); -- cgit v1.2.1