diff -Nru clearsilver-0.9.11/Makefile clearsilver-0.9.12/Makefile
--- clearsilver-0.9.11/Makefile	Fri May 14 17:37:39 2004
+++ clearsilver-0.9.12/Makefile	Wed Sep 29 18:09:41 2004
@@ -107,8 +107,8 @@
 		mkdir -p $$mdir; \
 	done
 
-CS_DISTDIR = clearsilver-0.9.9
-CS_LABEL = CLEARSILVER-0_9_9
+CS_DISTDIR = clearsilver-0.9.12
+CS_LABEL = CLEARSILVER-0_9_12
 CS_FILES = README README.python INSTALL LICENSE CS_LICENSE rules.mk.in Makefile util cs cgi python scripts mod_ecs imd java-jni perl ruby dso csharp acconfig.h autogen.sh config.guess config.sub configure.in cs_config.h.in mkinstalldirs install-sh ClearSilver.h ports contrib
 cs_dist:
 	@if cvs log Makefile | grep "${CS_LABEL}"; then \
diff -Nru clearsilver-0.9.11/cgi/cgi.c clearsilver-0.9.12/cgi/cgi.c
--- clearsilver-0.9.11/cgi/cgi.c	Wed Jul 28 15:17:51 2004
+++ clearsilver-0.9.12/cgi/cgi.c	Wed Sep 29 17:26:02 2004
@@ -320,7 +320,8 @@
   {
     if (buf[l] == '/' || buf[l] == '+' || buf[l] == '=' || buf[l] == '&' || 
 	buf[l] == '"' || buf[l] == '%' || buf[l] == '?' || buf[l] == '#' ||
-	buf[l] == '<' || buf[l] == '>' || buf[l] < 32 || buf[l] > 122)
+	buf[l] == '<' || buf[l] == '>' || buf[l] == '\'' ||
+        buf[l] < 32 || buf[l] > 122)
     {
       nl += 2;
     } 
@@ -359,7 +360,8 @@
     {
       if (buf[l] == '/' || buf[l] == '+' || buf[l] == '=' || buf[l] == '&' || 
 	  buf[l] == '"' || buf[l] == '%' || buf[l] == '?' || buf[l] == '#' ||
-	  buf[l] == '<' || buf[l] == '>' || buf[l] < 32 || buf[l] > 122)
+	  buf[l] == '<' || buf[l] == '>' || buf[l] == '\'' ||
+          buf[l] < 32 || buf[l] > 122)
       {
 	match = 1;
       }
diff -Nru clearsilver-0.9.11/cs/Makefile clearsilver-0.9.12/cs/Makefile
--- clearsilver-0.9.11/cs/Makefile	Thu Apr 22 00:41:53 2004
+++ clearsilver-0.9.12/cs/Makefile	Wed Aug  4 18:39:01 2004
@@ -32,7 +32,7 @@
 	   test14.cs test15.cs test16.cs test17.cs test18.cs test_var.cs \
 	   test_paren.cs test_chuck.cs test_trak1.cs test_iter.cs \
 	   test_each_array.cs test_name.cs test_with.cs test_numbers.cs \
-	   test_splice.cs
+	   test_splice.cs test_joo.cs
 
 all: $(TARGETS)
 
diff -Nru clearsilver-0.9.11/cs/cs.h clearsilver-0.9.12/cs/cs.h
--- clearsilver-0.9.11/cs/cs.h	Wed Jul 28 15:17:52 2004
+++ clearsilver-0.9.12/cs/cs.h	Wed Sep 29 17:46:33 2004
@@ -137,13 +137,12 @@
 {
   CSTOKEN_TYPE type;
   char *name;
-  int alloc;
-  union
-  {
-    char *s;
-    long int n;
-    HDF *h;
-  } value;
+  int map_alloc;
+  /* These three (s,n,h) used to be a union, but now we sometimes allocate
+   * a buffer in s with the "string" value of n, so its separate */
+  char *s;
+  long int n;
+  HDF *h;
   struct _local_map *next;
 } CS_LOCAL_MAP;
 
