diff -Nrbu clearsilver-0.9.12/cgi/cgi.c clearsilver-0.9.13/cgi/cgi.c
--- clearsilver-0.9.12/cgi/cgi.c	Wed Sep 29 17:26:02 2004
+++ clearsilver-0.9.13/cgi/cgi.c	Wed Nov 24 14:55:25 2004
@@ -1018,7 +1018,16 @@
 /* This ws strip function is Dave's version, designed to make debug
  * easier, and the output a bit smaller... but not as small as it could
  * be: essentially, it strips all empty lines, all extra space at the
- * end of the line, except in pre/textarea tags */
+ * end of the line, except in pre/textarea tags.
+ *
+ * Ok, expanding to 3 levels:
+ * 0 - No stripping
+ * 1 - Dave's debug stripper (as above)
+ * 2 - strip all extra white space
+ *
+ * We don't currently strip white space in a tag
+ *
+ * */
 
 #if 0
 static void debug_output(char *header, char *s, int n)
@@ -1033,14 +1042,17 @@
 }
 #endif 
 
-void cgi_html_ws_strip(STRING *str)
+void cgi_html_ws_strip(STRING *str, int level)
 {
   int ws = 0;
-  int seen_nonws = 0;
+  int seen_nonws = level > 1;
   int i, o, l;
   unsigned char *ch;
 
   i = o = 0;
+  if (str->len) {
+    ws = isspace(str->buf[0]);
+  }
   while (i < str->len)
   {
     if (str->buf[i] == '<')
@@ -1116,8 +1128,8 @@
        * erasing all blank lines */
       while (o && isspace(str->buf[o-1])) o--;
       str->buf[o++] = str->buf[i++];
-      ws = 0;
-      seen_nonws = 0;
+      ws = level > 1;
+      seen_nonws = level > 1;
     }
     else if (seen_nonws && isspace(str->buf[i]))
     {
@@ -1152,14 +1164,14 @@
   int use_gzip = 0;
   int do_debug = 0;
   int do_timefooter = 0;
-  int do_ws_strip = 0;
+  int ws_strip_level = 0;
   char *s, *e;
 
   s = hdf_get_value (cgi->hdf, "Query.debug", NULL);
   e = hdf_get_value (cgi->hdf, "Config.DebugPassword", NULL);
   if (s && e && !strcmp(s, e)) do_debug = 1;
   do_timefooter = hdf_get_int_value (cgi->hdf, "Config.TimeFooter", 1);
-  do_ws_strip = hdf_get_int_value (cgi->hdf, "Config.WhiteSpaceStrip", 1);
+  ws_strip_level = hdf_get_int_value (cgi->hdf, "Config.WhiteSpaceStrip", 1);
 
   dis = ne_timef();
   s = hdf_get_value (cgi->hdf, "cgiout.ContentType", "text/html");
@@ -1246,9 +1258,9 @@
       if (err != STATUS_OK) return nerr_pass(err);
     }
 
-    if (do_ws_strip)
+    if (ws_strip_level)
     {
-      cgi_html_ws_strip(str);
+      cgi_html_ws_strip(str, ws_strip_level);
     }
 
     if (do_debug)
@@ -1365,6 +1377,23 @@
   return nerr_pass(convert_text_html_alloc(str, strlen(str), ret));
 }
 
