]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Clean up path_join() implementation
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Thu, 15 May 2025 22:03:49 +0000 (16:03 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Thu, 15 May 2025 22:26:42 +0000 (16:26 -0600)
src/types/path.c
src/types/path.h
src/types/str.h
test/Makefile.am
test/types/path_test.c [new file with mode: 0644]

index d793ab327655c0f3872e5e409452b956650e189b..60ca4dc74f944145c0f091781e791eb60cdd9e74 100644 (file)
@@ -5,6 +5,7 @@
 #include "alloc.h"
 #include "config.h"
 #include "log.h"
+#include "types/str.h"
 
 /* These are arbitrary; feel free to change them. */
 #ifndef INITIAL_CAPACITY /* Unit tests want to override this */
@@ -46,37 +47,61 @@ path_filename(char const *path)
        return slash ? (slash + 1) : path;
 }
 
-/*
- * Cannot return NULL.
- *
- * XXX I'm starting to use this more. Probably sanitize better.
- */
-char *
-path_join(char const *path1, char const *path2)
+static void
+trim_leading_slashes(struct sized_string *str)
 {
-       // XXX needed?
-       if (path1[0] == 0)
-               return pstrdup(path2);
-       if (path2 == NULL || path2[0] == 0)
-               return pstrdup(path1);
+       while (str->str[0] == '/') {
+               str->str++;
+               str->len--;
+       }
+}
 
-       return path_njoin(path1, path2, strlen(path2));
+static void
+trim_trailing_slashes(struct sized_string *str)
+{
+       while (str->len > 1 && str->str[str->len - 1] == '/')
+               str->len--;
 }
 
+/* Result needs cleanup, cannot return NULL. */
 char *
-path_njoin(char const *p1, char const *p2, size_t p2len)
+path_join(char const *path1, char const *path2)
 {
+       struct sized_string p1;
+       struct sized_string p2;
        size_t n;
        char *result;
-       int written;
 
-       n = strlen(p1) + p2len + 2;
+       if (path1) {
+               p1.str = path1;
+               p1.len = strlen(path1);
+               trim_trailing_slashes(&p1);
+       } else {
+               memset(&p1, 0, sizeof(p1));
+       }
+
+       if (path2) {
+               p2.str = path2;
+               p2.len = strlen(path2);
+               trim_leading_slashes(&p2);
+       } else {
+               memset(&p2, 0, sizeof(p2));
+       }
+
+       if (p1.len == 0 && p2.len == 0)
+               return pstrdup("");
+       if (p1.len == 0 || p1.str[0] == '\0')
+               return pstrndup(p2.str, p2.len);
+       if (p2.len == 0 || p2.str[0] == '\0')
+               return pstrndup(p1.str, p1.len);
+
+       n = p1.len + p2.len + 2;
        result = pmalloc(n);
 
-       written = snprintf(result, n, "%s/%.*s", p1, (int) p2len, p2);
-       if (written != n - 1)
-               pr_crit("path_njoin: %zu %d %s %.*s",
-                   n, written, p1, (int) p2len, p2);
+       memcpy(result, p1.str, p1.len);
+       result[p1.len] = '/';
+       memcpy(result + p1.len + 1, p2.str, p2.len);
+       result[n - 1] = '\0';
 
        return result;
 }
index ec31211eb99a33e7d73d2b034dc70798947b5d3f..b0c5dedcd15e8a9851b3c724d939dd8f174164a0 100644 (file)
@@ -15,6 +15,5 @@ bool token_next(struct tokenizer *tkn);
 
 char const *path_filename(char const *);
 char *path_join(char const *, char const *);
-char *path_njoin(char const *, char const *, size_t);
 
 #endif /* SRC_TYPES_PATH_H_ */
index 6963ea46605a48bb751f7541a2fcdb5954c0b65e..33a9a9e91f077958b4e2a765aede49f4fba45fe2 100644 (file)
@@ -5,6 +5,11 @@
 #include <openssl/bn.h>
 #include <stdbool.h>
 
+struct sized_string {
+       char const *str;
+       size_t len;
+};
+
 char *str_concat(char const *, char const *);
 
 int hex2ulong(char const *, unsigned long *);
index 4a6a8b2769b8c5d6738561c3c892d11a2db4e067..6d50dd69e4897cbc6c60e4884bf59fdf4ce6bc11 100644 (file)
@@ -68,6 +68,10 @@ check_PROGRAMS +=            mft.test
 mft_test_SOURCES =             object/manifest_test.c
 mft_test_LDADD =               ${CHECK_LIBS}
 
+check_PROGRAMS +=              path.test
+path_test_SOURCES =            types/path_test.c
+path_test_LDADD =              ${CHECK_LIBS}
+
 check_PROGRAMS +=              pdu_handler.test
 pdu_handler_test_SOURCES =     rtr/pdu_handler_test.c
 pdu_handler_test_LDADD =       ${CHECK_LIBS}
diff --git a/test/types/path_test.c b/test/types/path_test.c
new file mode 100644 (file)
index 0000000..8f9f210
--- /dev/null
@@ -0,0 +1,73 @@
+#include <check.h>
+#include <stdlib.h>
+
+#include "alloc.c"
+#include "mock.c"
+#include "types/path.c"
+
+#define TEST_JOIN(expected, a, b)                              \
+       do {                                                    \
+               char *actual = path_join(a, b);                 \
+               ck_assert_pstr_eq(expected, actual);            \
+               free(actual);                                   \
+       } while (0);
+
+START_TEST(test_join)
+{
+       TEST_JOIN("", NULL, NULL);
+       TEST_JOIN("", "", NULL);
+       TEST_JOIN("", NULL, "");
+       TEST_JOIN("", "", "");
+
+       TEST_JOIN("a", "a", NULL);
+       TEST_JOIN("b", NULL, "b");
+       TEST_JOIN("a/b", "a", "b");
+       TEST_JOIN("abcd/efg", "abcd", "efg");
+
+       TEST_JOIN("c/d", "c/", "d");
+       TEST_JOIN("e/f", "e", "/f");
+       TEST_JOIN("g/h", "g/", "/h");
+
+       TEST_JOIN("/c/d/", "/c/", "d/");
+       TEST_JOIN("/e/f/", "/e", "/f/");
+       TEST_JOIN("/g/h/", "/g/", "/h/");
+
+       TEST_JOIN("c/d", "c/////", "d");
+       TEST_JOIN("e/f", "e", "/////////f");
+       TEST_JOIN("g/h", "g///////", "//////h");
+
+       TEST_JOIN("/", "/", "/");
+       TEST_JOIN("/", "/", "");
+       TEST_JOIN("/", "/", NULL);
+       TEST_JOIN("", "", "/");
+       TEST_JOIN("", NULL, "/");
+}
+END_TEST
+
+static Suite *
+create_suite(void)
+{
+       Suite *suite;
+       TCase *core;
+
+       core = tcase_create("join");
+       tcase_add_test(core, test_join);
+
+       suite = suite_create("path");
+       suite_add_tcase(suite, core);
+       return suite;
+}
+
+int
+main(void)
+{
+       SRunner *runner;
+       int failed;
+
+       runner = srunner_create(create_suite());
+       srunner_run_all(runner, CK_NORMAL);
+       failed = srunner_ntests_failed(runner);
+       srunner_free(runner);
+
+       return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}