diff mbox series

[3/3] ccan: sync to upstream ccan.git commit ca7c5a9e04f3

Message ID 20211208141558.513912-4-npiggin@gmail.com
State Accepted
Headers show
Series grab upstream ccan | expand

Checks

Context Check Description
snowpatch_ozlabs/github-Docker_builds_and_checks success Successfully ran 9 jobs.

Commit Message

Nicholas Piggin Dec. 8, 2021, 2:15 p.m. UTC
sync to upstream ccan.git commit ca7c5a9e04f3 ("ccan: make tal_dump()
format more regular.").

The recipe used to sync upstream is:

 $ cd ccan
 $ ./tools/create-ccan-tree -b make tmp \
     array_size check_type container_of heap \
     short_types build_assert endian list str
 $ # replace directories in skiboot/ccan/ with those in tmp/ccan/
 $ cd ../skiboot
 $ patch -p1 < ccan/skiboot.patch

This also adds a README.skiboot to help with future updates.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 ccan/README.skiboot                           |  26 +
 ccan/array_size/_info                         |   4 +-
 .../test/compile_fail-function-param.c        |   6 +-
 ccan/array_size/test/compile_fail.c           |   2 +
 ccan/array_size/test/run.c                    |   5 +-
 ccan/build_assert/_info                       |   2 +-
 ccan/build_assert/test/compile_fail-expr.c    |   2 +-
 ccan/build_assert/test/compile_fail.c         |   2 +-
 ccan/build_assert/test/compile_ok.c           |   2 +-
 .../test/run-BUILD_ASSERT_OR_ZERO.c           |   5 +-
 ccan/check_type/_info                         |   2 +-
 ccan/check_type/check_type.h                  |   2 +-
 .../check_type/test/compile_fail-check_type.c |   2 +
 .../test/compile_fail-check_type_unsigned.c   |   2 +
 .../test/compile_fail-check_types_match.c     |   1 +
 ccan/check_type/test/run.c                    |   4 +-
 ccan/config.h                                 |  27 +-
 ccan/container_of/_info                       |  14 +-
 ccan/container_of/container_of.h              |  38 +-
 .../container_of/test/compile_fail-bad-type.c |   2 +-
 ccan/container_of/test/compile_fail-types.c   |   2 +-
 .../test/compile_fail-var-types.c             |   2 +-
 ccan/container_of/test/run.c                  |  13 +-
 ccan/endian/.depends                          |   0
 ccan/endian/endian.h                          |   8 +
 ccan/endian/test/run.c                        |   5 +-
 ccan/heap/test/run.c                          |   4 +-
 ccan/list/_info                               |   6 +-
 ccan/list/list.h                              | 455 ++++++++++++++----
 ccan/list/test/run-CCAN_LIST_DEBUG.c          |  60 +++
 ccan/list/test/run-check-corrupt.c            |   9 +-
 ccan/list/test/run-check-nonconst.c           |  27 ++
 ccan/list/test/run-list_del_from-assert.c     |   6 +-
 ccan/list/test/run-list_prev-list_next.c      |  65 +++
 ccan/list/test/run-prepend_list.c             | 111 +++++
 ccan/list/test/run-single-eval.c              |   5 +-
 ccan/list/test/run.c                          | 116 ++++-
 ccan/short_types/test/run-endian.c            |   2 +-
 ccan/short_types/test/run.c                   |   2 +-
 ccan/str/_info                                |   8 +-
 ccan/str/debug.c                              | 108 +++++
 ccan/str/str.h                                |  16 +-
 ccan/str/str_debug.h                          |  30 ++
 ccan/str/test/compile_fail-STR_MAX_CHARS.c    |   2 +-
 ccan/str/test/compile_fail-isalnum.c          |   1 +
 ccan/str/test/compile_fail-isalpha.c          |   1 +
 ccan/str/test/compile_fail-isascii.c          |   1 +
 ccan/str/test/compile_fail-isblank.c          |   1 +
 ccan/str/test/compile_fail-iscntrl.c          |   1 +
 ccan/str/test/compile_fail-isdigit.c          |   1 +
 ccan/str/test/compile_fail-islower.c          |   1 +
 ccan/str/test/compile_fail-isprint.c          |   1 +
 ccan/str/test/compile_fail-ispunct.c          |   1 +
 ccan/str/test/compile_fail-isspace.c          |   1 +
 ccan/str/test/compile_fail-isupper.c          |   1 +
 ccan/str/test/compile_fail-isxdigit.c         |   1 +
 ccan/str/test/compile_fail-strchr.c           |   2 +-
 ccan/str/test/compile_fail-strrchr.c          |   2 +-
 ccan/str/test/compile_fail-strstr.c           |   2 +-
 .../test/compile_ok-STR_MAX_CHARS-static.c    |   8 +
 ccan/str/test/run-STR_MAX_CHARS.c             |  11 +-
 ccan/str/test/run.c                           |   5 +-
 62 files changed, 1055 insertions(+), 199 deletions(-)
 create mode 100644 ccan/README.skiboot
 delete mode 100644 ccan/endian/.depends
 create mode 100644 ccan/list/test/run-CCAN_LIST_DEBUG.c
 create mode 100644 ccan/list/test/run-check-nonconst.c
 create mode 100644 ccan/list/test/run-list_prev-list_next.c
 create mode 100644 ccan/list/test/run-prepend_list.c
 create mode 100644 ccan/str/debug.c
 create mode 100644 ccan/str/str_debug.h
 create mode 100644 ccan/str/test/compile_ok-STR_MAX_CHARS-static.c
diff mbox series

Patch

diff --git a/ccan/README.skiboot b/ccan/README.skiboot
new file mode 100644
index 000000000..3707ed2a7
--- /dev/null
+++ b/ccan/README.skiboot
@@ -0,0 +1,26 @@ 
+skiboot/ccan/ is a minimally modified version of upstream ccan that is
+hosted at github.com/rustyrussell/ccan.git
+
+This version is taken from ccan.git commit ca7c5a9e04f3 ("ccan: make tal_dump()
+format more regular.") with these modules:
+
+  array_size
+  check_type
+  container_of
+  heap
+  short_types
+  build_assert
+  endian
+  list
+  str
+
+Generated with `./tools/create-ccan-tree -b make ...` and replacing the
+corresponding directories in skiboot/ccan/, then skiboot/ccan/skiboot.patch
+is applied.
+
+The only other differences from upstream are the additions under the ccan/
+directory of this file README.skiboot, Makefile.inc, Makefile.check, config.h,
+tap/tap.h, skiboot.patch.
+
+Local ccan changes should be kept to a minimum, documented here as necessary,
+and submitted upstream if possible.
diff --git a/ccan/array_size/_info b/ccan/array_size/_info
index d670042de..69570f34c 100644
--- a/ccan/array_size/_info
+++ b/ccan/array_size/_info
@@ -1,6 +1,6 @@ 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
-#include "config.h"
 
 /**
  * array_size - routine for safely deriving the size of a visible array.
@@ -12,7 +12,7 @@ 
  * macro or constant.
  *
  * Example:
- *	// Outputs "Initialized 32 values"
+ *	// Outputs "Initialized 32 values\n"
  *	#include <ccan/array_size/array_size.h>
  *	#include <stdlib.h>
  *	#include <stdio.h>
diff --git a/ccan/array_size/test/compile_fail-function-param.c b/ccan/array_size/test/compile_fail-function-param.c
index cb64d9842..164c826f5 100644
--- a/ccan/array_size/test/compile_fail-function-param.c
+++ b/ccan/array_size/test/compile_fail-function-param.c
@@ -5,8 +5,8 @@  struct foo {
 	unsigned int a, b;
 };
 
-int check_parameter(const struct foo array[4]);
-int check_parameter(const struct foo array[4])
+int check_parameter(const struct foo *array);
+int check_parameter(const struct foo *array)
 {
 #ifdef FAIL
 	return (ARRAY_SIZE(array) == 4);
@@ -18,7 +18,7 @@  int check_parameter(const struct foo array[4])
 #endif
 }
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	return check_parameter(NULL);
 }
diff --git a/ccan/array_size/test/compile_fail.c b/ccan/array_size/test/compile_fail.c
index 37d315f21..9bd656826 100644
--- a/ccan/array_size/test/compile_fail.c
+++ b/ccan/array_size/test/compile_fail.c
@@ -2,6 +2,8 @@ 
 
 int main(int argc, char *argv[8])
 {
+	(void)argc;
+	(void)argv;
 	char array[100];
 #ifdef FAIL
 	return ARRAY_SIZE(argv) + ARRAY_SIZE(array);
diff --git a/ccan/array_size/test/run.c b/ccan/array_size/test/run.c
index a17f04588..3c4ae1893 100644
--- a/ccan/array_size/test/run.c
+++ b/ccan/array_size/test/run.c
@@ -16,11 +16,8 @@  static int array2_size = ARRAY_SIZE(array2);
 static int array3_size = ARRAY_SIZE(array3);
 static int array4_size = ARRAY_SIZE(array4);
 
-int __attribute__((const)) main(int argc, char *argv[])
+int main(void)
 {
-	(void)argc;
-	(void)argv;
-
 	plan_tests(8);
 	ok1(array1_size == 1);
 	ok1(array2_size == 2);
diff --git a/ccan/build_assert/_info b/ccan/build_assert/_info
index bce92b7e1..97ebe6c96 100644
--- a/ccan/build_assert/_info
+++ b/ccan/build_assert/_info
@@ -1,6 +1,6 @@ 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
-#include "config.h"
 
 /**
  * build_assert - routines for build-time assertions
diff --git a/ccan/build_assert/test/compile_fail-expr.c b/ccan/build_assert/test/compile_fail-expr.c
index 109215b8a..6322eb352 100644
--- a/ccan/build_assert/test/compile_fail-expr.c
+++ b/ccan/build_assert/test/compile_fail-expr.c
@@ -1,6 +1,6 @@ 
 #include <ccan/build_assert/build_assert.h>
 
-int main(int argc, char *argv[])
+int main(void)
 {
 #ifdef FAIL
 	return BUILD_ASSERT_OR_ZERO(1 == 0);
diff --git a/ccan/build_assert/test/compile_fail.c b/ccan/build_assert/test/compile_fail.c
index 37d95eddc..9fd827d6a 100644
--- a/ccan/build_assert/test/compile_fail.c
+++ b/ccan/build_assert/test/compile_fail.c
@@ -1,6 +1,6 @@ 
 #include <ccan/build_assert/build_assert.h>
 
-int main(int argc, char *argv[])
+int main(void)
 {
 #ifdef FAIL
 	BUILD_ASSERT(1 == 0);
diff --git a/ccan/build_assert/test/compile_ok.c b/ccan/build_assert/test/compile_ok.c
index 4105484d1..b4de8b414 100644
--- a/ccan/build_assert/test/compile_ok.c
+++ b/ccan/build_assert/test/compile_ok.c
@@ -1,6 +1,6 @@ 
 #include <ccan/build_assert/build_assert.h>
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	BUILD_ASSERT(1 == 1);
 	return 0;
diff --git a/ccan/build_assert/test/run-BUILD_ASSERT_OR_ZERO.c b/ccan/build_assert/test/run-BUILD_ASSERT_OR_ZERO.c
index 77bf94c8a..72f9ad1ba 100644
--- a/ccan/build_assert/test/run-BUILD_ASSERT_OR_ZERO.c
+++ b/ccan/build_assert/test/run-BUILD_ASSERT_OR_ZERO.c
@@ -1,11 +1,8 @@ 
 #include <ccan/build_assert/build_assert.h>
 #include <ccan/tap/tap.h>
 
-int __attribute__((const)) main(int argc, char *argv[])
+int main(void)
 {
-	(void)argc;
-	(void)argv;
-
 	plan_tests(1);
 	ok1(BUILD_ASSERT_OR_ZERO(1 == 1) == 0);
 	return exit_status();
diff --git a/ccan/check_type/_info b/ccan/check_type/_info
index cb19e2028..cc4267349 100644
--- a/ccan/check_type/_info
+++ b/ccan/check_type/_info
@@ -1,6 +1,6 @@ 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
-#include "config.h"
 
 /**
  * check_type - routines for compile time type checking
diff --git a/ccan/check_type/check_type.h b/ccan/check_type/check_type.h
index 77501a955..837aef7b1 100644
--- a/ccan/check_type/check_type.h
+++ b/ccan/check_type/check_type.h
@@ -43,7 +43,7 @@ 
  *	#define container_of(mbr_ptr, encl_type, mbr)			\
  *		(check_types_match((mbr_ptr), &((encl_type *)0)->mbr),	\
  *		 ((encl_type *)						\
- *		  ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr))))
+ *		  ((char *)(mbr_ptr) - offsetof(encl_type, mbr))))
  */
 #if HAVE_TYPEOF
 #define check_type(expr, type)			\
diff --git a/ccan/check_type/test/compile_fail-check_type.c b/ccan/check_type/test/compile_fail-check_type.c
index fe7d6a235..4c22c65a4 100644
--- a/ccan/check_type/test/compile_fail-check_type.c
+++ b/ccan/check_type/test/compile_fail-check_type.c
@@ -2,6 +2,8 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
+	(void)argv;
 #ifdef FAIL
 	check_type(argc, char);
 #endif
diff --git a/ccan/check_type/test/compile_fail-check_type_unsigned.c b/ccan/check_type/test/compile_fail-check_type_unsigned.c
index 574d4aeb2..795e76067 100644
--- a/ccan/check_type/test/compile_fail-check_type_unsigned.c
+++ b/ccan/check_type/test/compile_fail-check_type_unsigned.c
@@ -2,6 +2,8 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
+	(void)argv;
 #ifdef FAIL
 #if HAVE_TYPEOF
 	check_type(argc, unsigned int);
diff --git a/ccan/check_type/test/compile_fail-check_types_match.c b/ccan/check_type/test/compile_fail-check_types_match.c
index cbd6e9bc5..fb83738b9 100644
--- a/ccan/check_type/test/compile_fail-check_types_match.c
+++ b/ccan/check_type/test/compile_fail-check_types_match.c
@@ -3,6 +3,7 @@ 
 int main(int argc, char *argv[])
 {
 	unsigned char x = argc;
+	(void)argv;
 #ifdef FAIL
 	check_types_match(argc, x);
 #endif
diff --git a/ccan/check_type/test/run.c b/ccan/check_type/test/run.c
index be0e24696..09fd36343 100644
--- a/ccan/check_type/test/run.c
+++ b/ccan/check_type/test/run.c
@@ -1,13 +1,11 @@ 
 #include <ccan/check_type/check_type.h>
 #include <ccan/tap/tap.h>
 
-int __attribute__((const)) main(int argc, char *argv[])
+int main(int argc, char *argv[])
 {
 	int x = 0, y = 0;
 
-	(void)argc;
 	(void)argv;
-
 	plan_tests(9);
 
 	ok1(check_type(argc, int) == 0);
diff --git a/ccan/config.h b/ccan/config.h
index 39c0b4b8a..ae08a2cc8 100644
--- a/ccan/config.h
+++ b/ccan/config.h
@@ -14,17 +14,26 @@ 
  * limitations under the License.
  */
 /* Dummy config.h for CCAN test suite */
+#ifndef CCAN_CONFIG_H
+#define CCAN_CONFIG_H
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* Always use GNU extensions. */
+#endif
 
-#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1
-#define HAVE_TYPEOF 1
+#include <endian.h>
 
-#ifndef HAVE_BIG_ENDIAN
-#define HAVE_BIG_ENDIAN 0
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HAVE_BIG_ENDIAN         0
+#define HAVE_LITTLE_ENDIAN      1
+#else
+#define HAVE_BIG_ENDIAN         1
+#define HAVE_LITTLE_ENDIAN      0
 #endif
 
-#ifndef HAVE_LITTLE_ENDIAN
-#define HAVE_LITTLE_ENDIAN 0
-#endif
+#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1
+#define HAVE_TYPEOF 1
+
+#define HAVE_BYTESWAP_H 1
+#define HAVE_BSWAP_64 1
 
-#define HAVE_BYTESWAP_H 0
-#define HAVE_BSWAP_64 0
+#endif /* CCAN_CONFIG_H */
diff --git a/ccan/container_of/_info b/ccan/container_of/_info
index 77b3bd15f..b1160522e 100644
--- a/ccan/container_of/_info
+++ b/ccan/container_of/_info
@@ -1,6 +1,6 @@ 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
-#include "config.h"
 
 /**
  * container_of - routine for upcasting
@@ -26,17 +26,19 @@ 
  *		struct timer timer;
  *	};
  *
- *	static void register_timer(struct timer *timer)
- *	{
- *		//...
- *	}
- *
  *	static void my_timer_callback(struct timer *timer)
  *	{
  *		struct info *info = container_of(timer, struct info, timer);
  *		printf("my_stuff is %u\n", info->my_stuff);
  *	}
  *
+ *	static void register_timer(struct timer *timer)
+ *	{
+ *		(void)timer;
+ *		(void)my_timer_callback;
+ *		//...
+ *	}
+ *
  *	int main(void)
  *	{
  *		struct info info = { .my_stuff = 1 };
diff --git a/ccan/container_of/container_of.h b/ccan/container_of/container_of.h
index 2943b8f09..47a34d853 100644
--- a/ccan/container_of/container_of.h
+++ b/ccan/container_of/container_of.h
@@ -36,6 +36,42 @@ 
 	   - container_off(containing_type, member))			\
 	  + check_types_match(*(member_ptr), ((containing_type *)0)->member))
 
+
+/**
+ * container_of_or_null - get pointer to enclosing structure, or NULL
+ * @member_ptr: pointer to the structure member
+ * @containing_type: the type this member is within
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does pointer
+ * subtraction to return the pointer to the enclosing type, unless it
+ * is given NULL, in which case it also returns NULL.
+ *
+ * Example:
+ *	struct foo {
+ *		int fielda, fieldb;
+ *		// ...
+ *	};
+ *	struct info {
+ *		int some_other_field;
+ *		struct foo my_foo;
+ *	};
+ *
+ *	static struct info *foo_to_info_allowing_null(struct foo *foo)
+ *	{
+ *		return container_of_or_null(foo, struct info, my_foo);
+ *	}
+ */
+static inline char *container_of_or_null_(void *member_ptr, size_t offset)
+{
+	return member_ptr ? (char *)member_ptr - offset : NULL;
+}
+#define container_of_or_null(member_ptr, containing_type, member)	\
+	((containing_type *)						\
+	 container_of_or_null_(member_ptr,				\
+			       container_off(containing_type, member))	\
+	 + check_types_match(*(member_ptr), ((containing_type *)0)->member))
+
 /**
  * container_off - get offset to enclosing structure
  * @containing_type: the type this member is within
@@ -103,7 +139,7 @@ 
 	container_off(typeof(*var), member)
 #else
 #define container_off_var(var, member)			\
-	((char *)&(var)->member - (char *)(var))
+	((const char *)&(var)->member - (const char *)(var))
 #endif
 
 #endif /* CCAN_CONTAINER_OF_H */
diff --git a/ccan/container_of/test/compile_fail-bad-type.c b/ccan/container_of/test/compile_fail-bad-type.c
index b7a145938..55a911a1b 100644
--- a/ccan/container_of/test/compile_fail-bad-type.c
+++ b/ccan/container_of/test/compile_fail-bad-type.c
@@ -6,7 +6,7 @@  struct foo {
 	char b;
 };
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	struct foo foo = { .a = 1, .b = 2 };
 	int *intp = &foo.a;
diff --git a/ccan/container_of/test/compile_fail-types.c b/ccan/container_of/test/compile_fail-types.c
index cae1c7abd..fbb97a9ee 100644
--- a/ccan/container_of/test/compile_fail-types.c
+++ b/ccan/container_of/test/compile_fail-types.c
@@ -6,7 +6,7 @@  struct foo {
 	char b;
 };
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	struct foo foo = { .a = 1, .b = 2 }, *foop;
 	int *intp = &foo.a;
diff --git a/ccan/container_of/test/compile_fail-var-types.c b/ccan/container_of/test/compile_fail-var-types.c
index f254d9210..ecdd90916 100644
--- a/ccan/container_of/test/compile_fail-var-types.c
+++ b/ccan/container_of/test/compile_fail-var-types.c
@@ -6,7 +6,7 @@  struct foo {
 	char b;
 };
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	struct foo foo = { .a = 1, .b = 2 }, *foop;
 	int *intp = &foo.a;
diff --git a/ccan/container_of/test/run.c b/ccan/container_of/test/run.c
index 2bd6947f0..32557295d 100644
--- a/ccan/container_of/test/run.c
+++ b/ccan/container_of/test/run.c
@@ -6,22 +6,25 @@  struct foo {
 	char b;
 };
 
-int __attribute__((const)) main(int argc, char *argv[])
+int main(void)
 {
 	struct foo foo = { .a = 1, .b = 2 };
 	int *intp = &foo.a;
 	char *charp = &foo.b;
 
-	(void)argc;
-	(void)argv;
-
-	plan_tests(6);
+	plan_tests(12);
 	ok1(container_of(intp, struct foo, a) == &foo);
 	ok1(container_of(charp, struct foo, b) == &foo);
+	ok1(container_of_or_null(intp, struct foo, a) == &foo);
+	ok1(container_of_or_null(charp, struct foo, b) == &foo);
+	ok1(container_of_or_null((int *)NULL, struct foo, a) == NULL);
+	ok1(container_of_or_null((char *)NULL, struct foo, b) == NULL);
 	ok1(container_of_var(intp, &foo, a) == &foo);
 	ok1(container_of_var(charp, &foo, b) == &foo);
 
 	ok1(container_off(struct foo, a) == 0);
 	ok1(container_off(struct foo, b) == offsetof(struct foo, b));
+	ok1(container_off_var(&foo, a) == 0);
+	ok1(container_off_var(&foo, b) == offsetof(struct foo, b));
 	return exit_status();
 }
diff --git a/ccan/endian/.depends b/ccan/endian/.depends
deleted file mode 100644
index e69de29bb..000000000
diff --git a/ccan/endian/endian.h b/ccan/endian/endian.h
index 6732e8aa8..3753f4900 100644
--- a/ccan/endian/endian.h
+++ b/ccan/endian/endian.h
@@ -113,9 +113,17 @@  static inline uint64_t bswap_64(uint64_t val)
 #elif HAVE_LITTLE_ENDIAN && HAVE_BIG_ENDIAN
 #error "Can't compile for both big and little endian."
 #elif HAVE_LITTLE_ENDIAN
+#ifndef __BYTE_ORDER
 #define __BYTE_ORDER	__LITTLE_ENDIAN
+#elif __BYTE_ORDER != __LITTLE_ENDIAN
+#error "__BYTE_ORDER already defined, but not equal to __LITTLE_ENDIAN"
+#endif
 #elif HAVE_BIG_ENDIAN
+#ifndef __BYTE_ORDER
 #define __BYTE_ORDER	__BIG_ENDIAN
+#elif __BYTE_ORDER != __BIG_ENDIAN
+#error "__BYTE_ORDER already defined, but not equal to __BIG_ENDIAN"
+#endif
 #endif
 
 
diff --git a/ccan/endian/test/run.c b/ccan/endian/test/run.c
index e5b054b8d..9bf47f13a 100644
--- a/ccan/endian/test/run.c
+++ b/ccan/endian/test/run.c
@@ -3,7 +3,7 @@ 
 #include <stddef.h>
 #include <ccan/tap/tap.h>
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	union {
 		uint64_t u64;
@@ -18,9 +18,6 @@  int main(int argc, char *argv[])
 		unsigned char u16_bytes[2];
 	} u16;
 
-	(void)argc;
-	(void)argv;
-
 	plan_tests(48);
 
 	/* Straight swap tests. */
diff --git a/ccan/heap/test/run.c b/ccan/heap/test/run.c
index 2c6328398..6972a6bea 100644
--- a/ccan/heap/test/run.c
+++ b/ccan/heap/test/run.c
@@ -82,7 +82,7 @@  static bool some_test(size_t n, bool is_less)
 		item = &items[i];
 
 		item->v = rand();
-		/* printf("pushing %d\n", item->v); */
+		printf("pushing %d\n", item->v);
 		heap_push(h, item);
 		if (!heap_ok(h, is_less ? __less : __more, 0))
 			return false;
@@ -104,7 +104,7 @@  static bool some_test(size_t n, bool is_less)
 		item = heap_pop(h);
 		if (!heap_ok(h, is_less ? __less : __more, 0))
 			return false;
-		/* printf("popped %d\n", item->v); */
+		printf("popped %d\n", item->v);
 		if (i > 0) {
 			if (is_less) {
 				if (less(item, prev))
diff --git a/ccan/list/_info b/ccan/list/_info
index 41a81fb57..c4f3e2a0a 100644
--- a/ccan/list/_info
+++ b/ccan/list/_info
@@ -1,6 +1,6 @@ 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
-#include "config.h"
 
 /**
  * list - double linked list routines
@@ -31,7 +31,7 @@ 
  *	{
  *		struct parent p;
  *		struct child *c;
- *		unsigned int i;
+ *		int i;
  *
  *		if (argc < 2)
  *			errx(1, "Usage: %s parent children...", argv[0]);
@@ -62,7 +62,9 @@  int main(int argc, char *argv[])
 		return 1;
 
 	if (strcmp(argv[1], "depends") == 0) {
+		printf("ccan/str\n");
 		printf("ccan/container_of\n");
+		printf("ccan/check_type\n");
 		return 0;
 	}
 
diff --git a/ccan/list/list.h b/ccan/list/list.h
index 6dbaabfe0..a15321c59 100644
--- a/ccan/list/list.h
+++ b/ccan/list/list.h
@@ -1,8 +1,10 @@ 
 /* Licensed under BSD-MIT - see LICENSE file for details */
 #ifndef CCAN_LIST_H
 #define CCAN_LIST_H
+//#define CCAN_LIST_DEBUG 1
 #include <stdbool.h>
 #include <assert.h>
+#include <ccan/str/str.h>
 #include <ccan/container_of/container_of.h>
 #include <ccan/check_type/check_type.h>
 
@@ -88,12 +90,13 @@  struct list_head *list_check(const struct list_head *h, const char *abortstr);
 struct list_node *list_check_node(const struct list_node *n,
 				  const char *abortstr);
 
+#define LIST_LOC __FILE__  ":" stringify(__LINE__)
 #ifdef CCAN_LIST_DEBUG
-#define list_debug(h) list_check((h), __func__)
-#define list_debug_node(n) list_check_node((n), __func__)
+#define list_debug(h, loc) list_check((h), loc)
+#define list_debug_node(n, loc) list_check_node((n), loc)
 #else
-#define list_debug(h) (h)
-#define list_debug_node(n) (n)
+#define list_debug(h, loc) ((void)loc, h)
+#define list_debug_node(n, loc) ((void)loc, n)
 #endif
 
 /**
@@ -108,7 +111,7 @@  struct list_node *list_check_node(const struct list_node *n,
  * Example:
  *	static struct list_head my_list = LIST_HEAD_INIT(my_list);
  */
-#define LIST_HEAD_INIT(name) { { &name.n, &name.n } }
+#define LIST_HEAD_INIT(name) { { &(name).n, &(name).n } }
 
 /**
  * LIST_HEAD - define and initialize an empty list_head
@@ -142,6 +145,48 @@  static inline void list_head_init(struct list_head *h)
 	h->n.next = h->n.prev = &h->n;
 }
 
+/**
+ * list_node_init - initialize a list_node
+ * @n: the list_node to link to itself.
+ *
+ * You don't need to use this normally!  But it lets you list_del(@n)
+ * safely.
+ */
+static inline void list_node_init(struct list_node *n)
+{
+	n->next = n->prev = n;
+}
+
+/**
+ * list_add_after - add an entry after an existing node in a linked list
+ * @h: the list_head to add the node to (for debugging)
+ * @p: the existing list_node to add the node after
+ * @n: the new list_node to add to the list.
+ *
+ * The existing list_node must already be a member of the list.
+ * The new list_node does not need to be initialized; it will be overwritten.
+ *
+ * Example:
+ *	struct child c1, c2, c3;
+ *	LIST_HEAD(h);
+ *
+ *	list_add_tail(&h, &c1.list);
+ *	list_add_tail(&h, &c3.list);
+ *	list_add_after(&h, &c1.list, &c2.list);
+ */
+#define list_add_after(h, p, n) list_add_after_(h, p, n, LIST_LOC)
+static inline void list_add_after_(struct list_head *h,
+				   struct list_node *p,
+				   struct list_node *n,
+				   const char *abortstr)
+{
+	n->next = p->next;
+	n->prev = p;
+	p->next->prev = n;
+	p->next = n;
+	(void)list_debug(h, abortstr);
+}
+
 /**
  * list_add - add an entry at the start of a linked list.
  * @h: the list_head to add the node to
@@ -155,51 +200,40 @@  static inline void list_head_init(struct list_head *h)
  *	list_add(&parent->children, &child->list);
  *	parent->num_children++;
  */
-static inline void list_add(struct list_head *h, struct list_node *n)
+#define list_add(h, n) list_add_(h, n, LIST_LOC)
+static inline void list_add_(struct list_head *h,
+			     struct list_node *n,
+			     const char *abortstr)
 {
-	n->next = h->n.next;
-	n->prev = &h->n;
-	h->n.next->prev = n;
-	h->n.next = n;
-	(void)list_debug(h);
+	list_add_after_(h, &h->n, n, abortstr);
 }
 
 /**
- * list_add_before - add an entry before another entry.
- * @h: the list_head to add the node to (we use it for debug purposes, can be NULL)
- * @p: the list_node of the other entry
- * @n: the list_node to add to the list.
+ * list_add_before - add an entry before an existing node in a linked list
+ * @h: the list_head to add the node to (for debugging)
+ * @p: the existing list_node to add the node before
+ * @n: the new list_node to add to the list.
  *
- * The list_node does not need to be initialized; it will be overwritten.
+ * The existing list_node must already be a member of the list.
+ * The new list_node does not need to be initialized; it will be overwritten.
+ *
+ * Example:
+ *	list_head_init(&h);
+ *	list_add_tail(&h, &c1.list);
+ *	list_add_tail(&h, &c3.list);
+ *	list_add_before(&h, &c3.list, &c2.list);
  */
-static inline void list_add_before(struct list_head *h, struct list_node *p,
-				   struct list_node *n)
+#define list_add_before(h, p, n) list_add_before_(h, p, n, LIST_LOC)
+static inline void list_add_before_(struct list_head *h,
+				    struct list_node *p,
+				    struct list_node *n,
+				    const char *abortstr)
 {
 	n->next = p;
 	n->prev = p->prev;
+	p->prev->next = n;
 	p->prev = n;
-	n->prev->next = n;
-	if (h)
-		(void)list_debug(h);
-}
-
-/**
- * list_add_after - add an entry after another entry.
- * @h: the list_head to add the node to (we use it for debug purposes, can be NULL)
- * @p: the list_node of the other entry
- * @n: the list_node to add to the list.
- *
- * The list_node does not need to be initialized; it will be overwritten.
- */
-static inline void list_add_after(struct list_head *h, struct list_node *p,
-				  struct list_node *n)
-{
-	n->next = p->next;
-	n->prev = p;
-	p->next = n;
-	n->next->prev = n;
-	if (h)
-		(void)list_debug(h);
+	(void)list_debug(h, abortstr);
 }
 
 /**
@@ -212,13 +246,12 @@  static inline void list_add_after(struct list_head *h, struct list_node *p,
  *	list_add_tail(&parent->children, &child->list);
  *	parent->num_children++;
  */
-static inline void list_add_tail(struct list_head *h, struct list_node *n)
+#define list_add_tail(h, n) list_add_tail_(h, n, LIST_LOC)
+static inline void list_add_tail_(struct list_head *h,
+				  struct list_node *n,
+				  const char *abortstr)
 {
-	n->next = &h->n;
-	n->prev = h->n.prev;
-	h->n.prev->next = n;
-	h->n.prev = n;
-	(void)list_debug(h);
+	list_add_before_(h, &h->n, n, abortstr);
 }
 
 /**
@@ -230,11 +263,33 @@  static inline void list_add_tail(struct list_head *h, struct list_node *n)
  * Example:
  *	assert(list_empty(&parent->children) == (parent->num_children == 0));
  */
-static inline bool list_empty(const struct list_head *h)
+#define list_empty(h) list_empty_(h, LIST_LOC)
+static inline bool list_empty_(const struct list_head *h, const char* abortstr)
+{
+	(void)list_debug(h, abortstr);
+	return h->n.next == &h->n;
+}
+
+/**
+ * list_empty_nodebug - is a list empty (and don't perform debug checks)?
+ * @h: the list_head
+ *
+ * If the list is empty, returns true.
+ * This differs from list_empty() in that if CCAN_LIST_DEBUG is set it
+ * will NOT perform debug checks. Only use this function if you REALLY
+ * know what you're doing.
+ *
+ * Example:
+ *	assert(list_empty_nodebug(&parent->children) == (parent->num_children == 0));
+ */
+#ifndef CCAN_LIST_DEBUG
+#define list_empty_nodebug(h) list_empty(h)
+#else
+static inline bool list_empty_nodebug(const struct list_head *h)
 {
-	(void)list_debug(h);
 	return h->n.next == &h->n;
 }
+#endif
 
 /**
  * list_empty_nocheck - is a list empty?
@@ -259,15 +314,16 @@  static inline bool list_empty_nocheck(const struct list_head *h)
  * another list, but not deleted again.
  *
  * See also:
- *	list_del_from()
+ *	list_del_from(), list_del_init()
  *
  * Example:
  *	list_del(&child->list);
  *	parent->num_children--;
  */
-static inline void list_del(struct list_node *n)
+#define list_del(n) list_del_(n, LIST_LOC)
+static inline void list_del_(struct list_node *n, const char* abortstr)
 {
-	(void)list_debug_node(n);
+	(void)list_debug_node(n, abortstr);
 	n->next->prev = n->prev;
 	n->prev->next = n->next;
 #ifdef CCAN_LIST_DEBUG
@@ -276,6 +332,27 @@  static inline void list_del(struct list_node *n)
 #endif
 }
 
+/**
+ * list_del_init - delete a node, and reset it so it can be deleted again.
+ * @n: the list_node to be deleted.
+ *
+ * list_del(@n) or list_del_init() again after this will be safe,
+ * which can be useful in some cases.
+ *
+ * See also:
+ *	list_del_from(), list_del()
+ *
+ * Example:
+ *	list_del_init(&child->list);
+ *	parent->num_children--;
+ */
+#define list_del_init(n) list_del_init_(n, LIST_LOC)
+static inline void list_del_init_(struct list_node *n, const char *abortstr)
+{
+	list_del_(n, abortstr);
+	list_node_init(n);
+}
+
 /**
  * list_del_from - delete an entry from a known linked list.
  * @h: the list_head the node is in.
@@ -306,6 +383,39 @@  static inline void list_del_from(struct list_head *h, struct list_node *n)
 	list_del(n);
 }
 
+/**
+ * list_swap - swap out an entry from an (unknown) linked list for a new one.
+ * @o: the list_node to replace from the list.
+ * @n: the list_node to insert in place of the old one.
+ *
+ * Note that this leaves @o in an undefined state; it can be added to
+ * another list, but not deleted/swapped again.
+ *
+ * See also:
+ *	list_del()
+ *
+ * Example:
+ *	struct child x1, x2;
+ *	LIST_HEAD(xh);
+ *
+ *	list_add(&xh, &x1.list);
+ *	list_swap(&x1.list, &x2.list);
+ */
+#define list_swap(o, n) list_swap_(o, n, LIST_LOC)
+static inline void list_swap_(struct list_node *o,
+			      struct list_node *n,
+			      const char* abortstr)
+{
+	(void)list_debug_node(o, abortstr);
+	*n = *o;
+	n->next->prev = n;
+	n->prev->next = n;
+#ifdef CCAN_LIST_DEBUG
+	/* Catch use-after-del. */
+	o->next = o->prev = NULL;
+#endif
+}
+
 /**
  * list_entry - convert a list_node back into the structure containing it.
  * @n: the list_node
@@ -346,14 +456,23 @@  static inline const void *list_top_(const struct list_head *h, size_t off)
 }
 
 /**
- * list_pop - get the first entry in a list and dequeue it
+ * list_pop - remove the first entry in a list
  * @h: the list_head
  * @type: the type of the entry
  * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ *	struct child *one;
+ *	one = list_pop(&parent->children, struct child, list);
+ *	if (!one)
+ *		printf("Empty list!\n");
  */
 #define list_pop(h, type, member)					\
 	((type *)list_pop_((h), list_off_(type, member)))
-static inline const void *list_pop_(struct list_head *h, size_t off)
+
+static inline const void *list_pop_(const struct list_head *h, size_t off)
 {
 	struct list_node *n;
 
@@ -418,9 +537,29 @@  static inline const void *list_tail_(const struct list_head *h, size_t off)
  *		printf("Name: %s\n", child->name);
  */
 #define list_for_each_rev(h, i, member)					\
-	for (i = container_of_var(list_debug(h)->n.prev, i, member);	\
-	     &i->member != &(h)->n;					\
-	     i = container_of_var(i->member.prev, i, member))
+	list_for_each_rev_off(h, i, list_off_var_(i, member))
+
+/**
+ * list_for_each_rev_safe - iterate through a list backwards,
+ * maybe during deletion
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @nxt: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list backwards.
+ * It's a for loop, so you can break and continue as normal.  The extra
+ * variable * @nxt is used to hold the next element, so you can delete @i
+ * from the list.
+ *
+ * Example:
+ *	struct child *next;
+ *	list_for_each_rev_safe(&parent->children, child, next, list) {
+ *		printf("Name: %s\n", child->name);
+ *	}
+ */
+#define list_for_each_rev_safe(h, i, nxt, member)			\
+	list_for_each_rev_safe_off(h, i, nxt, list_off_var_(i, member))
 
 /**
  * list_for_each_safe - iterate through a list, maybe during deletion
@@ -434,7 +573,6 @@  static inline const void *list_tail_(const struct list_head *h, size_t off)
  * @nxt is used to hold the next element, so you can delete @i from the list.
  *
  * Example:
- *	struct child *next;
  *	list_for_each_safe(&parent->children, child, next, list) {
  *		list_del(&child->list);
  *		parent->num_children--;
@@ -443,6 +581,130 @@  static inline const void *list_tail_(const struct list_head *h, size_t off)
 #define list_for_each_safe(h, i, nxt, member)				\
 	list_for_each_safe_off(h, i, nxt, list_off_var_(i, member))
 
+/**
+ * list_next - get the next entry in a list
+ * @h: the list_head
+ * @i: a pointer to an entry in the list.
+ * @member: the list_node member of the structure
+ *
+ * If @i was the last entry in the list, returns NULL.
+ *
+ * Example:
+ *	struct child *second;
+ *	second = list_next(&parent->children, first, list);
+ *	if (!second)
+ *		printf("No second child!\n");
+ */
+#define list_next(h, i, member)						\
+	((list_typeof(i))list_entry_or_null(list_debug(h,		\
+					    __FILE__ ":" stringify(__LINE__)), \
+					    (i)->member.next,		\
+					    list_off_var_((i), member)))
+
+/**
+ * list_prev - get the previous entry in a list
+ * @h: the list_head
+ * @i: a pointer to an entry in the list.
+ * @member: the list_node member of the structure
+ *
+ * If @i was the first entry in the list, returns NULL.
+ *
+ * Example:
+ *	first = list_prev(&parent->children, second, list);
+ *	if (!first)
+ *		printf("Can't go back to first child?!\n");
+ */
+#define list_prev(h, i, member)						\
+	((list_typeof(i))list_entry_or_null(list_debug(h,		\
+					    __FILE__ ":" stringify(__LINE__)), \
+					    (i)->member.prev,		\
+					    list_off_var_((i), member)))
+
+/**
+ * list_append_list - empty one list onto the end of another.
+ * @to: the list to append into
+ * @from: the list to empty.
+ *
+ * This takes the entire contents of @from and moves it to the end of
+ * @to.  After this @from will be empty.
+ *
+ * Example:
+ *	struct list_head adopter;
+ *
+ *	list_append_list(&adopter, &parent->children);
+ *	assert(list_empty(&parent->children));
+ *	parent->num_children = 0;
+ */
+#define list_append_list(t, f) list_append_list_(t, f,			\
+				   __FILE__ ":" stringify(__LINE__))
+static inline void list_append_list_(struct list_head *to,
+				     struct list_head *from,
+				     const char *abortstr)
+{
+	struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
+	struct list_node *to_tail = list_debug(to, abortstr)->n.prev;
+
+	/* Sew in head and entire list. */
+	to->n.prev = from_tail;
+	from_tail->next = &to->n;
+	to_tail->next = &from->n;
+	from->n.prev = to_tail;
+
+	/* Now remove head. */
+	list_del(&from->n);
+	list_head_init(from);
+}
+
+/**
+ * list_prepend_list - empty one list into the start of another.
+ * @to: the list to prepend into
+ * @from: the list to empty.
+ *
+ * This takes the entire contents of @from and moves it to the start
+ * of @to.  After this @from will be empty.
+ *
+ * Example:
+ *	list_prepend_list(&adopter, &parent->children);
+ *	assert(list_empty(&parent->children));
+ *	parent->num_children = 0;
+ */
+#define list_prepend_list(t, f) list_prepend_list_(t, f, LIST_LOC)
+static inline void list_prepend_list_(struct list_head *to,
+				      struct list_head *from,
+				      const char *abortstr)
+{
+	struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
+	struct list_node *to_head = list_debug(to, abortstr)->n.next;
+
+	/* Sew in head and entire list. */
+	to->n.next = &from->n;
+	from->n.prev = &to->n;
+	to_head->prev = from_tail;
+	from_tail->next = to_head;
+
+	/* Now remove head. */
+	list_del(&from->n);
+	list_head_init(from);
+}
+
+/* internal macros, do not use directly */
+#define list_for_each_off_dir_(h, i, off, dir)				\
+	for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir,	\
+				   (off));				\
+	list_node_from_off_((void *)i, (off)) != &(h)->n;		\
+	i = list_node_to_off_(list_node_from_off_((void *)i, (off))->dir, \
+			      (off)))
+
+#define list_for_each_safe_off_dir_(h, i, nxt, off, dir)		\
+	for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir,	\
+				   (off)),				\
+	nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir,	\
+				(off));					\
+	list_node_from_off_(i, (off)) != &(h)->n;			\
+	i = nxt,							\
+	nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir,	\
+				(off)))
+
 /**
  * list_for_each_off - iterate through a list of memory regions.
  * @h: the list_head
@@ -454,9 +716,9 @@  static inline const void *list_tail_(const struct list_head *h, size_t off)
  * so you can break and continue as normal.
  *
  * WARNING! Being the low-level macro that it is, this wrapper doesn't know
- * nor care about the type of @i. The only assumtion made is that @i points
+ * nor care about the type of @i. The only assumption made is that @i points
  * to a chunk of memory that at some @offset, relative to @i, contains a
- * properly filled `struct node_list' which in turn contains pointers to
+ * properly filled `struct list_node' which in turn contains pointers to
  * memory chunks and it's turtles all the way down. With all that in mind
  * remember that given the wrong pointer/offset couple this macro will
  * happily churn all you memory until SEGFAULT stops it, in other words
@@ -473,10 +735,18 @@  static inline const void *list_tail_(const struct list_head *h, size_t off)
  *		printf("Name: %s\n", child->name);
  */
 #define list_for_each_off(h, i, off)                                    \