+NEOERR *cgi_register_strfuncs(CSPARSE *cs)
+{
+  NEOERR *err;
+
+  err = cs_register_strfunc(cs, "url_escape", cgi_url_escape);
+  if (err != STATUS_OK) return nerr_pass(err);
+  err = cs_register_strfunc(cs, "html_escape", cgi_html_escape_strfunc);
+  if (err != STATUS_OK) return nerr_pass(err);
+  err = cs_register_strfunc(cs, "text_html", cgi_text_html_strfunc);
+  if (err != STATUS_OK) return nerr_pass(err);
+  err = cs_register_strfunc(cs, "js_escape", cgi_js_escape);
+  if (err != STATUS_OK) return nerr_pass(err);
+  err = cs_register_strfunc(cs, "html_strip", cgi_html_strip_strfunc);
+  if (err != STATUS_OK) return nerr_pass(err);
+  return STATUS_OK;
+}
+
 NEOERR *cgi_cs_init(CGI *cgi, CSPARSE **cs)
 {
   NEOERR *err;
@@ -1375,15 +1404,7 @@
   {
     err = cs_init (cs, cgi->hdf);
     if (err != STATUS_OK) break;
-    err = cs_register_strfunc(*cs, "url_escape", cgi_url_escape);
-    if (err != STATUS_OK) break;
-    err = cs_register_strfunc(*cs, "html_escape", cgi_html_escape_strfunc);
-    if (err != STATUS_OK) break;
-    err = cs_register_strfunc(*cs, "text_html", cgi_text_html_strfunc);
-    if (err != STATUS_OK) break;
-    err = cs_register_strfunc(*cs, "js_escape", cgi_js_escape);
-    if (err != STATUS_OK) break;
-    err = cs_register_strfunc(*cs, "html_strip", cgi_html_strip_strfunc);
+    err = cgi_register_strfuncs(*cs);
     if (err != STATUS_OK) break;
   } while (0);
 
@@ -1410,15 +1431,7 @@
   {
     err = cs_init (&cs, cgi->hdf);
     if (err != STATUS_OK) break;
-    err = cs_register_strfunc(cs, "url_escape", cgi_url_escape);
-    if (err != STATUS_OK) break;
-    err = cs_register_strfunc(cs, "html_escape", cgi_html_escape_strfunc);
-    if (err != STATUS_OK) break;
-    err = cs_register_strfunc(cs, "text_html", cgi_text_html_strfunc);
-    if (err != STATUS_OK) break;
-    err = cs_register_strfunc(cs, "js_escape", cgi_js_escape);
-    if (err != STATUS_OK) break;
-    err = cs_register_strfunc(cs, "html_strip", cgi_html_strip_strfunc);
+    err = cgi_register_strfuncs(cs);
     if (err != STATUS_OK) break;
     err = cs_parse_file (cs, cs_file);
     if (err != STATUS_OK) break;
diff -Nrbu clearsilver-0.9.12/cgi/cgi.h clearsilver-0.9.13/cgi/cgi.h
--- clearsilver-0.9.12/cgi/cgi.h	Wed Jul 28 15:17:51 2004
+++ clearsilver-0.9.13/cgi/cgi.h	Wed Nov 24 14:55:25 2004
@@ -453,7 +453,8 @@
 NEOERR *cgi_html_strip_strfunc(unsigned char *str, unsigned char **ret);
 NEOERR *cgi_html_escape_strfunc(unsigned char *str, unsigned char **ret);
 NEOERR *cgi_js_escape (unsigned char *buf, unsigned char **esc);
-void cgi_html_ws_strip(STRING *str);
+void cgi_html_ws_strip_level(STRING *str, int level);
+NEOERR *cgi_register_strfuncs(CSPARSE *cs);
 
 /* internal use only */
 NEOERR * parse_rfc2388 (CGI *cgi);
diff -Nrbu clearsilver-0.9.12/java-jni/j_neo_cs.c clearsilver-0.9.13/java-jni/j_neo_cs.c
--- clearsilver-0.9.12/java-jni/j_neo_cs.c	Wed Sep 29 17:23:16 2004
+++ clearsilver-0.9.13/java-jni/j_neo_cs.c	Wed Nov 24 14:55:27 2004
@@ -42,15 +42,7 @@
 
   err = cs_init(&cs, hdf);
   if (err != STATUS_OK) return jNeoErr(env,err);
-  err = cs_register_strfunc(cs, "url_escape", cgi_url_escape);
-  if (err != STATUS_OK) return jNeoErr(env,err);
-  err = cs_register_strfunc(cs, "html_escape", cgi_html_escape_strfunc);
-  if (err != STATUS_OK) return jNeoErr(env,err);
-  err = cs_register_strfunc(cs, "text_html", cgi_text_html_strfunc);
-  if (err != STATUS_OK) return jNeoErr(env,err);
-  err = cs_register_strfunc(cs, "js_escape", cgi_js_escape);
-  if (err != STATUS_OK) return jNeoErr(env,err);
-  err = cs_register_strfunc(cs, "html_strip", cgi_html_strip_strfunc);
+  err = cgi_register_strfuncs(cs);
   if (err != STATUS_OK) return jNeoErr(env,err);
 
   return (jint) cs;
@@ -122,12 +114,12 @@
   STRING str;
   NEOERR *err;
   jstring retval;
-  int do_ws_strip = 0;
+  int ws_strip_level = 0;
   int do_debug = 0;
 
   // TODO: perhaps we should pass in whether this is html as well...
   do_debug = hdf_get_int_value(cs->hdf, "ClearSilver.DisplayDebug", 0);
-  do_ws_strip = hdf_get_int_value(cs->hdf, "ClearSilver.WhiteSpaceStrip", 0);
+  ws_strip_level = hdf_get_int_value(cs->hdf, "ClearSilver.WhiteSpaceStrip", 0);
   
   string_init(&str);
   err = cs_render(cs, &str, render_cb);
@@ -137,8 +129,8 @@
     return NULL; 
   }
 
-  if (do_ws_strip) {
-    cgi_html_ws_strip(&str);
+  if (ws_strip_level) {
+    cgi_html_ws_strip(&str, ws_strip_level);
   }
 
   if (do_debug) {
diff -Nrbu clearsilver-0.9.12/perl/ClearSilver.xs clearsilver-0.9.13/perl/ClearSilver.xs
--- clearsilver-0.9.12/perl/ClearSilver.xs	Tue Mar 16 00:44:19 2004
+++ clearsilver-0.9.13/perl/ClearSilver.xs	Wed Nov 24 14:55:28 2004
@@ -327,6 +327,9 @@
 	  RETVAL = NULL;
 	} else {
 	  cs->err = cs_init(&(cs->cs), hdf->hdf);
+	  if (cs->err == STATUS_OK) {
+	    cs->err = cgi_register_strfuncs(cs->cs);
+	  }
 	  RETVAL = cs;
 	}
     OUTPUT:
diff -Nrbu clearsilver-0.9.12/python/neo_cs.c clearsilver-0.9.13/python/neo_cs.c
--- clearsilver-0.9.12/python/neo_cs.c	Wed Jul 28 15:17:41 2004
+++ clearsilver-0.9.13/python/neo_cs.c	Wed Nov 24 14:55:30 2004
@@ -96,6 +96,8 @@
 
   err = cs_init (&cs, hdf);
   if (err) return p_neo_error (err);
+  err = cgi_register_strfuncs(cs);
+  if (err) return p_neo_error (err);
   return p_cs_to_object (cs);
 }
 
diff -Nrbu clearsilver-0.9.12/ruby/ext/hdf/neo_cs.c clearsilver-0.9.13/ruby/ext/hdf/neo_cs.c
--- clearsilver-0.9.12/ruby/ext/hdf/neo_cs.c	Wed Jul 28 15:17:45 2004
+++ clearsilver-0.9.13/ruby/ext/hdf/neo_cs.c	Wed Nov 24 14:55:31 2004
@@ -41,7 +41,8 @@
   if (hdf == NULL) rb_raise(eHdfError, "must include an Hdf object");
 
   err = cs_init (&cs, hdf);
-
+  if (err) Srb_raise(r_neo_error(err));
+  err = cgi_register_strfuncs(cs);
   if (err) Srb_raise(r_neo_error(err));
 
   r_cs = Data_Wrap_Struct(class, 0, c_free, cs);
diff -Nrbu clearsilver-0.9.12/rules.mk.in clearsilver-0.9.13/rules.mk.in
--- clearsilver-0.9.12/rules.mk.in	Mon Jan  5 02:38:28 2004
+++ clearsilver-0.9.13/rules.mk.in	Tue Nov 16 15:05:10 2004
@@ -73,7 +73,7 @@
 PERL	   = @PERL@
 RUBY       = @RUBY@
 
-CFLAGS     = @CFLAGS@ -Wall -c -I$(NEOTONIC_ROOT) @CPPFLAGS@
+CFLAGS     = @CFLAGS@ -Wall -I$(NEOTONIC_ROOT) @CPPFLAGS@
 CPPFLAGS   = -I$(NEOTONIC_ROOT) @CPPFLAGS@
 OUTPUT_OPTION = -o $@
 LD         = $(CC) -o
@@ -128,7 +128,7 @@
 ## endif
 
 .c.o:
-	$(CC) $(CFLAGS) $(OUTPUT_OPTION) $<
+	$(CC) $(CFLAGS) $(OUTPUT_OPTION) -c $<
 
 everything: depend all
 
diff -Nrbu clearsilver-0.9.12/util/neo_err.c clearsilver-0.9.13/util/neo_err.c
--- clearsilver-0.9.12/util/neo_err.c	Wed Jul 28 15:17:42 2004
+++ clearsilver-0.9.13/util/neo_err.c	Wed Oct 27 14:09:56 2004
@@ -348,14 +348,14 @@
   *err = STATUS_OK;
 }
 
