changeset 347:0969931b98e4

core: start removing POSIX APIs
author David Demelier <markand@malikania.fr>
date Tue, 19 Oct 2021 13:23:30 +0200
parents 323d13f49233
children 7d7991f97acf
files src/libmlk-core/CMakeLists.txt src/libmlk-core/core/buf.c src/libmlk-core/core/buf.h src/libmlk-core/core/vfs.c
diffstat 4 files changed, 448 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/libmlk-core/CMakeLists.txt	Mon Oct 18 21:52:46 2021 +0200
+++ b/src/libmlk-core/CMakeLists.txt	Tue Oct 19 13:23:30 2021 +0200
@@ -26,6 +26,8 @@
 	${libmlk-core_SOURCE_DIR}/core/alloc.h
 	${libmlk-core_SOURCE_DIR}/core/animation.c
 	${libmlk-core_SOURCE_DIR}/core/animation.h
+	${libmlk-core_SOURCE_DIR}/core/buf.c
+	${libmlk-core_SOURCE_DIR}/core/buf.h
 	${libmlk-core_SOURCE_DIR}/core/clock.c
 	${libmlk-core_SOURCE_DIR}/core/clock.h
 	${libmlk-core_SOURCE_DIR}/core/color.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core/core/buf.c	Tue Oct 19 13:23:30 2021 +0200