-  for (i = list_node_to_off_(list_debug(h)->n.next, (off));             \
-       list_node_from_off_((void *)i, (off)) != &(h)->n;                \
-       i = list_node_to_off_(list_node_from_off_((void *)i, (off))->next, \
-                             (off)))
+	list_for_each_off_dir_((h),(i),(off),next)
+
+/**
+ * list_for_each_rev_off - iterate through a list of memory regions backwards
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * See list_for_each_off for details
+ */
+#define list_for_each_rev_off(h, i, off)                                    \
+	list_for_each_off_dir_((h),(i),(off),prev)
 
 /**
  * list_for_each_safe_off - iterate through a list of memory regions, maybe
@@ -495,14 +765,26 @@  static inline const void *list_tail_(const struct list_head *h, size_t off)
  *		printf("Name: %s\n", child->name);
  */
 #define list_for_each_safe_off(h, i, nxt, off)                          \
-  for (i = list_node_to_off_(list_debug(h)->n.next, (off)),             \
-         nxt = list_node_to_off_(list_node_from_off_(i, (off))->next,   \
-                                 (off));                                \
-       list_node_from_off_(i, (off)) != &(h)->n;                        \
-       i = nxt,                                                         \
-         nxt = list_node_to_off_(list_node_from_off_(i, (off))->next,   \
-                                 (off)))
+	list_for_each_safe_off_dir_((h),(i),(nxt),(off),next)
 