@@ -178,6 +177,7 @@
   char *context;         /* A string identifying where the parser is parsing */
   int in_file;           /* Indicates if current context is a file */
   int offset;
+  char *context_string;
 
   char *tag;		/* Usually cs, but can be set via HDF Config.TagStart */
   int taglen;
diff -Nru clearsilver-0.9.11/cs/csparse.c clearsilver-0.9.12/cs/csparse.c
--- clearsilver-0.9.11/cs/csparse.c	Wed Jul 28 15:17:52 2004
+++ clearsilver-0.9.12/cs/csparse.c	Wed Sep 29 17:46:33 2004
@@ -9,6 +9,15 @@
  *
  */
 
+/*
+ * TODO: there is some really ugly pseudo reference counting in here
+ * for allocation of temporary strings (and passing references).  See the alloc
+ * member of various structs for details.  We should move this to an arena
+ * allocator so we can just allocate whenever we need to and just clean up
+ * all the allocation at the end (may require two arenas: one for parese and
+ * one for render)
+ */
+
 #include "cs_config.h"
 
 #include <sys/types.h>
@@ -301,7 +310,6 @@
 
 static char *find_context (CSPARSE *parse, int offset, char *buf, size_t blen)
 {
-  NEOERR *err;
   FILE *fp;
   int dump_err = 1;
   char line[256];
@@ -334,8 +342,8 @@
     }
     else
     {
-      err = uListGet(parse->alloc, -1, (void *)&data);
-      if (!err)
+      data = parse->context_string;
+      if (data != NULL)
       {
 	lineno = 1;
 	while (count < offset)
@@ -349,7 +357,6 @@
       }
       else
       {
-	nerr_ignore(&err);
 	if (parse->context)
 	  snprintf (buf, blen, "[%s:%d]", parse->context, offset);
 	else
@@ -405,6 +412,7 @@
   char *arg;
   int initial_stack_depth;
   int initial_offset;
+  char *initial_context;
   char tmp[256];
 
   err = uListAppend(parse->alloc, ibuf);
@@ -416,8 +424,10 @@
 
   initial_stack_depth = uListLength(parse->stack);
   initial_offset = parse->offset;
+  initial_context = parse->context_string;
 
   parse->offset = 0;
+  parse->context_string = ibuf;
   while (!done)
   {
     /* Stage 1: Find <?cs starter */
@@ -537,6 +547,7 @@
 
 cs_parse_done:
   parse->offset = initial_offset;
+  parse->context_string = initial_context;
   return nerr_pass(err);
 }
 
@@ -574,11 +585,11 @@
   {
     if (c == NULL)
     {
-      return map->value.h;
+      return map->h;
     }
     else
     {
-      return hdf_get_obj (map->value.h, c+1);
+      return hdf_get_obj (map->h, c+1);
     }
   }
   return hdf_get_obj (parse->hdf, name);
@@ -602,12 +613,12 @@
       {
 	if (c == NULL)
 	{
-	  return nerr_pass (hdf_set_value (map->value.h, NULL, value));
+	  return nerr_pass (hdf_set_value (map->h, NULL, value));
 	}
 	else
 	{
 	  *c = '.';
-	  return nerr_pass (hdf_set_value (map->value.h, c+1, value));
+	  return nerr_pass (hdf_set_value (map->h, c+1, value));
 	}
       }
       else
@@ -618,13 +629,13 @@
 	  /* If this is a string, it might be what we're setting,
 	   * ie <?cs set:value = value ?>
 	   */
-	  if (map->type == CS_TYPE_STRING && map->alloc)
-	    tmp = map->value.s;
+	  if (map->type == CS_TYPE_STRING && map->map_alloc)
+	    tmp = map->s;
 	  map->type = CS_TYPE_STRING;
-	  map->alloc = 1;
-	  map->value.s = strdup(value);
+	  map->map_alloc = 1;
+	  map->s = strdup(value);
 	  if (tmp != NULL) free(tmp);
-	  if (map->value.s == NULL && value != NULL)
+	  if (map->s == NULL && value != NULL)
 	    return nerr_raise(NERR_NOMEM, 
 		"Unable to allocate memory to set var");
 
@@ -654,11 +665,11 @@
     {
       if (c == NULL)
       {
-	return hdf_obj_value (map->value.h);
+	return hdf_obj_value (map->h);
       }
       else
       {
-	return hdf_get_value (map->value.h, c+1, NULL);
+	return hdf_get_value (map->h, c+1, NULL);
       }
     }
     /* Hmm, if c != NULL, they are asking for a sub member of something
@@ -668,13 +679,16 @@
      * string that will be deleted... where is it used? */
     else if (map->type == CS_TYPE_STRING)
     {
-      return map->value.s;
+      return map->s;
     }
     else if (map->type == CS_TYPE_NUM)
     {
-      static char buf[40];
-      snprintf (buf, sizeof(buf), "%ld", map->value.n);
-      return buf;
+      char buf[40];
+      if (map->s) return map->s;
+      snprintf (buf, sizeof(buf), "%ld", map->n);
+      map->s = strdup(buf);
+      map->map_alloc = 1;
+      return map->s;
     }
   }
   return hdf_get_value (parse->hdf, name, NULL);
@@ -888,12 +902,12 @@
   CS_OP_COMMA,
   CS_OP_OR,
   CS_OP_AND,
-  CS_OP_NOT | CS_OP_EXISTS,
   CS_OP_EQUAL | CS_OP_NEQUAL,
   CS_OP_GT | CS_OP_GTE | CS_OP_LT | CS_OP_LTE,
   CS_OP_ADD | CS_OP_SUB, 
-  CS_OP_MULT | CS_OP_DIV | CS_OP_MOD | CS_OP_DOT,
-  CS_OP_LBRACKET,
+  CS_OP_MULT | CS_OP_DIV | CS_OP_MOD,
+  CS_OP_NOT | CS_OP_EXISTS,
+  CS_OP_LBRACKET | CS_OP_DOT,
   0
 };
 
