Beispiel #1
0
int main(void)
{
	char *path, *ctx = tal_strdup(NULL, "ctx");

	plan_tests(26);

	path = path_basename(ctx, "/usr/lib");
	ok1(streq(path, "lib"));
	ok1(tal_parent(path) == ctx);
	path = path_basename(ctx, "/usr/");
	ok1(streq(path, "usr"));
	ok1(tal_parent(path) == ctx);
	path = path_basename(ctx, "/usr//");
	ok1(streq(path, "usr"));
	ok1(tal_parent(path) == ctx);
	path = path_basename(ctx, "usr");
	ok1(streq(path, "usr"));
	ok1(tal_parent(path) == ctx);
	path = path_basename(ctx, "/");
	ok1(streq(path, "/"));
	ok1(tal_parent(path) == ctx);
	path = path_basename(ctx, "//");
	ok1(streq(path, "/"));
	ok1(tal_parent(path) == ctx);
	path = path_basename(ctx, ".");
	ok1(streq(path, "."));
	ok1(tal_parent(path) == ctx);
	path = path_basename(ctx, "./");
	ok1(streq(path, "."));
	ok1(tal_parent(path) == ctx);
	path = path_basename(ctx, "..");
	ok1(streq(path, ".."));
	ok1(tal_parent(path) == ctx);
	path = path_basename(ctx, "../");
	ok1(streq(path, ".."));
	ok1(tal_parent(path) == ctx);
	tal_free(ctx);

	ctx = tal_strdup(NULL, "ctx");
	ok1(!tal_first(ctx));

	/* Test take */
	path = path_basename(ctx, take(tal_strdup(ctx, "..")));
	ok1(streq(path, ".."));
	ok1(tal_parent(path) == ctx);
	ok1(tal_first(ctx) == path && !tal_next(ctx, path));
	tal_free(path);
	ok1(path_basename(ctx, take(NULL)) == NULL);
	ok1(!tal_first(ctx));

	tal_free(ctx);

	return exit_status();
}
Beispiel #2
0
int main(void)
{
	char cwd[1024], *path, *path2, *ctx = tal_strdup(NULL, "ctx");

	plan_tests(15);

	if (!getcwd(cwd, sizeof(cwd)))
		abort();

	unlink("run-canon-link");
	rmdir("run-canon-foo");
	if (mkdir("run-canon-foo", 0700) != 0)
		abort();
	if (symlink("run-canon-foo", "run-canon-link") != 0)
		abort();

	path = path_canon(ctx, "run-canon-foo");
	ok1(tal_parent(path) == ctx);
	ok1(strends(path, "run-canon-foo"));
	ok1(strstarts(path, cwd));
	ok1(path[strlen(cwd)] == PATH_SEP);
	ok1(strlen(path) == strlen(cwd) + 1 + strlen("run-canon-foo"));
	tal_free(path);

	ok1(!path_canon(ctx, take(NULL)));
	ok1(tal_first(ctx) == NULL);

	/* Test take doesn't leak. */
	ok1(tal_first(ctx) == NULL);
	path = path_canon(ctx, take(tal_strdup(ctx, "run-canon-foo")));
	ok1(strends(path, "run-canon-foo"));
	ok1(strstarts(path, cwd));
	ok1(path[strlen(cwd)] == PATH_SEP);
	ok1(strlen(path) == strlen(cwd) + 1 + strlen("run-canon-foo"));
	ok1(tal_first(ctx) == path && tal_next(path) == NULL);
	path2 = path_canon(ctx, "run-canon-link");
	ok1(streq(path2, path));

	unlink("run-canon-link");
	if (symlink(".", "run-canon-link") != 0)
		abort();

	path = path_canon(ctx, "run-canon-link");
	ok1(streq(path, cwd));

	tal_free(ctx);

	return exit_status();
}
Beispiel #3
0
int main(void)
{
	char cwd[1024], *path, *ctx = tal_strdup(NULL, "ctx");

	plan_tests(6);

	if (!getcwd(cwd, sizeof(cwd)))
		abort();

	unlink("run-is_dir-dir-link");
	unlink("run-is_dir-file-link");
	unlink("run-is_dir-dir/file");
	rmdir("run-is_dir-dir");
	if (mkdir("run-is_dir-dir", 0700) != 0)
		abort();
	if (symlink("run-is_dir-dir", "run-is_dir-dir-link") != 0)
		abort();
	if (symlink("run-is_dir-dir/file", "run-is_dir-file-link") != 0)
		abort();
	close(open("run-is_dir-dir/file", O_WRONLY|O_CREAT, 0600));

	ok1(path_is_dir("run-is_dir-dir-link"));
	ok1(!path_is_dir("run-is_dir-file-link"));
	ok1(!path_is_dir("run-is_dir-dir/file"));
	ok1(path_is_dir("run-is_dir-dir"));

	path = path_join(ctx, cwd, "run-is_dir-dir/file");
	ok1(!path_is_dir(path));
	ok1(path_is_dir(cwd));

	tal_free(ctx);

	return exit_status();
}
Beispiel #4
0
static char *get_leaks(char *lines[], char **errs)
{
	char *leaks = tal_strdup(lines, "");
	unsigned int i;

	for (i = 0; i < tal_count(lines) - 1; i++) {
		if (strstr(lines[i], " lost ")) {
			/* A leak... */
			if (strstr(lines[i], " definitely lost ")) {
				/* Definite leak, report. */
				while (lines[i] && !blank_line(lines[i])) {
					tal_append_fmt(&leaks, "%s\n",
						       lines[i]);
					i++;
				}
			} else
				/* Not definite, ignore. */
				while (lines[i] && !blank_line(lines[i]))
					i++;
		} else {
			/* A real error. */
			while (lines[i] && !blank_line(lines[i])) {
				if (!*errs)
					*errs = tal_fmt(NULL, "%s\n", lines[i]);
				else
					tal_append_fmt(errs, "%s\n", lines[i]);
				i++;
			}
		}
	}
	return leaks;
}
Beispiel #5
0
/* Make copy of src, replacing "from" with "to". */
static char *replace(const void *ctx, const char *src,
		     const char *from, const char *to)
{
	char *ret = tal_strdup(ctx, "");
	unsigned int rlen, len, add;

	rlen = len = 0;
	for (;;) {
		const char *next = strstr(src+len, from);
		if (!next)
			add = strlen(src+len) + 1;
		else
			add = next - (src+len);

		tal_resize(&ret, rlen + add + strlen(to)+1);
		memcpy(ret+rlen, src+len, add);
		if (!next)
			return ret;
		len += add;
		rlen += add;
		strcpy(ret+rlen, to);
		rlen += strlen(to);
		len += strlen(from);
	}
}
Beispiel #6
0
/* We might need more ../ for nested modules. */
static const char *link_prefix(struct manifest *m)
{
	char *prefix = tal_strdup(m, "../../");
	unsigned int i;

	for (i = 0; i < strcount(m->modname, "/"); i++)
		prefix = tal_strcat(m, take(prefix), "../");

	return tal_strcat(m, take(prefix), "licenses/");
}
Beispiel #7
0
static char *cflags_list(const struct manifest *m)
{
	unsigned int i;
	char *ret = tal_strdup(m, cflags);

	char **flags = get_cflags(m, m->dir, get_or_compile_info);
	for (i = 0; flags[i]; i++)
		tal_append_fmt(&ret, " %s", flags[i]);
	return ret;
}
Beispiel #8
0
static struct json *json_parse(const tal_t * ctx, const char *str)
{
	struct json *j = tal(ctx, struct json);
	j->buffer = tal_strdup(j, str);
	convert_quotes(j->buffer);
	bool ok;
	j->toks = json_parse_input(j, j->buffer, strlen(j->buffer), &ok);
	assert(ok);
	j->toks = json_tok_copy(j, j->toks);
	return j;
}
Beispiel #9
0
static char *example_obj_list(const void *ctx, struct manifest **deps)
{
	char *list = tal_strdup(ctx, "");
	unsigned int i;

	for (i = 0; i < tal_count(deps); i++) {
		if (deps[i]->compiled[COMPILE_NORMAL])
			tal_append_fmt(&list, " %s",
				       deps[i]->compiled[COMPILE_NORMAL]);
	}
	return list;
}
Beispiel #10
0
static const char *concat(struct score *score, char *bits[])
{
	unsigned int i;
	char *ret = tal_strdup(score, "");

	for (i = 0; bits[i]; i++) {
		if (i)
			ret = tal_strcat(score, take(ret), " ");
		ret = tal_strcat(score, take(ret), bits[i]);
	}
	return ret;
}
Beispiel #11
0
static char *to_base58(const tal_t *ctx, u8 version,
		       const struct ripemd160 *rmd)
{
	char out[BASE58_ADDR_MAX_LEN + 1];
	size_t outlen = sizeof(out);

	b58_sha256_impl = my_sha256;
	if (!b58check_enc(out, &outlen, version, rmd, sizeof(*rmd))) {
		return NULL;
	}else{
		return tal_strdup(ctx, out);
	}
}
Beispiel #12
0
char *key_to_base58(const tal_t *ctx, bool test_net, const struct privkey *key)
{
	u8 buf[32 + 1];
	char out[BASE58_KEY_MAX_LEN + 2];
	u8 version = test_net ? 239 : 128;
	size_t outlen = sizeof(out);

	memcpy(buf, key->secret, sizeof(key->secret));
	/* Mark this as a compressed key. */
	buf[32] = 1;

	b58check_enc(out, &outlen, version, buf, sizeof(buf));
	return tal_strdup(ctx, out);
}
Beispiel #13
0
static char *example_lib_list(const void *ctx, struct manifest **deps)
{
	char *list = tal_strdup(ctx, "");
	char **libs;
	unsigned int i, j;

	/* FIXME: This doesn't uniquify. */
	for (i = 0; i < tal_count(deps); i++) {
		libs = get_libs(ctx, deps[i]->dir, NULL, get_or_compile_info);
		for (j = 0; libs[j]; j++)
			tal_append_fmt(&list, "-l%s ", libs[j]);
	}
	return list;
}
Beispiel #14
0
/* Simple LL(1) parser, inspired by Tridge's genstruct.pl. */
struct cdump_definitions *cdump_extract(const tal_t *ctx, const char *code,
					char **complaints)
{
	struct parse_state ps;
	const struct token *toks;

	ps.defs = tal(ctx, struct cdump_definitions);
	ps.complaints = tal_strdup(ctx, "");
	ps.code = code;

	strmap_init(&ps.defs->enums);
	strmap_init(&ps.defs->structs);
	strmap_init(&ps.defs->unions);
	tal_add_destructor(ps.defs, destroy_definitions);

	toks = ps.toks = tokenize(ps.defs, code);
	while (tok_peek(&ps.toks)) {
		if (tok_take_if(&ps.toks, "struct")) {
			if (!tok_take_conglom(&ps, CDUMP_STRUCT))
				goto fail;
		} else if (tok_take_if(&ps.toks, "union")) {
			if (!tok_take_conglom(&ps, CDUMP_UNION))
				goto fail;
		} else if (tok_take_if(&ps.toks, "enum")) {
			if (!tok_take_enum(&ps))
				goto fail;
		} else
			tok_take_unknown_statement(&ps);
	}

	/* Now, remove any undefined types! */
	remove_undefined(&ps.defs->enums);
	remove_undefined(&ps.defs->structs);
	remove_undefined(&ps.defs->unions);
	tal_free(toks);

out:
	if (streq(ps.complaints, ""))
		ps.complaints = tal_free(ps.complaints);

	if (complaints)
		*complaints = ps.complaints;
	else
		tal_free(ps.complaints);
	return ps.defs;

fail:
	ps.defs = tal_free(ps.defs);
	goto out;
}
Beispiel #15
0
static char *to_base58(const tal_t *ctx, u8 version,
		       const struct ripemd160 *rmd)
{
	u8 buf[1 + sizeof(*rmd) + 4];
	char out[BASE58_ADDR_MAX_LEN + 2], *p;

	buf[0] = version;
	memcpy(buf+1, rmd, sizeof(*rmd));

	/* Append checksum */
	base58_get_checksum(buf + 1 + sizeof(*rmd), buf, 1 + sizeof(*rmd));

	p = encode_base58(out, BASE58_ADDR_MAX_LEN, buf, sizeof(buf));
	return tal_strdup(ctx, p);
}
Beispiel #16
0
char *key_to_base58(const tal_t *ctx, bool test_net, const struct privkey *key)
{
	u8 buf[1 + 32 + 1 + 4];
	char out[BASE58_KEY_MAX_LEN + 2], *p;

	buf[0] = test_net ? 239 : 128;
	memcpy(buf + 1, key->secret, sizeof(key->secret));

	/* Mark this as a compressed key. */
	buf[1 + 32] = 1;

	/* Append checksum */
	base58_get_checksum(buf + 1 + 32 + 1, buf, 1 + 32 + 1);

	p = encode_base58(out, BASE58_KEY_MAX_LEN, buf, sizeof(buf));
	return tal_strdup(ctx, p);
}
Beispiel #17
0
char *bitcoin_to_base58(const tal_t *ctx, bool test_net,
			const struct bitcoin_address *addr)
{
	u8 buf[1 + sizeof(addr->addr) + 4];
	char out[BASE58_ADDR_MAX_LEN + 2], *p;

	buf[0] = test_net ? 111 : 0;

	BUILD_ASSERT(sizeof(addr->addr) == sizeof(struct ripemd160));
	memcpy(buf+1, addr, sizeof(addr->addr));

	/* Append checksum */
	base58_get_checksum(buf + 1 + sizeof(addr->addr),
			    buf, 1 + sizeof(addr->addr));

	p = encode_base58(out, BASE58_ADDR_MAX_LEN, buf, sizeof(buf));
	return tal_strdup(ctx, p);
}
Beispiel #18
0
static struct command_result *waitsendpay_expired(struct command *cmd,
						  struct pay_command *pc)
{
	char *errmsg, *data;