+/**
+ * list_for_each_rev_safe_off - iterate backwards through a list of
+ * memory regions, maybe during deletion
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @nxt: the structure containing the list_node
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * For details see `list_for_each_rev_off' and `list_for_each_rev_safe'
+ * descriptions.
+ *
+ * Example:
+ *	list_for_each_rev_safe_off(&parent->children, child,
+ *		next, offsetof(struct child, list))
+ *		printf("Name: %s\n", child->name);
+ */
+#define list_for_each_rev_safe_off(h, i, nxt, off)                      \
+	list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev)
 
 /* Other -off variants. */
 #define list_entry_off(n, type, off)		\
@@ -542,42 +824,19 @@  static inline struct list_node *list_node_from_off_(void *ptr, size_t off)
 	(container_off_var(var, member) +		\
 	 check_type(var->member, struct list_node))
 
-
 #if HAVE_TYPEOF
 #define list_typeof(var) typeof(var)
 #else
 #define list_typeof(var) void *
 #endif
 
-
 /* Returns member, or NULL if at end of list. */
 static inline void *list_entry_or_null(const struct list_head *h,
-                                      const struct list_node *n,
-                                      size_t off)
+				       const struct list_node *n,
+				       size_t off)
 {
-       if (n == &h->n)
-               return NULL;
-       return (char *)n - off;
+	if (n == &h->n)
+		return NULL;
+	return (char *)n - off;
 }
