Browse Source
Turns out that CCAN's create-ccan-tree has a bug with submodules. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
10 years ago
35 changed files with 0 additions and 2608 deletions
@ -1 +0,0 @@ |
|||
../../../licenses/CC0 |
@ -1,39 +0,0 @@ |
|||
#include "config.h" |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
/** |
|||
* str/hex - hex-to-string conversions and vice-versa |
|||
* |
|||
* This code contains simple routines for hexidecimal strings. |
|||
* |
|||
* License: CC0 (Public domain) |
|||
* Author: Rusty Russell <rusty@rustcorp.com.au> |
|||
* |
|||
* Example: |
|||
* int main(int argc, char *argv[]) |
|||
* { |
|||
* int i; |
|||
* |
|||
* for (i = 1; i < argc; i++) { |
|||
* char str[hex_str_size(strlen(argv[i]))]; |
|||
* |
|||
* hex_encode(str, sizeof(str), argv[i], strlen(argv[i])); |
|||
* printf("%s ", str); |
|||
* } |
|||
* printf("\n"); |
|||
* return 0; |
|||
* } |
|||
*/ |
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
/* Expect exactly one argument */ |
|||
if (argc != 2) |
|||
return 1; |
|||
|
|||
if (strcmp(argv[1], "depends") == 0) { |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
@ -1,70 +0,0 @@ |
|||
/* CC0 license (public domain) - see LICENSE file for details */ |
|||
#include <ccan/str/hex/hex.h> |
|||
#include <assert.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
|
|||
static bool char_to_hex(unsigned char *val, char c) |
|||
{ |
|||
if (c >= '0' && c <= '9') { |
|||
*val = c - '0'; |
|||
return true; |
|||
} |
|||
if (c >= 'a' && c <= 'f') { |
|||
*val = c - 'a' + 10; |
|||
return true; |
|||
} |
|||
if (c >= 'A' && c <= 'F') { |
|||
*val = c - 'A' + 10; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize) |
|||
{ |
|||
unsigned char v1, v2; |
|||
unsigned char *p = buf; |
|||
|
|||
while (slen > 1) { |
|||
if (!char_to_hex(&v1, str[0]) || !char_to_hex(&v2, str[1])) |
|||
return false; |
|||
if (!bufsize) |
|||
return false; |
|||
*(p++) = (v1 << 4) | v2; |
|||
str += 2; |
|||
slen -= 2; |
|||
bufsize--; |
|||
} |
|||
return slen == 0 && bufsize == 0; |
|||
} |
|||
|
|||
static char hexchar(unsigned int val) |
|||
{ |
|||
if (val < 10) |
|||
return '0' + val; |
|||
if (val < 16) |
|||
return 'a' + val - 10; |
|||
abort(); |
|||
} |
|||
|
|||
bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize) |
|||
{ |
|||
size_t used = 0; |
|||
|
|||
if (destsize < 1) |
|||
return false; |
|||
|
|||
while (used < bufsize) { |
|||
unsigned int c = ((const unsigned char *)buf)[used]; |
|||
if (destsize < 3) |
|||
return false; |
|||
*(dest++) = hexchar(c >> 4); |
|||
*(dest++) = hexchar(c & 0xF); |
|||
used++; |
|||
destsize -= 2; |
|||
} |
|||
*dest = '\0'; |
|||
|
|||
return used + 1; |
|||
} |
@ -1,73 +0,0 @@ |
|||
/* CC0 (Public domain) - see LICENSE file for details */ |
|||
#ifndef CCAN_HEX_H |
|||
#define CCAN_HEX_H |
|||
#include "config.h" |
|||
#include <stdbool.h> |
|||
#include <stdlib.h> |
|||
|
|||
/**
|
|||
* hex_decode - Unpack a hex string. |
|||
* @str: the hexidecimal string |
|||
* @slen: the length of @str |
|||
* @buf: the buffer to write the data into |
|||
* @bufsize: the length of @buf |
|||
* |
|||
* Returns false if there are any characters which aren't 0-9, a-f or A-F, |
|||
* of the string wasn't the right length for @bufsize. |
|||
* |
|||
* Example: |
|||
* unsigned char data[20]; |
|||
* |
|||
* if (!hex_decode(argv[1], strlen(argv[1]), data, 20)) |
|||
* printf("String is malformed!\n"); |
|||
*/ |
|||
bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize); |
|||
|
|||
/**
|
|||
* hex_encode - Create a nul-terminated hex string |
|||
* @buf: the buffer to read the data from |
|||
* @bufsize: the length of @buf |
|||
* @dest: the string to fill |
|||
* @destsize: the max size of the string |
|||
* |
|||
* Returns true if the string, including terminator, fit in @destsize; |
|||
* |
|||
* Example: |
|||
* unsigned char buf[] = { 0x1F, 0x2F }; |
|||
* char str[5]; |
|||
* |
|||
* if (!hex_encode(buf, sizeof(buf), str, sizeof(str))) |
|||
* abort(); |
|||
*/ |
|||
bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize); |
|||
|
|||
/**
|
|||
* hex_str_size - Calculate how big a nul-terminated hex string is |
|||
* @bytes: bytes of data to represent |
|||
* |
|||
* Example: |
|||
* unsigned char buf[] = { 0x1F, 0x2F }; |
|||
* char str[hex_str_size(sizeof(buf))]; |
|||
* |
|||
* hex_encode(buf, sizeof(buf), str, sizeof(str)); |
|||
*/ |
|||
static inline size_t hex_str_size(size_t bytes) |
|||
{ |
|||
return 2 * bytes + 1; |
|||
} |
|||
|
|||
/**
|
|||
* hex_data_size - Calculate how many bytes of data in a hex string |
|||
* @strlen: the length of the string (with or without NUL) |
|||
* |
|||
* Example: |
|||
* const char str[] = "1F2F"; |
|||
* unsigned char buf[hex_data_size(sizeof(str))]; |
|||
* |
|||
* hex_decode(str, strlen(str), buf, sizeof(buf)); |
|||
*/ |
|||
static inline size_t hex_data_size(size_t strlen) |
|||
{ |
|||
return strlen / 2; |
|||
} |
|||
#endif /* PETTYCOIN_HEX_H */ |
@ -1,42 +0,0 @@ |
|||
#include <ccan/str/hex/hex.h> |
|||
/* Include the C files directly. */ |
|||
#include <ccan/str/hex/hex.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include <string.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
const char teststr[] = "0123456789abcdefABCDEF"; |
|||
const char bad_teststr[] = "0123456789abcdefABCDEF1O"; |
|||
const unsigned char testdata[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, |
|||
0xcd, 0xef, 0xAB, 0xCD, 0xEF }; |
|||
unsigned char data[11]; |
|||
char str[23]; |
|||
size_t i; |
|||
|
|||
plan_tests(10 + sizeof(str)); |
|||
|
|||
ok1(hex_str_size(sizeof(testdata)) == sizeof(teststr)); |
|||
/* This gives right result with or without nul included */ |
|||
ok1(hex_data_size(strlen(teststr)) == sizeof(testdata)); |
|||
ok1(hex_data_size(sizeof(teststr)) == sizeof(testdata)); |
|||
|
|||
ok1(hex_decode(teststr, strlen(teststr), data, sizeof(data))); |
|||
ok1(memcmp(data, testdata, sizeof(testdata)) == 0); |
|||
ok1(hex_encode(testdata, sizeof(testdata), str, sizeof(str))); |
|||
ok1(strcmp(str, "0123456789abcdefabcdef") == 0); |
|||
|
|||
/* Bad char */ |
|||
ok1(!hex_decode(bad_teststr, strlen(bad_teststr), data, sizeof(data))); |
|||
/* Bad hex string len */ |
|||
ok1(!hex_decode(teststr, strlen(teststr) - 1, data, sizeof(data))); |
|||
/* Bad buffer len */ |
|||
ok1(!hex_decode(teststr, strlen(teststr), data, sizeof(data) - 1)); |
|||
|
|||
/* Bad deststring size. */ |
|||
for (i = 1; i <= sizeof(str); i++) |
|||
ok1(!hex_encode(testdata, sizeof(testdata), str, sizeof(str)-i)); |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -1 +0,0 @@ |
|||
../../../licenses/LGPL-2.1 |
@ -1,56 +0,0 @@ |
|||
#include "config.h" |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
/** |
|||
* tal/grab_file - file helper routines |
|||
* |
|||
* This contains simple functions for getting the contents of a file. |
|||
* |
|||
* Example: |
|||
* #include <err.h> |
|||
* #include <stdio.h> |
|||
* #include <string.h> |
|||
* #include <ccan/tal/grab_file/grab_file.h> |
|||
* #include <ccan/tal/tal.h> // for tal_free |
|||
* |
|||
* int main(int argc, char *argv[]) |
|||
* { |
|||
* char *file; |
|||
* |
|||
* file = grab_file(NULL, argv[1]); |
|||
* if (!file) |
|||
* err(1, "Could not read file %s", argv[1]); |
|||
* if (strlen(file)+1 != tal_count(file)) |
|||
* printf("File contains NUL characters\n"); |
|||
* else if (tal_count(file) == 1) |
|||
* printf("File contains nothing\n"); |
|||
* else if (strchr(file, '\n')) |
|||
* printf("File contains multiple lines\n"); |
|||
* else |
|||
* printf("File contains one line\n"); |
|||
* tal_free(file); |
|||
* |
|||
* return 0; |
|||
* } |
|||
* |
|||
* License: LGPL (v2.1 or any later version) |
|||
* Author: Rusty Russell <rusty@rustcorp.com.au> |
|||
*/ |
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
if (argc != 2) |
|||
return 1; |
|||
|
|||
if (strcmp(argv[1], "depends") == 0) { |
|||
printf("ccan/tal\n"); |
|||
printf("ccan/noerr\n"); |
|||
return 0; |
|||
} |
|||
if (strcmp(argv[1], "testdepends") == 0) { |
|||
printf("ccan/tal/str\n"); |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
@ -1,64 +0,0 @@ |
|||
/* Licensed under LGPLv2+ - see LICENSE file for details */ |
|||
#include "grab_file.h" |
|||
#include <ccan/tal/tal.h> |
|||
#include <ccan/noerr/noerr.h> |
|||
#include <unistd.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <fcntl.h> |
|||
|
|||
void *grab_fd(const void *ctx, int fd) |
|||
{ |
|||
int ret; |
|||
size_t max, size; |
|||
char *buffer; |
|||
struct stat st; |
|||
|
|||
size = 0; |
|||
|
|||
if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) |
|||
max = st.st_size; |
|||
else |
|||
max = 16384; |
|||
|
|||
buffer = tal_arr(ctx, char, max+1); |
|||
while ((ret = read(fd, buffer + size, max - size)) > 0) { |
|||
size += ret; |
|||
if (size == max) { |
|||
size_t extra = max; |
|||
if (extra > 1024 * 1024) |
|||
extra = 1024 * 1024; |
|||
|
|||
if (!tal_resize(&buffer, max+extra+1)) |
|||
return NULL; |
|||
|
|||
max += extra; |
|||
} |
|||
} |
|||
if (ret < 0) |
|||
buffer = tal_free(buffer); |
|||
else { |
|||
buffer[size] = '\0'; |
|||
tal_resize(&buffer, size+1); |
|||
} |
|||
|
|||
return buffer; |
|||
} |
|||
|
|||
void *grab_file(const void *ctx, const char *filename) |
|||
{ |
|||
int fd; |
|||
char *buffer; |
|||
|
|||
if (!filename) |
|||
fd = dup(STDIN_FILENO); |
|||
else |
|||
fd = open(filename, O_RDONLY, 0); |
|||
|
|||
if (fd < 0) |
|||
return NULL; |
|||
|
|||
buffer = grab_fd(ctx, fd); |
|||
close_noerr(fd); |
|||
return buffer; |
|||
} |
@ -1,60 +0,0 @@ |
|||
/* Licensed under LGPLv2+ - see LICENSE file for details */ |
|||
#ifndef CCAN_TAL_GRAB_FILE_H |
|||
#define CCAN_TAL_GRAB_FILE_H |
|||
#include <stdio.h> // For size_t |
|||
|
|||
/**
|
|||
* grab_fd - read all of a file descriptor into memory |
|||
* @ctx: the context to tallocate from (often NULL) |
|||
* @fd: the file descriptor to read from |
|||
* |
|||
* This function reads from the given file descriptor until no more |
|||
* input is available. The content is talloced off @ctx, and the |
|||
* tal_count() is the size in bytes plus one: for convenience, the |
|||
* byte after the end of the content will always be NUL. |
|||
* |
|||
* Example: |
|||
* #include <ccan/tal/str/str.h> |
|||
* #include <ccan/tal/tal.h> |
|||
* ... |
|||
* // Return all of standard input, as lines.
|
|||
* static char **read_stdin_as_lines(void) |
|||
* { |
|||
* char **lines, *all; |
|||
* |
|||
* all = grab_fd(NULL, 0); |
|||
* if (!all) |
|||
* return NULL; |
|||
* lines = tal_strsplit(NULL, all, "\n", STR_EMPTY_OK); |
|||
* tal_free(all); |
|||
* return lines; |
|||
* } |
|||
*/ |
|||
void *grab_fd(const void *ctx, int fd); |
|||
|
|||
/**
|
|||
* grab_file - read all of a file (or stdin) into memory |
|||
* @ctx: the context to tallocate from (often NULL) |
|||
* @filename: the file to read (NULL for stdin) |
|||
* |
|||
* This function reads from the given file until no more input is |
|||
* available. The content is talloced off @ctx, and the tal_count() |
|||
* is the size in bytes plus one: for convenience, the byte after the |
|||
* end of the content will always be NUL. |
|||
* |
|||
* Example: |
|||
* // Return all of a given file, as lines.
|
|||
* static char **read_file_as_lines(const char *filename) |
|||
* { |
|||
* char **lines, *all; |
|||
* |
|||
* all = grab_file(NULL, filename); |
|||
* if (!all) |
|||
* return NULL; |
|||
* lines = tal_strsplit(NULL, all, "\n", STR_EMPTY_OK); |
|||
* tal_free(all); |
|||
* return lines; |
|||
* } |
|||
*/ |
|||
void *grab_file(const void *ctx, const char *filename); |
|||
#endif /* CCAN_TAL_GRAB_FILE_H */ |
@ -1,37 +0,0 @@ |
|||
/* This is test for grab_file() function
|
|||
*/ |
|||
#include <ccan/tal/grab_file/grab_file.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
#include <err.h> |
|||
#include <sys/stat.h> |
|||
#include <ccan/tal/grab_file/grab_file.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include <ccan/tal/str/str.h> |
|||
|
|||
int |
|||
main(int argc, char *argv[]) |
|||
{ |
|||
unsigned int i; |
|||
char **split, *str; |
|||
int length; |
|||
struct stat st; |
|||
|
|||
str = grab_file(NULL, "test/run-grab.c"); |
|||
split = tal_strsplit(str, str, "\n", STR_EMPTY_OK); |
|||
length = strlen(split[0]); |
|||
ok1(!strcmp(split[0], "/* This is test for grab_file() function")); |
|||
for (i = 1; split[i]; i++) |
|||
length += strlen(split[i]); |
|||
ok1(!strcmp(split[i-1], "/* End of grab_file() test */")); |
|||
if (stat("test/run-grab.c", &st) != 0) |
|||
/* FIXME: ditto */ |
|||
if (stat("ccan/tal/grab_file/test/run-grab.c", &st) != 0) |
|||
err(1, "Could not stat self"); |
|||
ok1(st.st_size == length + i); |
|||
tal_free(str); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
/* End of grab_file() test */ |
@ -1 +0,0 @@ |
|||
../../../licenses/BSD-MIT |
@ -1,57 +0,0 @@ |
|||
#include "config.h" |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
/** |
|||
* tal/str - string helper routines which use tal |
|||
* |
|||
* This is a grab bag of functions for string operations, designed to enhance |
|||
* the standard string.h; these are separated from the non-tal-needing |
|||
* string utilities in "str.h". |
|||
* |
|||
* Example: |
|||
* #include <ccan/tal/str/str.h> |
|||
* #include <ccan/tal/grab_file/grab_file.h> |
|||
* #include <err.h> |
|||
* |
|||
* // Dumb demo program to double-linespace a file. |
|||
* int main(int argc, char *argv[]) |
|||
* { |
|||
* char *textfile; |
|||
* char **lines; |
|||
* |
|||
* // Grab lines in file. |
|||
* textfile = grab_file(NULL, argv[1]); |
|||
* if (!textfile) |
|||
* err(1, "Failed reading %s", argv[1]); |
|||
* lines = tal_strsplit(textfile, textfile, "\n", STR_EMPTY_OK); |
|||
* |
|||
* // Join them back together with two linefeeds. |
|||
* printf("%s", tal_strjoin(textfile, lines, "\n\n", STR_TRAIL)); |
|||
* |
|||
* // Free everything, just because we can. |
|||
* tal_free(textfile); |
|||
* return 0; |
|||
* } |
|||
* |
|||
* License: BSD-MIT |
|||
* Author: Rusty Russell <rusty@rustcorp.com.au> |
|||
*/ |
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
if (argc != 2) |
|||
return 1; |
|||
|
|||
if (strcmp(argv[1], "depends") == 0) { |
|||
printf("ccan/str\n"); |
|||
#ifdef TAL_USE_TALLOC |
|||
printf("ccan/tal/talloc\n"); |
|||
#else |
|||
printf("ccan/tal\n"); |
|||
#endif |
|||
printf("ccan/take\n"); |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
@ -1,312 +0,0 @@ |
|||
/* Licensed under BSD-MIT - see LICENSE file for details */ |
|||
#include <unistd.h> |
|||
#include <stdint.h> |
|||
#include <string.h> |
|||
#include <limits.h> |
|||
#include <stdlib.h> |
|||
#include "str.h" |
|||
#include <sys/types.h> |
|||
#include <regex.h> |
|||
#include <stdarg.h> |
|||
#include <unistd.h> |
|||
#include <stdio.h> |
|||
#include <ccan/str/str.h> |
|||
#include <ccan/take/take.h> |
|||
|
|||
char *tal_strdup(const tal_t *ctx, const char *p) |
|||
{ |
|||
/* We have to let through NULL for take(). */ |
|||
return tal_dup_(ctx, p, 1, p ? strlen(p) + 1: 1, 0, false, |
|||
TAL_LABEL(char, "[]")); |
|||
} |
|||
|
|||
char *tal_strndup(const tal_t *ctx, const char *p, size_t n) |
|||
{ |
|||
size_t len; |
|||
char *ret; |
|||
|
|||
/* We have to let through NULL for take(). */ |
|||
if (likely(p)) { |
|||
len = strlen(p); |
|||
if (len > n) |
|||
len = n; |
|||
} else |
|||
len = n; |
|||
|
|||
ret = tal_dup_(ctx, p, 1, len, 1, false, TAL_LABEL(char, "[]")); |
|||
if (ret) |
|||
ret[len] = '\0'; |
|||
return ret; |
|||
} |
|||
|
|||
char *tal_fmt(const tal_t *ctx, const char *fmt, ...) |
|||
{ |
|||
va_list ap; |
|||
char *ret; |
|||
|
|||
va_start(ap, fmt); |
|||
ret = tal_vfmt(ctx, fmt, ap); |
|||
va_end(ap); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
static bool do_vfmt(char **buf, size_t off, const char *fmt, va_list ap) |
|||
{ |
|||
/* A decent guess to start. */ |
|||
size_t max = strlen(fmt) * 2; |
|||
bool ok; |
|||
|
|||
for (;;) { |
|||
va_list ap2; |
|||
int ret; |
|||
|
|||
if (!tal_resize(buf, off + max)) { |
|||
ok = false; |
|||
break; |
|||
} |
|||
|
|||
va_copy(ap2, ap); |
|||
ret = vsnprintf(*buf + off, max, fmt, ap2); |
|||
va_end(ap2); |
|||
|
|||
if (ret < max) { |
|||
ok = true; |
|||
break; |
|||
} |
|||
max *= 2; |
|||
} |
|||
|
|||
if (taken(fmt)) |
|||
tal_free(fmt); |
|||
return ok; |
|||
} |
|||
|
|||
char *tal_vfmt(const tal_t *ctx, const char *fmt, va_list ap) |
|||
{ |
|||
char *buf; |
|||
|
|||
if (!fmt && taken(fmt)) |
|||
return NULL; |
|||
|
|||
/* A decent guess to start. */ |
|||
buf = tal_arr(ctx, char, strlen(fmt) * 2); |
|||
if (!do_vfmt(&buf, 0, fmt, ap)) |
|||
buf = tal_free(buf); |
|||
return buf; |
|||
} |
|||
|
|||
bool tal_append_vfmt(char **baseptr, const char *fmt, va_list ap) |
|||
{ |
|||
if (!fmt && taken(fmt)) |
|||
return false; |
|||
|
|||
return do_vfmt(baseptr, strlen(*baseptr), fmt, ap); |
|||
} |
|||
|
|||
bool tal_append_fmt(char **baseptr, const char *fmt, ...) |
|||
{ |
|||
va_list ap; |
|||
bool ret; |
|||
|
|||
va_start(ap, fmt); |
|||
ret = tal_append_vfmt(baseptr, fmt, ap); |
|||
va_end(ap); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
char *tal_strcat(const tal_t *ctx, const char *s1, const char *s2) |
|||
{ |
|||
size_t len1, len2; |
|||
char *ret; |
|||
|
|||
if (unlikely(!s2) && taken(s2)) { |
|||
if (taken(s1)) |
|||
tal_free(s1); |
|||
return NULL; |
|||
} |
|||
/* We have to let through NULL for take(). */ |
|||
len1 = s1 ? strlen(s1) : 0; |
|||
len2 = strlen(s2); |
|||
|
|||
/* We use tal_dup_ here to avoid attaching a length property. */ |
|||
ret = tal_dup_(ctx, s1, 1, len1, len2 + 1, false, |
|||
TAL_LABEL(char, "[]")); |
|||
if (likely(ret)) |
|||
memcpy(ret + len1, s2, len2 + 1); |
|||
|
|||
if (taken(s2)) |
|||
tal_free(s2); |
|||
return ret; |
|||
} |
|||
|
|||
char **tal_strsplit(const tal_t *ctx, |
|||
const char *string, const char *delims, enum strsplit flags) |
|||
{ |
|||
char **parts, *str; |
|||
size_t max = 64, num = 0; |
|||
|
|||
parts = tal_arr(ctx, char *, max + 1); |
|||
if (unlikely(!parts)) { |
|||
if (taken(string)) |
|||
tal_free(string); |
|||
if (taken(delims)) |
|||
tal_free(delims); |
|||
return NULL; |
|||
} |
|||
str = tal_strdup(parts, string); |
|||
if (unlikely(!str)) |
|||
goto fail; |
|||
if (unlikely(!delims) && is_taken(delims)) |
|||
goto fail; |
|||
|
|||
if (flags == STR_NO_EMPTY) |
|||
str += strspn(str, delims); |
|||
|
|||
while (*str != '\0') { |
|||
size_t len = strcspn(str, delims), dlen; |
|||
|
|||
parts[num] = str; |
|||
dlen = strspn(str + len, delims); |
|||
parts[num][len] = '\0'; |
|||
if (flags == STR_EMPTY_OK && dlen) |
|||
dlen = 1; |
|||
str += len + dlen; |
|||
if (++num == max && !tal_resize(&parts, max*=2 + 1)) |
|||
goto fail; |
|||
} |
|||
parts[num] = NULL; |
|||
|
|||
/* Ensure that tal_count() is correct. */ |
|||
if (unlikely(!tal_resize(&parts, num+1))) |
|||
goto fail; |
|||
|
|||
if (taken(delims)) |
|||
tal_free(delims); |
|||
return parts; |
|||
|
|||
fail: |
|||
tal_free(parts); |
|||
if (taken(delims)) |
|||
tal_free(delims); |
|||
return NULL; |
|||
} |
|||
|
|||
char *tal_strjoin(const tal_t *ctx, |
|||
char *strings[], const char *delim, enum strjoin flags) |
|||
{ |
|||
unsigned int i; |
|||
char *ret = NULL; |
|||
size_t totlen = 0, dlen; |
|||
|
|||
if (unlikely(!strings) && is_taken(strings)) |
|||
goto fail; |
|||
|
|||
if (unlikely(!delim) && is_taken(delim)) |
|||
goto fail; |
|||
|
|||
dlen = strlen(delim); |
|||
ret = tal_arr(ctx, char, dlen*2+1); |
|||
if (!ret) |
|||
goto fail; |
|||
|
|||
ret[0] = '\0'; |
|||
for (i = 0; strings[i]; i++) { |
|||
size_t len = strlen(strings[i]); |
|||
|
|||
if (flags == STR_NO_TRAIL && !strings[i+1]) |
|||
dlen = 0; |
|||
if (!tal_resize(&ret, totlen + len + dlen + 1)) |
|||
goto fail; |
|||
memcpy(ret + totlen, strings[i], len); |
|||
totlen += len; |
|||
memcpy(ret + totlen, delim, dlen); |
|||
totlen += dlen; |
|||
} |
|||
ret[totlen] = '\0'; |
|||
out: |
|||
if (taken(strings)) |
|||
tal_free(strings); |
|||
if (taken(delim)) |
|||
tal_free(delim); |
|||
return ret; |
|||
fail: |
|||
ret = tal_free(ret); |
|||
goto out; |
|||
} |
|||
|
|||
static size_t count_open_braces(const char *string) |
|||
{ |
|||
#if 1 |
|||
size_t num = 0, esc = 0; |
|||
|
|||
while (*string) { |
|||
if (*string == '\\') |
|||
esc++; |
|||
else { |
|||
/* An odd number of \ means it's escaped. */ |
|||
if (*string == '(' && (esc & 1) == 0) |
|||
num++; |
|||
esc = 0; |
|||
} |
|||
string++; |
|||
} |
|||
return num; |
|||
#else |
|||
return strcount(string, "("); |
|||
#endif |
|||
} |
|||
|
|||
bool tal_strreg(const tal_t *ctx, const char *string, const char *regex, ...) |
|||
{ |
|||
size_t nmatch = 1 + count_open_braces(regex); |
|||
regmatch_t matches[nmatch]; |
|||
regex_t r; |
|||
bool ret = false; |
|||
unsigned int i; |
|||
va_list ap; |
|||
|
|||
if (unlikely(!regex) && is_taken(regex)) |
|||
goto fail_no_re; |
|||
|
|||
if (regcomp(&r, regex, REG_EXTENDED) != 0) |
|||
goto fail_no_re; |
|||
|
|||
if (unlikely(!string) && is_taken(string)) |
|||
goto fail; |
|||
|
|||
if (regexec(&r, string, nmatch, matches, 0) != 0) |
|||
goto fail; |
|||
|
|||
ret = true; |
|||
va_start(ap, regex); |
|||
for (i = 1; i < nmatch; i++) { |
|||
char **arg = va_arg(ap, char **); |
|||
if (arg) { |
|||
/* eg. ([a-z])? can give "no match". */ |
|||
if (matches[i].rm_so == -1) |
|||
*arg = NULL; |
|||
else { |
|||
*arg = tal_strndup(ctx, |
|||
string + matches[i].rm_so, |
|||
matches[i].rm_eo |
|||
- matches[i].rm_so); |
|||
/* FIXME: If we fail, we set some and leak! */ |
|||
if (!*arg) { |
|||
ret = false; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
va_end(ap); |
|||
fail: |
|||
regfree(&r); |
|||
fail_no_re: |
|||
if (taken(regex)) |
|||
tal_free(regex); |
|||
if (taken(string)) |
|||
tal_free(string); |
|||
return ret; |
|||
} |
@ -1,186 +0,0 @@ |
|||
/* Licensed under BSD-MIT - see LICENSE file for details */ |
|||
#ifndef CCAN_STR_TAL_H |
|||
#define CCAN_STR_TAL_H |
|||
#ifdef TAL_USE_TALLOC |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#else |
|||
#include <ccan/tal/tal.h> |
|||
#endif |
|||
#include <string.h> |
|||
#include <stdbool.h> |
|||
|
|||
/**
|
|||
* tal_strdup - duplicate a string |
|||
* @ctx: NULL, or tal allocated object to be parent. |
|||
* @p: the string to copy (can be take()). |
|||
*/ |
|||
char *tal_strdup(const tal_t *ctx, const char *p); |
|||
|
|||
/**
|
|||
* tal_strndup - duplicate a limited amount of a string. |
|||
* @ctx: NULL, or tal allocated object to be parent. |
|||
* @p: the string to copy (can be take()). |
|||
* @n: the maximum length to copy. |
|||
* |
|||
* Always gives a nul-terminated string, with strlen() <= @n. |
|||
*/ |
|||
char *tal_strndup(const tal_t *ctx, const char *p, size_t n); |
|||
|
|||
/**
|
|||
* tal_fmt - allocate a formatted string |
|||
* @ctx: NULL, or tal allocated object to be parent. |
|||
* @fmt: the printf-style format (can be take()). |
|||
*/ |
|||
char *tal_fmt(const tal_t *ctx, const char *fmt, ...) PRINTF_FMT(2,3); |
|||
|
|||
/**
|
|||
* tal_vfmt - allocate a formatted string (va_list version) |
|||
* @ctx: NULL, or tal allocated object to be parent. |
|||
* @fmt: the printf-style format (can be take()). |
|||
* @va: the va_list containing the format args. |
|||
*/ |
|||
char *tal_vfmt(const tal_t *ctx, const char *fmt, va_list ap) |
|||
PRINTF_FMT(2,0); |
|||
|
|||
/**
|
|||
* tal_append_fmt - append a formatted string to a talloc string. |
|||
* @baseptr: a pointer to the tal string to be appended to. |
|||
* @fmt: the printf-style format (can be take()). |
|||
* |
|||
* Returns false on allocation failure. |
|||
*/ |
|||
bool tal_append_fmt(char **baseptr, const char *fmt, ...) PRINTF_FMT(2,3); |
|||
|
|||
/**
|
|||
* tal_append_vfmt - append a formatted string to a talloc string (va_list) |
|||
* @baseptr: a pointer to the tal string to be appended to. |
|||
* @fmt: the printf-style format (can be take()). |
|||
* @va: the va_list containing the format args. |
|||
* |
|||
* Returns false on allocation failure. |
|||
*/ |
|||
bool tal_append_vfmt(char **baseptr, const char *fmt, va_list ap); |
|||
|
|||
/**
|
|||
* tal_strcat - join two strings together |
|||
* @ctx: NULL, or tal allocated object to be parent. |
|||
* @s1: the first string (can be take()). |
|||
* @s2: the second string (can be take()). |
|||
*/ |
|||
char *tal_strcat(const tal_t *ctx, const char *s1, const char *s2); |
|||
|
|||
enum strsplit { |
|||
STR_EMPTY_OK, |
|||
STR_NO_EMPTY |
|||
}; |
|||
|
|||
/**
|
|||
* tal_strsplit - Split string into an array of substrings |
|||
* @ctx: the context to tal from (often NULL). |
|||
* @string: the string to split (can be take()). |
|||
* @delims: delimiters where lines should be split (can be take()). |
|||
* @flags: whether to include empty substrings. |
|||
* |
|||
* This function splits a single string into multiple strings. |
|||
* |
|||
* If @string is take(), the returned array will point into the |
|||
* mangled @string. |
|||
* |
|||
* Multiple delimiters result in empty substrings. By definition, no |
|||
* delimiters will appear in the substrings. |
|||
* |
|||
* The final char * in the array will be NULL, and tal_count() will |
|||
* return the number of elements plus 1 (for that NULL). |
|||
* |
|||
* Example: |
|||
* #include <ccan/tal/str/str.h> |
|||
* ... |
|||
* static unsigned int count_long_lines(const char *string) |
|||
* { |
|||
* char **lines; |
|||
* unsigned int i, long_lines = 0; |
|||
* |
|||
* // Can only fail on out-of-memory.
|
|||
* lines = tal_strsplit(NULL, string, "\n", STR_NO_EMPTY); |
|||
* for (i = 0; lines[i] != NULL; i++) |
|||
* if (strlen(lines[i]) > 80) |
|||
* long_lines++; |
|||
* tal_free(lines); |
|||
* return long_lines; |
|||
* } |
|||
*/ |
|||
char **tal_strsplit(const tal_t *ctx, |
|||
const char *string, const char *delims, enum strsplit flag); |
|||
|
|||
enum strjoin { |
|||
STR_TRAIL, |
|||
STR_NO_TRAIL |
|||
}; |
|||
|
|||
/**
|
|||
* tal_strjoin - Join an array of substrings into one long string |
|||
* @ctx: the context to tal from (often NULL). |
|||
* @strings: the NULL-terminated array of strings to join (can be take()) |
|||
* @delim: the delimiter to insert between the strings (can be take()) |
|||
* @flags: whether to add a delimieter to the end |
|||
* |
|||
* This function joins an array of strings into a single string. The |
|||
* return value is allocated using tal. Each string in @strings is |
|||
* followed by a copy of @delim. |
|||
* |
|||
* Example: |
|||
* // Append the string "--EOL" to each line.
|
|||
* static char *append_to_all_lines(const char *string) |
|||
* { |
|||
* char **lines, *ret; |
|||
* |
|||
* lines = tal_strsplit(NULL, string, "\n", STR_EMPTY_OK); |
|||
* ret = tal_strjoin(NULL, lines, "-- EOL\n", STR_TRAIL); |
|||
* tal_free(lines); |
|||
* return ret; |
|||
* } |
|||
*/ |
|||
char *tal_strjoin(const void *ctx, char *strings[], const char *delim, |
|||
enum strjoin flags); |
|||
|
|||
/**
|
|||
* tal_strreg - match/extract from a string via (extended) regular expressions. |
|||
* @ctx: the context to tal from (often NULL) |
|||
* @string: the string to try to match (can be take()) |
|||
* @regex: the regular expression to match (can be take()) |
|||
* ...: pointers to strings to allocate for subexpressions. |
|||
* |
|||
* Returns true if we matched, in which case any parenthesized |
|||
* expressions in @regex are allocated and placed in the char ** |
|||
* arguments following @regex. NULL arguments mean the match is not |
|||
* saved. The order of the strings is the order |
|||
* of opening braces in the expression: in the case of repeated |
|||
* expressions (eg "([a-z])*") the last one is saved, in the case of |
|||
* non-existent matches (eg "([a-z]*)?") the pointer is set to NULL. |
|||
* |
|||
* Allocation failures or malformed regular expressions return false. |
|||
* |
|||
* See Also: |
|||
* regcomp(3), regex(3). |
|||
* |
|||
* Example: |
|||
* // Given 'My name is Rusty' outputs 'Hello Rusty!'
|
|||
* // Given 'my first name is Rusty Russell' outputs 'Hello Rusty Russell!'
|
|||
* // Given 'My name isnt Rusty Russell' outputs 'Hello there!'
|
|||
* int main(int argc, char *argv[]) |
|||
* { |
|||
* char *person, *input; |
|||
* |
|||
* // Join args and trim trailing space.
|
|||
* input = tal_strjoin(NULL, argv+1, " ", STR_NO_TRAIL); |
|||
* if (tal_strreg(NULL, input, |
|||
* "[Mm]y (first )?name is ([A-Za-z ]+)", |
|||
* NULL, &person)) |
|||
* printf("Hello %s!\n", person); |
|||
* else |
|||
* printf("Hello there!\n"); |
|||
* return 0; |
|||
* } |
|||
*/ |
|||
bool tal_strreg(const void *ctx, const char *string, const char *regex, ...); |
|||
#endif /* CCAN_STR_TAL_H */ |
@ -1,22 +0,0 @@ |
|||
/* tal/talloc can't implement tal_first/tal_next. */ |
|||
#ifdef TAL_USE_TALLOC |
|||
static inline bool no_children(const void *ctx) |
|||
{ |
|||
return talloc_total_blocks(ctx) == 1; |
|||
} |
|||
|
|||
static inline bool single_child(const void *ctx, const void *child) |
|||
{ |
|||
return talloc_total_blocks(ctx) == 2 && tal_parent(child) == ctx; |
|||
} |
|||
#else |
|||
static inline bool no_children(const void *ctx) |
|||
{ |
|||
return !tal_first(ctx); |
|||
} |
|||
|
|||
static inline bool single_child(const void *ctx, const void *child) |
|||
{ |
|||
return tal_first(ctx) == child && !tal_next(ctx, child); |
|||
} |
|||
#endif |
@ -1,90 +0,0 @@ |
|||
#include <ccan/tal/str/str.h> |
|||
#include <ccan/tal/str/str.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include "helper.h" |
|||
|
|||
int main(void) |
|||
{ |
|||
char *parent, *c; |
|||
|
|||
plan_tests(32); |
|||
|
|||
parent = tal(NULL, char); |
|||
ok1(parent); |
|||
|
|||
c = tal_strdup(parent, "hello"); |
|||
ok1(strcmp(c, "hello") == 0); |
|||
ok1(tal_parent(c) == parent); |
|||
tal_free(c); |
|||
|
|||
c = tal_strndup(parent, "hello", 3); |
|||
ok1(strcmp(c, "hel") == 0); |
|||
ok1(tal_parent(c) == parent); |
|||
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_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_parent(c) == parent); |
|||
strcat(c, "x"); |
|||
tal_free(c); |
|||
|
|||
c = tal_fmt(parent, "hello %s", "there"); |
|||
ok1(strcmp(c, "hello there") == 0); |
|||
ok1(tal_parent(c) == parent); |
|||
tal_free(c); |
|||
|
|||
c = tal_strcat(parent, "hello ", "there"); |
|||
ok1(strcmp(c, "hello there") == 0); |
|||
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_parent(c) == parent); |
|||
ok1(single_child(parent, c)); |
|||
|
|||
c = tal_strcat(parent, "And ", take(c)); |
|||
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_append_fmt(&c, "%s %s", "there", "world")); |
|||
ok1(strcmp(c, "hithere world") == 0); |
|||
ok1(tal_parent(c) == parent); |
|||
|
|||
ok1(!tal_append_fmt(&c, take(NULL), "there", "world")); |
|||
ok1(strcmp(c, "hithere world") == 0); |
|||
|
|||
tal_free(parent); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,124 +0,0 @@ |
|||
#include <ccan/tal/str/str.h> |
|||
#include <ccan/tal/str/str.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include "helper.h" |
|||
|
|||
static bool find_parent(tal_t *child, tal_t *parent) |
|||
{ |
|||
tal_t *i; |
|||
|
|||
for (i = child; i; i = tal_parent(i)) |
|||
if (i == parent) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
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(); |
|||
} |
@ -1,48 +0,0 @@ |
|||
#include <ccan/tal/str/str.h> |
|||
#include <ccan/tal/str/str.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include "helper.h" |
|||
|
|||
int main(void) |
|||
{ |
|||
char *parent, *c; |
|||
|
|||
plan_tests(14); |
|||
|
|||
parent = tal(NULL, char); |
|||
ok1(parent); |
|||
|
|||
c = tal_strdup(parent, "hello"); |
|||
|
|||
c = tal_strdup(parent, take(c)); |
|||
ok1(strcmp(c, "hello") == 0); |
|||
ok1(tal_parent(c) == parent); |
|||
|
|||
c = tal_strndup(parent, take(c), 5); |
|||
ok1(strcmp(c, "hello") == 0); |
|||
ok1(tal_parent(c) == parent); |
|||
|
|||
c = tal_strndup(parent, take(c), 3); |
|||
ok1(strcmp(c, "hel") == 0); |
|||
ok1(tal_parent(c) == parent); |
|||
tal_free(c); |
|||
|
|||
c = tal_strdup(parent, "hello %s"); |
|||
c = tal_fmt(parent, take(c), "there"); |
|||
ok1(strcmp(c, "hello there") == 0); |
|||
ok1(tal_parent(c) == parent); |
|||
/* No leftover allocations. */ |
|||
tal_free(c); |
|||
ok1(no_children(parent)); |
|||
|
|||
tal_free(parent); |
|||
ok1(!taken_any()); |
|||
|
|||
/* NULL pass-through. */ |
|||
c = NULL; |
|||
ok1(tal_strdup(NULL, take(c)) == NULL); |
|||
ok1(tal_strndup(NULL, take(c), 5) == NULL); |
|||
ok1(tal_fmt(NULL, take(c), 0) == NULL); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,158 +0,0 @@ |
|||
#include <ccan/tal/str/str.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
#include <ccan/tal/str/str.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include "helper.h" |
|||
|
|||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) |
|||
|
|||
static const char *substrings[] |
|||
= { "far", "bar", "baz", "b", "ba", "z", "ar", NULL }; |
|||
|
|||
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(no_children(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(no_children(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(no_children(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(single_child(ctx, str)); |
|||
tal_free(str); |
|||
ok1(no_children(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(single_child(ctx, str)); |
|||
tal_free(str); |
|||
ok1(no_children(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(single_child(ctx, str)); |
|||
tal_free(str); |
|||
ok1(no_children(ctx)); |
|||
tal_free(ctx); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1 +0,0 @@ |
|||
../../../licenses/LGPL-3 |
@ -1,43 +0,0 @@ |
|||
#include "config.h" |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
/** |
|||
* tal/talloc - an implementation of the tal interface in terms of talloc. |
|||
* |
|||
* Tal and talloc are both hierarchical allocators, but have different APIs. |
|||
* The tal API is mostly a subset of talloc, but if your project already |
|||
* uses talloc then having both tal and talloc pointers is confusing, and |
|||
* a waste of resources. |
|||
* |
|||
* The standard convention to tell ccan modules to use this instead of |
|||
* ccan/tal is to define TAL_USE_TALLOC, usually on the commandline. |
|||
* |
|||
* Bugs: |
|||
* tal_first() and tal_next() can't be implemented. |
|||
* tal_set_backend() can only change the error function. |
|||
* |
|||
* License: LGPL |
|||
*/ |
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
if (argc != 2) |
|||
return 1; |
|||
|
|||
if (strcmp(argv[1], "depends") == 0) { |
|||
printf("ccan/take\n"); |
|||
printf("ccan/typesafe_cb\n"); |
|||
printf("ccan/compiler\n"); |
|||
printf("ccan/likely\n"); |
|||
printf("ccan/str\n"); |
|||
printf("talloc\n"); |
|||
return 0; |
|||
} |
|||
|
|||
if (strcmp(argv[1], "libs") == 0) { |
|||
printf("talloc\n"); |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
@ -1,263 +0,0 @@ |
|||
/* Licensed under LGPL - see LICENSE file for details */ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/take/take.h> |
|||
#include <errno.h> |
|||
#include <assert.h> |
|||
|
|||
static void (*errorfn)(const char *msg) = (void *)abort; |
|||
|
|||
static void COLD call_error(const char *msg) |
|||
{ |
|||
errorfn(msg); |
|||
} |
|||
|
|||
static void *error_on_null(void *p, const char *msg) |
|||
{ |
|||
if (!p) |
|||
call_error(msg); |
|||
return p; |
|||
} |
|||
|
|||
void *tal_talloc_(const tal_t *ctx, size_t bytes, bool clear, |
|||
const char *label) |
|||
{ |
|||
void *ret; |
|||
|
|||
if (clear) |
|||
ret = _talloc_zero(ctx, bytes, label); |
|||
else |
|||
ret = talloc_named_const(ctx, bytes, label); |
|||
|
|||
return error_on_null(ret, "allocation failure"); |
|||
} |
|||
|
|||
void *tal_talloc_arr_(const tal_t *ctx, size_t bytes, size_t count, bool clear, |
|||
const char *label) |
|||
{ |
|||
void *ret; |
|||
|
|||
if (clear) |
|||
ret = _talloc_zero_array(ctx, bytes, count, label); |
|||
else |
|||
ret = _talloc_array(ctx, bytes, count, label); |
|||
|
|||
return error_on_null(ret, "array allocation failure"); |
|||
} |
|||
|
|||
void *tal_talloc_free_(const tal_t *ctx) |
|||
{ |
|||
int saved_errno = errno; |
|||
talloc_free((void *)ctx); |
|||
errno = saved_errno; |
|||
return NULL; |
|||
} |
|||
|
|||
bool tal_talloc_set_name_(tal_t *ctx, const char *name, bool literal) |
|||
{ |
|||
if (!literal) { |
|||
name = talloc_strdup(ctx, name); |
|||
if (!name) { |
|||
call_error("set_name allocation failure"); |
|||
return false; |
|||
} |
|||
} |
|||
talloc_set_name_const(ctx, name); |
|||
return true; |
|||
} |
|||
|
|||
const char *tal_talloc_name_(const tal_t *ctx) |
|||
{ |
|||
const char *p = talloc_get_name(ctx); |
|||
if (p && unlikely(strcmp(p, "UNNAMED") == 0)) |
|||
p = NULL; |
|||
return p; |
|||
} |
|||
|
|||
static bool adjust_size(size_t *size, size_t count) |
|||
{ |
|||
/* Multiplication wrap */ |
|||
if (count && unlikely(*size * count / *size != count)) |
|||
goto overflow; |
|||
|
|||
*size *= count; |
|||
|
|||
/* Make sure we don't wrap adding header. */ |
|||
if (*size + 1024 < 1024) |
|||
goto overflow; |
|||
return true; |
|||
overflow: |
|||
call_error("allocation size overflow"); |
|||
return false; |
|||
} |
|||
|
|||
void *tal_talloc_dup_(const tal_t *ctx, const void *p, size_t size, |
|||
size_t n, size_t extra, const char *label) |
|||
{ |
|||
void *ret; |
|||
size_t nbytes = size; |
|||
|
|||
if (!adjust_size(&nbytes, n)) { |
|||
if (taken(p)) |
|||
tal_free(p); |
|||
return NULL; |
|||
} |
|||
|
|||
/* Beware addition overflow! */ |
|||
if (n + extra < n) { |
|||
call_error("dup size overflow"); |
|||
if (taken(p)) |
|||
tal_free(p); |
|||
return NULL; |
|||
} |
|||
|
|||
if (taken(p)) { |
|||
if (unlikely(!p)) |
|||
return NULL; |
|||
if (unlikely(!tal_talloc_resize_((void **)&p, size, n + extra))) |
|||
return tal_free(p); |
|||
if (unlikely(!tal_steal(ctx, p))) |
|||
return tal_free(p); |
|||
return (void *)p; |
|||
} |
|||
|
|||
ret = tal_talloc_arr_(ctx, size, n + extra, false, label); |
|||
if (ret) |
|||
memcpy(ret, p, nbytes); |
|||
return ret; |
|||
} |
|||
|
|||
bool tal_talloc_resize_(tal_t **ctxp, size_t size, size_t count) |
|||
{ |
|||
tal_t *newp; |
|||
|
|||
if (unlikely(count == 0)) { |
|||
/* Don't free it! */ |
|||
newp = talloc_size(talloc_parent(*ctxp), 0); |
|||
if (!newp) { |
|||
call_error("Resize failure"); |
|||
return false; |
|||
} |
|||
talloc_free(*ctxp); |
|||
*ctxp = newp; |
|||
return true; |
|||
} |
|||
|
|||
/* count is unsigned, not size_t, so check for overflow here! */ |
|||
if ((unsigned)count != count) { |
|||
call_error("Resize overflos"); |
|||
return false; |
|||
} |
|||
|
|||
newp = _talloc_realloc_array(NULL, *ctxp, size, count, NULL); |
|||
if (!newp) { |
|||
call_error("Resize failure"); |
|||
return false; |
|||
} |
|||
*ctxp = newp; |
|||
return true; |
|||
} |
|||
|
|||
bool tal_talloc_expand_(tal_t **ctxp, const void *src, size_t size, size_t count) |
|||
{ |
|||
bool ret = false; |
|||
size_t old_count = talloc_get_size(*ctxp) / size; |
|||
|
|||
/* Check for additive overflow */ |
|||
if (old_count + count < count) { |
|||
call_error("dup size overflow"); |
|||
goto out; |
|||
} |
|||
|
|||
/* Don't point src inside thing we're expanding! */ |
|||
assert(src < *ctxp |
|||
|| (char *)src >= (char *)(*ctxp) + (size * old_count)); |
|||
|
|||
if (!tal_talloc_resize_(ctxp, size, old_count + count)) |
|||
goto out; |
|||
|
|||
memcpy((char *)*ctxp + size * old_count, src, count * size); |
|||
ret = true; |
|||
|
|||
out: |
|||
if (taken(src)) |
|||
tal_free(src); |
|||
return ret; |
|||
} |
|||
|
|||
/* Sucky inline hash table implementation, to avoid deps. */ |
|||
#define HTABLE_BITS 10 |
|||
struct destructor { |
|||
struct destructor *next; |
|||
const tal_t *ctx; |
|||
void (*destroy)(void *me); |
|||
}; |
|||
static struct destructor *destr_hash[1 << HTABLE_BITS]; |
|||
|
|||
static unsigned int hash_ptr(const void *p) |
|||
{ |
|||
unsigned long h = (unsigned long)p / sizeof(void *); |
|||
|
|||
return (h ^ (h >> HTABLE_BITS)) & ((1 << HTABLE_BITS) - 1); |
|||
} |
|||
|
|||
static int tal_talloc_destroy(const tal_t *ctx) |
|||
{ |
|||
struct destructor **d = &destr_hash[hash_ptr(ctx)]; |
|||
while (*d) { |
|||
if ((*d)->ctx == ctx) { |
|||
struct destructor *this = *d; |
|||
this->destroy((void *)ctx); |
|||
*d = this->next; |
|||
talloc_free(this); |
|||
} |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
bool tal_talloc_add_destructor_(const tal_t *ctx, void (*destroy)(void *me)) |
|||
{ |
|||
struct destructor *d = talloc(ctx, struct destructor); |
|||
if (!d) |
|||
return false; |
|||
|
|||
d->next = destr_hash[hash_ptr(ctx)]; |
|||
d->ctx = ctx; |
|||
d->destroy = destroy; |
|||
destr_hash[hash_ptr(ctx)] = d; |
|||
talloc_set_destructor(ctx, tal_talloc_destroy); |
|||
return true; |
|||
} |
|||
|
|||
bool tal_talloc_del_destructor_(const tal_t *ctx, void (*destroy)(void *me)) |
|||
{ |
|||
struct destructor **d = &destr_hash[hash_ptr(ctx)]; |
|||
|
|||
while (*d) { |
|||
if ((*d)->ctx == ctx && (*d)->destroy == destroy) { |
|||
struct destructor *this = *d; |
|||
*d = this->next; |
|||
talloc_free(this); |
|||
return true; |
|||
} |
|||
d = &(*d)->next; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
void tal_talloc_set_backend_(void *(*alloc_fn)(size_t size), |
|||
void *(*resize_fn)(void *, size_t size), |
|||
void (*free_fn)(void *), |
|||
void (*error_fn)(const char *msg)) |
|||
{ |
|||
assert(!alloc_fn); |
|||
assert(!resize_fn); |
|||
assert(!free_fn); |
|||
errorfn = error_fn; |
|||
talloc_set_abort_fn(error_fn); |
|||
} |
|||
|
|||
bool tal_talloc_check_(const tal_t *ctx, const char *errorstr) |
|||
{ |
|||
/* We can't really check, but this iterates (and may abort). */ |
|||
return !ctx || talloc_total_blocks(ctx) >= 1; |
|||
} |
@ -1,316 +0,0 @@ |
|||
/* Licensed under LGPL - see LICENSE file for details */ |
|||
#ifndef CCAN_TAL_TALLOC_H |
|||
#define CCAN_TAL_TALLOC_H |
|||
#include "config.h" |
|||
#include <ccan/compiler/compiler.h> |
|||
#include <ccan/likely/likely.h> |
|||
#include <ccan/typesafe_cb/typesafe_cb.h> |
|||
#include <ccan/str/str.h> |
|||
#include <talloc.h> |
|||
#include <stdlib.h> |
|||
#include <stdbool.h> |
|||
#include <stdarg.h> |
|||
|
|||
/**
|
|||
* tal_t - convenient alias for void to mark tal pointers. |
|||
* |
|||
* Since any pointer can be a tal-allocated pointer, it's often |
|||
* useful to use this typedef to mark them explicitly. |
|||
*/ |
|||
typedef TALLOC_CTX tal_t; |
|||
|
|||
/**
|
|||
* tal - basic allocator function |
|||
* @ctx: NULL, or tal allocated object to be parent. |
|||
* @type: the type to allocate. |
|||
* |
|||
* Allocates a specific type, with a given parent context. The name |
|||
* of the object is a string of the type, but if CCAN_TAL_DEBUG is |
|||
* defined it also contains the file and line which allocated it. |
|||
* |
|||
* Example: |
|||
* int *p = tal(NULL, int); |
|||
* *p = 1; |
|||
*/ |
|||
#define tal(ctx, type) \ |
|||
((type *)tal_talloc_((ctx), sizeof(type), false, \ |
|||
TAL_LABEL(type, ""))) |
|||
|
|||
/**
|
|||
* talz - zeroing allocator function |
|||
* @ctx: NULL, or tal allocated object to be parent. |
|||
* @type: the type to allocate. |
|||
* |
|||
* Equivalent to tal() followed by memset() to zero. |
|||
* |
|||
* Example: |
|||
* p = talz(NULL, int); |
|||
* assert(*p == 0); |
|||
*/ |
|||
#define talz(ctx, type) \ |
|||
((type *)tal_talloc_((ctx), sizeof(type), true, \ |
|||
TAL_LABEL(type, ""))) |
|||
|
|||
/**
|
|||
* tal_free - free a tal-allocated pointer. |
|||
* @p: NULL, or tal allocated object to free. |
|||
* |
|||
* This calls the destructors for p (if any), then does the same for all its |
|||
* children (recursively) before finally freeing the memory. It returns |
|||
* NULL, for convenience. |
|||
* |
|||
* Note: errno is preserved by this call. |
|||
* |
|||
* Example: |
|||
* p = tal_free(p); |
|||
*/ |
|||
#define tal_free(p) tal_talloc_free_(p) |
|||
|
|||
/**
|
|||
* tal_arr - allocate an array of objects. |
|||
* @ctx: NULL, or tal allocated object to be parent. |
|||
* @type: the type to allocate. |
|||
* @count: the number to allocate. |
|||
* |
|||
* Note that an object allocated with tal_arr() has a length property; |
|||
* see tal_count(). |
|||
* |
|||
* Example: |
|||
* p = tal_arr(NULL, int, 2); |
|||
* p[0] = 0; |
|||
* p[1] = 1; |
|||
*/ |
|||
#define tal_arr(ctx, type, count) \ |
|||
((type *)tal_talloc_arr_((ctx), sizeof(type), (count), false, \ |
|||
TAL_LABEL(type, "[]"))) |
|||
|
|||
/**
|
|||
* tal_arrz - allocate an array of zeroed objects. |
|||
* @ctx: NULL, or tal allocated object to be parent. |
|||
* @type: the type to allocate. |
|||
* @count: the number to allocate. |
|||
* |
|||
* Note that an object allocated with tal_arrz() has a length property; |
|||
* see tal_count(). |
|||
* |
|||
* Example: |
|||
* p = tal_arrz(NULL, int, 2); |
|||
* assert(p[0] == 0 && p[1] == 0); |
|||
*/ |
|||
#define tal_arrz(ctx, type, count) \ |
|||
((type *)tal_talloc_arr_((ctx), sizeof(type), (count), true, \ |
|||
TAL_LABEL(type, "[]"))) |
|||
|
|||
/**
|
|||
* tal_resize - enlarge or reduce a tal_arr[z]. |
|||
* @p: A pointer to the tal allocated array to resize. |
|||
* @count: the number to allocate. |
|||
* |
|||
* This returns true on success (and may move *@p), or false on failure. |
|||
* If @p has a length property, it is updated on success. |
|||
* |
|||
* Example: |
|||
* tal_resize(&p, 100); |
|||
*/ |
|||
#define tal_resize(p, count) \ |
|||
tal_talloc_resize_((void **)(p), sizeof**(p), (count)) |
|||
|
|||
/**
|
|||
* tal_steal - change the parent of a tal-allocated pointer. |
|||
* @ctx: The new parent. |
|||
* @ptr: The tal allocated object to move. |
|||
* |
|||
* This may need to perform an allocation, in which case it may fail; thus |
|||
* it can return NULL, otherwise returns @ptr. |
|||
*/ |
|||
#define tal_steal(ctx, ptr) talloc_steal((ctx), (ptr)) |
|||
|
|||
/**
|
|||
* tal_add_destructor - add a callback function when this context is destroyed. |
|||
* @ptr: The tal allocated object. |
|||
* @function: the function to call before it's freed. |
|||
* |
|||
* This is a more convenient form of tal_add_notifier(@ptr, |
|||
* TAL_NOTIFY_FREE, ...), in that the function prototype takes only @ptr. |
|||
*/ |
|||
#define tal_add_destructor(ptr, function) \ |
|||
tal_talloc_add_destructor_((ptr), typesafe_cb(void, void *, \ |
|||
(function), (ptr))) |
|||
|
|||
/**
|
|||
* tal_del_destructor - remove a destructor callback function. |
|||
* @ptr: The tal allocated object. |
|||
* @function: the function to call before it's freed. |
|||
* |
|||
* If @function has not been successfully added as a destructor, this returns |
|||
* false. |
|||
* |
|||
* Note: you can't add more than one destructor with the talloc backend! |
|||
*/ |
|||
#define tal_del_destructor(ptr, function) \ |
|||
tal_talloc_del_destructor_((ptr), typesafe_cb(void, void *, \ |
|||
(function), (ptr))) |
|||
|
|||
/**
|
|||
* tal_set_name - attach a name to a tal pointer. |
|||
* @ptr: The tal allocated object. |
|||
* @name: The name to use. |
|||
* |
|||
* The name is copied, unless we're certain it's a string literal. |
|||
*/ |
|||
#define tal_set_name(ptr, name) \ |
|||
tal_talloc_set_name_((ptr), (name), TAL_TALLOC_IS_LITERAL(name)) |
|||
|
|||
/**
|
|||
* tal_name - get the name for a tal pointer. |
|||
* @ptr: The tal allocated object. |
|||
* |
|||
* Returns NULL if no name has been set. |
|||
*/ |
|||
#define tal_name(ptr) \ |
|||
tal_talloc_name_(ptr) |
|||
|
|||
/**
|
|||
* tal_count - get the count of objects in a tal_arr. |
|||
* @ptr: The tal allocated object array. |
|||
*/ |
|||
#define tal_count(ptr) talloc_array_length(ptr) |
|||
|
|||
/**
|
|||
* tal_parent - get the parent of a tal object. |
|||
* @ctx: The tal allocated object. |
|||
* |
|||
* Returns the parent, which may be NULL. Returns NULL if @ctx is NULL. |
|||
*/ |
|||
#define tal_parent(ctx) talloc_parent(ctx) |
|||
|
|||
/**
|
|||
* tal_dup - duplicate an object. |
|||
* @ctx: The tal allocated object to be parent of the result (may be NULL). |
|||
* @type: the type (should match type of @p!) |
|||
* @p: the object to copy (or reparented if take()) |
|||
*/ |
|||
#define tal_dup(ctx, type, p) \ |
|||
((type *)tal_talloc_dup_((ctx), tal_talloc_typechk_(p, type *), \ |
|||
sizeof(type), 1, 0, \ |
|||
TAL_LABEL(type, ""))) |
|||
|
|||
/**
|
|||
* tal_dup_arr - duplicate an array. |
|||
* @ctx: The tal allocated object to be parent of the result (may be NULL). |
|||
* @type: the type (should match type of @p!) |
|||
* @p: the array to copy (or resized & reparented if take()) |
|||
* @n: the number of sizeof(type) entries to copy. |
|||
* @extra: the number of extra sizeof(type) entries to allocate. |
|||
*/ |
|||
#define tal_dup_arr(ctx, type, p, n, extra) \ |
|||
((type *)tal_talloc_dup_((ctx), tal_talloc_typechk_(p, type *), \ |
|||
sizeof(type), (n), (extra), \ |
|||
TAL_LABEL(type, "[]"))) |
|||
|
|||
|
|||
/**
|
|||
* tal_set_backend - set the allocation or error functions to use |
|||
* @alloc_fn: NULL |
|||
* @resize_fn: NULL |
|||
* @free_fn: NULL |
|||
* @error_fn: called on errors or NULL (default is abort) |
|||
* |
|||
* The defaults are set up so tal functions never return NULL, but you |
|||
* can override error_fn to change that. error_fn can return, and is |
|||
* called if malloc or realloc fail. |
|||
*/ |
|||
#define tal_set_backend(alloc_fn, resize_fn, free_fn, error_fn) \ |
|||
tal_talloc_set_backend_((alloc_fn), (resize_fn), (free_fn), (error_fn)) |
|||
|
|||
/**
|
|||
* tal_expand - expand a tal array with contents. |
|||
* @a1p: a pointer to the tal array to expand. |
|||
* @a2: the second array (can be take()). |
|||
* @num2: the number of elements in the second array. |
|||
* |
|||
* Note that *@a1 and @a2 should be the same type. tal_count(@a1) will |
|||
* be increased by @num2. |
|||
* |
|||
* Example: |
|||
* int *arr1 = tal_arrz(NULL, int, 2); |
|||
* int arr2[2] = { 1, 3 }; |
|||
* |
|||
* tal_expand(&arr1, arr2, 2); |
|||
* assert(tal_count(arr1) == 4); |
|||
* assert(arr1[2] == 1); |
|||
* assert(arr1[3] == 3); |
|||
*/ |
|||
#define tal_expand(a1p, a2, num2) \ |
|||
tal_talloc_expand_((void **)(a1p), (a2), sizeof**(a1p), \ |
|||
(num2) + 0*sizeof(*(a1p) == (a2))) |
|||
|
|||
|
|||
/**
|
|||
* tal_check - set the allocation or error functions to use |
|||
* @ctx: a tal context, or NULL. |
|||
* @errorstr: a string to prepend calls to error_fn, or NULL. |
|||
* |
|||
* This sanity-checks a tal tree (unless NDEBUG is defined, in which case |
|||
* it simply returns true). If errorstr is not null, error_fn is called |
|||
* when a problem is found, otherwise it is not. |
|||
*/ |
|||
#define tal_check(ctx, errorstr) \ |
|||
tal_talloc_check_((ctx), (errorstr)) |
|||
|
|||
|
|||
/* Internal support functions */ |
|||
#ifndef TAL_TALLOC_LABEL |
|||
#ifdef CCAN_TAL_NO_LABELS |
|||
#define TAL_LABEL(type, arr) NULL |
|||
#else |
|||
#ifdef CCAN_TAL_DEBUG |
|||
#define TAL_LABEL(type, arr) \ |
|||
__FILE__ ":" stringify(__LINE__) ":" stringify(type) arr |
|||
#else |
|||
#define TAL_LABEL(type, arr) stringify(type) arr |
|||
#endif /* CCAN_TAL_DEBUG */ |
|||
#endif |
|||
#endif |
|||
|
|||
#if HAVE_BUILTIN_CONSTANT_P |
|||
#define TAL_TALLOC_IS_LITERAL(str) __builtin_constant_p(str) |
|||
#else |
|||
#define TAL_TALLOC_IS_LITERAL(str) false |
|||
#endif |
|||
|
|||
#if HAVE_TYPEOF && HAVE_STATEMENT_EXPR |
|||
/* Careful: ptr can be const foo *, ptype is foo *. Also, ptr could
|
|||
* be an array, eg "hello". */ |
|||
#define tal_talloc_typechk_(ptr, ptype) ({ __typeof__((ptr)+0) _p = (ptype)(ptr); _p; }) |
|||
#else |
|||
#define tal_talloc_typechk_(ptr, ptype) (ptr) |
|||
#endif |
|||
|
|||
void *tal_talloc_(const tal_t *ctx, size_t bytes, bool clear, |
|||
const char *label); |
|||
void *tal_talloc_arr_(const tal_t *ctx, size_t bytes, size_t count, bool clear, |
|||
const char *label); |
|||
void *tal_talloc_free_(const tal_t *ctx); |
|||
const char *tal_talloc_name_(const tal_t *ctx); |
|||
bool tal_talloc_set_name_(tal_t *ctx, const char *name, bool literal); |
|||
|
|||
bool tal_talloc_add_destructor_(const tal_t *ctx, void (*destroy)(void *me)); |
|||
bool tal_talloc_del_destructor_(const tal_t *ctx, void (*destroy)(void *me)); |
|||
|
|||
/* ccan/tal/str uses this, so define it. */ |
|||
#define tal_dup_(ctx, p, size, n, extra, add_count, label) \ |
|||
tal_talloc_dup_((ctx), (p), (size), (n), (extra), (label)) |
|||
void *tal_talloc_dup_(const tal_t *ctx, const void *p, size_t size, |
|||
size_t n, size_t extra, const char *label); |
|||
|
|||
bool tal_talloc_resize_(tal_t **ctxp, size_t size, size_t count); |
|||
bool tal_talloc_expand_(tal_t **ctxp, const void *src, size_t size, size_t count); |
|||
bool tal_talloc_check_(const tal_t *ctx, const char *errorstr); |
|||
|
|||
void tal_talloc_set_backend_(void *(*alloc_fn)(size_t size), |
|||
void *(*resize_fn)(void *, size_t size), |
|||
void (*free_fn)(void *), |
|||
void (*error_fn)(const char *msg)); |
|||
|
|||
#endif /* CCAN_TAL_TALLOC_H */ |
@ -1,46 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
char *parent, *c[4]; |
|||
int i; |
|||
|
|||
plan_tests(11); |
|||
|
|||
parent = tal(NULL, char); |
|||
ok1(parent); |
|||
|
|||
/* Zeroing allocations. */ |
|||
for (i = 0; i < 4; i++) { |
|||
c[i] = talz(parent, char); |
|||
ok1(*c[i] == '\0'); |
|||
tal_free(c[i]); |
|||
} |
|||
|
|||
/* Array allocation. */ |
|||
for (i = 0; i < 4; i++) { |
|||
c[i] = tal_arr(parent, char, 4); |
|||
strcpy(c[i], "abc"); |
|||
tal_free(c[i]); |
|||
} |
|||
|
|||
/* Zeroing array allocation. */ |
|||
for (i = 0; i < 4; i++) { |
|||
c[i] = tal_arrz(parent, char, 4); |
|||
ok1(!c[i][0] && !c[i][1] && !c[i][2] && !c[i][3]); |
|||
strcpy(c[i], "abc"); |
|||
tal_free(c[i]); |
|||
} |
|||
|
|||
/* Resizing. */ |
|||
c[0] = tal_arrz(parent, char, 4); |
|||
ok1(tal_resize(&c[0], 6)); |
|||
strcpy(c[0], "hello"); |
|||
tal_free(c[0]); |
|||
ok1(talloc_total_blocks(parent) == 1); |
|||
tal_free(parent); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,33 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
char *p1, *p2; |
|||
|
|||
plan_tests(12); |
|||
|
|||
p1 = tal(NULL, char); |
|||
ok1(p1); |
|||
ok1(tal_count(p1) == 1); |
|||
|
|||
p2 = tal_arr(p1, char, 1); |
|||
ok1(p2); |
|||
ok1(tal_count(p2) == 1); |
|||
ok1(tal_resize(&p2, 2)); |
|||
ok1(tal_count(p2) == 2); |
|||
ok1(tal_check(NULL, NULL)); |
|||
tal_free(p2); |
|||
|
|||
p2 = tal_arrz(p1, char, 7); |
|||
ok1(p2); |
|||
ok1(tal_count(p2) == 7); |
|||
ok1(tal_resize(&p2, 0)); |
|||
ok1(tal_count(p2) == 0); |
|||
ok1(tal_check(NULL, NULL)); |
|||
tal_free(p2); |
|||
tal_free(p1); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,67 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
static char *parent, *child; |
|||
static int destroy_count; |
|||
|
|||
/* Parent gets destroyed first. */ |
|||
static void destroy_parent(char *p) |
|||
{ |
|||
ok1(p == parent); |
|||
ok1(destroy_count == 0); |
|||
/* Can still access child. */ |
|||
*child = '1'; |
|||
destroy_count++; |
|||
} |
|||
|
|||
static void destroy_child(char *p) |
|||
{ |
|||
ok1(p == child); |
|||
ok1(destroy_count == 1); |
|||
/* Can still access parent (though destructor has been called). */ |
|||
*parent = '1'; |
|||
destroy_count++; |
|||
} |
|||
|
|||
static void destroy_inc(char *p) |
|||
{ |
|||
destroy_count++; |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
char *child2; |
|||
|
|||
plan_tests(18); |
|||
|
|||
destroy_count = 0; |
|||
parent = tal(NULL, char); |
|||
child = tal(parent, char); |
|||
ok1(tal_add_destructor(parent, destroy_parent)); |
|||
ok1(tal_add_destructor(child, destroy_child)); |
|||
tal_free(parent); |
|||
ok1(destroy_count == 2); |
|||
|
|||
destroy_count = 0; |
|||
parent = tal(NULL, char); |
|||
child = tal(parent, char); |
|||
ok1(tal_add_destructor(parent, destroy_parent)); |
|||
ok1(tal_add_destructor(child, destroy_child)); |
|||
ok1(tal_del_destructor(child, destroy_child)); |
|||
tal_free(parent); |
|||
ok1(destroy_count == 1); |
|||
|
|||
destroy_count = 0; |
|||
parent = tal(NULL, char); |
|||
child = tal(parent, char); |
|||
child2 = tal(parent, char); |
|||
ok1(tal_add_destructor(parent, destroy_inc)); |
|||
ok1(tal_add_destructor(parent, destroy_inc)); |
|||
ok1(tal_add_destructor(child, destroy_inc)); |
|||
ok1(tal_add_destructor(child2, destroy_inc)); |
|||
tal_free(parent); |
|||
ok1(destroy_count == 4); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,35 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
int *a; |
|||
const int arr[] = { 1, 2 }; |
|||
|
|||
plan_tests(14); |
|||
talloc_enable_null_tracking_no_autofree(); |
|||
|
|||
a = tal_arrz(NULL, int, 1); |
|||
ok1(a); |
|||
|
|||
ok1(tal_expand(&a, arr, 2)); |
|||
ok1(tal_count(a) == 3); |
|||
ok1(a[0] == 0); |
|||
ok1(a[1] == 1); |
|||
ok1(a[2] == 2); |
|||
|
|||
ok1(tal_expand(&a, take(tal_arrz(NULL, int, 1)), 1)); |
|||
ok1(tal_count(a) == 4); |
|||
ok1(a[0] == 0); |
|||
ok1(a[1] == 1); |
|||
ok1(a[2] == 2); |
|||
ok1(a[3] == 0); |
|||
ok1(talloc_total_blocks(NULL) == 2); |
|||
ok1(talloc_total_blocks(a) == 1); |
|||
|
|||
tal_free(a); |
|||
|
|||
talloc_disable_null_tracking(); |
|||
return exit_status(); |
|||
} |
@ -1,26 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include <errno.h> |
|||
|
|||
static void destroy_errno(char *p) |
|||
{ |
|||
errno = ENOENT; |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
char *p; |
|||
|
|||
plan_tests(2); |
|||
|
|||
p = tal(NULL, char); |
|||
ok1(tal_add_destructor(p, destroy_errno)); |
|||
|
|||
/* Errno save/restored across free. */ |
|||
errno = EINVAL; |
|||
tal_free(p); |
|||
ok1(errno == EINVAL); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,34 +0,0 @@ |
|||
#define CCAN_TAL_DEBUG |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
int *p; |
|||
char name[] = "test name"; |
|||
|
|||
plan_tests(6); |
|||
|
|||
p = tal(NULL, int); |
|||
ok1(strcmp(tal_name(p), __FILE__ ":13:int") == 0); |
|||
|
|||
tal_set_name(p, "some literal"); |
|||
ok1(strcmp(tal_name(p), "some literal") == 0); |
|||
|
|||
tal_set_name(p, name); |
|||
ok1(strcmp(tal_name(p), name) == 0); |
|||
/* You can't reuse my pointer though! */ |
|||
ok1(tal_name(p) != name); |
|||
|
|||
tal_set_name(p, "some other literal"); |
|||
ok1(strcmp(tal_name(p), "some other literal") == 0); |
|||
|
|||
tal_free(p); |
|||
|
|||
p = tal_arr(NULL, int, 2); |
|||
ok1(strcmp(tal_name(p), __FILE__ ":29:int[]") == 0); |
|||
tal_free(p); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,30 +0,0 @@ |
|||
#define CCAN_TAL_NO_LABELS |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
int *p; |
|||
char name[] = "test name"; |
|||
|
|||
plan_tests(5); |
|||
|
|||
p = tal(NULL, int); |
|||
ok1(tal_name(p) == NULL); |
|||
|
|||
tal_set_name(p, "some literal"); |
|||
ok1(strcmp(tal_name(p), "some literal") == 0); |
|||
|
|||
tal_set_name(p, name); |
|||
ok1(strcmp(tal_name(p), name) == 0); |
|||
/* You can't reuse my pointer though! */ |
|||
ok1(tal_name(p) != name); |
|||
|
|||
tal_set_name(p, "some other literal"); |
|||
ok1(strcmp(tal_name(p), "some other literal") == 0); |
|||
|
|||
tal_free(p); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,33 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
int *p; |
|||
char name[] = "test name"; |
|||
|
|||
plan_tests(6); |
|||
|
|||
p = tal(NULL, int); |
|||
ok1(strcmp(tal_name(p), "int") == 0); |
|||
|
|||
tal_set_name(p, "some literal"); |
|||
ok1(strcmp(tal_name(p), "some literal") == 0); |
|||
|
|||
tal_set_name(p, name); |
|||
ok1(strcmp(tal_name(p), name) == 0); |
|||
/* You can't reuse my pointer though! */ |
|||
ok1(tal_name(p) != name); |
|||
|
|||
tal_set_name(p, "some other literal"); |
|||
ok1(strcmp(tal_name(p), "some other literal") == 0); |
|||
|
|||
tal_free(p); |
|||
|
|||
p = tal_arr(NULL, int, 2); |
|||
ok1(strcmp(tal_name(p), "int[]") == 0); |
|||
tal_free(p); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,100 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
static int error_count; |
|||
|
|||
static void my_error(const char *msg) |
|||
{ |
|||
error_count++; |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
void *p; |
|||
int *pi, *origpi; |
|||
char *cp; |
|||
|
|||
plan_tests(30); |
|||
|
|||
tal_set_backend(NULL, NULL, NULL, my_error); |
|||
talloc_enable_null_tracking_no_autofree(); |
|||
|
|||
p = tal_arr(NULL, int, (size_t)-1); |
|||
ok1(!p); |
|||
ok1(error_count == 1); |
|||
|
|||
p = tal_arr(NULL, char, (size_t)-2); |
|||
ok1(!p); |
|||
ok1(error_count == 2); |
|||
|
|||
/* Now try overflow cases for tal_dup. */ |
|||
error_count = 0; |
|||
origpi = tal_arr(NULL, int, 100); |
|||
ok1(origpi); |
|||
ok1(error_count == 0); |
|||
pi = tal_dup_arr(NULL, int, origpi, (size_t)-1, 0); |
|||
ok1(!pi); |
|||
ok1(error_count == 1); |
|||
pi = tal_dup_arr(NULL, int, origpi, 0, (size_t)-1); |
|||
ok1(!pi); |
|||
ok1(error_count == 2); |
|||
|
|||
pi = tal_dup_arr(NULL, int, origpi, (size_t)-1UL / sizeof(int), |
|||
(size_t)-1UL / sizeof(int)); |
|||
ok1(!pi); |
|||
ok1(error_count == 3); |
|||
/* This will still overflow when tal_hdr is added. */ |
|||
pi = tal_dup_arr(NULL, int, origpi, (size_t)-1UL / sizeof(int) / 2, |
|||
(size_t)-1UL / sizeof(int) / 2); |
|||
ok1(!pi); |
|||
ok1(error_count == 4); |
|||
ok1(talloc_total_blocks(NULL) == 2); |
|||
tal_free(origpi); |
|||
|
|||
/* Now, check that with taltk() we free old one on failure. */ |
|||
origpi = tal_arr(NULL, int, 100); |
|||
error_count = 0; |
|||
pi = tal_dup_arr(NULL, int, take(origpi), (size_t)-1, 0); |
|||
ok1(!pi); |
|||
ok1(error_count == 1); |
|||
|
|||
origpi = tal_arr(NULL, int, 100); |
|||
error_count = 0; |
|||
pi = tal_dup_arr(NULL, int, take(origpi), 0, (size_t)-1); |
|||
ok1(!pi); |
|||
ok1(error_count == 1); |
|||
ok1(talloc_total_blocks(NULL) == 1); |
|||
|
|||
origpi = tal_arr(NULL, int, 100); |
|||
error_count = 0; |
|||
pi = tal_dup_arr(NULL, int, take(origpi), (size_t)-1UL / sizeof(int), |
|||
(size_t)-1UL / sizeof(int)); |
|||
ok1(!pi); |
|||
ok1(error_count == 1); |
|||
ok1(talloc_total_blocks(NULL) == 1); |
|||
|
|||
origpi = tal_arr(NULL, int, 100); |
|||
error_count = 0; |
|||
/* This will still overflow when tal_hdr is added. */ |
|||
pi = tal_dup_arr(NULL, int, take(origpi), (size_t)-1UL / sizeof(int) / 2, |
|||
(size_t)-1UL / sizeof(int) / 2); |
|||
ok1(!pi); |
|||
ok1(error_count == 1); |
|||
ok1(talloc_total_blocks(NULL) == 1); |
|||
|
|||
/* Overflow on expand addition. */ |
|||
cp = tal_arr(p, char, 100); |
|||
ok1(!tal_expand(&cp, NULL, (size_t)-99UL)); |
|||
ok1(error_count == 2); |
|||
tal_free(cp); |
|||
|
|||
/* Overflow when multiplied by size */ |
|||
origpi = tal_arr(NULL, int, 100); |
|||
ok1(!tal_expand(&origpi, NULL, (size_t)-1UL / sizeof(int))); |
|||
ok1(error_count == 3); |
|||
tal_free(origpi); |
|||
|
|||
talloc_disable_null_tracking(); |
|||
return exit_status(); |
|||
} |
@ -1,40 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
char *p[5]; |
|||
unsigned int i; |
|||
|
|||
plan_tests(9); |
|||
|
|||
p[0] = tal(NULL, char); |
|||
for (i = 1; i < 5; i++) |
|||
p[i] = tal(p[i-1], char); |
|||
|
|||
tal_check(NULL, "check"); |
|||
/* Steal node with no children. */ |
|||
ok1(tal_steal(p[0], p[4]) == p[4]); |
|||
tal_check(NULL, "check"); |
|||
/* Noop steal. */ |
|||
ok1(tal_steal(p[0], p[4]) == p[4]); |
|||
tal_check(NULL, "check"); |
|||
/* Steal with children. */ |
|||
ok1(tal_steal(p[0], p[1]) == p[1]); |
|||
tal_check(NULL, "check"); |
|||
/* Noop steal. */ |
|||
ok1(tal_steal(p[0], p[1]) == p[1]); |
|||
tal_check(NULL, "check"); |
|||
/* Steal from direct child. */ |
|||
ok1(tal_steal(p[0], p[2]) == p[2]); |
|||
tal_check(NULL, "check"); |
|||
|
|||
ok1(tal_parent(p[1]) == p[0]); |
|||
ok1(tal_parent(p[2]) == p[0]); |
|||
ok1(tal_parent(p[3]) == p[2]); |
|||
ok1(tal_parent(p[4]) == p[0]); |
|||
tal_free(p[0]); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,56 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
char *parent, *c; |
|||
|
|||
plan_tests(21); |
|||
|
|||
/* We can take NULL. */ |
|||
ok1(take(NULL) == NULL); |
|||
ok1(is_taken(NULL)); |
|||
ok1(taken(NULL)); /* Undoes take() */ |
|||
ok1(!is_taken(NULL)); |
|||
ok1(!taken(NULL)); |
|||
|
|||
parent = tal(NULL, char); |
|||
ok1(parent); |
|||
|
|||
ok1(take(parent) == parent); |
|||
ok1(is_taken(parent)); |
|||
ok1(taken(parent)); /* Undoes take() */ |
|||
ok1(!is_taken(parent)); |
|||
ok1(!taken(parent)); |
|||
|
|||
c = tal(parent, char); |
|||
*c = 'h'; |
|||
c = tal_dup(parent, char, take(c)); |
|||
ok1(c[0] == 'h'); |
|||
ok1(tal_parent(c) == parent); |
|||
|
|||
c = tal_dup_arr(parent, char, take(c), 1, 2); |
|||
ok1(c[0] == 'h'); |
|||
strcpy(c, "hi"); |
|||
ok1(tal_parent(c) == parent); |
|||
|
|||
/* dup must reparent child. */ |
|||
c = tal_dup(NULL, char, take(c)); |
|||
ok1(c[0] == 'h'); |
|||
ok1(tal_parent(c) == NULL); |
|||
|
|||
/* No leftover allocations. */ |
|||
tal_free(c); |
|||
ok1(talloc_total_blocks(parent) == 1); |
|||
|
|||
tal_free(parent); |
|||
ok1(!taken_any()); |
|||
|
|||
/* NULL pass-through. */ |
|||
c = NULL; |
|||
ok1(tal_dup_arr(NULL, char, take(c), 5, 5) == NULL); |
|||
ok1(!taken_any()); |
|||
|
|||
return exit_status(); |
|||
} |
@ -1,44 +0,0 @@ |
|||
#include <ccan/tal/talloc/talloc.h> |
|||
#include <ccan/tal/talloc/talloc.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
char *parent, *c[4]; |
|||
int i, j; |
|||
|
|||
plan_tests(9); |
|||
|
|||
/* tal_free(NULL) works. */ |
|||
ok1(tal_free(NULL) == NULL); |
|||
|
|||
parent = tal(NULL, char); |
|||
ok1(parent); |
|||
ok1(tal_parent(parent) == NULL); |
|||
ok1(tal_parent(NULL) == NULL); |
|||
|
|||
for (i = 0; i < 4; i++) |
|||
c[i] = tal(parent, char); |
|||
|
|||
for (i = 0; i < 4; i++) |
|||
ok1(tal_parent(c[i]) == parent); |
|||
|
|||
/* Free parent. */ |
|||
ok1(tal_free(parent) == NULL); |
|||
|
|||
parent = tal(NULL, char); |
|||
|
|||
/* Test freeing in every order */ |
|||
for (i = 0; i < 4; i++) { |
|||
for (j = 0; j < 4; j++) |
|||
c[j] = tal(parent, char); |
|||
|
|||
tal_free(c[i]); |
|||
tal_free(c[(i+1) % 4]); |
|||
tal_free(c[(i+2) % 4]); |
|||
tal_free(c[(i+3) % 4]); |
|||
} |
|||
tal_free(parent); |
|||
|
|||
return exit_status(); |
|||
} |
Loading…
Reference in new issue