#include "cachetmp.h"
#include <stdatomic.h>
+#include <stdio.h>
+#include "log.h"
#include "types/path.h"
static atomic_uint file_counter;
/*
- * Returns a unique temporary file name in the local cache. Note, it's a name,
- * and it's pretty much reserved. The file itself will not be created.
+ * Returns (in @buf, which needs to length CACHE_TMPFILE_BUFLEN) a unique
+ * temporary file name in the local cache.
+ * Note, it's a name, and it's pretty much reserved. The file itself will not be
+ * created.
*
* The file will not be automatically deleted when it is closed or the program
* terminates.
- *
- * The name of the function is inherited from tmpfile(3).
- *
- * The resulting string needs to be released.
*/
-int
-cache_tmpfile(char **filename)
+void
+cache_tmpfile(char *buf)
{
- struct path_builder pb;
- int error;
-
- pb_init(&pb);
-
- error = pb_append(&pb, CACHE_TMPDIR);
- if (error)
- goto fail;
- error = pb_append_u32(&pb, atomic_fetch_add(&file_counter, 1u));
- if (error)
- goto fail;
+ unsigned int next;
+ int written;
- *filename = pb.string;
- return 0;
+ next = atomic_fetch_add(&file_counter, 1u);
-fail: pb_cleanup(&pb);
- return error;
+ written = snprintf(buf, CACHE_TMPFILE_BUFLEN, CACHE_TMPDIR "/%X", next);
+ if (written >= CACHE_TMPFILE_BUFLEN)
+ pr_crit("I ran out of temporal directories: %u", next);
}
#define SRC_CACHETMP_H_
#define CACHE_TMPDIR "tmp"
+#define CACHE_TMPFILE_BUFLEN 24 /* tmp/%X\0 */
-int cache_tmpfile(char **); /* Return new unique path in <cache>/tmp/ */
+void cache_tmpfile(char *); /* Return new unique path in <cache>/tmp/ */
#endif /* SRC_CACHETMP_H_ */
static int
fetch_url(char const *url, char const *filename)
{
- struct path_builder pb;
+ char *path;
int error;
- pb_init(&pb);
- error = pb_append(&pb, config_get_tal());
- if (error)
- goto pbfail;
- error = pb_append(&pb, filename);
- if (error)
- goto pbfail;
-
- error = http_download_direct(url, pb.string);
- if (error)
- goto dlfail;
-
- fprintf(stdout, "Successfully fetched '%s'!\n\n", pb.string);
- pb_cleanup(&pb);
- return 0;
+ path = path_join(config_get_tal(), filename);
-pbfail:
- fprintf(stderr, "Cannot determine destination path: %s\n",
- strerror(abs(error)));
- pb_cleanup(&pb);
- return error;
+ error = http_download_direct(url, path);
+ if (error) {
+ fprintf(stderr, "Couldn't fetch '%s': %s\n",
+ path, strerror(abs(error)));
+ goto end;
+ }
-dlfail:
- fprintf(stderr, "Couldn't fetch '%s': %s\n", pb.string,
- strerror(abs(error)));
- pb_cleanup(&pb);
+ fprintf(stdout, "Successfully fetched '%s'!\n\n", path);
+end: free(path);
return error;
}
#include "object/signed_object.h"
#include "thread_var.h"
#include "types/path.h"
+#include "types/url.h"
static int
decode_manifest(struct signed_object *sobj, struct Manifest **result)
shuffle_mft_files(mft);
rpp = &parent->rpp;
- rpp_url = path_parent(mft_url);
+ rpp_url = url_parent(mft_url); // XXX
rpp->nfiles = mft->fileList.list.count;
rpp->files = pzalloc(rpp->nfiles * sizeof(*rpp->files));
if (error)
goto revert;
- dst->url = path_childn(rpp_url,
+ dst->url = path_njoin(rpp_url,
(char const *)src->file.buf,
src->file.size);
{
#define TMPDIR "/tmp/fort-XXXXXX"
- struct path_builder pb;
char buf[sizeof(TMPDIR)];
char *tmpdir;
+ char *tmpfile;
BIO *result = NULL;
- int error;
strcpy(buf, TMPDIR);
tmpdir = mkdtemp(buf);
return NULL;
}
- pb_init(&pb);
- error = pb_append(&pb, tmpdir);
- if (error)
- goto end;
- error = pb_append(&pb, path_filename(src));
- if (error)
- goto end;
-
- result = __rsync2bio(src, pb.string);
+ tmpfile = path_join(tmpdir, path_filename(src));
+ result = __rsync2bio(src, tmpfile);
+ free(tmpfile);
-end: pb_cleanup(&pb);
return result;
}
/* TODO (performance) Stream instead of caching notifs, snapshots & deltas. */
static int
-dl_tmp(char const *url, char **path)
+dl_tmp(char const *url, char *path)
{
- int error;
-
- error = cache_tmpfile(path);
- if (error)
- return error;
-
- error = http_download(url, *path, 0, NULL);
- if (error)
- free(*path);
-
- return error;
+ cache_tmpfile(path);
+ return http_download(url, path, 0, NULL);
}
static int
handle_snapshot(struct update_notification *new, struct rrdp_state *state)
{
- char *tmppath;
+ char tmppath[CACHE_TMPFILE_BUFLEN];
int error;
pr_val_debug("Processing snapshot.");
fnstack_push(new->snapshot.uri);
- error = dl_tmp(new->snapshot.uri, &tmppath);
+ error = dl_tmp(new->snapshot.uri, tmppath);
if (error)
- goto end1;
+ goto end;
error = validate_hash(&new->snapshot, tmppath);
if (error)
- goto end2;
+ goto end;
error = parse_snapshot(&new->session, tmppath, state);
// delete_file(tmppath); XXX
-end2: free(tmppath);
-end1: fnstack_pop();
+end: fnstack_pop();
return error;
}
handle_delta(struct update_notification *notif,
struct notification_delta *delta, struct rrdp_state *state)
{
- char *tmppath;
+ char tmppath[CACHE_TMPFILE_BUFLEN];
int error;
pr_val_debug("Processing delta '%s'.", delta->meta.uri);
fnstack_push(delta->meta.uri);
- error = dl_tmp(delta->meta.uri, &tmppath);
+ error = dl_tmp(delta->meta.uri, tmppath);
if (error)
goto end;
error = parse_delta(notif, delta, tmppath, state);
// delete_file(tmppath); XXX
- free(tmppath);
end: fnstack_pop();
return error;
}
dl_notif(struct cache_mapping const *map, time_t mtim, bool *changed,
struct update_notification *new)
{
- char *tmppath;
+ char tmppath[CACHE_TMPFILE_BUFLEN];
int error;
- error = cache_tmpfile(&tmppath);
- if (error)
- return error;
+ cache_tmpfile(tmppath);
*changed = false;
error = http_download(map->url, tmppath, mtim, changed);
if (error)
- goto end;
+ return error;
if (!(*changed)) {
pr_val_debug("The Notification has not changed.");
- goto end;
+ return 0;
}
error = parse_notification(map->url, tmppath, new);
if (error)
- goto end;
+ return error;
if (remove(tmppath) < 0) {
pr_val_warn("Can't remove notification's temporal file: %s",
/* Nonfatal; fall through */
}
-end: free(tmppath);
- return error;
+ return 0;
}
/*
return true;
}
-/* @reserve needs to be < INITIAL_CAPACITY. */
-void
-__pb_init(struct path_builder *pb, size_t reserve)
-{
- pb->string = pmalloc(INITIAL_CAPACITY);
- pb->string[reserve] = 0;
- pb->len = reserve;
- pb->capacity = INITIAL_CAPACITY;
-}
-
-static int
-pb_grow(struct path_builder *pb, size_t total_len, char const *addend)
-{
- if (total_len > MAX_CAPACITY) {
- pr_val_err("Unable to concatenate '%.32s' (might be truncated) to path '%s': Path too long (%zu > %u)",
- addend, pb->string, total_len, MAX_CAPACITY);
- return ENOSPC;
- }
-
- do {
- pb->capacity *= 2;
- } while (total_len > pb->capacity);
-
- pb->string = prealloc(pb->string, pb->capacity);
- return 0;
-}
-
-int
-pb_appendn(struct path_builder *pb, char const *addend, size_t addlen)
-{
- size_t total_len;
- bool add_slash;
- int error;
-
- if (addlen == 0)
- return 0;
-
- add_slash = (pb->len != 0);
- if (add_slash)
- addlen++;
-
- total_len = pb->len + addlen + 1;
- if (total_len > pb->capacity) {
- error = pb_grow(pb, total_len, addend);
- if (error)
- return error;
- }
-
- if (add_slash) {
- pb->string[pb->len] = '/';
- memcpy(pb->string + pb->len + 1, addend, addlen);
- } else {
- memcpy(pb->string + pb->len, addend, addlen);
- }
-
- pb->len += addlen;
- pb->string[pb->len] = 0;
-
- return 0;
-}
-
-int
-pb_append(struct path_builder *pb, char const *addend)
-{
- return (addend != NULL) ? pb_appendn(pb, addend, strlen(addend)) : 0;
-}
-
-int
-pb_append_u32(struct path_builder *pb, uint32_t num)
-{
-#define MAX_STRLEN 9 /* 8 hexadecimal digits plus null chara */
- char buffer[MAX_STRLEN];
- int num_len;
-
- num_len = snprintf(buffer, MAX_STRLEN, "%X", num);
- if (num_len < 0) {
- pr_val_err("Cannot stringify number '%u': Unknown cause. Error code might be %d.",
- num, num_len);
- return EIO; /* num_len is not necessarily an error code */
- }
- if (num_len >= MAX_STRLEN)
- pr_crit("pb: Number %u requires %d digits", num, num_len);
-
- return pb_appendn(pb, buffer, num_len);
-}
-
-/* Removes the last component added. */
-int
-pb_pop(struct path_builder *pb, bool fatal)
-{
- size_t i;
-
- if (pb->len == 0 || (pb->len == 1 && pb->string[0] == '/')) {
- if (fatal)
- pr_crit("Programming error: Attempting to pop empty path builder");
- return -pr_val_err("Path cannot '..' over the root.");
- }
-
- for (i = pb->len - 1; i >= 1; i--) {
- if (pb->string[i] == '/') {
- pb->string[i] = 0;
- pb->len = i;
- return 0;
- }
- }
-
- if (pb->string[0] == '/') {
- pb->string[1] = 0;
- pb->len = 1;
- } else {
- pb->string[0] = 0;
- pb->len = 0;
- }
- return 0;
-}
-
-static void
-reverse_string(char *str, size_t len)
-{
- char *b, *e; /* beginning, end */
- char tmp;
-
- for (b = str, e = str + len - 1; b < e; b++, e--) {
- tmp = *b;
- *b = *e;
- *e = tmp;
- }
-}
-
-/* Turns ab/cd/ef/gh into gh/ef/cd/ab. */
-void
-pb_reverse(struct path_builder *pb)
-{
- size_t min;
- size_t max;
-
- reverse_string(pb->string, pb->len);
-
- min = 0;
- for (max = 1; max < pb->len; max++) {
- if (pb->string[max] == '/') {
- reverse_string(&pb->string[min], max - min);
- max++;
- min = max;
- }
- }
- reverse_string(&pb->string[min], pb->len - min);
-}
-
-void
-pb_cleanup(struct path_builder *pb)
-{
- free(pb->string);
-}
-
-/* Note, fatal is hardcoded as 1. */
-char *
-path_parent(char const *child)
-{
- struct path_builder pb;
- pb.string = pstrdup(child);
- pb.len = pb.capacity = strlen(pb.string);
- pb_pop(&pb, true);
- return pb.string;
-}
-
-char *
-path_childn(char const *p1, char const *p2, size_t p2len)
-{
- struct path_builder pb;
-
- pb_init(&pb);
- pb_append(&pb, p1); // XXX
- pb_appendn(&pb, p2, p2len); // XXX
-
- return pb.string;
-}
-
char const *
path_filename(char const *path)
{
/*
* Cannot return NULL.
*
- * XXX I'm starting to use this more. Probably clean the slashes.
+ * XXX I'm starting to use this more. Probably sanitize better.
*/
char *
path_join(char const *path1, char const *path2)
{
- size_t n;
- char *result;
- int written;
-
// XXX needed?
if (path1[0] == 0)
return pstrdup(path2);
if (path2 == NULL || path2[0] == 0)
return pstrdup(path1);
- n = strlen(path1) + strlen(path2) + 2;
+ return path_njoin(path1, path2, strlen(path2));
+}
+
+char *
+path_njoin(char const *p1, char const *p2, size_t p2len)
+{
+ size_t n;
+ char *result;
+ int written;
+
+ n = strlen(p1) + p2len + 2;
result = pmalloc(n);
- written = snprintf(result, n, "%s/%s", path1, path2);
+ written = snprintf(result, n, "%s/%.*s", p1, (int) p2len, p2);
if (written != n - 1)
- pr_crit("join_paths: %zu %d %s %s", n, written, path1, path2);
+ pr_crit("path_njoin: %zu %d %s %.*s",
+ n, written, p1, (int) p2len, p2);
return result;
}
#ifndef SRC_TYPES_PATH_H_
#define SRC_TYPES_PATH_H_
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
#include <stdbool.h>
#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <sys/types.h>
-#include <unistd.h>
// XXX rename
struct tokenizer {
void token_init(struct tokenizer *, char const *);
bool token_next(struct tokenizer *tkn);
-struct path_builder {
- char *string;
- size_t len; /* Includes the null chara */
- size_t capacity;
-};
-
-void __pb_init(struct path_builder *, size_t);
-#define pb_init(pb) __pb_init(pb, 0)
-
-/*
- * The appends are atomic.
- * They are also naive; they don't collapse `.`, `..` nor slashes.
- */
-
-int pb_appendn(struct path_builder *, char const *, size_t);
-int pb_append(struct path_builder *, char const *);
-int pb_append_u32(struct path_builder *, uint32_t);
-
-int pb_pop(struct path_builder *, bool);
-
-void pb_reverse(struct path_builder *);
-
-void pb_cleanup(struct path_builder *);
-
-char *path_parent(char const *);
-char *path_childn(char const *, char const *, size_t);
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_ */
return NULL;
}
+char *
+url_parent(char const *child)
+{
+ char *slash = strrchr(child, '/');
+ return (slash != NULL) ? pstrndup(child, slash - child) : NULL;
+}
+
bool
url_same_origin(char const *url1, char const *url2)
{
bool url_is_https(char const *);
char *url_normalize(char const *);
+char *url_parent(char const *);
bool url_same_origin(char const *, char const *);
#endif /* SRC_TYPES_URL_H_ */
check_PROGRAMS += deltas_array.test
check_PROGRAMS += hash.test
check_PROGRAMS += mft.test
-check_PROGRAMS += path.test
check_PROGRAMS += pdu_handler.test
check_PROGRAMS += pdu_stream.test
check_PROGRAMS += rrdp.test
mft_test_SOURCES = object/manifest_test.c
mft_test_LDADD = ${MY_LDADD}
-path_test_SOURCES = types/path_test.c
-path_test_LDADD = ${MY_LDADD}
-
pdu_handler_test_SOURCES = rtr/pdu_handler_test.c
pdu_handler_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS}
+++ /dev/null
-#include <check.h>
-#include <stdlib.h>
-
-#define INITIAL_CAPACITY 8
-
-#include "alloc.c"
-#include "mock.c"
-#include "types/path.c"
-
-#define CHECK_PB(_string, _capacity) \
- ck_assert_str_eq(_string, pb.string); \
- ck_assert_uint_eq(strlen(_string), pb.len); \
- ck_assert_uint_eq(_capacity, pb.capacity);
-
-START_TEST(test_append)
-{
- struct path_builder pb;
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, ""));
- CHECK_PB("", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- CHECK_PB("a", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "/a"));
- CHECK_PB("/a", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- CHECK_PB("a", 8);
- ck_assert_int_eq(0, pb_append(&pb, "b"));
- CHECK_PB("a/b", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a/b"));
- CHECK_PB("a/b", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a/"));
- CHECK_PB("a/", 8);
- ck_assert_int_eq(0, pb_append(&pb, "b/"));
- CHECK_PB("a//b/", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a/"));
- CHECK_PB("a/", 8);
- ck_assert_int_eq(0, pb_append(&pb, "b"));
- CHECK_PB("a//b", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- CHECK_PB("a", 8);
- ck_assert_int_eq(0, pb_append(&pb, "/b"));
- CHECK_PB("a//b", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a/"));
- CHECK_PB("a/", 8);
- ck_assert_int_eq(0, pb_append(&pb, "/b"));
- CHECK_PB("a///b", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "//a"));
- CHECK_PB("//a", 8);
- ck_assert_int_eq(0, pb_append(&pb, "///"));
- CHECK_PB("//a////", 8);
- ck_assert_int_eq(0, pb_append(&pb, "b////"));
- CHECK_PB("//a/////b////", 16);
- ck_assert_int_eq(0, pb_append(&pb, "/////c//////"));
- CHECK_PB("//a/////b//////////c//////", 32);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "//a///b//c//"));
- CHECK_PB("//a///b//c//", 16);
- pb_cleanup(&pb);
-}
-END_TEST
-
-/* Actually mainly designed to manhandle capacity expansion */
-START_TEST(test_uint)
-{
- struct path_builder pb;
-
- pb_init(&pb);
- pb_append_u32(&pb, 0x123);
- CHECK_PB("123", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- pb_append_u32(&pb, 0x1234567);
- CHECK_PB("1234567", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- pb_append_u32(&pb, 0x12345678);
- CHECK_PB("12345678", 16);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- pb_append_u32(&pb, 0x12345);
- CHECK_PB("12345", 8);
- pb_append_u32(&pb, 0x7);
- CHECK_PB("12345/7", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- pb_append_u32(&pb, 0x12345);
- CHECK_PB("12345", 8);
- pb_append_u32(&pb, 0x78);
- CHECK_PB("12345/78", 16);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- pb_append_u32(&pb, 0x12345);
- CHECK_PB("12345", 8);
- pb_append_u32(&pb, 0x789);
- CHECK_PB("12345/789", 16);
- pb_cleanup(&pb);
-}
-END_TEST
-
-START_TEST(test_pop)
-{
- struct path_builder pb;
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- CHECK_PB("a", 8);
- ck_assert_int_eq(0, pb_append(&pb, "b"));
- CHECK_PB("a/b", 8);
- ck_assert_int_eq(0, pb_pop(&pb, false));
- CHECK_PB("a", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "abc"));
- CHECK_PB("abc", 8);
- ck_assert_int_eq(0, pb_append(&pb, "def"));
- CHECK_PB("abc/def", 8);
- ck_assert_int_eq(0, pb_pop(&pb, false));
- CHECK_PB("abc", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- CHECK_PB("a", 8);
- ck_assert_int_eq(0, pb_pop(&pb, false));
- CHECK_PB("", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "/a"));
- CHECK_PB("/a", 8);
- ck_assert_int_eq(0, pb_pop(&pb, false));
- CHECK_PB("/", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(EINVAL, pb_pop(&pb, false));
- CHECK_PB("", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- ck_assert_int_eq(0, pb_pop(&pb, false));
- CHECK_PB("", 8);
- ck_assert_int_eq(EINVAL, pb_pop(&pb, false));
- CHECK_PB("", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "/"));
- CHECK_PB("/", 8);
- ck_assert_int_eq(EINVAL, pb_pop(&pb, false));
- CHECK_PB("/", 8);
- pb_cleanup(&pb);
-}
-END_TEST
-
-START_TEST(test_reverse)
-{
- struct path_builder pb;
-
- /* 0 components */
- pb_init(&pb);
- pb_reverse(&pb);
- CHECK_PB("", 8);
- pb_cleanup(&pb);
-
- /* 1 component */
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- pb_reverse(&pb);
- CHECK_PB("a", 8);
- pb_cleanup(&pb);
-
- /* 2 components */
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- ck_assert_int_eq(0, pb_append(&pb, "b"));
- pb_reverse(&pb);
- CHECK_PB("b/a", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "abc"));
- ck_assert_int_eq(0, pb_append(&pb, "def"));
- pb_reverse(&pb);
- CHECK_PB("def/abc", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "abcd"));
- ck_assert_int_eq(0, pb_append(&pb, "efgh"));
- pb_reverse(&pb);
- CHECK_PB("efgh/abcd", 16);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "abc"));
- ck_assert_int_eq(0, pb_append(&pb, "efgh"));
- pb_reverse(&pb);
- CHECK_PB("efgh/abc", 16);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "abcd"));
- ck_assert_int_eq(0, pb_append(&pb, "fgh"));
- pb_reverse(&pb);
- CHECK_PB("fgh/abcd", 16);
- pb_cleanup(&pb);
-
- /* 3 components */
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "abc"));
- ck_assert_int_eq(0, pb_append(&pb, "def"));
- ck_assert_int_eq(0, pb_append(&pb, "ghi"));
- pb_reverse(&pb);
- CHECK_PB("ghi/def/abc", 16);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "ab"));
- ck_assert_int_eq(0, pb_append(&pb, "cde"));
- ck_assert_int_eq(0, pb_append(&pb, "fghi"));
- pb_reverse(&pb);
- CHECK_PB("fghi/cde/ab", 16);
- pb_cleanup(&pb);
-
- /* 4 components */
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- ck_assert_int_eq(0, pb_append(&pb, "b"));
- ck_assert_int_eq(0, pb_append(&pb, "c"));
- ck_assert_int_eq(0, pb_append(&pb, "d"));
- pb_reverse(&pb);
- CHECK_PB("d/c/b/a", 8);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "ab"));
- ck_assert_int_eq(0, pb_append(&pb, "cd"));
- ck_assert_int_eq(0, pb_append(&pb, "ef"));
- ck_assert_int_eq(0, pb_append(&pb, "gh"));
- pb_reverse(&pb);
- CHECK_PB("gh/ef/cd/ab", 16);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "a"));
- ck_assert_int_eq(0, pb_append(&pb, "bcd"));
- ck_assert_int_eq(0, pb_append(&pb, "efgh"));
- ck_assert_int_eq(0, pb_append(&pb, "ijklm"));
- pb_reverse(&pb);
- CHECK_PB("ijklm/efgh/bcd/a", 32);
- pb_cleanup(&pb);
-
- pb_init(&pb);
- ck_assert_int_eq(0, pb_append(&pb, "abcdefghijklmnopq"));
- ck_assert_int_eq(0, pb_append(&pb, "r"));
- ck_assert_int_eq(0, pb_append(&pb, "stu"));
- ck_assert_int_eq(0, pb_append(&pb, "vx"));
- pb_reverse(&pb);
- CHECK_PB("vx/stu/r/abcdefghijklmnopq", 32);
- pb_cleanup(&pb);
-}
-END_TEST
-
-static Suite *
-create_suite(void)
-{
- Suite *suite;
- TCase *core;
-
- core = tcase_create("functions");
- tcase_add_test(core, test_append);
- tcase_add_test(core, test_uint);
- tcase_add_test(core, test_pop);
- tcase_add_test(core, test_reverse);
-
- suite = suite_create("path_builder");
- suite_add_tcase(suite, core);
- return suite;
-}
-
-int
-main(int argc, char **argv)
-{
- Suite *suite;
- SRunner *runner;
- int tests_failed;
-
- suite = create_suite();
-
- runner = srunner_create(suite);
- srunner_run_all(runner, CK_NORMAL);
- tests_failed = srunner_ntests_failed(runner);
- srunner_free(runner);
-
- return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-}