-
-/**
- * list_next - get the next entry in a list
- * @h: the list_head
- * @i: a pointer to an entry in the list.
- * @member: the list_node member of the structure
- *
- * If @i was the last entry in the list, returns NULL.
- *
- * Example:
- *     struct child *second;
- *     second = list_next(&parent->children, first, list);
- *     if (!second)
- *             printf("No second child!\n");
- */
-#define list_next(h, i, member)                                                \
-       ((list_typeof(i))list_entry_or_null(list_debug(h),              \
-                                           (i)->member.next,           \
-                                           list_off_var_((i), member)))
-
-
 #endif /* CCAN_LIST_H */
diff --git a/ccan/list/test/run-CCAN_LIST_DEBUG.c b/ccan/list/test/run-CCAN_LIST_DEBUG.c
new file mode 100644
index 000000000..b8e5165a6
--- /dev/null
+++ b/ccan/list/test/run-CCAN_LIST_DEBUG.c
@@ -0,0 +1,60 @@ 
+/* Check that CCAN_LIST_DEBUG works */
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <err.h>
+
+/* We don't actually want it to exit... */
+static jmp_buf aborted;
+#define abort() longjmp(aborted, 1)
+
+#define fprintf my_fprintf
+static char printf_buffer[1000];
+
+static int my_fprintf(FILE *stream, const char *format, ...)
+{
+	va_list ap;
+	int ret;
+	(void)stream;
+	va_start(ap, format);
+	ret = vsprintf(printf_buffer, format, ap);
+	va_end(ap);
+	return ret;
+}
+
+#define CCAN_LIST_DEBUG 1
+#include <ccan/list/list.h>
+#include <ccan/tap/tap.h>
+#include <ccan/list/list.c>
+
+int main(void)
+{
+	struct list_head list;
+	struct list_node n1;
+	char expect[100];
+
+	plan_tests(2);
+	/* Empty list. */
+	list.n.next = &list.n;
+	list.n.prev = &list.n;
+	ok1(list_check(&list, NULL) == &list);
+
+	/* Bad back ptr */
+	list.n.prev = &n1;
+
+	/* Aborting version. */
+	sprintf(expect, "run-CCAN_LIST_DEBUG.c:51: prev corrupt in node %p (0) of %p\n",
+		&list, &list);
+	if (setjmp(aborted) == 0) {
+		assert(list_empty(&list));
+		fail("list_empty on empty with bad back ptr didn't fail!");
+	} else {
+		/* __FILE__ might give full path. */
+		int prep = strlen(printf_buffer) - strlen(expect);
+		ok1(prep >= 0 && strcmp(printf_buffer + prep, expect) == 0);
+	}
+
+	return exit_status();
+}
diff --git a/ccan/list/test/run-check-corrupt.c b/ccan/list/test/run-check-corrupt.c
index da4578ae7..94c2e67e7 100644
--- a/ccan/list/test/run-check-corrupt.c
+++ b/ccan/list/test/run-check-corrupt.c
@@ -16,11 +16,9 @@  static int my_fprintf(FILE *stream, const char *format, ...)
 {
 	va_list ap;
 	int ret;
-
 	(void)stream;
-
 	va_start(ap, format);
-	ret = vsnprintf(printf_buffer, sizeof(printf_buffer), format, ap);
+	ret = vsprintf(printf_buffer, format, ap);
 	va_end(ap);
 	return ret;
 }