@@ -965,7 +979,7 @@
   NEOERR *err;
   char tmp[256];
   char tmp2[256];
-  int x, op = 0;
+  int x, op;
   int m;
 
 #if DEBUG_EXPR_PARSE
@@ -1019,6 +1033,7 @@
   }
   */
 
+  op = 0;
   while (OperatorOrder[op])
   {
     x = ntokens-1;
@@ -1878,7 +1893,7 @@
         if (arg1.op_type & (CS_TYPE_VAR | CS_TYPE_VAR_NUM))
         {
           s1 = arg_eval (parse, &arg1);
-          if (s1 == NULL || *s1 == '\0')
+          if (s1 == NULL)
             result->n = 0;
           else
             result->n = 1;
@@ -2351,6 +2366,8 @@
   CSARG val;
   HDF *var, *child;
 
+  memset(&each_map, 0, sizeof(each_map));
+
   err = eval_expr(parse, &(node->arg2), &val);
   if (err) return nerr_pass(err);
 
@@ -2371,8 +2388,12 @@
 	child = hdf_obj_child (var);
 	while (child != NULL)
 	{
-	  each_map.value.h = child;
+	  each_map.h = child;
 	  err = render_node (parse, node->case_0);
+          if (each_map.map_alloc) {
+            free(each_map.s);
+            each_map.s = NULL;
+          }
 	  if (err != STATUS_OK) break;
 	  child = hdf_obj_next (child);
 	}
@@ -2396,6 +2417,8 @@
   CSARG val;
   HDF *var;
 
+  memset(&with_map, 0, sizeof(with_map));
+
   err = eval_expr(parse, &(node->arg2), &val);
   if (err) return nerr_pass(err);
 
@@ -2409,10 +2432,11 @@
       with_map.type = CS_TYPE_VAR;
       with_map.name = node->arg1.s;
       with_map.next = parse->locals;
-      with_map.value.h = var;
+      with_map.h = var;
       parse->locals = &with_map;
       err = render_node (parse, node->case_0);
       /* Remove local map */
+      if (with_map.map_alloc) free(with_map.s);
       parse->locals = with_map.next;
     }
   } /* else WARNING */