-int nerr_handle (NEOERR **err, int type)
+int nerr_handle (NEOERR **err, int etype)
 {
   NEOERR *walk = *err;
 
   while (walk != STATUS_OK && walk != INTERNAL_ERR)
   {
 
-    if (walk->error == type)
+    if (walk->error == etype)
     {
       _err_free(*err);
       *err = STATUS_OK;
@@ -364,12 +364,12 @@
     walk = walk->next;
   }
 
-  if (walk == STATUS_OK && (NEOERR *)type == STATUS_OK)
+  if (walk == STATUS_OK && etype == STATUS_OK_INT)
     return 1;
   if (walk == STATUS_OK)
     return 0;
 
-  if (walk == INTERNAL_ERR && (NEOERR *)type == INTERNAL_ERR)
+  if (walk == INTERNAL_ERR && etype == INTERNAL_ERR_INT)
   {
     *err = STATUS_OK;
     return 1;
@@ -380,22 +380,22 @@
   return 0;
 }
 
-int nerr_match (NEOERR *err, int type)
+int nerr_match (NEOERR *err, int etype)
 {
   while (err != STATUS_OK && err != INTERNAL_ERR)
   {
 
-    if (err->error == type)
+    if (err->error == etype)
       return 1;
     err = err->next;
   }
 
-  if (err == STATUS_OK && (NEOERR *)type == STATUS_OK)
+  if (err == STATUS_OK && etype == STATUS_OK_INT)
     return 1;
   if (err == STATUS_OK)
     return 0;
 
-  if (err == INTERNAL_ERR && (NEOERR *)type == INTERNAL_ERR)
+  if (err == INTERNAL_ERR && etype == INTERNAL_ERR_INT)
     return 1;
   if (err == INTERNAL_ERR)
     return 0;
diff -Nrbu clearsilver-0.9.12/util/neo_err.h clearsilver-0.9.13/util/neo_err.h
--- clearsilver-0.9.12/util/neo_err.h	Wed Jul 28 15:17:42 2004
+++ clearsilver-0.9.13/util/neo_err.h	Wed Nov 10 16:45:46 2004
@@ -14,15 +14,19 @@
 
 __BEGIN_DECLS
 
+/* For 64 bit systems which don't like mixing ints and pointers, we have the
+ * _INT version for doing that comparison */
 #define STATUS_OK ((NEOERR *)0)
+#define STATUS_OK_INT 0
 #define INTERNAL_ERR ((NEOERR *)1)
+#define INTERNAL_ERR_INT 1
 
 /* NEOERR flags */
 #define NE_IN_USE (1<<0)
 
 typedef int NERR_TYPE;
 
-/* Types */
+/* Predefined Error Types - These are all registered in nerr_init */
 extern NERR_TYPE NERR_PASS;
 extern NERR_TYPE NERR_ASSERT;
 extern NERR_TYPE NERR_NOT_FOUND;
@@ -111,7 +115,21 @@
 void nerr_log_error (NEOERR *err);
 
 #include "util/neo_str.h"
+/* function: nerr_error_string
+ * description: returns the string associated with an error (the bottom
+ *              level of the error chain)
+ * arguments: err - error
+ *            str - string to which the data is appended
+ * returns: None - errors appending to the string are ignored
+ */
 void nerr_error_string (NEOERR *err, STRING *str);
+
+/* function: nerr_error_traceback
+ * description: returns the full traceback of the error chain
+ * arguments: err - error
+ *            str - string to which the data is appended
+ * returns: None - errors appending to the string are ignored
+ */
 void nerr_error_traceback (NEOERR *err, STRING *str);
 
 /* function: nerr_ignore
@@ -120,12 +138,47 @@
  */
 void nerr_ignore (NEOERR **err);
 
+/* function: nerr_register
+ * description: register an error type.  This will assign a numeric value
+ *              to the type, and keep track of the "pretty name" for it.
+ * arguments: err - pointer to a NERR_TYPE
+ *            name - pretty name for the error type 
+ * returns: NERR_NOMEM on no memory
+ */
 NEOERR *nerr_register (NERR_TYPE *err, const char *name);
 
+/* function: nerr_init
+ * description: initialize the NEOERR system.  Can be called more than once.
+ *              Is not thread safe.  This registers all of the built in
+ *              error types as defined at the top of this file.  If you don't
+ *              call this, all exceptions will be returned as UnknownError.
+ * arguments: None
+ * returns: possibly NERR_NOMEM, but somewhat unlikely.  Possibly an
+ *          UnknownError if NERR_NOMEM hasn't been registered yet.
+ */
 NEOERR *nerr_init (void);
 
-int nerr_handle (NEOERR **err, NERR_TYPE type);
+/* function: nerr_match
+ * description: nerr_match is used to walk the NEOERR chain and match
+ *              the error against a specific error type.  In exception
+ *              parlance, this would be the equivalent of "catch".
+ *              Typically, you can just compare a NEOERR against STATUS_OK
+ *              or just test for true if you are checking for any error.
+ * arguments: err - the NEOERR that has an error. 
+ *            type - the NEOERR type, as registered with nerr_register
+ * returns: true on match
+ */
 int nerr_match (NEOERR *err, NERR_TYPE type);
+
+/* function: nerr_handle
+ * description: nerr_handle is a convenience function.  It is the equivalent
+ *              of nerr_match, but it will also deallocate the error chain
+ *              on a match.
+ * arguments: err - pointer to a pointer NEOERR 
+ *            type - the NEOERR type, as registered with nerr_register
+ * returns: true on match
+ */
+int nerr_handle (NEOERR **err, NERR_TYPE type);
 
 __END_DECLS
 
diff -Nrbu clearsilver-0.9.12/util/neo_hdf.c clearsilver-0.9.13/util/neo_hdf.c
--- clearsilver-0.9.12/util/neo_hdf.c	Wed Jul 28 15:17:42 2004
+++ clearsilver-0.9.13/util/neo_hdf.c	Fri Nov  5 02:00:21 2004
@@ -118,31 +118,43 @@
 
 static void _dealloc_hdf (HDF **hdf)
 {
-  if (*hdf == NULL) return;
-  if ((*hdf)->child != NULL)
-    _dealloc_hdf(&((*hdf)->child));
-  if ((*hdf)->next != NULL)
-    _dealloc_hdf(&((*hdf)->next));
-  if ((*hdf)->name != NULL)
+  HDF *myhdf = *hdf;
+  HDF *next = NULL;
+
+  if (myhdf == NULL) return;
+  if (myhdf->child != NULL)
+    _dealloc_hdf(&(myhdf->child));
+
+  /* This was easier recursively, but dangerous on long lists, so we
+   * walk it ourselves */
+  next = myhdf->next;
+  while (next != NULL) 
   {
-    free ((*hdf)->name);
-    (*hdf)->name = NULL;
+    myhdf->next = next->next;
+    next->next = NULL;
+    _dealloc_hdf(&next);
+    next = myhdf->next;
   }
-  if ((*hdf)->value != NULL)
+  if (myhdf->name != NULL)
   {
-    if ((*hdf)->alloc_value)
-      free ((*hdf)->value);
-    (*hdf)->value = NULL;
+    free (myhdf->name);
+    myhdf->name = NULL;
   }
-  if ((*hdf)->attr != NULL)
+  if (myhdf->value != NULL)
   {
-    _dealloc_hdf_attr(&((*hdf)->attr));
+    if (myhdf->alloc_value)
+      free (myhdf->value);
+    myhdf->value = NULL;
   }
-  if ((*hdf)->hash != NULL)
+  if (myhdf->attr != NULL)
   {
-    ne_hash_destroy(&(*hdf)->hash);
+    _dealloc_hdf_attr(&(myhdf->attr));
   }
-  free (*hdf);
+  if (myhdf->hash != NULL)
+  {
+    ne_hash_destroy(&myhdf->hash);
+  }
+  free(myhdf);
   *hdf = NULL;
 }
 
diff -Nrbu clearsilver-0.9.12/util/test/Makefile clearsilver-0.9.13/util/test/Makefile
--- clearsilver-0.9.12/util/test/Makefile	Fri Jun 18 19:11:20 2004
+++ clearsilver-0.9.13/util/test/Makefile	Fri Nov  5 02:00:28 2004
@@ -26,6 +26,10 @@
 HDFCOPYTEST_SRC = hdf_copy_test.c
 HDFCOPYTEST_OBJ = $(HDFCOPYTEST_SRC:%.c=%.o)
 
+HDFDEALLOCTEST_EXE = hdf_dealloc_test
+HDFDEALLOCTEST_SRC = hdf_dealloc_test.c
+HDFDEALLOCTEST_OBJ = $(HDFDEALLOCTEST_SRC:%.c=%.o)
+
 NETTEST_EXE = net_test
 NETTEST_SRC = net_test.c
 NETTEST_OBJ = $(NETTEST_SRC:%.c=%.o)
@@ -46,7 +50,7 @@
 LIBS += -L$(LIB_DIR) -lneo_utl 
 
 TARGETS = $(HDFTEST_EXE) $(LISTDIRTEST_EXE) $(HDFCOPYTEST_EXE) \
-	$(HDFSORTTEST_EXE) \
+	$(HDFSORTTEST_EXE) $(HDFDEALLOCTEST_EXE) \
 	$(HDFLOADTEST_EXE) $(NETTEST_EXE) $(DATETEST_EXE) \
 	$(HASHTEST_EXE) $(ULISTTEST_EXE)
 
@@ -60,6 +64,9 @@
 
 $(HDFSORTTEST_EXE): $(HDFSORTTEST_OBJ) $(NTR_LIB)
 	$(LD) $@ $(HDFSORTTEST_OBJ) $(LIBS)
+
+$(HDFDEALLOCTEST_EXE): $(HDFDEALLOCTEST_OBJ) $(NTR_LIB)
+	$(LD) $@ $(HDFDEALLOCTEST_OBJ) $(LIBS)
 
 $(HDFLOADTEST_EXE): $(HDFLOADTEST_OBJ) $(NTR_LIB)
 	$(LD) $@ $(HDFLOADTEST_OBJ) $(LIBS) # -lefence
diff -Nrbu clearsilver-0.9.12/util/test/hdf_dealloc_test.c clearsilver-0.9.13/util/test/hdf_dealloc_test.c
--- clearsilver-0.9.12/util/test/hdf_dealloc_test.c	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.13/util/test/hdf_dealloc_test.c	Fri Nov  5 02:00:28 2004
@@ -0,0 +1,28 @@
+
+
+#include "cs_config.h"
+#include <unistd.h>
+#include "util/neo_misc.h"
+#include "util/neo_hdf.h"
+#include "util/neo_rand.h"
+
+int main(int argc, char *argv[])
+{
+  HDF *hdf = NULL;
+  int i, j;
+
+  hdf_init(&hdf);
+
+  ne_warn("creating 100000x10 nodes");
+  for (i = 0; i < 100000; i++) {
+    char buffer[64];
+    for (j = 0; j < 10; j++) {
+      snprintf(buffer, sizeof(buffer), "node.%d.test.%d", i, j);
+      hdf_set_value(hdf, buffer, "test");
+    }
+  }
+
+  ne_warn("calling dealloc");
+  hdf_destroy(&hdf);    // <-- this takes forever to return with a hugely
+  return 0;
+}