@@ -29,15 +27,12 @@  static int my_fprintf(FILE *stream, const char *format, ...)
 #include <ccan/tap/tap.h>
 #include <ccan/list/list.c>
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	struct list_head list;
 	struct list_node n1;
 	char expect[100];
 
-	(void)argc;
-	(void)argv;
-
 	plan_tests(9);
 	/* Empty list. */
 	list.n.next = &list.n;
diff --git a/ccan/list/test/run-check-nonconst.c b/ccan/list/test/run-check-nonconst.c
new file mode 100644
index 000000000..d3cb652a3
--- /dev/null
+++ b/ccan/list/test/run-check-nonconst.c
@@ -0,0 +1,27 @@ 
+#include <ccan/list/list.h>
+#include <ccan/tap/tap.h>
+#include <ccan/list/list.c>
+#include "helper.h"
+
+struct child {
+	const char *name;
+	struct list_node list;
+};
+
+int main(void)
+{
+	struct child c1, c2;
+	struct list_head list = LIST_HEAD_INIT(list);
+
+	plan_tests(1);
+
+	list_add(&list, &c1.list);
+	list_add_tail(list_check(&list, "Bad list!"), &c2.list);
+	list_del_from(list_check(&list, "Bad list!"),
+		      list_check_node(&c2.list, "Bad node!"));
+	list_del_from(list_check(&list, "Bad list!"),
+		      list_check_node(&c1.list, "Bad node!"));
+	ok1(list_empty(list_check(&list, "Bad emptied list")));
+
+	return exit_status();
+}
diff --git a/ccan/list/test/run-list_del_from-assert.c b/ccan/list/test/run-list_del_from-assert.c
index 453dc0f22..9404b7120 100644
--- a/ccan/list/test/run-list_del_from-assert.c
+++ b/ccan/list/test/run-list_del_from-assert.c
@@ -7,16 +7,13 @@ 
 #include <unistd.h>
 #include <signal.h>
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	struct list_head list1, list2;
 	struct list_node n1, n2, n3;
 	pid_t child;
 	int status;
 