@@ -2770,14 +2794,14 @@
     if (err) break;
     if (val.op_type & CS_TYPE_STRING)
     {
-      map->value.s = val.s;
+      map->s = val.s;
       map->type = val.op_type;
-      map->alloc = val.alloc;
+      map->map_alloc = val.alloc;
       val.alloc = 0;
     }
     else if (val.op_type & CS_TYPE_NUM)
     {
-      map->value.n = val.n;
+      map->n = val.n;
       map->type = CS_TYPE_NUM;
     }
     else if (val.op_type & (CS_TYPE_VAR | CS_TYPE_VAR_NUM))
@@ -2791,19 +2815,19 @@
 	 * number... then copy  */
 	if (lmap->type == CS_TYPE_NUM)
 	{
-	  map->value.n = lmap->value.n;
+	  map->n = lmap->n;
 	  map->type = lmap->type;
 	}
 	else
 	{
-	  map->value.s = lmap->value.s;
+	  map->s = lmap->s;
 	  map->type = lmap->type;
 	}
       }
       else
       {
 	var = var_lookup_obj (parse, val.s);
-	map->value.h = var;
+	map->h = var;
 	map->type = CS_TYPE_VAR;
       }
     }
@@ -2827,7 +2851,7 @@
   }
   for (x = 0; x < macro->n_args; x++)
   {
-    if (call_map[x].alloc) free(call_map[x].value.s);
+    if (call_map[x].map_alloc) free(call_map[x].s);
   }
   free (call_map);
 
@@ -3047,6 +3071,8 @@
   CSARG *carg;
   CSARG val;
 
+  memset(&each_map, 0, sizeof(each_map));
+
   carg = node->vargs;
   if (carg == NULL) return nerr_raise (NERR_ASSERT, "No arguments in loop eval?");
   err = eval_expr(parse, carg, &val);
@@ -3095,8 +3121,12 @@
     var = start;
     for (x = 0, var = start; x < iter; x++, var += step)
     {
-      each_map.value.n = var;
+      each_map.n = var;
       err = render_node (parse, node->case_0);
+      if (each_map.map_alloc) {
+        free(each_map.s);
+        each_map.s = NULL;
+      }
       if (err != STATUS_OK) break;
     } 
 
diff -Nru clearsilver-0.9.11/cs/test.hdf clearsilver-0.9.12/cs/test.hdf
--- clearsilver-0.9.11/cs/test.hdf	Thu Feb 26 19:32:36 2004
+++ clearsilver-0.9.12/cs/test.hdf	Wed Aug  4 18:39:01 2004
@@ -2,6 +2,8 @@
 arg1 = 1
 var =
 
