diff -ur clearsilver-0.6.1/Makefile clearsilver-0.6.2/Makefile
--- clearsilver-0.6.1/Makefile	Thu Apr 25 18:58:13 2002
+++ clearsilver-0.6.2/Makefile	Mon May 13 17:43:00 2002
@@ -72,8 +72,8 @@
 		mkdir -p $$mdir; \
 	done
 
-CS_DISTDIR = clearsilver-0.6
-CS_LABEL = CLEARSILVER-0_6_0
+CS_DISTDIR = clearsilver-0.6.2
+CS_LABEL = CLEARSILVER-0_6_2
 CS_FILES = LICENSE CS_LICENSE rules.mk Makefile util cs cgi python scripts mod_ecs imd
 cs_dist:
 	rm -rf $(CS_DISTDIR)
diff -ur clearsilver-0.6.1/cgi/cgi.h clearsilver-0.6.2/cgi/cgi.h
--- clearsilver-0.6.1/cgi/cgi.h	Thu Apr 11 18:11:39 2002
+++ clearsilver-0.6.2/cgi/cgi.h	Mon May 13 13:40:33 2002
@@ -15,6 +15,8 @@
 #include "util/neo_err.h"
 #include "util/neo_hdf.h"
 
+__BEGIN_DECLS
+
 extern NERR_TYPE CGIFinished;
 extern NERR_TYPE CGIUploadCancelled;
 
@@ -333,5 +335,7 @@
 /* internal use only */
 NEOERR * parse_rfc2388 (CGI *cgi);
 NEOERR * open_upload(CGI *cgi, int unlink_files, FILE **fpw);
+
+__END_DECLS
 
 #endif /* __CGI_H_ */
diff -ur clearsilver-0.6.1/cgi/cgiwrap.h clearsilver-0.6.2/cgi/cgiwrap.h
--- clearsilver-0.6.1/cgi/cgiwrap.h	Mon Aug  6 14:28:16 2001
+++ clearsilver-0.6.2/cgi/cgiwrap.h	Mon May 13 13:40:33 2002
@@ -24,6 +24,8 @@
 #include <stdarg.h>
 #include "util/neo_err.h"
 
+__BEGIN_DECLS
+
 typedef int (*READ_FUNC)(void *, char *, int);
 typedef int (*WRITEF_FUNC)(void *, char *, va_list);
 typedef int (*WRITE_FUNC)(void *, char *, int);
@@ -158,5 +160,7 @@
  * Returns: None
  */
 void cgiwrap_read (char *buf, int buf_len, int *read_len);
+
+__END_DECLS
 
 #endif /* __CGIWRAP_H_ */
diff -ur clearsilver-0.6.1/cgi/date.h clearsilver-0.6.2/cgi/date.h
--- clearsilver-0.6.1/cgi/date.h	Mon Aug  6 14:28:16 2001
+++ clearsilver-0.6.2/cgi/date.h	Mon May 13 13:40:33 2002
@@ -13,7 +13,11 @@
 
 #include <time.h>
 
+__BEGIN_DECLS
+
 NEOERR *export_date_tm (HDF *obj, char *prefix, struct tm *ttm);
 NEOERR *export_date_time_t (HDF *obj, char *prefix, char *timezone, time_t tt);
+
+__END_DECLS
 
 #endif /* __DATE_H_ */
diff -ur clearsilver-0.6.1/cgi/html.h clearsilver-0.6.2/cgi/html.h
--- clearsilver-0.6.1/cgi/html.h	Mon Aug  6 14:28:16 2001
+++ clearsilver-0.6.2/cgi/html.h	Mon May 13 13:40:33 2002
@@ -15,7 +15,11 @@
 #include "util/neo_err.h"
 #include "util/neo_hdf.h"
 
+__BEGIN_DECLS
+
 NEOERR *convert_text_html_alloc (char *src, int slen, char **out);
 NEOERR *html_escape_alloc (char *src, int slen, char **out);
+
+__END_DECLS
 
 #endif /* __HTML_H_ */
diff -ur clearsilver-0.6.1/cs/cs.h clearsilver-0.6.2/cs/cs.h
--- clearsilver-0.6.1/cs/cs.h	Thu Mar 28 01:18:51 2002
+++ clearsilver-0.6.2/cs/cs.h	Mon May 13 13:40:35 2002
@@ -45,6 +45,8 @@
 #include "util/ulist.h"
 #include "util/neo_hdf.h"
 
