summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2010-10-25 11:35:45 +0100
committerLars Wirzenius <liw@liw.fi>2010-10-25 11:35:45 +0100
commitf6cee05cf1132209612989f7c30b2752b366e4e6 (patch)
tree49e50c9650856040a5e34b311d93e3d9751a8603
parent3a9a575bf5bf9aac76a673459fd79e2e8ea4a1a6 (diff)
downloaddynstr-f6cee05cf1132209612989f7c30b2752b366e4e6.tar.gz
Implement dynstr_fread and dynstr_read.
-rw-r--r--dynstr.c68
-rw-r--r--dynstr.h8
-rw-r--r--unittests.c67
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]);