#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 */
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;
}
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_ */
#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 *);
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}
--- /dev/null
+#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;
+}