-	(void)argc;
-	(void)argv;
-
 	plan_tests(1);
 	list_head_init(&list1);
 	list_head_init(&list2);
@@ -28,7 +25,6 @@  int main(int argc, char *argv[])
 	if (child) {
 		wait(&status);
 	} else {
-		close(2); /* Close stderr so we don't print confusing assert */
 		/* This should abort. */
 		list_del_from(&list1, &n3);
 		exit(0);
diff --git a/ccan/list/test/run-list_prev-list_next.c b/ccan/list/test/run-list_prev-list_next.c
new file mode 100644
index 000000000..cc61e03a0
--- /dev/null
+++ b/ccan/list/test/run-list_prev-list_next.c
@@ -0,0 +1,65 @@ 
+#include <ccan/list/list.h>
+#include <ccan/tap/tap.h>
+#include <ccan/list/list.c>
+#include "helper.h"
+
+struct parent {
+	const char *name;
+	unsigned int num_children;
+	struct list_head children;
+};
+
+struct child {
+	const char *name;
+	struct list_node list;
+};
+
+int main(void)
+{
+	struct parent parent;
+	struct child c1, c2, c3;
+	const struct parent *p;
+	const struct child *c;
+
+	plan_tests(20);
+	parent.num_children = 0;
+	list_head_init(&parent.children);
+
+	c1.name = "c1";
+	list_add(&parent.children, &c1.list);
+
+	ok1(list_next(&parent.children, &c1, list) == NULL);
+	ok1(list_prev(&parent.children, &c1, list) == NULL);
+
+	c2.name = "c2";
+	list_add_tail(&parent.children, &c2.list);
+
+	ok1(list_next(&parent.children, &c1, list) == &c2);
+	ok1(list_prev(&parent.children, &c1, list) == NULL);
+	ok1(list_next(&parent.children, &c2, list) == NULL);
+	ok1(list_prev(&parent.children, &c2, list) == &c1);
+
+	c3.name = "c3";
+	list_add_tail(&parent.children, &c3.list);
+
+	ok1(list_next(&parent.children, &c1, list) == &c2);
+	ok1(list_prev(&parent.children, &c1, list) == NULL);
+	ok1(list_next(&parent.children, &c2, list) == &c3);
+	ok1(list_prev(&parent.children, &c2, list) == &c1);
+	ok1(list_next(&parent.children, &c3, list) == NULL);
+	ok1(list_prev(&parent.children, &c3, list) == &c2);
+
+	/* Const variants */
+	p = &parent;
+	c = &c2;
+	ok1(list_next(&p->children, &c1, list) == &c2);
+	ok1(list_prev(&p->children, &c1, list) == NULL);
+	ok1(list_next(&p->children, c, list) == &c3);
+	ok1(list_prev(&p->children, c, list) == &c1);
+	ok1(list_next(&parent.children, c, list) == &c3);
+	ok1(list_prev(&parent.children, c, list) == &c1);
+	ok1(list_next(&p->children, &c3, list) == NULL);
+	ok1(list_prev(&p->children, &c3, list) == &c2);
+
+	return exit_status();
+}
diff --git a/ccan/list/test/run-prepend_list.c b/ccan/list/test/run-prepend_list.c
new file mode 100644
index 000000000..fecd4196f
--- /dev/null
+++ b/ccan/list/test/run-prepend_list.c
@@ -0,0 +1,111 @@ 
+#include <ccan/list/list.h>
+#include <ccan/tap/tap.h>
+#include <ccan/list/list.c>
+#include <stdarg.h>
+
+static bool list_expect(struct list_head *h, ...)
+{
+	va_list ap;
+	struct list_node *n = &h->n, *expected;
+
+	va_start(ap, h);
+	while ((expected = va_arg(ap, struct list_node *)) != NULL) {
+		n = n->next;
+		if (n != expected)
+			return false;
+	}
+	return (n->next == &h->n);
+}
+
+int main(void)
+{
+	struct list_head h1, h2;
+	struct list_node n[4];
+
+	plan_tests(40);
+
+	list_head_init(&h1);
+	list_head_init(&h2);
+
+	/* Append an empty list to an empty list. */
+	list_append_list(&h1, &h2);
+	ok1(list_empty(&h1));
+	ok1(list_empty(&h2));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+
+	/* Prepend an empty list to an empty list. */
+	list_prepend_list(&h1, &h2);
+	ok1(list_empty(&h1));
+	ok1(list_empty(&h2));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+
+	/* Append an empty list to a non-empty list */
+	list_add(&h1, &n[0]);
+	list_append_list(&h1, &h2);
+	ok1(list_empty(&h2));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+	ok1(list_expect(&h1, &n[0], NULL));
+
+	/* Prepend an empty list to a non-empty list */
+	list_prepend_list(&h1, &h2);
+	ok1(list_empty(&h2));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+	ok1(list_expect(&h1, &n[0], NULL));
+
+	/* Append a non-empty list to an empty list. */
+	list_append_list(&h2, &h1);
+	ok1(list_empty(&h1));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+	ok1(list_expect(&h2, &n[0], NULL));
+
+	/* Prepend a non-empty list to an empty list. */
+	list_prepend_list(&h1, &h2);
+	ok1(list_empty(&h2));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+	ok1(list_expect(&h1, &n[0], NULL));
+
+	/* Prepend a non-empty list to non-empty list. */
+	list_add(&h2, &n[1]);
+	list_prepend_list(&h1, &h2);
+	ok1(list_empty(&h2));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+	ok1(list_expect(&h1, &n[1], &n[0], NULL));
+
+	/* Append a non-empty list to non-empty list. */
+	list_add(&h2, &n[2]);
+	list_append_list(&h1, &h2);
+	ok1(list_empty(&h2));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+	ok1(list_expect(&h1, &n[1], &n[0], &n[2], NULL));
+
+	/* Prepend a 2-entry list to a 2-entry list. */
+	list_del_from(&h1, &n[2]);
+	list_add(&h2, &n[2]);
+	list_add_tail(&h2, &n[3]);
+	list_prepend_list(&h1, &h2);
+	ok1(list_empty(&h2));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+	ok1(list_expect(&h1, &n[2], &n[3], &n[1], &n[0], NULL));
+
+	/* Append a 2-entry list to a 2-entry list. */
+	list_del_from(&h1, &n[2]);
+	list_del_from(&h1, &n[3]);
+	list_add(&h2, &n[2]);
+	list_add_tail(&h2, &n[3]);
+	list_append_list(&h1, &h2);
+	ok1(list_empty(&h2));
+	ok1(list_check(&h1, NULL));
+	ok1(list_check(&h2, NULL));
+	ok1(list_expect(&h1, &n[1], &n[0], &n[2], &n[3], NULL));
+
+	return exit_status();
+}
diff --git a/ccan/list/test/run-single-eval.c b/ccan/list/test/run-single-eval.c
index 3c17e0376..db0bffdda 100644
--- a/ccan/list/test/run-single-eval.c
+++ b/ccan/list/test/run-single-eval.c
@@ -19,7 +19,7 @@  static LIST_HEAD(static_list);
 
 #define ref(obj, counter) ((counter)++, (obj))
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	struct parent parent;
 	struct child c1, c2, c3, *c, *n;
@@ -28,9 +28,6 @@  int main(int argc, char *argv[])
 		node_count = 0;
 	struct list_head list = LIST_HEAD_INIT(list);
 
-	(void)argc;
-	(void)argv;
-
 	plan_tests(74);
 	/* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */
 	ok1(list_empty(ref(&static_list, static_count)));
diff --git a/ccan/list/test/run.c b/ccan/list/test/run.c
index bc9d26661..53542266b 100644
--- a/ccan/list/test/run.c
+++ b/ccan/list/test/run.c
@@ -17,19 +17,17 @@  struct child {
 
 static LIST_HEAD(static_list);
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	struct parent parent;
-	struct child c1, c2, c3, *c, *n;
+	struct child c1, c2, c3, x1, *c, *n;
 	unsigned int i;
 	struct list_head list = LIST_HEAD_INIT(list);
 	opaque_t *q, *nq;
 	struct list_head opaque_list = LIST_HEAD_INIT(opaque_list);
+	LIST_HEAD(rev);
 
-	(void)argc;
-	(void)argv;
-
-	plan_tests(65);
+	plan_tests(92);
 	/* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */
 	ok1(list_empty(&static_list));
 	ok1(list_check(&static_list, NULL));
@@ -89,6 +87,11 @@  int main(int argc, char *argv[])
 	/* Test list_top */
 	ok1(list_top(&parent.children, struct child, list) == &c1);
 
+	/* Test list_pop */
+	ok1(list_pop(&parent.children, struct child, list) == &c1);
+	ok1(list_top(&parent.children, struct child, list) == &c2);
+	list_add(&parent.children, &c1.list);
+
 	/* Test list_tail */
 	ok1(list_tail(&parent.children, struct child, list) == &c3);
 
@@ -147,6 +150,10 @@  int main(int argc, char *argv[])
 			list_del_from(&parent.children, &c->list);
 			break;
 		}
+
+		/* prepare for list_for_each_rev_safe test */
+		list_add(&rev, &c->list);
+
 		ok1(list_check(&parent.children, NULL));
 		if (i > 2)
 			break;
@@ -154,6 +161,43 @@  int main(int argc, char *argv[])
 	ok1(i == 3);
 	ok1(list_empty(&parent.children));
 
+	/* Test list_for_each_rev_safe, list_del and list_del_from. */
+	i = 0;
+	list_for_each_rev_safe(&rev, c, n, list) {
+		switch (i++) {
+		case 0:
+			ok1(c == &c1);
+			list_del(&c->list);
+			break;
+		case 1:
+			ok1(c == &c2);
+			list_del_from(&rev, &c->list);
+			break;
+		case 2:
+			ok1(c == &c3);
+			list_del_from(&rev, &c->list);
+			break;
+		}
+		ok1(list_check(&rev, NULL));
+		if (i > 2)
+			break;
+	}
+	ok1(i == 3);
+	ok1(list_empty(&rev));
+
+	/* Test list_node_init: safe to list_del after this. */
+	list_node_init(&c->list);
+	list_del(&c->list);
+
+	/* Test list_del_init */
+	list_add(&parent.children, &c->list);
+	ok1(!list_empty(&parent.children));
+	list_del_init(&c->list);
+	ok1(list_empty(&parent.children));
+	/* We can call this as many times as we like. */
+	list_del_init(&c->list);
+	list_del_init(&c->list);
+
 	/* Test list_for_each_off. */
 	list_add_tail(&opaque_list,
 		      (struct list_node *)create_opaque_blob());
@@ -197,8 +241,66 @@  int main(int argc, char *argv[])
 	ok1(i == 3);
 	ok1(list_empty(&opaque_list));
 
-	/* Test list_top/list_tail on empty list. */
+	/* Test list_top/list_tail/list_pop on empty list. */
 	ok1(list_top(&parent.children, struct child, list) == NULL);
 	ok1(list_tail(&parent.children, struct child, list) == NULL);
+	ok1(list_pop(&parent.children, struct child, list) == NULL);
+
+	/* Test list_add_before and list_add_after */
+	list_add(&parent.children, &c1.list);
+	list_add_after(&parent.children, &c1.list, &c2.list);
+	ok1(list_check(&parent.children, "list_add_after"));
+
+	i = 0;
+	list_for_each(&parent.children, c, list) {
+		switch (i++) {
+		case 0:
+			ok1(c == &c1);
+			break;
+		case 1:
+			ok1(c == &c2);
+			break;
+		}
+	}
+	ok1(i == 2);
+
+	list_add_before(&parent.children, &c2.list, &c3.list);
+	ok1(list_check(&parent.children, "list_add_before"));
+
+	i = 0;
+	list_for_each(&parent.children, c, list) {
+		switch (i++) {
+		case 0:
+			ok1(c == &c1);
+			break;
+		case 1:
+			ok1(c == &c3);
+			break;
+		case 2:
+			ok1(c == &c2);
+			break;
+		}
+	}
+	ok1(i == 3);
+
+	/* test list_swap */
+	list_swap(&c3.list, &x1.list);
+	ok1(list_check(&parent.children, "list_swap"));
+	i = 0;
+	list_for_each(&parent.children, c, list) {
+		switch (i++) {
+		case 0:
+			ok1(c == &c1);
+			break;
+		case 1:
+			ok1(c == &x1);
+			break;
+		case 2:
+			ok1(c == &c2);
+			break;
+		}
+	}
+	ok1(i == 3);
+
 	return exit_status();
 }