+Empty =
+
 
 Numbers {
   hdf9 = 9
diff -Nru clearsilver-0.9.11/cs/test_joo.cs clearsilver-0.9.12/cs/test_joo.cs
--- clearsilver-0.9.11/cs/test_joo.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.12/cs/test_joo.cs	Wed Aug  4 18:39:01 2004
@@ -0,0 +1,206 @@
+Testing Empty String and empty var
+Empty has no value assigned (ie, empty), Foo has a value, NotExist doesn't exist
+Some of these tests are pretty silly
+----------------------------------------------------------------------------------
+
+Testing  == '' 
+[1] Empty == ''
+<?cs if:Empty == '' ?>
+PASS
+<?cs else ?>
+FAIL - empty string should equal empty string [1]
+<?cs /if ?>
+[2] Foo == ''
+<?cs if:Foo == '' ?>
+FAIL - existing var shouldn't equal empty string [2]
+<?cs else ?>
+PASS
+<?cs /if ?>
+[3] NotExist == ''
+<?cs if:NotExist == '' ?>
+FAIL - non-existing should be NULL, not empty string [3]
+<?cs else ?>
+PASS
+<?cs /if ?>
+	  
+Testing  != '' 
+[4] Empty != ''
+<?cs if:Empty != '' ?>
+FAIL - Empty var should equal empty string [4]
+<?cs else ?>
+PASS
+<?cs /if ?>
+[5] Foo != ''
+<?cs if:Foo != '' ?>
+PASS
+<?cs else ?>
+FAIL - [5]
+<?cs /if ?>
+[6] NotExist != ''
+<?cs if:NotExist != '' ?>
+PASS - Non existing var doesn't equal empty string
+<?cs else ?>
+FAIL - [6]
+<?cs /if ?>
+	  
+Testing ? 
+[7] ?Empty
+<?cs if:?Empty ?>
+PASS
+<?cs else ?>
+FAIL - [7]
+<?cs /if ?>
+[8] ?Foo
+<?cs if:?Foo ?>
+PASS
+<?cs else ?>
+FAIL - [8]
+<?cs /if ?>
+[9] ?NotExist
+<?cs if:?NotExist ?>
+FAIL - non existing var shouldn't exist [9]
+<?cs else ?>
+PASS
+<?cs /if ?>
+
+Testing ! 
+[10] !Empty
+<?cs if:!Empty ?>
+PASS
+<?cs else ?>
+FAIL - [10]
+<?cs /if ?>
+[11] !Foo
+<?cs if:!Foo ?>
+FAIL - existing string shouldn't evaluate false [11]
+<?cs else ?>
+PASS
+<?cs /if ?>
+[12] !NotExist
+<?cs if:!NotExist ?>
+PASS
+<?cs else ?>
+FAIL - [12]
+<?cs /if ?>
+  
+Testing !? 
+[13] !?Empty
+<?cs if:!?Empty ?>
+FAIL - empty string shouldn't evaluate non-existing [13]
+<?cs else ?>
+PASS
+<?cs /if ?>
+[14] !?Foo
+<?cs if:!?Foo ?>
+FAIL - non-empty string shouldn't evaluate non-existing [14]
+<?cs else ?>
+PASS
+<?cs /if ?>
+[15] !?NotExist
+<?cs if:!?NotExist ?>
+PASS
+<?cs else ?>
+FAIL - [15]
+<?cs /if ?>
+
+Testing ?! - Existance only works on a var, otherwise always returns
+true, so ?! is always true
+[16] ?!Empty
+<?cs if:?!Empty ?>
+PASS
+<?cs else ?>
+FAIL - [16]
+<?cs /if ?>
+[17] ?!Foo
+<?cs if:?!Foo ?>
+PASS
+<?cs else ?>
+FAIL - [17]
+<?cs /if ?>
+[18] ?!NotExist
+<?cs if:?!NotExist ?>
+PASS
+<?cs else ?>
+FAIL - [18]
+<?cs /if ?>
+
+Testing ? and == '' - boolean vs. equality? um... boolean is a number,
+so these are numeric evals, and empty string is 0
+[19] ?Empty == ''
+<?cs if:?Empty == ''?>
+FAIL - IF boolean true equals empty [19]
+<?cs else ?>
+PASS - ELSE boolean true doesn't equal empty (1 != 0)
+<?cs /if ?>
+[20] ?Foo == ''
+<?cs if:?Foo == ''?>
+FAIL - IF boolean true equals empty [20]
+<?cs else ?>
+PASS - ELSE boolean true doesn't equal empty (1 != 0)
+<?cs /if ?>
+[21] ?NotExist == ''
+<?cs if:?NotExist == '' ?>
+PASS - IF boolean false equals empty (0 == 0)
+<?cs else ?>
+[22] FAIL - ELSE boolean false doesn't equal empty [22]
+<?cs /if ?>
+
+Testing ? and != '' - boolean vs. in-equality? um...
+[23] ?Empty != ''
+<?cs if:?Empty != ''?>
+PASS - IF boolean true not equal empty (1 != 0)
+<?cs else ?>
+FAIL - ELSE boolean true equals empty [23]
+<?cs /if ?>
+[24] ?Foo != ''
+<?cs if:?Foo != ''?>
+PASS - IF boolean true not equal empty (1 != 0)
+<?cs else ?>
+FAIL - ELSE boolean true equals empty [24]
+<?cs /if ?>
+[25] ?NotExist != ''
+<?cs if:?NotExist != '' ?>
+FAIL - IF boolean false not equal empty [25]
+<?cs else ?>
+PASS - ELSE boolean false equals empty (0 == 0)
+<?cs /if ?>
+
+Testing !? and == '' - all boolean true equals empty
+[26] !?Empty == ''
+<?cs if:!?Empty == ''?>
+PASS - IF boolean true equals empty
+<?cs else ?>
+FAIL - ELSE boolean true doesn't equal empty [26]
+<?cs /if ?>
+[27] !?Foo == ''
+<?cs if:!?Foo == ''?>
+PASS - IF boolean true equals empty
+<?cs else ?>
+FAIL - ELSE boolean true doesn't equal empty [27]
+<?cs /if ?>
+[28] !?NotExist == ''
+<?cs if:!?NotExist == '' ?>
+FAIL - IF boolean true equals empty [28]
+<?cs else ?>
+PASS - ELSE boolean true doesn't equal empty
+<?cs /if ?>
+
+Testing !? and != ''
+[29] !?Empty != ''
+<?cs if:!?Empty != '' ?>
+FAIL - IF boolean true not equal empty [29]
+<?cs else ?>
+PASS - ELSE boolean true equals empty
+<?cs /if ?>
+[30] !?Foo != ''
+<?cs if:!?Foo != '' ?>
+FAIL - IF boolean true not equal empty [30]
+<?cs else ?>
+PASS - ELSE boolean true equals empty
+<?cs /if ?>
+[31] !?NotExist != ''
+<?cs if:!?NotExist != '' ?>
+PASS - IF boolean true not equal empty
+<?cs else ?>
+FAIL - ELSE boolean true equals empty [31]
+<?cs /if ?>
diff -Nru clearsilver-0.9.11/cs/test_joo.cs.gold clearsilver-0.9.12/cs/test_joo.cs.gold
--- clearsilver-0.9.11/cs/test_joo.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.12/cs/test_joo.cs.gold	Wed Aug  4 18:39:01 2004
@@ -0,0 +1,147 @@
+Parsing test_joo.cs
+Testing Empty String and empty var
+Empty has no value assigned (ie, empty), Foo has a value, NotExist doesn't exist
+Some of these tests are pretty silly
+----------------------------------------------------------------------------------
+
+Testing  == '' 
+[1] Empty == ''
+
+PASS
+
+[2] Foo == ''
+
+PASS
+
+[3] NotExist == ''
+
+PASS
+
+	  
+Testing  != '' 
+[4] Empty != ''
+
+PASS
+
+[5] Foo != ''
+
+PASS
+
+[6] NotExist != ''
+
+PASS - Non existing var doesn't equal empty string
+
+	  
+Testing ? 
+[7] ?Empty
+
+PASS
+
+[8] ?Foo
+
+PASS
+
+[9] ?NotExist
+
+PASS
+
+
+Testing ! 
+[10] !Empty
+
+PASS
+
+[11] !Foo
+
+PASS
+
+[12] !NotExist
+
+PASS
+
+  
+Testing !? 
+[13] !?Empty
+
+PASS
+
+[14] !?Foo
+
+PASS
+
+[15] !?NotExist
+
+PASS
+
+
+Testing ?! - Existance only works on a var, otherwise always returns
+true, so ?! is always true
+[16] ?!Empty
+
+PASS
+
+[17] ?!Foo
+
+PASS
+
+[18] ?!NotExist
+
+PASS
+
+
+Testing ? and == '' - boolean vs. equality? um... boolean is a number,
+so these are numeric evals, and empty string is 0
+[19] ?Empty == ''
+
+PASS - ELSE boolean true doesn't equal empty (1 != 0)
+
+[20] ?Foo == ''
+
+PASS - ELSE boolean true doesn't equal empty (1 != 0)
+
+[21] ?NotExist == ''
+
+PASS - IF boolean false equals empty (0 == 0)
+
+
+Testing ? and != '' - boolean vs. in-equality? um...
+[23] ?Empty != ''
+
+PASS - IF boolean true not equal empty (1 != 0)
+
+[24] ?Foo != ''
+
+PASS - IF boolean true not equal empty (1 != 0)
+
+[25] ?NotExist != ''
+
+PASS - ELSE boolean false equals empty (0 == 0)
+
+
+Testing !? and == '' - all boolean true equals empty
+[26] !?Empty == ''
+
+PASS - IF boolean true equals empty
+
+[27] !?Foo == ''
+
+PASS - IF boolean true equals empty
+
+[28] !?NotExist == ''
+
+PASS - ELSE boolean true doesn't equal empty
+
+
+Testing !? and != ''
+[29] !?Empty != ''
+
+PASS - ELSE boolean true equals empty
+
+[30] !?Foo != ''
+
+PASS - ELSE boolean true equals empty
+
+[31] !?NotExist != ''
+
+PASS - IF boolean true not equal empty
+
diff -Nru clearsilver-0.9.11/java-jni/CS.java clearsilver-0.9.12/java-jni/CS.java
--- clearsilver-0.9.11/java-jni/CS.java	Fri Sep 20 15:13:08 2002
+++ clearsilver-0.9.12/java-jni/CS.java	Wed Sep 29 17:23:16 2004
@@ -18,6 +18,7 @@
   public CS(HDF ho) {
     csptr = _init(ho.hdfptr);
   }
+
   public void finalize() {
     _dealloc(csptr);
   }
diff -Nru clearsilver-0.9.11/java-jni/CSTest.java clearsilver-0.9.12/java-jni/CSTest.java
--- clearsilver-0.9.11/java-jni/CSTest.java	Tue Aug  3 14:26:35 2004
+++ clearsilver-0.9.12/java-jni/CSTest.java	Wed Sep 29 17:23:16 2004
@@ -7,14 +7,20 @@
     public static void main( String [] args ) throws IOException {
 	org.clearsilver.HDF hdf = new org.clearsilver.HDF();
 
+        System.out.println("Testing HDF set and dump\n");
 	hdf.setValue("Foo.Bar","10");
         hdf.setValue("Foo.Baz","20");
         System.out.println( hdf.dump() );
 
+	String foo = hdf.getValue("Foo.Bar", "");
+        System.out.println("Testing HDF get\n");
+	System.out.println( foo );
+
 	System.out.println( "----" );
 
 	org.clearsilver.CS cs = new org.clearsilver.CS(hdf);
 	
+        System.out.println("Testing HDF parse/render\n");
 	String tmplstr = "Foo.Bar:<?cs var:Foo.Bar ?>\nFoo.Baz:<?cs var:Foo.Baz ?>\n";
 	System.out.println(tmplstr);
 	System.out.println("----");
@@ -23,11 +29,31 @@
 	System.out.println(cs.render());
 
         // test registered functions
+        System.out.println("Testing registered string functions\n");
         hdf.setValue("Foo.EscapeTest","abc& 231<>/?");
    
         tmplstr = " <?cs var:url_escape(Foo.EscapeTest) ?> <?cs var:html_escape(Foo.EscapeTest) ?>";
 
 	cs.parseStr(tmplstr);
 	System.out.println(cs.render());
+
+	cs = new org.clearsilver.CS(hdf);
+
+        System.out.println("Testing white space stripping\n");
+	// test white space stripping
+	tmplstr = "      <?cs var:Foo.Bar ?> This is a       string     without whitespace stripped";
+	cs.parseStr(tmplstr);
+	System.out.println(cs.render());
+
+        hdf.setValue("ClearSilver.WhiteSpaceStrip", "1");
+	System.out.println(cs.render());
+
+	// Now, test debug dump
+        System.out.println("Testing debug dump\n");
+        hdf.setValue("ClearSilver.DisplayDebug", "1");
+	System.out.println(cs.render());
+	
+        System.out.println("Final HDF dump\n");
+        System.out.println( hdf.dump() );
     }
 };