+__BEGIN_DECLS
+
 typedef enum
 {
   /* Unary operators */
@@ -277,5 +279,7 @@
  * Return: None
  */
 void cs_destroy (CSPARSE **parse);
+
+__END_DECLS
 
 #endif /* _CSHDF_H_ */
diff -ur clearsilver-0.6.1/cs/csparse.c clearsilver-0.6.2/cs/csparse.c
--- clearsilver-0.6.1/cs/csparse.c	Tue Apr 30 19:57:02 2002
+++ clearsilver-0.6.2/cs/csparse.c	Mon May 13 17:42:18 2002
@@ -72,6 +72,8 @@
 static NEOERR *each_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
 static NEOERR *end_parse (CSPARSE *parse, int cmd, char *arg);
 static NEOERR *include_parse (CSPARSE *parse, int cmd, char *arg);
+static NEOERR *linclude_parse (CSPARSE *parse, int cmd, char *arg);
+static NEOERR *linclude_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
 static NEOERR *def_parse (CSPARSE *parse, int cmd, char *arg);
 static NEOERR *skip_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
 static NEOERR *call_parse (CSPARSE *parse, int cmd, char *arg);
@@ -123,6 +125,8 @@
     end_parse, skip_eval, 0},
   {"include", sizeof("include")-1, ST_ANYWHERE,     ST_SAME, 
     include_parse, skip_eval, 1},
+  {"linclude", sizeof("linclude")-1, ST_ANYWHERE,     ST_SAME, 
+    linclude_parse, linclude_eval, 1},
   {"def",     sizeof("def")-1,     ST_ANYWHERE,     ST_DEF, 
     def_parse, skip_eval, 1},
   {"/def",    sizeof("/def")-1,    ST_DEF,          ST_POP,
@@ -1155,6 +1159,33 @@
   return STATUS_OK;
 }
 
+static NEOERR *linclude_parse (CSPARSE *parse, int cmd, char *arg)
+{
+  NEOERR *err;
+  CSTREE *node;
+
+  /* ne_warn ("linclude: %s", arg); */
+  err = alloc_node (&node);
+  if (err) return nerr_pass(err);
+  node->cmd = cmd;
+  if (arg[0] == '!')
+    node->flags |= CSF_REQUIRED;
+  arg++;
+  /* Validate arg is a var (regex /^[#" ]$/) */
+  err = parse_expr (parse, arg, &(node->arg1));
+  if (err)
+  {
+    dealloc_node(&node);
+    return nerr_pass(err);
+  }
+
+  *(parse->next) = node;
+  parse->next = &(node->next);
+  parse->current = node;
+  
+  return STATUS_OK;
+}
+
 static NEOERR *alt_parse (CSPARSE *parse, int cmd, char *arg)
 {
   NEOERR *err;
@@ -1629,6 +1660,50 @@
   return nerr_pass(err);
 }
 
+static NEOERR *linclude_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
+{
+  NEOERR *err = STATUS_OK;
+  CSARG val;
+
+  err = eval_expr(parse, &(node->arg1), &val);
+  if (err) return nerr_pass(err);
+  if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM))
+  { 
+    char buf[256];
+    long int n_val;
+
+    n_val = arg_eval_num (parse, &val);
+    snprintf (buf, sizeof(buf), "%ld", n_val);
+    err = parse->output_cb (parse->output_ctx, buf);
+  }
+  else
+  {
+    char *s = arg_eval (parse, &val);
+    
+    if (s)
+    {
+      CSPARSE *cs = NULL;
+      do {
+	err = cs_init(&cs, parse->hdf);
+	if (err) break;
+	err = cs_parse_file(cs, s);
+	if (!(node->flags & CSF_REQUIRED))
+	{
+	  nerr_handle(&err, NERR_NOT_FOUND);
+	}
+	if (err) break;
+	err = cs_render(cs, parse->output_ctx, parse->output_cb);
+	if (err) break;
+      } while (0);
+      cs_destroy(&cs);
+    }
+  }
+  if (val.alloc) free(val.s);
+
+  *next = node->next;
+  return nerr_pass(err);
+}
+
 /* if the expr evaluates to true, display it, else render the alternate */
 static NEOERR *alt_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
 {
@@ -1962,7 +2037,13 @@
   parse->next = &(node->next);
   parse->current = node;
 
-  return nerr_pass (cs_parse_file (parse, s));
+  err = cs_parse_file(parse, s);
+  if (!(node->flags & CSF_REQUIRED))
+  {
+    nerr_handle(&err, NERR_NOT_FOUND);
+  }
+
+  return nerr_pass (err);
 }
 
 static NEOERR *def_parse (CSPARSE *parse, int cmd, char *arg)