@@ -0,0 +1,346 @@
+/*
+ * buf.c -- simple string buffer for C
+ *
+ * Copyright (c) 2019-2021 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "buf.h"
+
+/*
+ * Try to increase the buffer length by a power of two until we have enough
+ * space to fit `desired'.
+ *
+ * Detects overflow and return -1 if happened or reallocation could not
+ * occur.
+ */
+static int
+growdbl(struct buf *b, size_t desired)
+{
+	size_t newcap = b->capacity;
+	void *newptr;
+
+	while (desired > newcap - b->length) {
+		const size_t r = newcap * 2;
+
+		/* Overflow occured. */
+		if (r / newcap != 2) {
+#if defined(ENOMEM)
+			errno = ENOMEM;
+#endif
+			return -1;
+		}
+
+		newcap = r;
+	}
+
+	/* At this step we must have enough room. */
+	assert(newcap - b->length >= desired);
+
+	/* Pretty much impossible to reach but always assume it's possible. */
+	if (newcap == SIZE_MAX) {
+#if defined(ENOMEM)
+		errno = ENOMEM;
+#endif
+		return -1;
+	}
+
+	if (!(newptr = BUF_REALLOC(b->data, newcap + 1)))
+		return -1;
+
+	b->data = newptr;
+	b->capacity = newcap;
+
+	return 0;
+}
+
+/*
+ * Try to allocate just enough space for the `desired' amount of space. This is
+ * only used when the buffer is already too large but hasn't reached SIZE_MAX
+ * yet.
+ *
+ * Returns -1 if allocation failed.
+ */
+static int
+growmin(struct buf *b, size_t desired)
+{
+	size_t newcap;
+	void *newptr;
+
+	if (desired >= SIZE_MAX - b->length) {
+#if defined(ENOMEM)
+		errno = ENOMEM;
+#endif
+		return -1;
+	}
+
+	/* Don't forget to keep what's remaining between capacity and length. */
+	newcap = b->capacity + (desired - (b->capacity - b->length));
+
+	/* Try to reallocate. */
+	if (!(newptr = BUF_REALLOC(b->data, newcap + 1)))
+		return -1;
+
+	b->data = newptr;
+	b->capacity = newcap;
+
+	return 0;
+}
+
+/*
+ * Entry point for reallocating data. Will try to allocate twice until we have
+ * enough room and then only the minimal amount.
+ */
+static int
+grow(struct buf *b, size_t desired)
+{
+	const size_t avail = b->capacity - b->length;
+
+	if (avail >= desired)
+		return 0;
+
+	if (!b->capacity) {
+		if (!(b->data = BUF_MALLOC(desired + 1)))
+			return -1;
+
+		b->capacity = desired;
+	} else if (growdbl(b, desired) < 0 && growmin(b, desired) < 0)
+		return -1;
+
+	return 0;
+}
+
+void
+buf_init(struct buf *b)
+{
+	assert(b);
+
+	memset(b, 0, sizeof (*b));
+}
+
+int
+buf_reserve(struct buf *b, size_t amount)
+{
+	assert(b);
+
+	if (grow(b, amount) < 0)
+		return -1;
+
+	return 0;
+}
+
+int
+buf_resize(struct buf *b, size_t size, char ch)
+{
+	assert(b);
+
+	/* New size is smaller than curren't length, just update it. */
+	if (size < b->length) {
+		b->data[b->length = size] = 0;
+		return 0;
+	}
+
+	/* New size is bigger, data may be reallocated. */
+	if (grow(b, size - b->length) < 0)
+		return -1;
+
+	memset(&b->data[b->length], ch, size - b->length);
+	b->length = size;
+	b->data[b->length] = 0;
+
+	return 0;
+}
+
+int
+buf_shrink(struct buf *b)
+{
+	assert(b);
+
+	void *newptr;
+
+	if (b->length == 0) {
+		free(b->data);
+		b->data = NULL;
+		b->length = b->capacity = 0;
+		return 0;
+	}
+
+	if (!(newptr = BUF_REALLOC(b->data, b->length + 1)))
+		return -1;
+
+	b->data = newptr;
+	b->capacity = b->length;
+
+	return 0;
+}
+
+void
+buf_erase(struct buf *b, size_t pos, size_t count)
+{
+	assert(b);
+	assert(pos <= b->length);
+
+	if (count > b->length - pos) {
+		/* Optimize whole erase at pos. */
+		b->data[pos] = 0;
+		b->length = pos;
+	} else {
+		memmove(&b->data[pos], &b->data[pos + count], b->length - count);
+		b->length -= count;
+	}
+}
+
+int
+buf_putc(struct buf *b, char c)
+{
+	assert(b);
+
+	if (grow(b, 1) < 0)
+		return -1;
+
+	b->data[b->length++] = c;
+	b->data[b->length] = 0;
+
+	return 0;
+}
+
+int
+buf_puts(struct buf *b, const char *s)
+{
+	assert(b);
+	assert(s);
+
+	const size_t len = strlen(s);
+
+	if (grow(b, len) < 0)
+		return -1;
+
+	memcpy(&b->data[b->length], s, len + 1);
+	b->length += len;
+
+	return 0;
+}
+
+int
+buf_printf(struct buf *b, const char *fmt, ...)
+{
+	assert(b);
+	assert(fmt);
+
+	va_list ap;
+	int ret;
+
+	va_start(ap, fmt);
+	ret = buf_vprintf(b, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+int
+buf_vprintf(struct buf *b, const char *fmt, va_list args)
+{
+	assert(b);
+	assert(fmt);
+
+	va_list ap;
+	int amount;
+
+	/* Determine length. */
+	va_copy(ap, args);
+	amount = vsnprintf(NULL, 0, fmt, ap);
+	va_end(ap);
+
+	if (amount < 0)
+		return -1;
+
+	/* Do actual copy. */
+	if (grow(b, amount) < 0)
+		return -1;
+
+	va_copy(ap, args);
+	amount = vsprintf(&b->data[b->length], fmt, ap);
+	va_end(ap);
+
+	if (amount < 0)
+		return -1;
+
+	b->length += amount;
+
+	return 0;
+}
+
+int
+buf_sub(struct buf *b, const struct buf *src, size_t pos, size_t count)
+{
+	assert(b);
+	assert(src);
+	assert(pos <= src->length);
+
+	if (count >= src->length)
+		count = src->length - pos;
+	if (!(b->data = BUF_MALLOC(count + 1)))
+		return -1;
+
+	strncpy(b->data, &src->data[pos], count);
+	b->length = count;
+	b->capacity = count;
+	b->data[b->length] = 0;
+
+	return 0;
+}
+
+int
+buf_dup(struct buf *b, const struct buf *src)
+{
+	assert(b);
+	assert(src);
+
+	if (!src->data)
+		return 0;
+	if (!(b->data = BUF_MALLOC(src->length + 1)))
+		return -1;
+
+	memcpy(b->data, src->data, src->length + 1);
+	b->capacity = src->length;
+	b->length = src->length;
+
+	return 0;
+}
+
+void
+buf_clear(struct buf *b)
+{
+	assert(b);
+
+	if (b->data)
+		b->data[b->length = 0] = 0;
+}
+
+void
+buf_finish(struct buf *b)
+{
+	assert(b);
+
+	BUF_FREE(b->data);
+	b->data = NULL;
+	b->capacity = b->length = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core/core/buf.h	Tue Oct 19 13:23:30 2021 +0200
@@ -0,0 +1,90 @@
+/*
+ * buf.h -- simple string buffer for C
+ *
+ * Copyright (c) 2019-2021 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BUF_H
+#define BUF_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#if !defined(BUF_MALLOC)
+#	define BUF_MALLOC malloc
+#endif
+
+#if !defined(BUF_REALLOC)
+#	define BUF_REALLOC realloc
+#endif
+
+#if !defined(BUF_FREE)
+#	define BUF_FREE free
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct buf {
+	char *data;
+	size_t length;
+	size_t capacity;
+};
+
+void
+buf_init(struct buf *);
+
+int
+buf_reserve(struct buf *, size_t);
+
+int
+buf_resize(struct buf *, size_t, char);
+
+int
+buf_shrink(struct buf *);
+
+void
+buf_erase(struct buf *, size_t, size_t);
+
+int
+buf_putc(struct buf *, char);
+
+int
+buf_puts(struct buf *, const char *);
+
+int
+buf_printf(struct buf *, const char *, ...);
+
+int
+buf_vprintf(struct buf *, const char *, va_list);
+
+int
+buf_sub(struct buf *, const struct buf *, size_t, size_t);
+
+int
+buf_dup(struct buf *, const struct buf *);
+
+void
+buf_clear(struct buf *);
+
+void
+buf_finish(struct buf *);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* !BUF_H */
--- a/src/libmlk-core/core/vfs.c	Mon Oct 18 21:52:46 2021 +0200
+++ b/src/libmlk-core/core/vfs.c	Tue Oct 19 13:23:30 2021 +0200
@@ -18,10 +18,10 @@
 
 #include <assert.h>
 #include <errno.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include "buf.h"
 #include "error.h"
 #include "vfs.h"
 #include "vfs_p.h"
@@ -70,28 +70,22 @@
 char *
 vfs_file_aread(struct vfs_file *file, size_t *outlen)
 {
-	FILE *fp;
-	char *out = NULL, buf[BUFSIZ];
-	size_t len, nr;
+	struct buf buf = {0};
+	char data[BUFSIZ];
+	size_t nr;
 
-	if (!(fp = open_memstream(&out, &len)))
-		return errorf("%s", strerror(errno)), NULL;
-
-	while ((nr = vfs_file_read(file, buf, sizeof (buf))) > 0) {
-		if (fwrite(buf, 1, nr, fp) != nr) {
+	while ((nr = vfs_file_read(file, data, sizeof (data))) > 0) {
+		if (buf_printf(&buf, "%.*s", (int)nr, data) < 0) {
 			errorf("%s", strerror(errno));
-			fclose(fp);
-			free(out);
+			buf_finish(&buf);
 			return NULL;
 		}
 	}
 
-	fclose(fp);
+	if (outlen)
+		*outlen = buf.length;
 
-	if (outlen)
-		*outlen = len;
-
-	return out;
+	return buf.data;
 }
 
 size_t