pathuf supports constructing a path up to PATH_MAX.
---
include/platform/pathbuf.h | 15 +++++++++++
src/platform/meson.build | 1 +
src/platform/pathbuf.c | 53 +++++++++++++++++++++++++++++++++++++
tests/unit/meson.build | 1 +
tests/unit/pathbuf.c | 54 ++++++++++++++++++++++++++++++++++++++
5 files changed, 124 insertions(+)
create mode 100644 include/platform/pathbuf.h
create mode 100644 src/platform/pathbuf.c
create mode 100644 tests/unit/pathbuf.c
diff --git a/include/platform/pathbuf.h b/include/platform/pathbuf.h
new file mode 100644
index 0000000..b6c5c67
--- /dev/null
+++ b/include/platform/pathbuf.h
@@ -0,0 +1,15 @@
+#ifndef MUON_PLATFORM_PATHBUF_H
+#define MUON_PLATFORM_PATHBUF_H
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct pathbuf {
+ char buf[PATH_MAX];
+ size_t len;
+};
+
+bool pathbuf_init(struct pathbuf *buf, const char *path);
+bool pathbuf_append(struct pathbuf *buf, const char *path);
+
+#endif
diff --git a/src/platform/meson.build b/src/platform/meson.build
index b551cdd..9ebf3f4 100644
--- a/src/platform/meson.build
+++ b/src/platform/meson.build
@@ -3,6 +3,7 @@ platform_sources = files(
'filesystem.c',
'mem.c',
'path.c',
+ 'pathbuf.c',
'run_cmd.c',
'term.c',
'uname.c',
diff --git a/src/platform/pathbuf.c b/src/platform/pathbuf.c
new file mode 100644
index 0000000..236545d
--- /dev/null
+++ b/src/platform/pathbuf.c
@@ -0,0 +1,53 @@
+#include "posix.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "platform/pathbuf.h"
+
+bool
+pathbuf_init(struct pathbuf *buf, const char *path)
+{
+ size_t n;
+
+ if (!buf || !path)
+ return false;
+
+ n = strlen(path);
+
+ if (n >= sizeof(buf->buf))
+ return false;
+
+ memset(buf->buf, '\0', sizeof(buf->buf));
+
+ strncpy(buf->buf, path, n);
+ buf->len = n;
+
+ if (buf->len < sizeof(buf->buf) && buf->buf[buf->len] != '/')
+ buf->buf[buf->len++] = '/';
+
+ return true;
+}
+
+bool
+pathbuf_append(struct pathbuf *buf, const char *path)
+{
+ size_t n;
+
+ if (!buf || !path)
+ return false;
+
+ n = strlen(path);
+
+ if (n + buf->len >= sizeof(buf->buf))
+ return false;
+
+ strncpy(buf->buf + buf->len + 1, path, n);
+ buf->len += n;
+
+ if (buf->len < sizeof(buf->buf) && buf->buf[buf->len] != '/')
+ buf->buf[buf->len++] = '/';
+
+ return true;
+}
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 99c9627..3c98463 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -1,5 +1,6 @@
tests = [
['path', [files('path.c')], {'dependencies': muon_dep}],
+ ['pathbuf', [files('pathbuf.c')], {'dependencies': muon_dep}],
]
foreach t : tests
diff --git a/tests/unit/pathbuf.c b/tests/unit/pathbuf.c
new file mode 100644
index 0000000..d4471d3
--- /dev/null
+++ b/tests/unit/pathbuf.c
@@ -0,0 +1,54 @@
+#include "posix.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "platform/pathbuf.h"
+
+static void
+test_pathbuf_init(void)
+{
+ struct pathbuf buf;
+ char long_path[PATH_MAX + 1];
+
+ memset(long_path, 'a', PATH_MAX + 1);
+ long_path[PATH_MAX] = '\0';
+
+ assert(!pathbuf_init(NULL, ""));
+ assert(!pathbuf_init(&buf, NULL));
+ assert(!pathbuf_init(&buf, long_path));
+ assert(pathbuf_init(&buf, "/path"));
+ assert(strcmp(buf.buf, "/path/") == 0);
+ assert(buf.len == strlen("/path/"));
+}
+
+static void
+test_pathbuf_append(void)
+{
+ struct pathbuf buf;
+ char long_path[PATH_MAX + 1];
+
+ memset(long_path, 'a', PATH_MAX + 1);
+ long_path[PATH_MAX] = '\0';
+
+ pathbuf_init(&buf, "/path");
+
+ assert(!pathbuf_append(NULL, ""));
+ assert(!pathbuf_append(&buf, NULL));
+ assert(!pathbuf_append(&buf, long_path));
+ assert(pathbuf_append(&buf, "otherpath"));
+ assert(strcmp(buf.buf, "/path/otherpath/"));
+ assert(buf.len == strlen("/path/otherpath/"));
+}
+
+int
+main(void)
+{
+ log_init();
+ log_set_lvl(log_debug);
+
+ test_pathbuf_init();
+ test_pathbuf_append();
+}
--
2.36.1