diff --git a/ccan/short_types/test/run-endian.c b/ccan/short_types/test/run-endian.c
index d8953a3d1..108e3ab7d 100644
--- a/ccan/short_types/test/run-endian.c
+++ b/ccan/short_types/test/run-endian.c
@@ -4,7 +4,7 @@ 
 #include <stdlib.h>
 #include <err.h>
 
-int __attribute__((const)) main(void)
+int main(void)
 {
 	plan_tests(6);
 
diff --git a/ccan/short_types/test/run.c b/ccan/short_types/test/run.c
index ac8b31bee..2bff4b78b 100644
--- a/ccan/short_types/test/run.c
+++ b/ccan/short_types/test/run.c
@@ -3,7 +3,7 @@ 
 #include <stdlib.h>
 #include <err.h>
 
-int __attribute__((const)) main(void)
+int main(void)
 {
 	plan_tests(16);
 
diff --git a/ccan/str/_info b/ccan/str/_info
index 548f059d7..b579525fa 100644
--- a/ccan/str/_info
+++ b/ccan/str/_info
@@ -1,6 +1,6 @@ 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
-#include "config.h"
 
 /**
  * str - string helper routines
@@ -26,11 +26,11 @@ 
  *
  *	int main(int argc, char *argv[])
  *	{
- *		if (argv[1] && streq(argv[1], "--verbose"))
+ *		if (argc > 1 && streq(argv[1], "--verbose"))
  *			printf("verbose set\n");
- *		if (argv[1] && strstarts(argv[1], "--"))
+ *		if (argc > 1 && strstarts(argv[1], "--"))
  *			printf("Some option set\n");
- *		if (argv[1] && strends(argv[1], "cow-powers"))
+ *		if (argc > 1 && strends(argv[1], "cow-powers"))
  *			printf("Magic option set\n");
  *		return 0;
  *	}
diff --git a/ccan/str/debug.c b/ccan/str/debug.c
new file mode 100644
index 000000000..8c519442d
--- /dev/null
+++ b/ccan/str/debug.c
@@ -0,0 +1,108 @@ 
+/* CC0 (Public domain) - see LICENSE file for details */
+#include "config.h"
+#include <ccan/str/str_debug.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef CCAN_STR_DEBUG
+/* Because we mug the real ones with macros, we need our own wrappers. */
+int str_isalnum(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isalnum(i);
+}
+
+int str_isalpha(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isalpha(i);
+}
+
+int str_isascii(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isascii(i);
+}
+
+#if HAVE_ISBLANK
+int str_isblank(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isblank(i);
+}
+#endif
+
+int str_iscntrl(int i)
+{
+	assert(i >= -1 && i < 256);
+	return iscntrl(i);
+}
+
+int str_isdigit(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isdigit(i);
+}
+
+int str_isgraph(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isgraph(i);
+}
+
+int str_islower(int i)
+{
+	assert(i >= -1 && i < 256);
+	return islower(i);
+}
+
+int str_isprint(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isprint(i);
+}
+
+int str_ispunct(int i)
+{
+	assert(i >= -1 && i < 256);
+	return ispunct(i);
+}
+
+int str_isspace(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isspace(i);
+}
+
+int str_isupper(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isupper(i);
+}
+
+int str_isxdigit(int i)
+{
+	assert(i >= -1 && i < 256);
+	return isxdigit(i);
+}
+
+#undef strstr
+#undef strchr
+#undef strrchr
+
+char *str_strstr(const char *haystack, const char *needle)
+{
+	return strstr(haystack, needle);
+}
+
+char *str_strchr(const char *haystack, int c)
+{
+	return strchr(haystack, c);
+}
+
+char *str_strrchr(const char *haystack, int c)
+{
+	return strrchr(haystack, c);
+}
+#endif
diff --git a/ccan/str/str.h b/ccan/str/str.h
index 89668c689..076840ed5 100644
--- a/ccan/str/str.h
+++ b/ccan/str/str.h
@@ -94,13 +94,27 @@  size_t strcount(const char *haystack, const char *needle);
 #if HAVE_TYPEOF
 /* Only a simple type can have 0 assigned, so test that. */
 #define STR_MAX_CHARS_TCHECK_(type_or_expr)		\
-	({ typeof(type_or_expr) x = 0; (void)x; 0; })
+	(sizeof(({ typeof(type_or_expr) x = 0; x; }))*0)
 #else
 #define STR_MAX_CHARS_TCHECK_(type_or_expr) 0
 #endif
 
+#include <ccan/str/str_debug.h>
+
 /* These checks force things out of line, hence they are under DEBUG. */
 #ifdef CCAN_STR_DEBUG
+#include <ccan/build_assert/build_assert.h>
+
+/* You can use a char if char is unsigned. */
+#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
+#define str_check_arg_(i)						\
+	((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \
+								  char)	\
+				    || (char)255 > 0))
+#else
+#define str_check_arg_(i) (i)
+#endif
+
 #if HAVE_TYPEOF
 /* With GNU magic, we can make const-respecting standard string functions. */
 #undef strstr
diff --git a/ccan/str/str_debug.h b/ccan/str/str_debug.h
new file mode 100644
index 000000000..92c10c41c
--- /dev/null
+++ b/ccan/str/str_debug.h
@@ -0,0 +1,30 @@ 
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_STR_DEBUG_H
+#define CCAN_STR_DEBUG_H
+
+/* #define CCAN_STR_DEBUG 1 */
+
+#ifdef CCAN_STR_DEBUG
+/* Because we mug the real ones with macros, we need our own wrappers. */
+int str_isalnum(int i);
+int str_isalpha(int i);
+int str_isascii(int i);
+#if HAVE_ISBLANK
+int str_isblank(int i);
+#endif
+int str_iscntrl(int i);
+int str_isdigit(int i);
+int str_isgraph(int i);
+int str_islower(int i);
+int str_isprint(int i);
+int str_ispunct(int i);
+int str_isspace(int i);
+int str_isupper(int i);
+int str_isxdigit(int i);
+
+char *str_strstr(const char *haystack, const char *needle);
+char *str_strchr(const char *s, int c);
+char *str_strrchr(const char *s, int c);
+#endif /* CCAN_STR_DEBUG */
+
+#endif /* CCAN_STR_DEBUG_H */
diff --git a/ccan/str/test/compile_fail-STR_MAX_CHARS.c b/ccan/str/test/compile_fail-STR_MAX_CHARS.c
index 74448c1b8..8e0fd2e2f 100644
--- a/ccan/str/test/compile_fail-STR_MAX_CHARS.c
+++ b/ccan/str/test/compile_fail-STR_MAX_CHARS.c
@@ -4,7 +4,7 @@  struct s {
 	int val;
 };
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	struct s
 #ifdef FAIL
diff --git a/ccan/str/test/compile_fail-isalnum.c b/ccan/str/test/compile_fail-isalnum.c
index 930defffa..5d9895822 100644
--- a/ccan/str/test/compile_fail-isalnum.c
+++ b/ccan/str/test/compile_fail-isalnum.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check isalnum.
diff --git a/ccan/str/test/compile_fail-isalpha.c b/ccan/str/test/compile_fail-isalpha.c
index 200510982..33d365538 100644
--- a/ccan/str/test/compile_fail-isalpha.c
+++ b/ccan/str/test/compile_fail-isalpha.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check isalpha.
diff --git a/ccan/str/test/compile_fail-isascii.c b/ccan/str/test/compile_fail-isascii.c
index ee55e4997..3946e0b3b 100644
--- a/ccan/str/test/compile_fail-isascii.c
+++ b/ccan/str/test/compile_fail-isascii.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check isascii.
diff --git a/ccan/str/test/compile_fail-isblank.c b/ccan/str/test/compile_fail-isblank.c
index f4cb961d7..e14b0d7e6 100644
--- a/ccan/str/test/compile_fail-isblank.c
+++ b/ccan/str/test/compile_fail-isblank.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF || !HAVE_ISBLANK
 #error We need typeof to check isblank.
diff --git a/ccan/str/test/compile_fail-iscntrl.c b/ccan/str/test/compile_fail-iscntrl.c
index bc7414654..f9abf1dc5 100644
--- a/ccan/str/test/compile_fail-iscntrl.c
+++ b/ccan/str/test/compile_fail-iscntrl.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check iscntrl.
diff --git a/ccan/str/test/compile_fail-isdigit.c b/ccan/str/test/compile_fail-isdigit.c
index 71d1c7143..a3ee439c6 100644
--- a/ccan/str/test/compile_fail-isdigit.c
+++ b/ccan/str/test/compile_fail-isdigit.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check isdigit.
diff --git a/ccan/str/test/compile_fail-islower.c b/ccan/str/test/compile_fail-islower.c
index ca3f9907e..8f5c45619 100644
--- a/ccan/str/test/compile_fail-islower.c
+++ b/ccan/str/test/compile_fail-islower.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check islower.
diff --git a/ccan/str/test/compile_fail-isprint.c b/ccan/str/test/compile_fail-isprint.c
index 6432e41d2..85ed028f6 100644
--- a/ccan/str/test/compile_fail-isprint.c
+++ b/ccan/str/test/compile_fail-isprint.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check isprint.
diff --git a/ccan/str/test/compile_fail-ispunct.c b/ccan/str/test/compile_fail-ispunct.c
index 5d941fcba..09d4279a9 100644
--- a/ccan/str/test/compile_fail-ispunct.c
+++ b/ccan/str/test/compile_fail-ispunct.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check ispunct.
diff --git a/ccan/str/test/compile_fail-isspace.c b/ccan/str/test/compile_fail-isspace.c
index bfee1f89f..798cfcd47 100644
--- a/ccan/str/test/compile_fail-isspace.c
+++ b/ccan/str/test/compile_fail-isspace.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check isspace.
diff --git a/ccan/str/test/compile_fail-isupper.c b/ccan/str/test/compile_fail-isupper.c
index 4cf9fd357..56f5dee11 100644
--- a/ccan/str/test/compile_fail-isupper.c
+++ b/ccan/str/test/compile_fail-isupper.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check isupper.
diff --git a/ccan/str/test/compile_fail-isxdigit.c b/ccan/str/test/compile_fail-isxdigit.c
index 65e6006a8..ea4d5269a 100644
--- a/ccan/str/test/compile_fail-isxdigit.c
+++ b/ccan/str/test/compile_fail-isxdigit.c
@@ -3,6 +3,7 @@ 
 
 int main(int argc, char *argv[])
 {
+	(void)argc;
 #ifdef FAIL
 #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF
 #error We need typeof to check isxdigit.
diff --git a/ccan/str/test/compile_fail-strchr.c b/ccan/str/test/compile_fail-strchr.c
index 74a7314d0..bdaf034ab 100644
--- a/ccan/str/test/compile_fail-strchr.c
+++ b/ccan/str/test/compile_fail-strchr.c
@@ -1,7 +1,7 @@ 
 #define CCAN_STR_DEBUG 1
 #include <ccan/str/str.h>
 
-int main(int argc, char *argv[])
+int main(void)
 {
 #ifdef FAIL
 #if !HAVE_TYPEOF
diff --git a/ccan/str/test/compile_fail-strrchr.c b/ccan/str/test/compile_fail-strrchr.c
index ba7d17e03..57fba0ed5 100644
--- a/ccan/str/test/compile_fail-strrchr.c
+++ b/ccan/str/test/compile_fail-strrchr.c
@@ -1,7 +1,7 @@ 
 #define CCAN_STR_DEBUG 1
 #include <ccan/str/str.h>
 
-int main(int argc, char *argv[])
+int main(void)
 {
 #ifdef FAIL
 #if !HAVE_TYPEOF
diff --git a/ccan/str/test/compile_fail-strstr.c b/ccan/str/test/compile_fail-strstr.c
index deefef654..7bd8ac22f 100644
--- a/ccan/str/test/compile_fail-strstr.c
+++ b/ccan/str/test/compile_fail-strstr.c
@@ -1,7 +1,7 @@ 
 #define CCAN_STR_DEBUG 1
 #include <ccan/str/str.h>
 
-int main(int argc, char *argv[])
+int main(void)
 {
 #ifdef FAIL
 #if !HAVE_TYPEOF
diff --git a/ccan/str/test/compile_ok-STR_MAX_CHARS-static.c b/ccan/str/test/compile_ok-STR_MAX_CHARS-static.c
new file mode 100644
index 000000000..bc6aff7a3
--- /dev/null
+++ b/ccan/str/test/compile_ok-STR_MAX_CHARS-static.c
@@ -0,0 +1,8 @@ 
+#include <ccan/str/str.h>
+
+int main(void)
+{
+	static char str[STR_MAX_CHARS(int)];
+
+	return str[0] ? 0 : 1;
+}
diff --git a/ccan/str/test/run-STR_MAX_CHARS.c b/ccan/str/test/run-STR_MAX_CHARS.c
index 1343e047b..fa45bad8a 100644
--- a/ccan/str/test/run-STR_MAX_CHARS.c
+++ b/ccan/str/test/run-STR_MAX_CHARS.c
@@ -4,9 +4,9 @@ 
 #include <ccan/tap/tap.h>
 #include <stdint.h>
 
-int main(int argc, char *argv[])
+int main(void)
 {
-	char *str = (char*)malloc(sizeof(char)*1000);
+	char str[1000];
 	struct {
 		uint8_t u1byte;
 		int8_t s1byte;
@@ -19,11 +19,6 @@  int main(int argc, char *argv[])
 		void *ptr;
 	} types;
 
-	(void)argc;
-	(void)argv;
-
-	assert(str);
-
 	plan_tests(13);
 
 	memset(&types, 0xFF, sizeof(types));
@@ -60,7 +55,5 @@  int main(int argc, char *argv[])
 	sprintf(str, "%p", types.ptr);
 	ok1(strlen(str) < STR_MAX_CHARS(types.ptr));
 
-	free(str);
-
 	return exit_status();
 }				
diff --git a/ccan/str/test/run.c b/ccan/str/test/run.c
index 216e1410b..9917fe711 100644
--- a/ccan/str/test/run.c
+++ b/ccan/str/test/run.c
@@ -21,13 +21,10 @@  static char *strdup_rev(const char *s)
 	return ret;
 }
 
-int main(int argc, char *argv[])
+int main(void)
 {
 	unsigned int i, j, n;
 	char *strings[NUM_SUBSTRINGS * NUM_SUBSTRINGS];
-
-	(void)argc;
-	(void)argv;
 	
 	n = 0;
 	for (i = 0; i < NUM_SUBSTRINGS; i++) {