summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2010-10-25 12:03:12 +0100
committerLars Wirzenius <liw@liw.fi>2010-10-25 12:03:12 +0100
commitfc6e2a8f7018a01ce84e566c252a545a55d5f70c (patch)
treefc1efec16de3d2a17d28baad58bd6c3393838de5
parentf6cee05cf1132209612989f7c30b2752b366e4e6 (diff)
downloaddynstr-fc6e2a8f7018a01ce84e566c252a545a55d5f70c.tar.gz
Implement dynstr_readline and dynstr_freadline.
This is a very stupid implementation.
-rw-r--r--dynstr.c84
-rw-r--r--unittests.c73
2 files changed, 157 insertions, 0 deletions
diff --git a/dynstr.c b/dynstr.c
index 246c16f..de02f79 100644
--- a/dynstr.c
+++ b/dynstr.c
@@ -369,3 +369,87 @@ Dynstr *dynstr_read(int file, size_t size)
return read_helper(read_callback, NULL, file, size);
}
+
+static Dynstr *readline_helper(int (*callback)(FILE *, int), FILE *f, int fd)
+{
+ Dynstr *line;
+ Dynstr *temp1;
+ Dynstr *temp2;
+ int c;
+ unsigned char byte;
+
+ line = dynstr_new_empty();
+
+ for (;;) {
+ temp1 = NULL;
+ temp2 = NULL;
+
+ c = callback(f, fd);
+ if (c == -1)
+ goto error;
+ else if (c == -2)
+ break;
+
+ byte = c;
+ temp1 = dynstr_new_from_constant_memory(&byte, 1);
+ if (temp1 == NULL)
+ goto error;
+ temp2 = dynstr_cat(line, temp1, NULL);
+ dynstr_free(temp1);
+ dynstr_free(line);
+ line = temp2;
+
+ if (c == '\n')
+ break;
+ }
+
+ return line;
+
+error:
+ dynstr_free(line);
+ dynstr_free(temp1);
+ dynstr_free(temp2);
+ return NULL;
+}
+
+
+static int freadline_callback(FILE *f, int fd)
+{
+ int c;
+
+ c = getc(f);
+ if (c == EOF && ferror(f))
+ return -1;
+ else if (c == EOF)
+ return -2;
+ else
+ return c;
+}
+
+
+Dynstr *dynstr_freadline(FILE *file)
+{
+ return readline_helper(freadline_callback, file, -1);
+}
+
+
+static int readline_callback(FILE *f, int fd)
+{
+ unsigned char c;
+ int n;
+
+ n = read(fd, &c, 1);
+ if (n == 0)
+ return -2;
+ else if (n == -1)
+ return -1;
+ else
+ return c;
+}
+
+
+Dynstr *dynstr_readline(int file)
+{
+ return readline_helper(readline_callback, NULL, file);
+}
+
diff --git a/unittests.c b/unittests.c
index b4ad978..32bb270 100644
--- a/unittests.c
+++ b/unittests.c
@@ -1096,6 +1096,77 @@ static int test_read_reads_string(void)
}
+static int readline_test(Dynstr *(*callback)(char *filename))
+{
+ char tempname[] = "unittest.XXXXXX";
+ int fd;
+ const char cline1[] = "life is too short for str* and mem* in apps\n";
+ const char cline2[] = "use dynstr instead!\n";
+ Dynstr *lines;
+ Dynstr *line1;
+ Dynstr *line2;
+ Dynstr *result;
+
+ fd = mkstemp(tempname);
+ if (fd == -1)
+ abort();
+
+ line1 = dynstr_new_from_constant_cstring(cline1);
+ line2 = dynstr_new_from_constant_cstring(cline2);
+ lines = dynstr_cat(line1, line2, NULL);
+ if (dynstr_write(fd, lines) != dynstr_len(lines))
+ abort();
+ close(fd);
+
+ result = callback(tempname);
+
+ FAIL_UNLESS_EQUAL(dynstr_cmp(line1, result), 0);
+
+ dynstr_free(line1);
+ dynstr_free(line2);
+ dynstr_free(lines);
+ dynstr_free(result);
+
+ return true;
+}
+
+
+static Dynstr *freadline_callback(char *filename)
+{
+ FILE *f;
+ Dynstr *line1;
+
+ f = fopen(filename, "r");
+ line1 = dynstr_freadline(f);
+ fclose(f);
+ return line1;
+}
+
+
+static int test_freadline_reads_first_line(void)
+{
+ return readline_test(freadline_callback);
+}
+
+
+static Dynstr *readline_callback(char *filename)
+{
+ int fd;
+ Dynstr *line1;
+
+ fd = open(filename, O_RDONLY, 0);
+ line1 = dynstr_readline(fd);
+ close(fd);
+ return line1;
+}
+
+
+static int test_readline_reads_first_line(void)
+{
+ return readline_test(readline_callback);
+}
+
+
static void setup(void)
{
dynstr_init();
@@ -1186,6 +1257,8 @@ static const struct test tests[] = {
TEST(test_write_writes_string),
TEST(test_fread_reads_string),
TEST(test_read_reads_string),
+ TEST(test_freadline_reads_first_line),
+ TEST(test_readline_reads_first_line),
};
static const int num_tests = sizeof(tests) / sizeof(tests[0]);