	errmsg = tal_fmt(pc, "Gave up after %zu attempts",
			 tal_count(pc->ps->attempts));
	data = tal_strdup(pc, "'attempts': [ ");
	for (size_t i = 0; i < tal_count(pc->ps->attempts); i++) {
		if (pc->ps->attempts[i].route)
			tal_append_fmt(&data, "%s { 'route': %s,\n 'failure': %s\n }",
				       i == 0 ? "" : ",",
				       pc->ps->attempts[i].route,
				       pc->ps->attempts[i].failure);
		else
			tal_append_fmt(&data, "%s { 'failure': %s\n }",
				       i == 0 ? "" : ",",
				       pc->ps->attempts[i].failure);
	}
	tal_append_fmt(&data, "]");
	return command_done_err(cmd, PAY_STOPPED_RETRYING, errmsg, data);
}
Beispiel #19
0
struct ccan_file *new_ccan_file(const void *ctx, const char *dir,
				const char *name)
{
	struct ccan_file *f;
	unsigned int i;

	assert(dir[0] == '/');

	f = tal(ctx, struct ccan_file);
	f->lines = NULL;
	f->line_info = NULL;
	f->doc_sections = NULL;
	for (i = 0; i < ARRAY_SIZE(f->compiled); i++)
		f->compiled[i] = NULL;
	f->name = tal_strdup(f, name);
	f->fullname = path_join(f, dir, f->name);
	f->contents = NULL;
	f->simplified = NULL;
	f->idempotent_cond = NULL;

	return f;
}
Beispiel #20
0
int main(void)
{
	void *ctx = tal_strdup(NULL, "toplevel");
	char *a, *b;
	/* If it accesses this, it will crash. */
	char **invalid = (char **)1L;

	plan_tests(41);
	/* Simple matching. */
	ok1(tal_strreg(ctx, "hello world!", "hello") == true);
	ok1(tal_strreg(ctx, "hello world!", "hi") == false);

	/* No parentheses means we don't use any extra args. */
	ok1(tal_strreg(ctx, "hello world!", "hello", invalid) == true);
	ok1(tal_strreg(ctx, "hello world!", "hi", invalid) == false);

	ok1(tal_strreg(ctx, "hello world!", "[a-z]+", invalid) == true);
	ok1(tal_strreg(ctx, "hello world!", "([a-z]+)", &a, invalid) == true);
	/* Found string */
	ok1(streq(a, "hello"));
	/* Allocated off ctx */
	ok1(find_parent(a, ctx));
	tal_free(a);

	ok1(tal_strreg(ctx, "hello world!", "([a-z]*) ([a-z]+)",
		       &a, &b, invalid) == true);
	ok1(streq(a, "hello"));
	ok1(streq(b, "world"));
	ok1(find_parent(a, ctx));
	ok1(find_parent(b, ctx));
	tal_free(a);
	tal_free(b);

	/* * after parentheses returns last match. */
	ok1(tal_strreg(ctx, "hello world!", "([a-z])* ([a-z]+)",
		       &a, &b, invalid) == true);
	ok1(streq(a, "o"));
	ok1(streq(b, "world"));
	tal_free(a);
	tal_free(b);

	/* Nested parentheses are ordered by open brace. */
	ok1(tal_strreg(ctx, "hello world!", "(([a-z]*) world)",
		       &a, &b, invalid) == true);
	ok1(streq(a, "hello world"));
	ok1(streq(b, "hello"));
	tal_free(a);
	tal_free(b);

	/* Nested parentheses are ordered by open brace. */
	ok1(tal_strreg(ctx, "hello world!", "(([a-z]*) world)",
		       &a, &b, invalid) == true);
	ok1(streq(a, "hello world"));
	ok1(streq(b, "hello"));
	tal_free(a);
	tal_free(b);

	/* NULL means we're not interested. */
	ok1(tal_strreg(ctx, "hello world!", "((hello|goodbye) world)",
		       &a, NULL, invalid) == true);
	ok1(streq(a, "hello world"));
	tal_free(a);

	/* No leaks! */
	ok1(no_children(ctx));

	/* NULL arg with take means always fail. */
	ok1(tal_strreg(ctx, take(NULL), "((hello|goodbye) world)",
		       &b, NULL, invalid) == false);

	/* Take string. */
	a = tal_strdup(ctx, "hello world!");
	ok1(tal_strreg(ctx, take(a), "([a-z]+)", &b, invalid) == true);
	ok1(streq(b, "hello"));
	ok1(tal_parent(b) == ctx);
	tal_free(b);
	ok1(no_children(ctx));

	/* Take regex. */
	a = tal_strdup(ctx, "([a-z]+)");
	ok1(tal_strreg(ctx, "hello world!", take(a), &b, invalid) == true);
	ok1(streq(b, "hello"));
	ok1(tal_parent(b) == ctx);
	tal_free(b);
	ok1(no_children(ctx));

	/* Take both. */
	a = tal_strdup(ctx, "([a-z]+)");
	ok1(tal_strreg(ctx, take(tal_strdup(ctx, "hello world!")),
		       take(a), &b, invalid) == true);
	ok1(streq(b, "hello"));
	ok1(tal_parent(b) == ctx);
	tal_free(b);
	ok1(no_children(ctx));

	/* ... even if we fail to match. */
	a = tal_strdup(ctx, "([a-z]+)");
	ok1(tal_strreg(ctx, take(tal_strdup(ctx, "HELLO WORLD!")),
		       take(a), &b, invalid) == false);
	ok1(no_children(ctx));
	tal_free(ctx);

	/* Don't get fooled by \(! */
	ok1(tal_strreg(ctx, "(hello) (world)!", "\\([a-z]*\\) \\([a-z]+\\)",
		       invalid) == true);

	return exit_status();
}
Beispiel #21
0
int main(void)
{
	char *path, *ctx = tal_strdup(NULL, "ctx");

	plan_tests(34);

	path = path_join(ctx, "foo", "bar");
	ok1(streq(path, "foo/bar"));
	ok1(tal_parent(path) == ctx);
	tal_free(path);

	path = path_join(ctx, "foo/", "bar");
	ok1(streq(path, "foo/bar"));
	ok1(tal_parent(path) == ctx);
	tal_free(path);

	path = path_join(ctx, "foo/", "/bar");
	ok1(streq(path, "/bar"));
	ok1(tal_parent(path) == ctx);
	tal_free(path);

	path = path_join(ctx, "foo", "/bar");
	ok1(streq(path, "/bar"));
	ok1(tal_parent(path) == ctx);
	tal_free(path);

	/* Test take */
	path = path_join(ctx, "foo", take(tal_strdup(ctx, "bar")));
	ok1(streq(path, "foo/bar"));
	ok1(tal_parent(path) == ctx);
	ok1(tal_first(ctx) == path && tal_next(path) == NULL && tal_first(path) == NULL);
	tal_free(path);

	path = path_join(ctx, "foo", take(tal_strdup(ctx, "/bar")));
	ok1(streq(path, "/bar"));
	ok1(tal_parent(path) == ctx);
	ok1(tal_first(ctx) == path && tal_next(path) == NULL && tal_first(path) == NULL);
	tal_free(path);

	path = path_join(ctx, take(tal_strdup(ctx, "foo")), "bar");
	ok1(streq(path, "foo/bar"));
	ok1(tal_parent(path) == ctx);
	ok1(tal_first(ctx) == path && tal_next(path) == NULL && tal_first(path) == NULL);
	tal_free(path);

	path = path_join(ctx, take(tal_strdup(ctx, "foo")), "/bar");
	ok1(streq(path, "/bar"));
	ok1(tal_parent(path) == ctx);
	ok1(tal_first(ctx) == path && tal_next(path) == NULL && tal_first(path) == NULL);
	tal_free(path);

	path = path_join(ctx, take(tal_strdup(ctx, "foo")),
			 take(tal_strdup(ctx, "bar")));
	ok1(streq(path, "foo/bar"));
	ok1(tal_parent(path) == ctx);
	ok1(tal_first(ctx) == path && tal_next(path) == NULL && tal_first(path) == NULL);
	tal_free(path);

	path = path_join(ctx, take(tal_strdup(ctx, "foo")),
			 take(tal_strdup(ctx, "/bar")));
	ok1(streq(path, "/bar"));
	ok1(tal_parent(path) == ctx);
	ok1(tal_first(ctx) == path && tal_next(path) == NULL && tal_first(path) == NULL);
	tal_free(path);

	path = path_join(ctx, take(NULL), "bar");
	ok1(!path);
	ok1(!tal_first(ctx));

	/* This is allowed to succeed, as first arg unneeded. */
	path = path_join(ctx, take(NULL), "/bar");
	ok1(!path || streq(path, "/bar"));
	tal_free(path);
	ok1(!tal_first(ctx));

	path = path_join(ctx, "foo", take(NULL));
	ok1(!path);
	ok1(!tal_first(ctx));

	path = path_join(ctx, take(NULL), take(NULL));
	ok1(!path);
	ok1(!tal_first(ctx));

	tal_free(ctx);

	return exit_status();
}
Beispiel #22
0
/* This just tests parser for the moment. */
int main(int argc, char *argv[])
{
	unsigned int i;
	struct line_info *line_info;
	struct ccan_file *f = tal(NULL, struct ccan_file);

	plan_tests(NUM_LINES * 2 + 2 + 86);

	f->num_lines = NUM_LINES;
	f->line_info = NULL;
	f->lines = tal_array(f, char *, f->num_lines);
	for (i = 0; i < f->num_lines; i++)
		f->lines[i] = tal_strdup(f->lines, testfile[i].line);
	
	line_info = get_ccan_line_info(f);
	ok1(line_info == f->line_info);
	for (i = 0; i < f->num_lines; i++) {
		ok(f->line_info[i].type == testfile[i].type,
		   "Line %u:'%s' type %s should be %s",
		   i, testfile[i].line,
		   line_type_name(f->line_info[i].type),
		   line_type_name(testfile[i].type));
		ok(f->line_info[i].continued == testfile[i].continued,
		   "Line %u:'%s' continued should be %s",
		   i, testfile[i].line,
		   testfile[i].continued ? "TRUE" : "FALSE");
	}

	/* Should cache. */
	ok1(get_ccan_line_info(f) == line_info);

	/* Expect line 1 condition to be NULL. */
	ok1(line_info[0].cond == NULL);
	/* Line 2, should depend on TEST_H being undefined. */
	ok1(line_info[1].cond != NULL);
	ok1(line_info[1].cond->type == PP_COND_IFDEF);
	ok1(line_info[1].cond->inverse);
	ok1(line_info[1].cond->parent == NULL);
	ok1(streq(line_info[1].cond->symbol, "TEST_H"));

	/* Every line BAR should depend on BAR being defined. */
	for (i = 0; i < f->num_lines; i++) {
		if (!streq(testfile[i].line, "BAR"))
			continue;
		ok1(line_info[i].cond->type == PP_COND_IFDEF);
		ok1(!line_info[i].cond->inverse);
		ok1(streq(line_info[i].cond->symbol, "BAR"));
		ok1(line_info[i].cond->parent == line_info[1].cond);
	}

	/* Every line !BAR should depend on BAR being undefined. */
	for (i = 0; i < f->num_lines; i++) {
		if (!streq(testfile[i].line, "!BAR"))
			continue;
		ok1(line_info[i].cond->type == PP_COND_IFDEF);
		ok1(line_info[i].cond->inverse);
		ok1(streq(line_info[i].cond->symbol, "BAR"));
		ok1(line_info[i].cond->parent == line_info[1].cond);
	}
	
	/* Every line HAVE_BAR should depend on HAVE_BAR being set. */
	for (i = 0; i < f->num_lines; i++) {
		if (!streq(testfile[i].line, "HAVE_BAR"))
			continue;
		ok1(line_info[i].cond->type == PP_COND_IF);
		ok1(!line_info[i].cond->inverse);
		ok1(streq(line_info[i].cond->symbol, "HAVE_BAR"));
		ok1(line_info[i].cond->parent == line_info[1].cond);
	}
	
	/* Every line HAVE_FOO should depend on HAVE_FOO being set. */
	for (i = 0; i < f->num_lines; i++) {
		if (!streq(testfile[i].line, "HAVE_FOO"))
			continue;
		ok1(line_info[i].cond->type == PP_COND_IF);
		ok1(!line_info[i].cond->inverse);
		ok1(streq(line_info[i].cond->symbol, "HAVE_FOO"));
		ok1(line_info[i].cond->parent == line_info[1].cond);
	}

	/* Now check using interface. */
	for (i = 0; i < f->num_lines; i++) {
		unsigned int val = 1;
		if (streq(testfile[i].line, "BAR")) {
			/* If we don't know if the TEST_H was undefined,
			 * best we get is a MAYBE. */
			ok1(get_ccan_line_pp(line_info[i].cond, "BAR", &val,
					     NULL) == MAYBE_COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "BAR", NULL,
					     NULL) == NOT_COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "BAR", &val,
					     "TEST_H", NULL,
					     NULL) == COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "BAR", NULL,
					     "TEST_H", NULL,
					     NULL) == NOT_COMPILED);
		} else if (streq(testfile[i].line, "!BAR")) {
			ok1(get_ccan_line_pp(line_info[i].cond, "BAR", &val,
					     NULL) == NOT_COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "BAR", NULL,
					     NULL) == MAYBE_COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "BAR", &val,
					     "TEST_H", NULL,
					     NULL) == NOT_COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "BAR", NULL,
					     "TEST_H", NULL,
					     NULL) == COMPILED);
		} else if (streq(testfile[i].line, "HAVE_BAR")) {
			ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_BAR",
					     &val, NULL) == MAYBE_COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_BAR",
					     &val, "TEST_H", NULL,
					     NULL) == COMPILED);
			val = 0;
			ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_BAR",
					     &val, NULL) == NOT_COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_BAR",
					     &val, "TEST_H", NULL,
					     NULL) == NOT_COMPILED);
		} else if (streq(testfile[i].line, "HAVE_FOO")) {
			ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_FOO",
					     &val, NULL) == MAYBE_COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_FOO",
					     &val, "TEST_H", NULL,
					     NULL) == COMPILED);
			val = 0;
			ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_FOO",
					     &val, NULL) == NOT_COMPILED);
			ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_FOO",
					     &val, "TEST_H", NULL,
					     NULL) == NOT_COMPILED);
		}
	}

	return exit_status();
}
Beispiel #23
0
int main(int argc, char *argv[])
{
	void *ctx;
	unsigned count;
	int i, j;
	struct timespec tv;
	void *p1, *p2[100], *p3[100];
	bool run_talloc = true, run_tal = true, run_malloc = true;

	if (argv[1]) {
		if (strcmp(argv[1], "--talloc") == 0)
			run_tal = run_malloc = false;
		else if (strcmp(argv[1], "--tal") == 0)
			run_talloc = run_malloc = false;
		else if (strcmp(argv[1], "--malloc") == 0)
			run_talloc = run_tal = false;
		else
			errx(1, "Bad flag %s", argv[1]);
	}

	if (!run_talloc)
		goto after_talloc;

	ctx = talloc_new(NULL);
	tv = time_now();
	count = 0;
	do {
		for (i=0;i<LOOPS;i++) {
			p1 = talloc_size(ctx, LOOPS % 128);
			for (j = 0; j < 100; j++) {
				p2[j] = talloc_strdup(p1, "foo bar");
				p3[j] = talloc_size(p1, 300);
			}
			talloc_free(p1);
		}
		count += (1 + 200) * LOOPS;
	} while (time_sub(time_now(), tv).tv_sec < 5);

	fprintf(stderr, "talloc: %.0f ops/sec\n", count/5.0);

	talloc_free(ctx);

after_talloc:
	if (!run_tal)
		goto after_tal;

	ctx = tal(NULL, char);
	tv = time_now();
	count = 0;
	do {
		for (i=0;i<LOOPS;i++) {
			p1 = tal_arr(ctx, char, LOOPS % 128);
			for (j = 0; j < 100; j++) {
				p2[j] = tal_strdup(p1, "foo bar");
				p3[j] = tal_arr(p1, char, 300);
			}
			tal_free(p1);
		}
		count += (1 + 200) * LOOPS;
	} while (time_sub(time_now(), tv).tv_sec < 5);
	fprintf(stderr, "tal:    %.0f ops/sec\n", count/5.0);

	tal_free(ctx);

after_tal:
	if (!run_malloc)
		goto after_malloc;

	tv = time_now();
	count = 0;
	do {
		for (i=0;i<LOOPS;i++) {
			p1 = malloc(LOOPS % 128);
			for (j = 0; j < 100; j++) {
				p2[j] = strdup("foo bar");
				p3[j] = malloc(300);
			}
			for (j = 0; j < 100; j++) {
				free(p2[j]);
				free(p3[j]);
			}
			free(p1);
		}
		count += (1 + 200) * LOOPS;
	} while (time_sub(time_now(), tv).tv_sec < 5);
	fprintf(stderr, "malloc: %.0f ops/sec\n", count/5.0);

after_malloc:
	printf("success: speed\n");

	return 0;
}
Beispiel #24
0
void pettycoin_dir_register_opts(const tal_t *ctx,
				 char **pettycoin_dir, char **rpc_filename)
{
	*pettycoin_dir = tal_strdup(ctx, ".");
	*rpc_filename = tal_strdup(ctx, "-");
}
Beispiel #25
0
static void check_has_license(struct manifest *m,
			      unsigned int *timeleft, struct score *score)
{
	char buf[PATH_MAX];
	ssize_t len;
	char *license = path_join(m, m->dir, "LICENSE");
	const char *expected;
	struct doc_section *d;
	const char *prefix = link_prefix(m);

	d = find_license_tag(m);
	if (!d) {
		score->error = tal_strdup(score, "No License: tag in _info");
		return;
	}

	m->license = which_license(d);
	if (m->license == LICENSE_UNKNOWN) {
		score_file_error(score, m->info_file, d->srcline,
				 "WARNING: unknown License: in _info: %s",
				 d->lines[0]);
		/* FIXME: For historical reasons, don't fail here. */
		score->pass = true;
		return;
	}

	/* If they have a license tag at all, we pass. */
	score->pass = true;

	expected = expected_link(m, prefix, m->license);

	len = readlink(license, buf, sizeof(buf));
	if (len < 0) {
		/* Could be a real file... OK if not a standard license. */
		if (errno == EINVAL) {
			if (!expected) {
				score->score = score->total;
				return;
			}
			score->error
				= tal_fmt(score,
					  "License in _info is '%s',"
					  " expect LICENSE symlink '%s'",
					  d->lines[0], expected);
			return;
		}
		if (errno == ENOENT) {
			/* Public domain doesn't really need a file. */
			if (m->license == LICENSE_PUBLIC_DOMAIN) {
				score->score = score->total;
				return;
			}
			score->error = tal_strdup(score,
						     "LICENSE does not exist");
			if (expected)
				license_exists.handle = handle_license_link;
			return;
		}
		err(1, "readlink on %s", license);
	}
	if (len >= sizeof(buf))
		errx(1, "Reading symlink %s gave huge result", license);

	buf[len] = '\0';

	if (!strstarts(buf, prefix)) {
		score->error = tal_fmt(score,
				       "Expected symlink into %s not %s",
				       prefix, buf);
		return;
	}

	if (!expected) {
		score->error = tal_fmt(score,
				       "License in _info is unknown '%s',"
				       " but LICENSE symlink is '%s'",
				       d->lines[0], buf);
		return;
	}

	if (!streq(buf, expected)) {
		score->error = tal_fmt(score,
				       "Expected symlink to %s not %s",
				       expected, buf);
		return;
	}
	score->pass = true;
	score->score = score->total;
}
Beispiel #26
0
int main(void)
{
	jsmntok_t *toks_arr, *toks_obj,
		*arg1, *arg2, *arg3, *arg4, *arg5;
	const jsmntok_t *arr_params, *obj_params;
	void *ctx;
	bool valid;
	char *cmd_arr, *cmd_obj;
	struct protocol_double_sha sha;

	ctx = tal(NULL, char);

	cmd_arr = tal_strdup(ctx,
			     "{ \"method\" : \"dev-echo\", "
			     "\"params\" : [ null, [ 1, 2, 3 ], { \"one\" : 1 }, \"four\" ], "
			     "\"id\" : \"1\" }");

	cmd_obj = tal_strdup(ctx,
			     "{ \"method\" : \"dev-echo\", "
			     "\"params\" : { \"arg2\" : [ 1, 2, 3 ],"
				" \"arg3\" : { \"one\" : 1 },"
				" \"arg4\" : \"four\" }, "
			     "\"id\" : \"1\" }");

	/* Partial id we skip } */
	toks_arr = json_parse_input(cmd_arr, strlen(cmd_arr) - 1, &valid);
	assert(!toks_arr);
	assert(valid);
	toks_obj = json_parse_input(cmd_obj, strlen(cmd_obj) - 1, &valid);
	assert(!toks_obj);
	assert(valid);

	/* This should work */
	toks_arr = json_parse_input(cmd_arr, strlen(cmd_arr), &valid);
	assert(toks_arr);
	assert(tal_count(toks_arr) == 17);
	assert(valid);
	toks_obj = json_parse_input(cmd_obj, strlen(cmd_obj), &valid);
	assert(toks_obj);
	assert(tal_count(toks_obj) == 19);
	assert(valid);

	assert(toks_arr[0].type == JSMN_OBJECT);
	assert(json_tok_len(toks_arr) == strlen(cmd_arr));
	assert(strncmp(json_tok_contents(cmd_arr, toks_arr), cmd_arr,
		       json_tok_len(toks_arr)) == 0);

	assert(toks_obj[0].type == JSMN_OBJECT);
	assert(json_tok_len(toks_obj) == strlen(cmd_obj));
	assert(strncmp(json_tok_contents(cmd_obj, toks_obj), cmd_obj,
		       json_tok_len(toks_obj)) == 0);

	/* It's not a string, so this will fail. */
	assert(!json_tok_streq(cmd_arr, toks_arr, cmd_obj));
	assert(json_tok_streq(cmd_arr, toks_arr+1, "method"));
	assert(json_tok_streq(cmd_obj, toks_obj+1, "method"));

	assert(json_tok_is_null(cmd_arr, toks_arr + 5));
	assert(!json_tok_is_null(cmd_arr, toks_arr + 6));
	assert(!json_tok_is_null(cmd_arr, toks_arr + 7));

	assert(json_get_member(cmd_arr, toks_arr, "method") == toks_arr+2);
	assert(json_get_member(cmd_obj, toks_obj, "method") == toks_obj+2);
	assert(!json_get_member(cmd_arr, toks_arr, "dev-echo"));
	assert(!json_get_member(cmd_obj, toks_obj, "arg2"));

	arr_params = json_get_member(cmd_arr, toks_arr, "params");
	assert(arr_params == toks_arr+4);
	assert(arr_params->type == JSMN_ARRAY);
	obj_params = json_get_member(cmd_obj, toks_obj, "params");
	assert(obj_params == toks_obj+4);
	assert(obj_params->type == JSMN_OBJECT);

	assert(json_get_member(cmd_arr, toks_arr, "id") == toks_arr+15);
	assert(json_get_member(cmd_obj, toks_obj, "id") == toks_obj+17);

	/* get_member works in sub objects */
	assert(json_get_member(cmd_obj, obj_params, "arg4") == toks_obj + 15);

	json_get_params(cmd_arr, arr_params,
			"arg1", &arg1,
			"arg2", &arg2,
			"arg3", &arg3,
			"arg4", &arg4,
			"arg5", &arg5,
			NULL);
	assert(arg1 == NULL);
	assert(arg2 == toks_arr + 6);
	assert(arg2->type == JSMN_ARRAY);
	assert(arg3 == toks_arr + 10);
	assert(arg3->type == JSMN_OBJECT);
	assert(arg4 == toks_arr + 13);
	assert(arg4->type == JSMN_STRING);
	assert(arg5 == NULL);

	json_get_params(cmd_obj, obj_params,
			"arg1", &arg1,
			"arg2", &arg2,
			"arg3", &arg3,
			"arg4", &arg4,
			"arg5", &arg5,
			NULL);
	assert(arg1 == NULL);
	assert(arg2 == toks_obj + 6);
	assert(arg2->type == JSMN_ARRAY);
	assert(arg3 == toks_obj + 11);
	assert(arg3->type == JSMN_OBJECT);
	assert(arg4 == toks_obj + 15);
	assert(arg4->type == JSMN_STRING);	
	assert(arg5 == NULL);

	/* Test json_delve() */
	assert(json_delve(cmd_arr, toks_arr, ".method") == toks_arr + 2);
	assert(json_delve(cmd_arr, toks_arr, ".params[0]") == toks_arr + 5);
	assert(json_delve(cmd_arr, toks_arr, ".params[1]") == toks_arr + 6);
	assert(json_delve(cmd_arr, toks_arr, ".params[2]") == toks_arr + 10);
	assert(json_delve(cmd_arr, toks_arr, ".params[1][2]") == toks_arr + 9);
	assert(json_delve(cmd_arr, toks_arr, ".params[4]") == NULL);
	assert(json_delve(cmd_arr, toks_arr, ".params[1][4]") == NULL);
	assert(json_delve(cmd_arr, toks_arr, ".params[3][4]") == NULL);
	assert(json_delve(cmd_arr, toks_arr, ".unknown") == NULL);
	assert(json_delve(cmd_arr, toks_arr, ".unknown[1]") == NULL);
	assert(json_delve(cmd_arr, toks_arr, ".param") == NULL);
	assert(json_delve(cmd_arr, toks_arr, ".params\"") == NULL);
	assert(json_delve(cmd_arr, toks_arr, ".dev-echo") == NULL);
	assert(json_delve(cmd_arr, toks_arr, ".id[0]") == NULL);

	assert(json_delve(cmd_obj, toks_obj, ".params.arg3.one")
	       == toks_obj + 13);

	/* More exotic object creation */
	cmd_arr = tal_arr(ctx, char, 0);
	json_add_object(&cmd_arr,
			"arg2", JSMN_ARRAY, "[ 1, 2, 3 ]",
			"arg3", JSMN_OBJECT, "{ \"one\" : 1 }",
			"arg4", JSMN_STRING, "four",
			NULL);
	assert(streq(cmd_arr,
		     "{ \"arg2\" : [ 1, 2, 3 ],"
		     " \"arg3\" : { \"one\" : 1 },"
		     " \"arg4\" : \"four\" }"));

	cmd_arr = tal_arr(ctx, char, 0);
	json_object_start(&cmd_arr, NULL);

	json_add_pubkey(&cmd_arr, "key", helper_public_key(0));
	memset(&sha, 42, sizeof(sha));
	json_add_double_sha(&cmd_arr, "sha", &sha);
	json_add_address(&cmd_arr, "test-address", true, helper_addr(0));
	json_add_address(&cmd_arr, "address", false, helper_addr(0));
	json_object_end(&cmd_arr);

	assert(streq(cmd_arr, "{ \"key\" : \"0214f24666a59e62c8b92a0b4b58f2a1cdeb573ea377e42f411be028292ff81926\","
		     " \"sha\" : \"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\","
		     " \"test-address\" : \"qKCafy33t92L9Nmoxx8H6NHDuiyGViqWBZ\","
		     " \"address\" : \"PZZyf1xcSbNFodrGQ6ot4LrsdSUu1bgmkc\" }"));
	tal_free(ctx);
	return 0;
}
Beispiel #27
0
int main(void)
{
	char *parent, *c;

	plan_tests(43);

	parent = tal(NULL, char);
	ok1(parent);

	c = tal_strdup(parent, "hello");
	ok1(strcmp(c, "hello") == 0);
	ok1(tal_parent(c) == parent);
	ok1(tal_count(c) == strlen(c) + 1);
	tal_free(c);

	c = tal_strndup(parent, "hello", 3);
	ok1(strcmp(c, "hel") == 0);
	ok1(tal_parent(c) == parent);
	ok1(tal_count(c) == strlen(c) + 1);
	tal_free(c);

#ifdef TAL_USE_TALLOC
	c = tal_talloc_typechk_(parent, char *);
#else
	c = tal_typechk_(parent, char *);
#endif
	c = tal_dup_arr(parent, char, "hello", 6, 0);
	ok1(strcmp(c, "hello") == 0);
	ok1(strcmp(tal_name(c), "char[]") == 0);
	ok1(tal_count(c) == 6);
	ok1(tal_parent(c) == parent);
	tal_free(c);

	/* Now with an extra byte. */
	c = tal_dup_arr(parent, char, "hello", 6, 1);
	ok1(strcmp(c, "hello") == 0);
	ok1(strcmp(tal_name(c), "char[]") == 0);
	ok1(tal_count(c) == 7);
	ok1(tal_parent(c) == parent);
	strcat(c, "x");
	tal_free(c);

	c = tal_fmt(parent, "hello %s", "there");
	ok1(strcmp(c, "hello there") == 0);
	ok1(tal_count(c) == strlen(c) + 1);
	ok1(tal_parent(c) == parent);
	tal_free(c);

	c = tal_strcat(parent, "hello ", "there");
	ok1(strcmp(c, "hello there") == 0);
	ok1(tal_count(c) == strlen(c) + 1);
	ok1(tal_parent(c) == parent);

	/* Make sure take works correctly. */
	c = tal_strcat(parent, take(c), " again");
	ok1(strcmp(c, "hello there again") == 0);
	ok1(tal_count(c) == strlen(c) + 1);
	ok1(tal_parent(c) == parent);
	ok1(single_child(parent, c));

	c = tal_strcat(parent, "And ", take(c));
	ok1(tal_count(c) == strlen(c) + 1);
	ok1(strcmp(c, "And hello there again") == 0);
	ok1(tal_parent(c) == parent);
	ok1(single_child(parent, c));

	/* NULL pass through works... */
	c = tal_strcat(parent, take(NULL), take(c));
	ok1(!c);
	ok1(no_children(parent));

	c = tal_strcat(parent, take(tal_strdup(parent, "hi")),
		       take(NULL));
	ok1(!c);
	ok1(no_children(parent));

	c = tal_strcat(parent, take(NULL), take(NULL));
	ok1(!c);
	ok1(no_children(parent));

	/* Appending formatted strings. */
	c = tal_strdup(parent, "hi");
	ok1(tal_count(c) == strlen(c) + 1);
	ok1(tal_append_fmt(&c, "%s %s", "there", "world"));
	ok1(strcmp(c, "hithere world") == 0);
	ok1(tal_count(c) == strlen(c) + 1);
	ok1(tal_parent(c) == parent);

	ok1(!tal_append_fmt(&c, take(NULL), "there", "world"));
	ok1(strcmp(c, "hithere world") == 0);
	ok1(tal_count(c) == strlen(c) + 1);

	tal_free(parent);

	return exit_status();
}
Beispiel #28
0
static char *ask_process(const tal_t *ctx,
			 const char *name,
			 const char *arg1,
			 const char *arg2,
			 const char *arg3,
			 const char *arg4,
			 const char *arg5)
{
	struct json_result *response = new_json_result(ctx);

	if (streq(name, "bitcoind")) {
		assert(streq(arg1, "-testnet"));
		if (streq(arg2, "listtransactions")) {
			unsigned int i, num, skip;

			assert(streq(arg3, "gateway"));
			num = atoi(arg4 ? arg4 : "10");
			assert(num);
			skip = atoi(arg5 ? arg5 : "0");

			json_array_start(response, NULL);
			/* Like bitcoind, list oldest first. */
			for (i = skip; i < skip+num; i++) {
				unsigned int confs;

				if (i >= ARRAY_SIZE(listtxs_response))
					break;
				/* We only show one the first time. */
				if (i > sleeps)
					break;
				/* First one is 16 confs, then 4, 1, then 0,
				 * plus one each time you ask. */
				confs = (1 << ((ARRAY_SIZE(listtxs_response)
						- i) * 2)) + sleeps;

				result_append_fmt(response, listtxs_response[i],
						  confs);
			}
			json_array_end(response);
			assert(!response->indent);
			return response->s;
		} else if (streq(arg2, "getrawtransaction")) {
			unsigned int i;

			/* We only do verbose mode */
			assert(streq(arg4, "1"));
			assert(arg5 == NULL);

			/* Search through responses for this txid */
			for (i = 0; i < ARRAY_SIZE(getrawtxs_response); i++) {
				const char *p;
				p = strstr(getrawtxs_response[i],
					   "    \"txid\" : \"");
				if (strstarts(p + strlen("    \"txid\" : \""),
					      arg3))
					return tal_strdup(ctx,
							  getrawtxs_response[i]);
			}
		} else if (streq(arg2, "getinfo")) {
			return tal_strdup(ctx, getinfo_response);
		} else if (streq(arg2, "sendtoaddress")) {
			if (mark_off_payment(arg3,
					     amount_in_satoshis(arg4,
								strlen(arg4))))
				return tal_strdup(ctx, "some-new-bitcoin-txid");
		}
	} else if (streq(name, "pettycoin-tx")) {
		assert(streq(arg1, "--no-fee"));
		assert(streq(arg2, "from-gateway"));
		assert(streq(arg3, "FAKE-gateway-privkey"));

		if (mark_off_payment(arg4, atol(arg5)))
			return tal_fmt(ctx, "raw-transaction-%s", arg4);
	} else if (streq(name, "pettycoin-query")) {
		assert(streq(arg1, "sendrawtransaction"));
		assert(strstarts(arg2, "raw-transaction-"));
		assert(arg3 == NULL);
		assert(arg4 == NULL);
		assert(arg5 == NULL);
		return tal_fmt(ctx, "txid for %s", arg2);
	}

	printf("ask_process: name=%s arg1=%s arg2=%s arg3=%s arg4=%s arg5=%s",
	       name, arg1, arg2, arg3, arg4, arg5);
	return NULL;
}
Beispiel #29
0
int main(int argc, char *argv[])
{
	char **split, *str;
	void *ctx;

	plan_tests(69);
	split = tal_strsplit(NULL, "hello  world", " ", STR_EMPTY_OK);
	ok1(!strcmp(split[0], "hello"));
	ok1(!strcmp(split[1], ""));
	ok1(!strcmp(split[2], "world"));
	ok1(split[3] == NULL);
	ok1(tal_count(split) == 4);
	tal_free(split);

	split = tal_strsplit(NULL, "hello  world", " ", STR_NO_EMPTY);
	ok1(!strcmp(split[0], "hello"));
	ok1(!strcmp(split[1], "world"));
	ok1(split[2] == NULL);
	ok1(tal_count(split) == 3);
	tal_free(split);

	split = tal_strsplit(NULL, "  hello  world", " ", STR_NO_EMPTY);
	ok1(!strcmp(split[0], "hello"));
	ok1(!strcmp(split[1], "world"));
	ok1(split[2] == NULL);
	ok1(tal_count(split) == 3);
	tal_free(split);

	split = tal_strsplit(NULL, "hello  world", "o ", STR_EMPTY_OK);
	ok1(!strcmp(split[0], "hell"));
	ok1(!strcmp(split[1], ""));
	ok1(!strcmp(split[2], ""));
	ok1(!strcmp(split[3], "w"));
	ok1(!strcmp(split[4], "rld"));
	ok1(split[5] == NULL);
	ok1(tal_count(split) == 6);

	ctx = split;
	split = tal_strsplit(ctx, "hello  world", "o ", STR_EMPTY_OK);
	ok1(tal_parent(split) == ctx);
	tal_free(ctx);

	str = tal_strjoin(NULL, (char **)substrings, ", ", STR_TRAIL);
	ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar, "));
	ctx = str;
	str = tal_strjoin(ctx, (char **)substrings, "", STR_TRAIL);
	ok1(!strcmp(str, "farbarbazbbazar"));
	ok1(tal_parent(str) == ctx);
	str = tal_strjoin(ctx, (char **)substrings, ", ", STR_NO_TRAIL);
	ok1(tal_parent(str) == ctx);
	ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar"));
	str = tal_strjoin(ctx, (char **)substrings, "", STR_NO_TRAIL);
	ok1(!strcmp(str, "farbarbazbbazar"));
	ok1(tal_parent(str) == ctx);
	tal_free(ctx);

	ctx = tal_strdup(NULL, "context");
	/* Pass through NULLs from take. */
	ok1(tal_strsplit(NULL, take(NULL), " ", STR_EMPTY_OK) == NULL);
	ok1(tal_strsplit(NULL, "foo", take(NULL), STR_EMPTY_OK) == NULL);

	/* tal_strsplit take string.  It reallocs it to same size, but
	 * that sometimes causes a move, so we can't directly check
	 * that split[0] == str. */
	str = tal_strdup(ctx, "hello world");
	ok1(tal_check(ctx, NULL));
	ok1(tal_check(str, NULL));
	split = tal_strsplit(ctx, take(str), " ", STR_EMPTY_OK);
	ok1(tal_parent(split) == ctx);
	ok1(!strcmp(split[0], "hello"));
	ok1(!strcmp(split[1], "world"));
	ok1(split[2] == NULL);
	ok1(tal_check(split, NULL));
	ok1(tal_check(ctx, NULL));
	tal_free(split);
	/* Previous free should get rid of str */
	ok1(!tal_first(ctx));

	/* tal_strsplit take delims */
	str = tal_strdup(ctx, " ");
	split = tal_strsplit(ctx, "hello world", take(str), STR_EMPTY_OK);
	ok1(tal_parent(split) == ctx);
	ok1(!strcmp(split[0], "hello"));
	ok1(!strcmp(split[1], "world"));
	ok1(split[2] == NULL);
	ok1(tal_check(split, NULL));
	ok1(tal_check(ctx, NULL));
	tal_free(split);
	/* str is gone... */
	ok1(!tal_first(ctx));

	/* tal_strsplit takes both. */
	split = tal_strsplit(ctx, take(tal_strdup(NULL, "hello world")),
			     take(tal_strdup(NULL, " ")), STR_EMPTY_OK);
	ok1(tal_parent(split) == ctx);
	ok1(!strcmp(split[0], "hello"));
	ok1(!strcmp(split[1], "world"));
	ok1(split[2] == NULL);
	ok1(tal_check(split, NULL));
	ok1(tal_check(ctx, NULL));
	tal_free(split);
	/* temp allocs are gone... */
	ok1(!tal_first(ctx));

	/* tal_strjoin passthrough taken NULLs OK. */
	ok1(tal_strjoin(ctx, take(NULL), "", STR_TRAIL) == NULL);
	ok1(tal_strjoin(ctx, take(NULL), "", STR_NO_TRAIL) == NULL);
	ok1(tal_strjoin(ctx, split, take(NULL), STR_TRAIL) == NULL);
	ok1(tal_strjoin(ctx, split, take(NULL), STR_NO_TRAIL) == NULL);

	/* tal_strjoin take strings[] */
	split = tal_strsplit(ctx, "hello world", " ", STR_EMPTY_OK);
	str = tal_strjoin(ctx, take(split), " there ", STR_NO_TRAIL);
	ok1(!strcmp(str, "hello there world"));
	ok1(tal_parent(str) == ctx);
	/* split is gone... */
	ok1(tal_first(ctx) == str && !tal_next(ctx, str));
	tal_free(str);
	ok1(!tal_first(ctx));

	/* tal_strjoin take delim */
	split = tal_strsplit(ctx, "hello world", " ", STR_EMPTY_OK);
	str = tal_strjoin(ctx, split, take(tal_strdup(ctx, " there ")),
			  STR_NO_TRAIL);
	ok1(!strcmp(str, "hello there world"));
	ok1(tal_parent(str) == ctx);
	tal_free(split);
	/* tmp alloc is gone, str is only remainder. */
	ok1(tal_first(ctx) == str && !tal_next(ctx, str));
	tal_free(str);
	ok1(!tal_first(ctx));

	/* tal_strjoin take both. */
	str = tal_strjoin(ctx, take(tal_strsplit(ctx, "hello world", " ",
						 STR_EMPTY_OK)),
			  take(tal_strdup(ctx, " there ")), STR_NO_TRAIL);
	ok1(!strcmp(str, "hello there world"));
	ok1(tal_parent(str) == ctx);
	/* tmp allocs are gone, str is only remainder. */
	ok1(tal_first(ctx) == str && !tal_next(ctx, str));
	tal_free(str);
	ok1(!tal_first(ctx));
	tal_free(ctx);

	return exit_status();
}