Allow forward declarations of structs

Now ltrace can display singly-linked lists.  Recursion detection was added
to format_pointer.  It relies on the fact that ltrace is not multi-threaded
and doesn't need per-process or per-thread cache of already-displayed
values, because we display one value at a time anyway.

Several test cases added.
diff --git a/lens_default.c b/lens_default.c
index a2233b8..f3e328f 100644
--- a/lens_default.c
+++ b/lens_default.c
@@ -27,6 +27,7 @@
 #include <inttypes.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <string.h>
 
 #include "proc.h"
 #include "lens_default.h"
@@ -250,6 +251,36 @@
 	if (value_is_zero(value, arguments))
 		return fprintf(stream, "nil");
 
+	/* The following is for detecting recursion.  We keep track of
+	 * the values that were already displayed.  Each time a
+	 * pointer should be dereferenced, we compare its value to the
+	 * value of each of the pointers dereferenced so far.  If one
+	 * of them matches, instead of recursing, we just printf which
+	 * superstructure this pointer recurses to.  */
+	static struct vect pointers = {};
+	if (pointers.elt_size == 0)
+		VECT_INIT(&pointers, struct value *);
+
+	size_t len = vect_size(&pointers);
+	size_t i;
+	for (i = len; i-- > 0 ;) {
+		struct value **old = VECT_ELEMENT(&pointers, struct value *, i);
+		int rc = value_equal(value, *old, arguments);
+		if (rc < 0)
+			return -1;
+		if (rc > 0) {
+			size_t reclevel = len - i - 1;
+			char buf[reclevel + 1];
+			memset(buf, '^', sizeof buf);
+			buf[reclevel] = 0;
+			return fprintf(stream, "recurse%s", buf);
+		}
+	}
+
+	/* OK, not a recursion.  Remember this value for tracking.  */
+	if (VECT_PUSHBACK(&pointers, &value) < 0)
+		return -1;
+
 	struct value element;
 	int o;
 	if (value_init_deref(&element, value) < 0) {
@@ -260,6 +291,7 @@
 	value_destroy(&element);
 
 done:
+	vect_popback(&pointers);
 	return o;
 }