@@ -2558,14 +2639,15 @@
 
 static NEOERR *render_node (CSPARSE *parse, CSTREE *node)
 {
-  NEOERR *err;
+  NEOERR *err = STATUS_OK;
 
   while (node != NULL)
   {
     /* ne_warn ("%s %08x", Commands[node->cmd].cmd, node); */
     err = (*(Commands[node->cmd].eval_handler))(parse, node, &node);
+    if (err) break;
   }
-  return STATUS_OK;
+  return nerr_pass(err);
 }
 
 NEOERR *cs_render (CSPARSE *parse, void *ctx, CSOUTFUNC cb)
diff -ur clearsilver-0.6.1/util/Makefile clearsilver-0.6.2/util/Makefile
--- clearsilver-0.6.1/util/Makefile	Tue Apr 30 20:05:17 2002
+++ clearsilver-0.6.2/util/Makefile	Fri May 10 17:41:07 2002
@@ -9,7 +9,7 @@
 UTL_LIB = $(LIB_DIR)libneo_utl.a
 UTL_SRC = neo_err.c neo_files.c neo_misc.c neo_test.c ulist.c neo_hdf.c \
 	  neo_str.c ulocks.c skiplist.c dict.c neo_date.c rcfs.c \
-	  wildmat.c
+	  wildmat.c filter.c
 ifeq ($(USE_DB2),1)
 UTL_SRC += wdb.c
 endif
diff -ur clearsilver-0.6.1/util/neo_hdf.c clearsilver-0.6.2/util/neo_hdf.c
--- clearsilver-0.6.1/util/neo_hdf.c	Thu Apr 25 18:47:18 2002
+++ clearsilver-0.6.2/util/neo_hdf.c	Fri May 10 12:39:59 2002
@@ -621,29 +621,6 @@
   return nerr_raise (NERR_NOT_FOUND, "Unable to find %s", src);
 }
 
-/* grody bubble sort from Wheeler, but sorting a singly linked list
- * is annoying */
-void hdf_sort_obj_bubble(HDF *h, int (*compareFunc)(HDF *, HDF *))
-{
-  HDF *p, *c = hdf_obj_child(h);
-  HDF *prev;
-  int swapped;
-
-  do {
-    swapped = 0;
-    for (p = c, prev = c; p && p->next; prev = p, p = p->next) {
-      if (compareFunc(p, p->next) > 0) {
-	HDF *tmp = p->next;
-	prev->next = tmp;
-	p->next = tmp->next;
-	tmp->next = p;
-	p = tmp;
-	swapped = 1;
-      }
-    }
-  } while (swapped);
-}
-
 /* Ok, this version avoids the bubble sort by walking the level once to
  * load them all into a ULIST, qsort'ing the list, and then dumping them
  * back out... */
@@ -860,73 +837,73 @@
 
 /* BUG: currently, this only prints something if there is a value...
  * but we now allow attributes on nodes with no value... */
-NEOERR* hdf_dump(HDF *hdf, char *prefix)
+
+static void gen_ml_break(char *ml, size_t len)
 {
-  char *p;
-  char op = '=';
+  int nlen;
+  int x = 0;
 
-  if (hdf->value)
+  ml[x++] = '\n';
+  nlen = 2 + (random() % (len-5));
+  if (nlen == 0)
   {
-    if (hdf->link) op = ':';
-    if (prefix)
-    {
-      printf("%s.%s ", prefix, hdf->name);
-    }
-    else
-    {
-      printf("%s ", hdf->name);
-    }
-    if (hdf->attr)
-    {
-      HDF_ATTR *attr = hdf->attr;
-      char *v = NULL;
-      fputs("[", stdout);
-      while (attr != NULL)
-      {
-	if (attr->value == NULL || !strcmp(attr->value, "1"))
-	  printf("%s", attr->key);
-	else
-	{
-	  v = repr_string_alloc(attr->value);
-
-	  if (v == NULL) 
-	    return nerr_raise(NERR_NOMEM, "Unable to repr attr %s value %s", attr->key, attr->value);
-	  printf("%s=%s", attr->key, v);
-	  free(v);
-	}
-	if (attr->next)
-	  fputs(", ", stdout);
-	attr = attr->next;
-      }
-      printf("] ");
-    }
-    printf("%c %s\n", op, hdf->value);
+    nlen = len / 2;
   }
-  if (hdf->child)
+  while (nlen)
   {
-    if (prefix)
-    {
-      p = (char *) malloc (strlen(hdf->name) + strlen(prefix) + 2);
-      sprintf (p, "%s.%s", prefix, hdf->name);
-      hdf_dump(hdf->child, p);
-      free(p);
-    }
-    else
-    {
-      hdf_dump(hdf->child, hdf->name);
-    }
-  }
-  if (hdf->next)
-  {
-    hdf_dump(hdf->next, prefix);
+    ml[x++] = ('A' + random() % 26);
+    nlen--;
   }
+  ml[x++] = '\n';
+  ml[x] = '\0';
+}
+
+typedef NEOERR *(*DUMPF_CB)(void *rock, char *fmt, ...);
+
+static NEOERR *_fp_dump_cb (void *rock, char *fmt, ...)
+{
+  FILE *fp = (FILE *)rock;
+  va_list ap;
+  
+  va_start (ap, fmt);
+  vfprintf(fp, fmt, ap);
+  va_end(ap);
   return STATUS_OK;
 }
 