diff -Nru clearsilver-0.9.11/java-jni/j_neo_cs.c clearsilver-0.9.12/java-jni/j_neo_cs.c
--- clearsilver-0.9.11/java-jni/j_neo_cs.c	Tue Aug  3 14:26:35 2004
+++ clearsilver-0.9.12/java-jni/j_neo_cs.c	Wed Sep 29 17:23:16 2004
@@ -40,7 +40,7 @@
   //    _hdfobjFldID = (*env)->GetFieldID(env,objClass,"hdfptr","i");
   //  }
 
-  err = cs_init(&cs,hdf);
+  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);
@@ -122,15 +122,46 @@
   STRING str;
   NEOERR *err;
   jstring retval;
+  int do_ws_strip = 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);
   
   string_init(&str);
-  err = cs_render(cs,&str,render_cb);
-  if (err) { jNeoErr(env,err); return NULL; }
+  err = cs_render(cs, &str, render_cb);
+  if (err) { 
+    string_clear(&str);
+    jNeoErr(env,err); 
+    return NULL; 
+  }
+
+  if (do_ws_strip) {
+    cgi_html_ws_strip(&str);
+  }
+
+  if (do_debug) {
+    do {
+      err = string_append (&str, "<hr>");
+      if (err != STATUS_OK) break;
+      err = string_append (&str, "<pre>");
+      if (err != STATUS_OK) break;
+      err = hdf_dump_str (cs->hdf, NULL, 0, &str);
+      if (err != STATUS_OK) break;
+      err = string_append (&str, "</pre>");
+      if (err != STATUS_OK) break;
+    } while (0);
+    if (err) { 
+      string_clear(&str);
+      jNeoErr(env,err); 
+      return NULL; 
+    }
+  }
   
