Replace all POSIX-features to become fully ISO-C99

As it turned out, the only things that needed replacing were
getline(), strdup() and the timing in the benchmarks. Analogously,
we replace -D_DEFAULT_SOURCE with -D_ISOC99_SOURCE.

This way we further extend the number of platforms where libgrapheme can
be compiled and run on, e.g. MSVC still does not include getline().

Signed-off-by: Laslo Hunhold <dev@frign.de>
diff --git a/benchmark/util.c b/benchmark/util.c
index 94531bb..bdad3a5 100644
--- a/benchmark/util.c
+++ b/benchmark/util.c
@@ -71,10 +71,9 @@
 }
 
 static double
-time_diff(struct timespec *a, struct timespec *b)
+time_diff(clock_t a, clock_t b)
 {
-	return (double)(b->tv_sec - a->tv_sec) +
-	       (double)(b->tv_nsec - a->tv_nsec) * 1E-9;
+	return (double)(b - a) / CLOCKS_PER_SEC;
 }
 
 void
@@ -82,14 +81,14 @@
               const char *comment, const char *unit, double *baseline,
               size_t num_iterations, size_t units_per_iteration)
 {
-	struct timespec start, end;
+	clock_t start, end;
 	size_t i;
 	double diff;
 
 	printf("\t%s ", name);
 	fflush(stdout);
 
-	clock_gettime(CLOCK_MONOTONIC, &start);
+	start = clock();
 	for (i = 0; i < num_iterations; i++) {
 		func(payload);
 
@@ -98,8 +97,8 @@
 			fflush(stdout);
 		}
 	}
-	clock_gettime(CLOCK_MONOTONIC, &end);
-	diff = time_diff(&start, &end) / (double)num_iterations /
+	end = clock();
+	diff = time_diff(start, end) / (double)num_iterations /
 	       (double)units_per_iteration;
 
 	if (isnan(*baseline)) {
diff --git a/config.mk b/config.mk
index 5dcc742..c5284c5 100644
--- a/config.mk
+++ b/config.mk
@@ -14,7 +14,7 @@
 BINSUFFIX = 
 
 # flags
-CPPFLAGS = -D_DEFAULT_SOURCE
+CPPFLAGS = -D_ISOC99_SOURCE
 CFLAGS   = -std=c99 -Os -Wall -Wextra -Wpedantic
 LDFLAGS  = -s
 
diff --git a/gen/util.c b/gen/util.c
index 9d076b2..332be82 100644
--- a/gen/util.c
+++ b/gen/util.c
@@ -146,6 +146,43 @@
 	return 0;
 }
 
+static bool
+get_line(char **buf, size_t *bufsize, FILE *fp, size_t *len)
+{
+	int ret = EOF;
+
+	for (*len = 0;; (*len)++) {
+		if (*len > 0 && *buf != NULL && (*buf)[*len - 1] == '\n') {
+			/*
+			 * if the previously read character was a newline,
+			 * we fake an end-of-file so we NUL-terminate and
+			 * are done.
+			 */
+			ret = EOF;
+		} else {
+			ret = fgetc(fp);
+		}
+
+		if (*len >= *bufsize) {
+			/* the buffer needs to be expanded */
+			*bufsize += 512;
+			if ((*buf = realloc(*buf, *bufsize)) == NULL) {
+				fprintf(stderr, "get_line: Out of memory.\n");
+				exit(1);
+			}
+		}
+
+		if (ret != EOF) {
+			(*buf)[*len] = (char)ret;
+		} else {
+			(*buf)[*len] = '\0';
+			break;
+		}
+	}
+
+	return *len == 0 && (feof(fp) || ferror(fp));
+}
+
 void
 parse_file_with_callback(const char *fname,
                          int (*callback)(const char *, char **, size_t, char *,
@@ -154,8 +191,7 @@
 {
 	FILE *fp;
 	char *line = NULL, **field = NULL, *comment;
-	size_t linebufsize = 0, i, fieldbufsize = 0, j, nfields;
-	ssize_t len;
+	size_t linebufsize = 0, i, fieldbufsize = 0, j, nfields, len;
 
 	/* open file */
 	if (!(fp = fopen(fname, "r"))) {
@@ -164,7 +200,7 @@
 		exit(1);
 	}
 
-	while ((len = getline(&line, &linebufsize, fp)) >= 0) {
+	while (!get_line(&line, &linebufsize, fp, &len)) {
 		/* remove trailing newline */
 		if (len > 0 && line[len - 1] == '\n') {
 			line[len - 1] = '\0';
@@ -654,7 +690,8 @@
 {
 	struct break_test *t,
 		**test = ((struct break_test_payload *)payload)->test;
-	size_t i, *testlen = ((struct break_test_payload *)payload)->testlen;
+	size_t i, *testlen = ((struct break_test_payload *)payload)->testlen,
+		  commentlen;
 	char *token;
 
 	(void)fname;
@@ -733,11 +770,15 @@
 	}
 
 	/* store comment */
-	if (comment != NULL &&
-	    ((*test)[*testlen - 1].descr = strdup(comment)) == NULL) {
-		fprintf(stderr, "break_test_callback: strdup: %s.\n",
-		        strerror(errno));
-		return 1;
+	if (comment != NULL) {
+		commentlen = strlen(comment) + 1;
+		if (((*test)[*testlen - 1].descr = malloc(commentlen)) ==
+		    NULL) {
+			fprintf(stderr, "break_test_callback: malloc: %s.\n",
+			        strerror(errno));
+			return 1;
+		}
+		memcpy((*test)[*testlen - 1].descr, comment, commentlen);
 	}
 
 	return 0;