-NEOERR* hdf_dump_str(HDF *hdf, char *prefix, int compact, STRING *str)
+static NEOERR *_string_dump_cb (void *rock, char *fmt, ...)
+{
+  NEOERR *err;
+  STRING *str = (STRING *)rock;
+  va_list ap;
+  
+  va_start (ap, fmt);
+  err = string_appendvf(str, fmt, ap);
+  va_end(ap);
+  return nerr_pass(err);
+}
+
+#define DUMP_TYPE_DOTTED 0
+#define DUMP_TYPE_COMPACT 1
+#define DUMP_TYPE_PRETTY 2
+
+static NEOERR* hdf_dump_cb(HDF *hdf, char *prefix, int dtype, int lvl, void *rock, DUMPF_CB dump_cbf)
 {
   NEOERR *err;
   char *p, op;
+  char ml[10] = "\nEOM\n";
+  int ml_len = strlen(ml);
+  char whsp[256] = "";
+
+  if (dtype == DUMP_TYPE_PRETTY)
+  {
+    memset(whsp, ' ', 256);
+    if (lvl > 127)
+      lvl = 127;
+    whsp[lvl*2] = '\0';
+  }
+
+  if (hdf != NULL) hdf = hdf->child;
 
   while (hdf != NULL)
   {
@@ -934,13 +911,13 @@
     if (hdf->value)
     {
       if (hdf->link) op = ':';
-      if (prefix && !compact)
+      if (prefix && (dtype == DUMP_TYPE_DOTTED))
       {
-	err = string_appendf (str, "%s.%s", prefix, hdf->name);
+	err = dump_cbf(rock, "%s.%s", prefix, hdf->name);
       }
       else
       {
-	err = string_append (str, hdf->name);
+	err = dump_cbf(rock, "%s%s", whsp, hdf->name);
       }
       if (err) return nerr_pass (err);
       if (hdf->attr)
@@ -948,67 +925,74 @@
 	HDF_ATTR *attr = hdf->attr;
 	char *v = NULL;
 
-	err = string_append(str, " [");
+	err = dump_cbf(rock, " [");
 	if (err) return nerr_pass(err);
 	while (attr != NULL)
 	{
 	  if (attr->value == NULL || !strcmp(attr->value, "1"))
-	    err = string_append(str, attr->key);
+	    err = dump_cbf(rock, "%s", attr->key);
 	  else
 	  {
 	    v = repr_string_alloc(attr->value);
 
 	    if (v == NULL) 
 	      return nerr_raise(NERR_NOMEM, "Unable to repr attr %s value %s", attr->key, attr->value);
-	    err = string_appendf(str, "%s=%s", attr->key, v);
+	    err = dump_cbf(rock, "%s=%s", attr->key, v);
 	    free(v);
 	  }
 	  if (err) return nerr_pass(err);
 	  if (attr->next)
 	  {
-	    err = string_append(str, ", ");
+	    err = dump_cbf(rock, ", ");
 	    if (err) return nerr_pass(err);
 	  }
 	  attr = attr->next;
 	}
-	err = string_append(str, "] ");
+	err = dump_cbf(rock, "] ");
 	if (err) return nerr_pass(err);
       }
       if (strchr (hdf->value, '\n'))
       {
+	int vlen = strlen(hdf->value);
+
+	while (strstr(hdf->value, ml) || ((vlen > ml_len) && !strncmp(hdf->value + vlen - ml_len + 1, ml, strlen(ml) - 1)))
+	{
+	  gen_ml_break(ml, sizeof(ml));
+	  ml_len = strlen(ml);
+	}
 	if (hdf->value[strlen(hdf->value)-1] != '\n')
-	  err = string_appendf (str, " << EOM\n%s\nEOM\n", hdf->value);
+	  err = dump_cbf(rock, " << %s%s%s", ml+1, hdf->value, ml);
 	else
-	  err = string_appendf (str, " << EOM\n%sEOM\n", hdf->value);
+	  err = dump_cbf(rock, " << %s%s%s", ml+1, hdf->value, ml+1);
       }
       else
       {
-	err = string_appendf (str, " %c %s\n", op, hdf->value);
+	err = dump_cbf(rock, " %c %s\n", op, hdf->value);
       }
       if (err) return nerr_pass (err);
     }
     if (hdf->child)
     {
-      if (prefix && !compact)
+      if (prefix && (dtype == DUMP_TYPE_DOTTED))
       {
 	p = (char *) malloc (strlen(hdf->name) + strlen(prefix) + 2);
 	sprintf (p, "%s.%s", prefix, hdf->name);
-	err = hdf_dump_str (hdf->child, p, compact, str);
+	err = hdf_dump_cb (hdf, p, dtype, lvl+1, rock, dump_cbf);
 	free(p);
       }
       else
       {
-	if (compact && hdf->name)
+	if (hdf->name && (dtype != DUMP_TYPE_DOTTED))
 	{
-	  err = string_appendf(str, "%s {\n", hdf->name);
+	  err = dump_cbf(rock, "%s%s {\n", whsp, hdf->name);
 	  if (err) return nerr_pass (err);
-	  err = hdf_dump_str (hdf->child, hdf->name, compact, str);
+	  err = hdf_dump_cb (hdf, hdf->name, dtype, lvl+1, rock, dump_cbf);
 	  if (err) return nerr_pass (err);
-	  err = string_append(str, "}\n");
+	  err = dump_cbf(rock, "%s}\n", whsp);
 	}
 	else
 	{
-	  err = hdf_dump_str (hdf->child, hdf->name, compact, str);
+	  err = hdf_dump_cb (hdf, hdf->name, dtype, lvl+1, rock, dump_cbf);
 	}
       }
       if (err) return nerr_pass (err);
@@ -1018,75 +1002,19 @@
   return STATUS_OK;
 }
 
-NEOERR* hdf_dump_format (HDF *hdf, int lvl, FILE *fp)
+NEOERR* hdf_dump_str (HDF *hdf, char *prefix, int dtype, STRING *str)
 {
-  char prefix[256];
-  char op;
-
-  memset(prefix, ' ', 256);
-  if (lvl > 127)
-    lvl = 127;
-  prefix[lvl*2] = '\0';
+  return nerr_pass(hdf_dump_cb(hdf, prefix, dtype, 0, str, _string_dump_cb));
+}
 
-  while (hdf != NULL)
-  {
-    op = '=';
-    if (hdf->value)
-    {
-      if (hdf->link) op = ':';
-      fprintf(fp, "%s%s", prefix, hdf->name);
-      if (hdf->attr)
-      {
-	HDF_ATTR *attr = hdf->attr;
-	char *v = NULL;
-	fputs("[", fp);
-	while (attr != NULL)
-	{
-	  if (attr->value == NULL || !strcmp(attr->value, "1"))
-	    fprintf(fp, "%s", attr->key);
-	  else
-	  {
-	    v = repr_string_alloc(attr->value);
+NEOERR* hdf_dump(HDF *hdf, char *prefix)
+{
+  return nerr_pass(hdf_dump_cb(hdf, prefix, DUMP_TYPE_DOTTED, 0, stdout, _fp_dump_cb));
+}
 
-	    if (v == NULL) 
-	      return nerr_raise(NERR_NOMEM, "Unable to repr attr %s value %s", attr->key, attr->value);
-	    fprintf(fp, "%s=%s", attr->key, v);
-	    free(v);
-	  }
-	  if (attr->next)
-	    fputs(", ", fp);
-	  attr = attr->next;
-	}
-	fputs("] ", fp);
-      }
-      if (strchr (hdf->value, '\n'))
-      {
-	if (hdf->value[strlen(hdf->value)-1] != '\n')
-	  fprintf(fp, " << EOM\n%s\nEOM\n", hdf->value);
-	else
-	  fprintf(fp, " << EOM\n%sEOM\n", hdf->value);
-      }
-      else
-      {
-	fprintf(fp, " %c %s\n", op, hdf->value);
-      }
-    }
-    if (hdf->child)
-    {
-      if (hdf->name)
-      {
-	fprintf(fp, "%s%s {\n", prefix, hdf->name);
-	hdf_dump_format(hdf->child, lvl+1, fp);
-	fprintf(fp, "%s}\n", prefix);
-      }
-      else
-      {
-	hdf_dump_format(hdf->child, lvl, fp);
-      }
-    }
-    hdf = hdf->next;
-  }
-  return STATUS_OK;
+NEOERR* hdf_dump_format (HDF *hdf, int lvl, FILE *fp)
+{
+  return nerr_pass(hdf_dump_cb(hdf, "", DUMP_TYPE_PRETTY, 0, fp, _fp_dump_cb));
 }
 
 NEOERR *hdf_write_file (HDF *hdf, char *path)
@@ -1118,8 +1046,15 @@
     string_clear (&str);
     return nerr_pass(err);
   }