-  retval = (*env)->NewStringUTF(env,str.buf);
+  retval = (*env)->NewStringUTF(env, str.buf);
   string_clear(&str);
 
   return retval;
-  
 }
 
diff -Nru clearsilver-0.9.11/java-jni/j_neo_util.c clearsilver-0.9.12/java-jni/j_neo_util.c
--- clearsilver-0.9.11/java-jni/j_neo_util.c	Tue Aug  3 14:26:35 2004
+++ clearsilver-0.9.12/java-jni/j_neo_util.c	Wed Sep 29 17:23:16 2004
@@ -96,7 +96,7 @@
   r = hdf_get_value(hdf,(char *)hdfname,(char *)default_value);
 
   (*env)->ReleaseStringUTFChars(env,j_hdfname,hdfname);
-  return (r ? 0 : (*env)->NewStringUTF(env,r));
+  return (r ? (*env)->NewStringUTF(env,r) : 0);
 }
 
 
diff -Nru clearsilver-0.9.11/java-jni/javatest.gold clearsilver-0.9.12/java-jni/javatest.gold
--- clearsilver-0.9.11/java-jni/javatest.gold	Tue Aug  3 14:26:35 2004
+++ clearsilver-0.9.12/java-jni/javatest.gold	Wed Sep 29 17:23:16 2004
@@ -1,7 +1,14 @@
+Testing HDF set and dump
+
 Foo.Bar = 10
 Foo.Baz = 20
 
+Testing HDF get
+
+10
 ----
+Testing HDF parse/render
+
 Foo.Bar:<?cs var:Foo.Bar ?>
 Foo.Baz:<?cs var:Foo.Baz ?>
 
@@ -9,6 +16,28 @@
 Foo.Bar:10
 Foo.Baz:20
 
+Testing registered string functions
+
 Foo.Bar:10
 Foo.Baz:20
  abc%26+231%3C%3E%2F%3F abc&amp; 231&lt;&gt;/?
+Testing white space stripping
+
+      10 This is a       string     without whitespace stripped
+  10 This is a string without whitespace stripped
+Testing debug dump
+
+  10 This is a string without whitespace stripped<hr><pre>Foo.Bar = 10
+Foo.Baz = 20
+Foo.EscapeTest = abc& 231<>/?
+ClearSilver.WhiteSpaceStrip = 1
+ClearSilver.DisplayDebug = 1
+</pre>
+Final HDF dump
+
+Foo.Bar = 10
+Foo.Baz = 20
+Foo.EscapeTest = abc& 231<>/?
+ClearSilver.WhiteSpaceStrip = 1
+ClearSilver.DisplayDebug = 1
+