-
-  *s = str.buf;
+  if (str.buf == NULL)
+  {
+    *s = strdup("");
+    if (*s == NULL) return nerr_raise(NERR_NOMEM, "Unable to allocate empty string");
+  }
+  else
+  {
+    *s = str.buf;
+  }
 
   return STATUS_OK;
 }
diff -ur clearsilver-0.6.1/util/neo_str.c clearsilver-0.6.2/util/neo_str.c
--- clearsilver-0.6.1/util/neo_str.c	Thu Apr 25 18:47:18 2002
+++ clearsilver-0.6.2/util/neo_str.c	Mon May  6 16:16:24 2002
@@ -20,6 +20,12 @@
 #include "neo_misc.h"
 #include "ulist.h"
 
+#if !defined(va_copy) && defined(__va_copy)
+#define va_copy(dest,src) __va_copy(dest,src)
+#else
+#define va_copy(dest,src) ((dest) = (src))
+#endif
+
 char *neos_strip (char *s)
 {
   int x;
@@ -36,7 +42,7 @@
 {
   int n = strlen (s)-1;
 
-  while (n > 0 && isspace(s[n]))
+  while (n >= 0 && isspace(s[n]))
   {
     s[n] = '\0';
     n--;
@@ -134,7 +140,9 @@
   NEOERR *err;
   char buf[4096];
   int bl, size;
+  va_list tmp;
 
+  va_copy(tmp, ap);
   /* determine length */
   size = sizeof (buf);
   bl = vsnprintf (buf, size, fmt, ap);
@@ -143,6 +151,7 @@
 
   err = string_check_length (str, bl+1);
   if (err != STATUS_OK) return nerr_pass (err);
+  va_copy(ap, tmp);
   vsprintf (str->buf + str->len, fmt, ap);
   str->len += bl;
   str->buf[str->len] = '\0';
@@ -244,7 +253,12 @@
   char buf[4096];
   char *b = NULL;
   int bl, size;
+  va_list tmp;
 
+/* PPC doesn't like you re-using a va_list... and it might not be
+ * supposed to work at all */
+  va_copy(tmp, ap);
+  
   size = sizeof (buf);
   bl = vsnprintf (buf, sizeof (buf), fmt, ap);
   if (bl > -1 && bl < size)
@@ -259,6 +273,7 @@
   if (b == NULL) return NULL;
   while (1)
   {
+    va_copy(ap, tmp);
     bl = vsnprintf (b, size, fmt, ap);
     if (bl > -1 && bl < size)
       return b;
diff -ur clearsilver-0.6.1/util/wdb.c clearsilver-0.6.2/util/wdb.c
--- clearsilver-0.6.1/util/wdb.c	Mon Aug  6 14:28:17 2001
+++ clearsilver-0.6.2/util/wdb.c	Fri May 10 17:41:07 2002
@@ -7,6 +7,16 @@
  *
  * Copyright (C) 2001 by Brandon Long
  */
+/*
+ * The wdb is a wrapper around the sleepycat db library which adds
+ * a relatively simple data/column definition.  In many respects, this
+ * code is way more complicated than it ever needed to be, but it works,
+ * so I'm loathe to "fix" it.
+ *
+ * One of they key features of this is the ability to update the
+ * "schema" of the wdb without changing all of the existing rows of
+ * data.
+ */
 
 #include <unistd.h>
 #include <stdlib.h>
