diff -Nru clearsilver-0.8.1/Makefile clearsilver-0.9.0/Makefile
--- clearsilver-0.8.1/Makefile	Thu Apr  3 17:39:49 2003
+++ clearsilver-0.9.0/Makefile	Mon Apr 14 17:15:51 2003
@@ -31,7 +31,22 @@
 	    if test -f $$mdir/Makefile.PL -a ! -f $$mdir/Makefile; then \
 	      cd $$mdir; $(PERL) Makefile.PL; cd ..; \
 	    fi; \
-	    $(MAKE) -C $$mdir; \
+	    $(MAKE) -C $$mdir PREFIX=$(prefix); \
+	  fi; \
+	done
+
+install: all
+	./mkinstalldirs $(DESTDIR)$(cs_includedir)
+	./mkinstalldirs $(DESTDIR)$(bindir)
+	./mkinstalldirs $(DESTDIR)$(libdir)
+	$(INSTALL) -m 644 ClearSilver.h $(DESTDIR)$(cs_includedir)/
+	$(INSTALL) -m 644 cs_config.h $(DESTDIR)$(cs_includedir)/
+	@for mdir in $(SUBDIRS); do \
+	  if test -d $$mdir; then \
+	    if test -f $$mdir/Makefile.PL -a ! -f $$mdir/Makefile; then \
+	      cd $$mdir; $(PERL) Makefile.PL; cd ..; \
+	    fi; \
+	    $(MAKE) -C $$mdir PREFIX=$(prefix) install; \
 	  fi; \
 	done
 
diff -Nru clearsilver-0.8.1/acconfig.h clearsilver-0.9.0/acconfig.h
--- clearsilver-0.8.1/acconfig.h	Wed Apr  2 15:07:26 2003
+++ clearsilver-0.9.0/acconfig.h	Mon Apr 14 16:05:07 2003
@@ -50,6 +50,12 @@
 /* Does your system have pthreads? */
 #undef HAVE_PTHREADS
 
+/* Does your system have lockf ? */
+#undef HAVE_LOCKF
+
+/* Does your system have Berkeley DB v2 ? */
+#undef HAVE_DB2
+
 @BOTTOM@
 
 #endif /* __CS_CONFIG_H_ */
diff -Nru clearsilver-0.8.1/cgi/Makefile clearsilver-0.9.0/cgi/Makefile
--- clearsilver-0.8.1/cgi/Makefile	Wed Apr  2 16:26:48 2003
+++ clearsilver-0.9.0/cgi/Makefile	Mon Apr 14 17:13:40 2003
@@ -31,6 +31,15 @@
 $(STATIC_CSO): $(STATIC_OBJ) $(DEP_LIBS)
 	$(LDSHARED) -o $@ $(STATIC_OBJ) $(LIBS)
 
+install: all
+	$(NEOTONIC_ROOT)mkinstalldirs $(DESTDIR)$(cs_includedir)/cgi
+	$(INSTALL) -m 644 cgi.h $(DESTDIR)$(cs_includedir)/cgi
+	$(INSTALL) -m 644 cgiwrap.h $(DESTDIR)$(cs_includedir)/cgi
+	$(INSTALL) -m 644 date.h $(DESTDIR)$(cs_includedir)/cgi
+	$(INSTALL) -m 644 html.h $(DESTDIR)$(cs_includedir)/cgi
+	$(INSTALL) -m 644 $(CGI_LIB) $(DESTDIR)$(libdir)
+	$(INSTALL) $(STATIC_EXE) $(DESTDIR)$(bindir)
+
 clean:
 	$(RM) *.o
 
diff -Nru clearsilver-0.8.1/cgi/cgi.c clearsilver-0.9.0/cgi/cgi.c
--- clearsilver-0.8.1/cgi/cgi.c	Wed Apr  2 15:07:27 2003
+++ clearsilver-0.9.0/cgi/cgi.c	Sun Jun 29 22:32:58 2003
@@ -266,7 +266,7 @@
 
   while (buf[l])
   {
-    if (buf[l] == '/' || buf[l] == '&' || buf[l] == '"' || buf[l] == '\'' ||
+    if (buf[l] == '/' || buf[l] == '"' || buf[l] == '\'' ||
 	buf[l] == '\\' || buf[l] == '>' || buf[l] == '<' || buf[l] < 32)
     {
       nl += 3;
@@ -283,7 +283,7 @@
   nl = 0; l = 0;
   while (buf[l])
   {
-    if (buf[l] == '/' || buf[l] == '&' || buf[l] == '"' || buf[l] == '\'' ||
+    if (buf[l] == '/' || buf[l] == '"' || buf[l] == '\'' ||
 	buf[l] == '\\' || buf[l] == '>' || buf[l] == '<' || buf[l] < 32)
     {
       s[nl++] = '\\';
@@ -314,7 +314,7 @@
   while (buf[l])
   {
     if (buf[l] == '/' || 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)
     {
       nl += 2;
@@ -353,7 +353,7 @@
     else
     {
       if (buf[l] == '/' || 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)
       {
 	match = 1;
@@ -407,7 +407,7 @@
     k = strtok_r(query, "=", &l);
     while (k)
     {
-      if (*l == '&')
+      if (l != NULL && *l == '&')
       {
 	l++;
 	v = "";
@@ -418,7 +418,7 @@
       }
       if (v == NULL) v = "";
       snprintf(buf, sizeof(buf), "Query.%s", cgi_url_unescape(k));
-      if (!(cgi->ignore_empty_form_vars && (v == NULL || *v == '\0')))
+      if (!(cgi->ignore_empty_form_vars && (*v == '\0')))
       {
 	cgi_url_unescape(v);
 	obj = hdf_get_obj (cgi->hdf, buf);
@@ -977,7 +977,7 @@
 	o += l;
 	i += l;
       }
-      else if (!strncasecmp(str->buf + i, "pre", 8))
+      else if (!strncasecmp(str->buf + i, "pre", 3))
       {
 	ch = str->buf + i;
 	do
@@ -1069,7 +1069,7 @@
   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", 0);
+  do_ws_strip = hdf_get_int_value (cgi->hdf, "Config.WhiteSpaceStrip", 1);
 
   dis = ne_timef();
   if (err != STATUS_OK) return nerr_pass (err);
diff -Nru clearsilver-0.8.1/cgi/static.c clearsilver-0.9.0/cgi/static.c
--- clearsilver-0.8.1/cgi/static.c	Wed Apr  2 15:07:28 2003
+++ clearsilver-0.9.0/cgi/static.c	Mon Apr 14 16:05:09 2003
@@ -8,17 +8,13 @@
  * Copyright (C) 2001 by Brandon Long
  */
 
-#include "cs_config.h"
+#include "ClearSilver.h"
 
 #include <unistd.h>
 #include <limits.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include "util/neo_misc.h"
-#include "util/neo_err.h"
-#include "cgi/cgi.h"
-#include "cgi/cgiwrap.h"
 
 int main (int argc, char **argv, char **envp)
 {
diff -Nru clearsilver-0.8.1/configure.in clearsilver-0.9.0/configure.in
--- clearsilver-0.8.1/configure.in	Thu Apr  3 17:44:12 2003
+++ clearsilver-0.9.0/configure.in	Tue Jun 17 14:20:40 2003
@@ -46,21 +46,24 @@
 
 dnl Checks for libraries.
 EXTRA_UTL_OBJS=
+EXTRA_UTL_SRC=
 cs_cv_wdb=no
 AC_SEARCH_LIBS(db_open, db db2, [cs_cv_wdb=yes])
 if test $cs_cv_wdb = yes; then
-  EXTRA_UTL_OBJS="$EXTRA_UTL_OBJS wdb.o"
+  AC_DEFINE(HAVE_DB2)
+  EXTRA_UTL_SRC="$EXTRA_UTL_SRC wdb.c"
 fi
 
 dnl Check for locks
 AC_CHECK_FUNC(lockf, [
-  EXTRA_UTL_OBJS="$EXTRA_UTL_OBJS ulocks.o rcfs.o"
+  AC_DEFINE(HAVE_LOCKF)
+  EXTRA_UTL_SRC="$EXTRA_UTL_SRC ulocks.c rcfs.c"
 
   cs_cv_pthread=no
   AC_CHECK_HEADER(pthread.h, [cs_cv_pthread=yes])
   if test $cs_cv_pthread = yes; then
     AC_DEFINE(HAVE_PTHREADS)
-    EXTRA_UTL_OBJS="$EXTRA_UTL_OBJS skiplist.o dict.o"
+    EXTRA_UTL_SRC="$EXTRA_UTL_SRC skiplist.c dict.c"
   fi
 ])
 
@@ -69,7 +72,7 @@
   CPPFLAGS="$CPPFLAGS -D__WINDOWS_GCC__"
   USE_MINGW32="USE_MINGW32 = 1"
 else
-  EXTRA_UTL_OBJS="$EXTRA_UTL_OBJS filter.o neo_net.o neo_server.o"
+  EXTRA_UTL_SRC="$EXTRA_UTL_SRC filter.c neo_net.c neo_server.c"
 fi
 
 dnl Check for snprintf and vsnprintf
@@ -96,7 +99,7 @@
 AC_CHECK_FUNC(regexec, [AC_DEFINE(HAVE_REGEX)], [cs_cv_regex=no])
 if test $cs_cv_regex = no; then
   CPPFLAGS="$CPPFLAGS -I\$(NEOTONIC_ROOT)/util/regex"
-  EXTRA_UTL_OBJS="$EXTRA_UTL_OBJS regex/regex.o"
+  EXTRA_UTL_SRC="$EXTRA_UTL_SRC regex/regex.c"
 fi
 
 cs_cv_compression=yes
@@ -195,6 +198,7 @@
 	if test -f $path/include/python$vers/Python.h; then
 	  python_inc=$path/include/python$vers
 	  python_lib="-L$path/lib/python$vers/config -lpython$vers"
+	  python_site=$path/lib/python$vers/site-packages
 	  break 2
 	fi
 	dnl This is currently special cased mostly for Windows
@@ -202,6 +206,7 @@
 	if test -f $path/python$vers/include/Python.h; then
 	  python_inc=$path/python$vers/include
 	  python_lib="-L$path/python$vers/libs -lpython$vers"
+	  python_site=$path/python$vers/lib/site-packages
 	  break 2
 	fi
       done
@@ -211,10 +216,12 @@
     AC_MSG_RESULT(not found)
     PYTHON_INC=
     PYTHON_LIB=
+    PYTHON_SITE=
   else
     AC_MSG_RESULT(found $python_inc)
     PYTHON_INC="-I$python_inc"
     PYTHON_LIB=$python_lib
+    PYTHON_SITE=$python_site
     BUILD_WRAPPERS="$BUILD_WRAPPERS python"
   fi
 fi
@@ -255,6 +262,39 @@
   fi
 fi
 
+dnl Check for Ruby binary
+cs_cv_ruby=yes
+AC_ARG_ENABLE(ruby, [  --disable-ruby		Disables building of ruby module],
+  [if test $enableval = no; then
+     cs_cv_ruby=no;
+     AC_MSG_RESULT(Disabling ruby module)
+   fi])
+AC_ARG_WITH(ruby, [  --with-ruby=path		Set location of Ruby binary], [cs_cv_ruby_path="$withval"], [cs_cv_ruby_path=no])
+
+if test $cs_cv_ruby = yes; then
+  AC_MSG_CHECKING(for ruby)
+  ruby_path=no
+  ruby_search_path="/neo/opt /usr/local /usr"
+  if test $cs_cv_ruby_path != "no" -a -x $cs_cv_ruby_path; then
+    ruby_path=$cs_cv_ruby_path
+  else
+    for path in $ruby_search_path; do
+      if test -x $path/bin/ruby; then
+	ruby_path=$path/bin/ruby
+	break
+      fi
+    done
+  fi
+  if test "x$ruby_path" = "xno"; then
+    AC_MSG_RESULT(not found)
+    RUBY=
+  else
+    AC_MSG_RESULT(found $ruby_path)
+    RUBY="$ruby_path"
+    BUILD_WRAPPERS="$BUILD_WRAPPERS ruby"
+  fi
+fi
+
 dnl Check for Java library/includes
 cs_cv_java=yes
 AC_ARG_ENABLE(java, [  --disable-java		Disables building of java module],
@@ -309,10 +349,13 @@
 AC_SUBST(USE_MINGW32)
 AC_SUBST(APXS_PATH)
 AC_SUBST(PERL)
+AC_SUBST(RUBY)
 AC_SUBST(BUILD_WRAPPERS)
 AC_SUBST(JAVA_PATH)
 AC_SUBST(PYTHON_INC)
 AC_SUBST(PYTHON_LIB)
+AC_SUBST(PYTHON_SITE)
+AC_SUBST(EXTRA_UTL_SRC)
 AC_SUBST(EXTRA_UTL_OBJS)
 
 AC_OUTPUT(rules.mk)
diff -Nru clearsilver-0.8.1/cs/Makefile clearsilver-0.9.0/cs/Makefile
--- clearsilver-0.8.1/cs/Makefile	Wed Apr  2 19:03:02 2003
+++ clearsilver-0.9.0/cs/Makefile	Wed Jul  2 17:40:06 2003
@@ -14,6 +14,10 @@
 CSTEST_SRC = cstest.c
 CSTEST_OBJ = $(CSTEST_SRC:%.c=%.o)
 
+CSR_EXE = cs
+CSR_SRC = cs.c
+CSR_OBJ = $(CSR_SRC:%.c=%.o)
+
 CSDUMP_EXE = csdump
 CSDUMP_SRC = csdump.c
 CSDUMP_OBJ = $(CSDUMP_SRC:%.c=%.o)
@@ -21,9 +25,9 @@
 CFLAGS += -I$(NEOTONIC_ROOT)
 LIBS += -L$(LIB_DIR) -lneo_cs -lneo_utl # -lefence
 
-TARGETS = $(CS_LIB) $(CSTEST_EXE) test
+TARGETS = $(CS_LIB) $(CSTEST_EXE) $(CSR_EXE) test
 
-CS_TESTS = test.cs test2.cs test3.cs test4.cs test5.cs test6.cs test7.cs test8.cs test9.cs test10.cs test11.cs test12.cs test13.cs test14.cs test15.cs test16.cs test17.cs
+CS_TESTS = test.cs test2.cs test3.cs test4.cs test5.cs test6.cs test7.cs test8.cs test9.cs test10.cs test11.cs test12.cs test13.cs 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
 
 all: $(TARGETS)
 
@@ -33,6 +37,9 @@
 $(CSTEST_EXE): $(CSTEST_OBJ) $(CS_LIB)
 	$(LD) $@ $(CSTEST_OBJ) $(LIBS) # -lefence
 
+$(CSR_EXE): $(CSR_OBJ) $(CS_LIB)
+	$(LD) $@ $(CSR_OBJ) $(LIBS) # -lefence
+
 $(CSDUMP_EXE): $(CSDUMP_OBJ) $(CS_LIB)
 	$(LD) $@ $(CSDUMP_OBJ) $(LIBS)
 
@@ -41,24 +48,42 @@
 	@for test in $(CS_TESTS); do \
 		rm -f $$test.gold; \
 		./cstest test.hdf $$test > $$test.gold; \
-	done
+	done; \
+	./cstest test_tag.hdf test_tag.cs > test_tag.cs.gold
 	@echo "Generated Gold Files"
 
 test: $(CSTEST_EXE) $(CS_TESTS)
 	@echo "Running cs regression tests"
-	@for test in $(CS_TESTS); do \
+	@failed=0; \
+	for test in $(CS_TESTS); do \
 		rm -f $$test.out; \
-		./cstest test.hdf $$test > $$test.out; \
+		./cstest test.hdf $$test > $$test.out 2>&1; \
 		diff --brief $$test.out $$test.gold; \
 		return_code=$$?; \
 		if [ $$return_code -ne 0 ]; then \
-		  echo "Failed Regression Test: $$test.out"; \
-		  exit 1; \
+		  echo "Failed Regression Test: $$test"; \
+		  failed=1; \
 		fi; \
-	done
+	done; \
+	rm -f test_tag.cs.out; \
+	./cstest test_tag.hdf test_tag.cs> test_tag.cs.out 2>&1; \
+	diff --brief test_tag.cs.out test_tag.cs.gold; \
+	return_code=$$?; \
+	if [ $$return_code -ne 0 ]; then \
+	  echo "Failed Regression Test: test_tag.cs"; \
+	  failed=1; \
+	fi; \
+	if [ $$failed -eq 1 ]; then \
+	  exit 1; \
+	fi;
 	@touch test
 	@echo "Passed"
 	
+install: all
+	$(NEOTONIC_ROOT)mkinstalldirs $(DESTDIR)$(cs_includedir)/cs
+	$(INSTALL) -m 644 cs.h $(DESTDIR)$(cs_includedir)/cs
+	$(INSTALL) -m 644 $(CS_LIB) $(DESTDIR)$(libdir)
+	$(INSTALL) $(CSTEST_EXE) $(DESTDIR)$(bindir)
 
 clean:
 	$(RM) core *.o
diff -Nru clearsilver-0.8.1/cs/cs.c clearsilver-0.9.0/cs/cs.c
--- clearsilver-0.8.1/cs/cs.c	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/cs.c	Tue Jun 17 14:25:09 2003
@@ -0,0 +1,105 @@
+/*
+ * Neotonic ClearSilver Templating System
+ *
+ * This code is made available under the terms of the 
+ * Neotonic ClearSilver License.
+ * http://www.neotonic.com/clearsilver/license.hdf
+ *
+ * Copyright (C) 2001 by Brandon Long
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "cs.h"
+#include "util/neo_misc.h"
+#include "util/neo_hdf.h"
+
+static NEOERR *output (void *ctx, char *s)
+{
+  printf ("%s", s);
+  return STATUS_OK;
+}
+
+int main (int argc, char *argv[])
+{
+  NEOERR *err;
+  CSPARSE *parse;
+  HDF *hdf;
+  int verbose = 0;
+  char *hdf_file, *cs_file;
+  char c;
+
+  extern char *optarg;
+
+  err = hdf_init(&hdf);
+  if (err != STATUS_OK)
+  {
+    nerr_log_error(err);
+    return -1;
+  }
+
+  err = cs_init (&parse, hdf);
+  if (err != STATUS_OK) {
+    nerr_log_error(err);
+    return -1;
+  }
+
+  while ((c = getopt(argc, argv, "Hvh:c:")) != EOF )
+
+    switch (c) {
+    case 'h':
+      hdf_file=optarg;
+      err = hdf_read_file(hdf, hdf_file);
+      if (err != STATUS_OK) {
+	nerr_log_error(err);
+	return -1;
+      }
+      break;
+    case 'c':
+      cs_file=optarg;
+      if ( verbose )
+	printf ("Parsing %s\n", cs_file);
+
+      err = cs_parse_file (parse, cs_file);
+      if (err != STATUS_OK) {
+	err = nerr_pass(err);
+	nerr_log_error(err);
+	return -1;
+      }
+      break;
+    case 'v':
+      verbose=1;
+      break;
+    case 'H':
+      fprintf(stderr, "Usage: %s [-v] [-h <file.hdf>] [-c <file.cs>]\n", argv[0]);
+      fprintf(stderr, "     -h <file.hdf> load hdf file file.hdf (multiple allowed)\n");
+      fprintf(stderr, "     -c <file.cs>  load cs file file.cs (multiple allowed)\n");
+      fprintf(stderr, "     -v            verbose output\n");
+      return -1;
+      break;
+    }
+
+
+  err = cs_render(parse, NULL, output);
+  if (err != STATUS_OK) {
+    err = nerr_pass(err);
+    nerr_log_error(err);
+    return -1;
+  }
+
+  if (verbose) {
+    printf ("\n-----------------------\nCS DUMP\n");
+    err = cs_dump(parse, NULL, output);
+  }
+
+  cs_destroy (&parse);
+
+  if (verbose) {
+    printf ("\n-----------------------\nHDF DUMP\n");
+    hdf_dump (hdf, NULL);
+  }
+
+  return 0;
+}
diff -Nru clearsilver-0.8.1/cs/cs.h clearsilver-0.9.0/cs/cs.h
--- clearsilver-0.8.1/cs/cs.h	Wed Apr  2 15:07:29 2003
+++ clearsilver-0.9.0/cs/cs.h	Wed Jun 25 20:11:36 2003
@@ -176,6 +176,9 @@
   int in_file;           /* Indicates if current context is a file */
   int offset;
 
+  char *tag;		/* Usually cs, but can be set via HDF Config.TagStart */
+  int taglen;
+
   ULIST *stack;
   ULIST *alloc;
   CSTREE *tree;
diff -Nru clearsilver-0.8.1/cs/csparse.c clearsilver-0.9.0/cs/csparse.c
--- clearsilver-0.8.1/cs/csparse.c	Wed Apr  2 15:07:29 2003
+++ clearsilver-0.9.0/cs/csparse.c	Wed Jul  2 18:04:16 2003
@@ -39,17 +39,18 @@
   ST_IF = 1<<1,
   ST_ELSE = 1<<2,
   ST_EACH = 1<<3,
-  ST_POP = 1<<4,
-  ST_DEF = 1<<5,
-  ST_LOOP =  1<<6,
-  ST_ALT = 1<<7,
+  ST_WITH = 1<<4,
+  ST_POP = 1<<5,
+  ST_DEF = 1<<6,
+  ST_LOOP =  1<<7,
+  ST_ALT = 1<<8,
 } CS_STATE;
 
-#define ST_ANYWHERE (ST_EACH | ST_ELSE | ST_IF | ST_GLOBAL | ST_DEF | ST_LOOP | ST_ALT)
+#define ST_ANYWHERE (ST_EACH | ST_WITH | ST_ELSE | ST_IF | ST_GLOBAL | ST_DEF | ST_LOOP | ST_ALT)
 
 typedef struct _stack_entry 
 {
-  int state;
+  CS_STATE state;
   CSTREE *tree;
   CSTREE *next_tree;
   int num_local;
@@ -70,8 +71,9 @@
 static NEOERR *else_parse (CSPARSE *parse, int cmd, char *arg);
 static NEOERR *elif_parse (CSPARSE *parse, int cmd, char *arg);
 static NEOERR *endif_parse (CSPARSE *parse, int cmd, char *arg);
-static NEOERR *each_parse (CSPARSE *parse, int cmd, char *arg);
+static NEOERR *each_with_parse (CSPARSE *parse, int cmd, char *arg);
 static NEOERR *each_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
+static NEOERR *with_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);
@@ -93,8 +95,8 @@
 {
   char *cmd;
   int cmdlen;
-  int allowed_state;
-  int next_state;
+  CS_STATE allowed_state;
+  CS_STATE next_state;
   NEOERR* (*parse_handler)(CSPARSE *parse, int cmd, char *arg);
   NEOERR* (*eval_handler)(CSPARSE *parse, CSTREE *node, CSTREE **next);
   int has_arg;
@@ -122,9 +124,13 @@
   {"/if",     sizeof("/if")-1,     ST_IF | ST_ELSE, ST_POP,  
     endif_parse, skip_eval,   0},
   {"each",    sizeof("each")-1,    ST_ANYWHERE,     ST_EACH, 
-    each_parse, each_eval,    1},
+    each_with_parse, each_eval,    1},
   {"/each",   sizeof("/each")-1,   ST_EACH,         ST_POP,  
     end_parse, skip_eval, 0},
+  {"with",    sizeof("each")-1,    ST_ANYWHERE,     ST_WITH, 
+    each_with_parse, with_eval,    1},
+  {"/with",   sizeof("/with")-1,   ST_WITH,         ST_POP,  
+    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, 
@@ -228,18 +234,23 @@
   *csf = NULL;
 }
 
-static int find_open_delim (char *buf, int x, int len)
+static int find_open_delim (CSPARSE *parse, char *buf, int x, int len)
 {
   char *p;
+  int ws_index = 2+parse->taglen;
 
   while (x < len)
   {
     p = strchr (&(buf[x]), '<');
     if (p == NULL) return -1;
+    if (p[1] == '?' && !strncasecmp(&p[2], parse->tag, parse->taglen) &&
+	(p[ws_index] == ' ' || p[ws_index] == '\n' || p[ws_index] == '\t' || p[ws_index] == '\r'))
+      /*
     if (p[1] && p[1] == '?' &&
 	p[2] && (p[2] == 'C' || p[2] == 'c') &&
 	p[3] && (p[3] == 'S' || p[3] == 's') &&
 	p[4] && (p[4] == ' ' || p[4] == '\n' || p[4] == '\t' || p[4] == '\r'))
+	*/
     {
       return p - buf;
     }
@@ -362,6 +373,8 @@
     return "ELSE";
   else if (state & ST_EACH)
     return "EACH";
+  else if (state & ST_WITH)
+    return "WITH";
   else if (state & ST_DEF)
     return "DEF";
   else if (state & ST_LOOP)
@@ -400,7 +413,7 @@
   while (!done)
   {
     /* Stage 1: Find <?cs starter */
-    i = find_open_delim (ibuf, parse->offset, ibuf_len);
+    i = find_open_delim (parse, ibuf, parse->offset, ibuf_len);
     if (i >= 0)
     {
       ibuf[i] = '\0';
@@ -408,7 +421,7 @@
       /* ne_warn ("literal -> %d-%d", parse->offset, i);  */
       err = (*(Commands[0].parse_handler))(parse, 0, &(ibuf[parse->offset]));
       /* skip delim */
-      token = &(ibuf[i+5]);
+      token = &(ibuf[i+3+parse->taglen]);
       while (*token && isspace(*token)) token++;
 
       p = strstr (token, "?>");
@@ -718,7 +731,8 @@
   int ntokens = 0;
   int x;
   BOOL found;
-  char *p;
+  BOOL last_is_op = 1;
+  char *p, *p2;
   char *expr = arg;
 
   while (arg && *arg != '\0')
@@ -727,20 +741,30 @@
     if (*arg == '\0') break;
     x = 0;
     found = FALSE;
-    while ((found == FALSE) && SimpleTokens[x].token)
-    {
-      if (((SimpleTokens[x].two_chars == TRUE) && 
-	    (*arg == SimpleTokens[x].token[0]) &&
-	    (*(arg + 1) == SimpleTokens[x].token[1])) ||
-	  ((SimpleTokens[x].two_chars == FALSE) && 
-	   (*arg == SimpleTokens[x].token[0])))
-      {
-	tokens[ntokens++].type = SimpleTokens[x].type;
-	found = TRUE;
-	arg++;
-	if (SimpleTokens[x].two_chars) arg++;
-      }
-      x++;
+
+    /* If we already so an operator, and this is a +/-, assume its 
+     * a number */
+    if (!(last_is_op && (*arg == '+' || *arg == '-')))
+    {
+      while ((found == FALSE) && SimpleTokens[x].token)
+      {
+	if (((SimpleTokens[x].two_chars == TRUE) && 
+	      (*arg == SimpleTokens[x].token[0]) &&
+	      (*(arg + 1) == SimpleTokens[x].token[1])) ||
+	    ((SimpleTokens[x].two_chars == FALSE) && 
+	     (*arg == SimpleTokens[x].token[0])))
+	{
+	  tokens[ntokens++].type = SimpleTokens[x].type;
+	  found = TRUE;
+	  arg++;
+	  if (SimpleTokens[x].two_chars) arg++;
+	}
+	x++;
+      }
+      /* Another special case: RPAREN and RBRACKET can have another op
+       * after it */
+      if (found && !(tokens[ntokens-1].type == CS_OP_RPAREN || tokens[ntokens-1].type == CS_OP_RBRACKET))
+	last_is_op = 1;
     }
     
     if (found == FALSE)
@@ -756,7 +780,7 @@
 	  tokens[ntokens].type = CS_TYPE_VAR_NUM;
 	  p = strpbrk(arg, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
 	  if (p == arg)
-	    return nerr_raise (NERR_PARSE, "%s Missing arg after #: %s",
+	    return nerr_raise (NERR_PARSE, "%s Missing varname/number after #: %s",
 		find_context(parse, -1, tmp, sizeof(tmp)), arg);
 	}
 	if (p == NULL)
@@ -779,14 +803,27 @@
 	ntokens++;
 	arg = p + 1;
       }
-      else
+      else if (*arg == '\'')
+      {
+	arg++;
+	tokens[ntokens].type = CS_TYPE_STRING;
+	tokens[ntokens].value = arg;
+	p = strchr (arg, '\'');
+	if (p == NULL)
+	  return nerr_raise (NERR_PARSE, "%s Missing end of string: %s", 
+	      find_context(parse, -1, tmp, sizeof(tmp)), arg);
+	tokens[ntokens].len = p - arg;
+	ntokens++;
+	arg = p + 1;
+      }
+      else if (*arg == '$')
       {
+	arg++;
 	tokens[ntokens].type = CS_TYPE_VAR;
 	tokens[ntokens].value = arg;
 	p = strpbrk(arg, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
 	if (p == arg)
-	  return nerr_raise (NERR_PARSE, 
-	      "%s Var arg specified with no varname: %s",
+	  return nerr_raise (NERR_PARSE, "%s Missing varname after $: %s",
 	      find_context(parse, -1, tmp, sizeof(tmp)), arg);
 	if (p == NULL)
 	  tokens[ntokens].len = strlen(arg);
@@ -795,10 +832,41 @@
 	ntokens++;
 	arg = p;
       }
+      else
+      {
+	tokens[ntokens].type = CS_TYPE_VAR;
+	tokens[ntokens].value = arg;
+	/* Special case for Dave: If this is entirely a number, treat it
+	 * as one */
+	strtol(arg, &p2, 0);
+	p = strpbrk(arg, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
+	/* This is complicated because +/- is valid in a number, but not
+	 * in a varname */
+	if (p2 != arg && (p <= p2 || (p == NULL && *p2 == '\0')))
+	{
+	  tokens[ntokens].type = CS_TYPE_NUM;
+	  tokens[ntokens].len = p2 - arg;
+	  arg = p2;
+	}
+	else 
+	{
+	  if (p == arg)
+	    return nerr_raise (NERR_PARSE, 
+		"%s Var arg specified with no varname: %s",
+		find_context(parse, -1, tmp, sizeof(tmp)), arg);
+	  if (p == NULL)
+	    tokens[ntokens].len = strlen(arg);
+	  else
+	    tokens[ntokens].len = p - arg;
+	  arg = p;
+	}
+	ntokens++;
+      }
+      last_is_op = 0;
     }
     if (ntokens >= MAX_TOKENS)
 	return nerr_raise (NERR_PARSE, 
-	    "%s Expression exceeds maximum number of tokens of %d: %s",
+	    "%s Expression exceeds maximum number of tokens of %d: %s", 
 	    find_context(parse, -1, tmp, sizeof(tmp)), MAX_TOKENS, expr);
   }
   *used_tokens = ntokens;
@@ -865,12 +933,12 @@
     {
       save = tokens[i].value[tokens[i].len];
       tokens[i].value[tokens[i].len] = '\0';
-      t = snprintf(p, buflen, " %d:%s:'%s'", i, expand_token_type(tokens[i].type, 0), tokens[i].value);
+      t = snprintf(p, buflen, "%s%d:%s:'%s'", i ? "  ":"", i, expand_token_type(tokens[i].type, 0), tokens[i].value);
       tokens[i].value[tokens[i].len] = save;
     }
     else 
     {
-      t = snprintf(p, buflen, " %d:%s", i, expand_token_type(tokens[i].type, 0));
+      t = snprintf(p, buflen, "%s%d:%s", i ? "  ":"", i, expand_token_type(tokens[i].type, 0));
     }
     if (t == -1 || t >= buflen) return buf;
     buflen -= t;
@@ -889,6 +957,7 @@
   int m;
 
 #if DEBUG_EXPR_PARSE
+  fprintf(stderr, "%s\n", token_list(tokens, ntokens, tmp, sizeof(tmp)));
   for (x = 0; x < ntokens; x++)
   {
     fprintf (stderr, "%s ", expand_token_type(tokens[x].type, 0));
@@ -1414,6 +1483,7 @@
   }
 }
 
+/* This coerces everything to numbers */
 long int arg_eval_num (CSPARSE *parse, CSARG *arg)
 {
   long int v = 0;
@@ -1439,10 +1509,52 @@
   return v;
 }
 
+/* This is different from arg_eval_num because we don't force strings to
+ * numbers, a string is either a number (if it is all numeric) or we're
+ * testing existance.  At least, that's what perl does and what dave
+ * wants */
+long int arg_eval_bool (CSPARSE *parse, CSARG *arg)
+{
+  long int v = 0;
+  char *s, *r;
+
+  switch ((arg->op_type & CS_TYPES))
+  {
+    case CS_TYPE_STRING:
+    case CS_TYPE_VAR:
+      if (arg->op_type == CS_TYPE_VAR)
+	s = var_lookup(parse, arg->s);
+      else
+	s = arg->s;
+      if (!s || *s == '\0') return 0; /* non existance or empty is false(0) */
+      v = strtol(s, &r, 0);
+      if (*r == '\0') /* entire string converted, treat as number */
+	return v;
+      /* if the entire string didn't convert, then its non-numeric and
+       * exists, so its true (1) */
+      return 1;
+    case CS_TYPE_NUM:
+      return arg->n;
+    case CS_TYPE_VAR_NUM: /* this implies forced numeric evaluation */
+      return var_int_lookup (parse, arg->s);
+      break;
+    default:
+      ne_warn ("Unsupported type %s in arg_eval_bool", expand_token_type(arg->op_type, 1));
+      v = 0;
+      break;
+  }
+  return v;
+}
+
 #if DEBUG_EXPR_EVAL
-static char *expand_arg (CSARG *arg)
+static void expand_arg (CSPARSE *parse, int depth, char *where, CSARG *arg)
 {
-  fprintf(stderr, "op: %s alloc: %d value: ", expand_token_type(arg->op_type, 0), arg->alloc);
+  int x;
+
+  for (x=0; x<depth; x++)
+    fputc(' ', stderr);
+
+  fprintf(stderr, "%s op: %s alloc: %d value: ", where, expand_token_type(arg->op_type, 0), arg->alloc);
   if (arg->op_type & CS_OP_NOT)
     fprintf(stderr, "!");
   if (arg->op_type & CS_OP_NUM)
@@ -1453,24 +1565,203 @@
     fprintf(stderr, "#");
   if (arg->op_type & CS_TYPE_NUM)
     fprintf(stderr, "%ld\n", arg->n);
-  else if (arg->op_type & (CS_TYPE_VAR_NUM | CS_TYPE_VAR | CS_TYPE_STRING))
-    fprintf(stderr, "%s\n", arg->s);
+  else if (arg->op_type & CS_TYPE_STRING)
+    fprintf(stderr, "'%s'\n", arg->s);
+  else if (arg->op_type & CS_TYPE_VAR)
+    fprintf(stderr, "%s = %s\n", arg->s, var_lookup(parse, arg->s));
+  else if (arg->op_type & CS_TYPE_VAR_NUM)
+    fprintf(stderr, "%s = %ld\n", arg->s, var_int_lookup(parse, arg->s));
   else
     fprintf(stderr, "\n");
 }
 #endif
 
+static NEOERR *eval_expr_string(CSPARSE *parse, CSARG *arg1, CSARG *arg2, CSTOKEN_TYPE op, CSARG *result)
+{
+  char *s1, *s2;
+  int out;
+
+  result->op_type = CS_TYPE_NUM;
+  s1 = arg_eval (parse, arg1);
+  s2 = arg_eval (parse, arg2);
+
+  if ((s1 == NULL) || (s2 == NULL))
+  {
+    switch (op)
+    {
+      case CS_OP_EQUAL:
+	result->n = (s1 == s2) ? 1 : 0;
+	break;
+      case CS_OP_NEQUAL:
+	result->n = (s1 != s2) ? 1 : 0;
+	break;
+      case CS_OP_LT:
+	result->n = ((s1 == NULL) && (s2 != NULL)) ? 1 : 0;
+	break;
+      case CS_OP_LTE:
+	result->n = (s1 == NULL) ? 1 : 0;
+	break;
+      case CS_OP_GT:
+	result->n = ((s1 != NULL) && (s2 == NULL)) ? 1 : 0;
+	break;
+      case CS_OP_GTE:
+	result->n = (s2 == NULL) ? 1 : 0;
+	break;
+      case CS_OP_ADD:
+	/* be sure to transfer ownership of the string here */
+	result->op_type = CS_TYPE_STRING;
+	if (s1 == NULL) 
+	{
+	  result->s = s2;
+	  result->alloc = arg2->alloc;
+	  arg2->alloc = 0;
+	}
+	else
+	{
+	  result->s = s1;
+	  result->alloc = arg1->alloc;
+	  arg1->alloc = 0;
+	}
+	break;
+      default:
+	ne_warn ("Unsupported op %s in eval_expr", expand_token_type(op, 1));
+	break;
+    }
+  }
+  else
+  {
+    out = strcmp (s1, s2);
+    switch (op)
+    {
+      case CS_OP_EQUAL:
+	result->n = (!out) ? 1 : 0;
+	break;
+      case CS_OP_NEQUAL:
+	result->n = (out) ? 1 : 0;
+	break;
+      case CS_OP_LT:
+	result->n = (out < 0) ? 1 : 0;
+	break;
+      case CS_OP_LTE:
+	result->n = (out <= 0) ? 1 : 0;
+	break;
+      case CS_OP_GT:
+	result->n = (out > 0) ? 1 : 0;
+	break;
+      case CS_OP_GTE:
+	result->n = (out >= 0) ? 1 : 0;
+	break;
+      case CS_OP_ADD:
+	result->op_type = CS_TYPE_STRING;
+	result->alloc = 1;
+	result->s = (char *) calloc ((strlen(s1) + strlen(s2) + 1), sizeof(char));
+	if (result->s == NULL)
+	  return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate strings in expression: %s + %s", s1, s2);
+	strcpy(result->s, s1);
+	strcat(result->s, s2);
+	break;
+      default:
+	ne_warn ("Unsupported op %s in eval_expr_string", expand_token_type(op, 1));
+	break;
+    }
+  }
+  return STATUS_OK;
+}
+
+static NEOERR *eval_expr_num(CSPARSE *parse, CSARG *arg1, CSARG *arg2, CSTOKEN_TYPE op, CSARG *result)
+{
+  long int n1, n2;
+
+  result->op_type = CS_TYPE_NUM;
+  n1 = arg_eval_num (parse, arg1);
+  n2 = arg_eval_num (parse, arg2);
+
+  switch (op)
+  {
+    case CS_OP_EQUAL:
+      result->n = (n1 == n2) ? 1 : 0;
+      break;
+    case CS_OP_NEQUAL:
+      result->n = (n1 != n2) ? 1 : 0;
+      break;
+    case CS_OP_LT:
+      result->n = (n1 < n2) ? 1 : 0;
+      break;
+    case CS_OP_LTE:
+      result->n = (n1 <= n2) ? 1 : 0;
+      break;
+    case CS_OP_GT:
+      result->n = (n1 > n2) ? 1 : 0;
+      break;
+    case CS_OP_GTE:
+      result->n = (n1 >= n2) ? 1 : 0;
+      break;
+    case CS_OP_ADD:
+      result->n = (n1 + n2);
+      break;
+    case CS_OP_SUB:
+      result->n = (n1 - n2);
+      break;
+    case CS_OP_MULT:
+      result->n = (n1 * n2);
+      break;
+    case CS_OP_DIV:
+      if (n2 == 0) result->n = UINT_MAX;
+      else result->n = (n1 / n2);
+      break;
+    case CS_OP_MOD:
+      if (n2 == 0) result->n = 0;
+      else result->n = (n1 % n2);
+      break;
+    default:
+      ne_warn ("Unsupported op %s in eval_expr_num", expand_token_type(op, 1));
+      break;
+  }
+  return STATUS_OK;
+}
+
+static NEOERR *eval_expr_bool(CSPARSE *parse, CSARG *arg1, CSARG *arg2, CSTOKEN_TYPE op, CSARG *result)
+{
+  long int n1, n2;
+
+  result->op_type = CS_TYPE_NUM;
+  n1 = arg_eval_bool (parse, arg1);
+  n2 = arg_eval_bool (parse, arg2);
+
+  switch (op)
+  {
+    case CS_OP_AND:
+      result->n = (n1 && n2) ? 1 : 0;
+      break;
+    case CS_OP_OR:
+      result->n = (n1 || n2) ? 1 : 0;
+      break;
+    default:
+      ne_warn ("Unsupported op %s in eval_expr_bool", expand_token_type(op, 1));
+      break;
+  }
+  return STATUS_OK;
+}
+
+#if DEBUG_EXPR_EVAL
+static int _depth = 0;
+#endif
+
 static NEOERR *eval_expr (CSPARSE *parse, CSARG *expr, CSARG *result)
 {
   CSARG arg1, arg2;
   NEOERR *err;
-  long int n1, n2;
+  long int n2;
   char *s1, *s2;
-  int out;
+
+  if (expr == NULL)
+    return nerr_raise (NERR_ASSERT, "expr is NULL");
+  if (result == NULL)
+    return nerr_raise (NERR_ASSERT, "result is NULL");
 
 #if DEBUG_EXPR_EVAL
-  fprintf(stderr, "expr ");
-  expand_arg(expr);
+  _depth++;
+  expand_arg(parse, _depth, "expr", expr);
 #endif
 
   memset(result, 0, sizeof(CSARG));
@@ -1480,8 +1771,8 @@
     /* we transfer ownership of the string here.. ugh */
     if (expr->alloc) expr->alloc = 0;
 #if DEBUG_EXPR_EVAL
-    fprintf(stderr, "result ");
-    expand_arg(result);
+    expand_arg(parse, _depth, "result", result);
+    _depth--;
 #endif
     return STATUS_OK;
   }
@@ -1490,8 +1781,7 @@
     err = eval_expr (parse, expr->expr1, &arg1);
     if (err) return nerr_pass(err);
 #if DEBUG_EXPR_EVAL
-    fprintf(stderr, "arg1 ");
-    expand_arg(&arg1);
+    expand_arg(parse, _depth, "arg1", &arg1);
 #endif
     if (expr->op_type & CS_TYPE_FUNCTION)
     {
@@ -1508,9 +1798,11 @@
       result->op_type = CS_TYPE_NUM;
       switch (expr->op_type) {
 	case CS_OP_NOT:
+	  result->n = arg_eval_bool(parse, &arg1) ? 0 : 1;
+	  /*
 	  if (arg1.op_type & CS_TYPE_VAR)
 	  {
-	    /* This case is a "not exist" test */
+	    / * This case is a "not exist" test * /
 	    s1 = arg_eval (parse, &arg1);
 	    if (s1 == NULL || *s1 == '\0')
 	      result->n = 1;
@@ -1522,6 +1814,7 @@
 	    result->n = arg_eval_num (parse, &arg1);
 	    result->n = result->n ? 0 : 1;
 	  }
+	  */
 	  break;
 	case CS_OP_EXISTS:
 	  if (arg1.op_type & (CS_TYPE_VAR | CS_TYPE_VAR_NUM))
@@ -1551,8 +1844,7 @@
     {
       err = eval_expr (parse, expr->expr2, &arg2);
 #if DEBUG_EXPR_EVAL
-      fprintf(stderr, "arg2 ");
-      expand_arg(&arg2);
+      expand_arg(parse, _depth, "arg2", &arg2);
 #endif
       if (err) return nerr_pass(err);
 
@@ -1625,150 +1917,22 @@
 	  }
 	}
       }
+      else if (expr->op_type & (CS_OP_AND | CS_OP_OR))
+      {
+	/* eval as bool */
+	err = eval_expr_bool (parse, &arg1, &arg2, expr->op_type, result);
+      }
       else if ((arg1.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) ||
 	  (arg2.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) ||
 	  (expr->op_type & (CS_OP_AND | CS_OP_OR | CS_OP_SUB | CS_OP_MULT | CS_OP_DIV | CS_OP_MOD)))
       {
 	/* eval as num */
+	err = eval_expr_num(parse, &arg1, &arg2, expr->op_type, result);
 
-	result->op_type = CS_TYPE_NUM;
-	n1 = arg_eval_num (parse, &arg1);
-	n2 = arg_eval_num (parse, &arg2);
-
-	switch (expr->op_type)
-	{
-	  case CS_OP_EQUAL:
-	    result->n = (n1 == n2) ? 1 : 0;
-	    break;
-	  case CS_OP_NEQUAL:
-	    result->n = (n1 != n2) ? 1 : 0;
-	    break;
-	  case CS_OP_LT:
-	    result->n = (n1 < n2) ? 1 : 0;
-	    break;
-	  case CS_OP_LTE:
-	    result->n = (n1 <= n2) ? 1 : 0;
-	    break;
-	  case CS_OP_GT:
-	    result->n = (n1 > n2) ? 1 : 0;
-	    break;
-	  case CS_OP_GTE:
-	    result->n = (n1 >= n2) ? 1 : 0;
-	    break;
-	  case CS_OP_AND:
-	    result->n = (n1 && n2) ? 1 : 0;
-	    break;
-	  case CS_OP_OR:
-	    result->n = (n1 || n2) ? 1 : 0;
-	    break;
-	  case CS_OP_ADD:
-	    result->n = (n1 + n2);
-	    break;
-	  case CS_OP_SUB:
-	    result->n = (n1 - n2);
-	    break;
-	  case CS_OP_MULT:
-	    result->n = (n1 * n2);
-	    break;
-	  case CS_OP_DIV:
-	    if (n2 == 0) result->n = UINT_MAX;
-	    else result->n = (n1 / n2);
-	    break;
-	  case CS_OP_MOD:
-	    if (n2 == 0) result->n = 0;
-	    else result->n = (n1 % n2);
-	    break;
-	  default:
-	    ne_warn ("Unsupported op %s in eval_expr", expand_token_type(expr->op_type, 1));
-	    break;
-	}
       }
       else /* eval as string */
       {
-	result->op_type = CS_TYPE_NUM;
-	s1 = arg_eval (parse, &arg1);
-	s2 = arg_eval (parse, &arg2);
-
-	if ((s1 == NULL) || (s2 == NULL))
-	{
-	  switch (expr->op_type)
-	  {
-	    case CS_OP_EQUAL:
-	      result->n = (s1 == s2) ? 1 : 0;
-	      break;
-	    case CS_OP_NEQUAL:
-	      result->n = (s1 != s2) ? 1 : 0;
-	      break;
-	    case CS_OP_LT:
-	      result->n = ((s1 == NULL) && (s2 != NULL)) ? 1 : 0;
-	      break;
-	    case CS_OP_LTE:
-	      result->n = (s1 == NULL) ? 1 : 0;
-	      break;
-	    case CS_OP_GT:
-	      result->n = ((s1 != NULL) && (s2 == NULL)) ? 1 : 0;
-	      break;
-	    case CS_OP_GTE:
-	      result->n = (s2 == NULL) ? 1 : 0;
-	      break;
-	    case CS_OP_ADD:
-	      /* be sure to transfer ownership of the string here */
-	      result->op_type = CS_TYPE_STRING;
-	      if (s1 == NULL) 
-	      {
-		result->s = s2;
-		result->alloc = arg2.alloc;
-		arg2.alloc = 0;
-	      }
-	      else
-	      {
-		result->s = s1;
-		result->alloc = arg1.alloc;
-		arg1.alloc = 0;
-	      }
-	      break;
-	    default:
-	      ne_warn ("Unsupported op %s in eval_expr", expand_token_type(expr->op_type, 1));
-	      break;
-	  }
-	}
-	else
-	{
-	  out = strcmp (s1, s2);
-	  switch (expr->op_type)
-	  {
-	    case CS_OP_EQUAL:
-	      result->n = (!out) ? 1 : 0;
-	      break;
-	    case CS_OP_NEQUAL:
-	      result->n = (out) ? 1 : 0;
-	      break;
-	    case CS_OP_LT:
-	      result->n = (out < 0) ? 1 : 0;
-	      break;
-	    case CS_OP_LTE:
-	      result->n = (out <= 0) ? 1 : 0;
-	      break;
-	    case CS_OP_GT:
-	      result->n = (out > 0) ? 1 : 0;
-	      break;
-	    case CS_OP_GTE:
-	      result->n = (out >= 0) ? 1 : 0;
-	      break;
-	    case CS_OP_ADD:
-	      result->op_type = CS_TYPE_STRING;
-	      result->alloc = 1;
-	      result->s = (char *) calloc ((strlen(s1) + strlen(s2) + 1), sizeof(char));
-	      if (result->s == NULL)
-		return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate strings in expression: %s + %s", s1, s2);
-	      strcpy(result->s, s1);
-	      strcat(result->s, s2);
-	      break;
-	    default:
-	      ne_warn ("Unsupported op %s in eval_expr", expand_token_type(expr->op_type, 1));
-	      break;
-	  }
-	}
+	err = eval_expr_string(parse, &arg1, &arg2, expr->op_type, result);
       }
 
       if (arg1.alloc) free(arg1.s);
@@ -1776,8 +1940,8 @@
     }
   }
 #if DEBUG_EXPR_EVAL
-  fprintf(stderr, "result ");
-  expand_arg(result);
+  expand_arg(parse, _depth, "result", result);
+  _depth--;
 #endif
   return STATUS_OK;
 }
@@ -1925,41 +2089,26 @@
 
   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;
+  eval_true = arg_eval_bool(parse, &val);
+  if (eval_true)
+  {
+    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);
-    if (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
     {
-      eval_true = 0;
-    }
-  }
-  else
-  {
-    char *s;
-    BOOL not = FALSE;
-    if (val.op_type & CS_OP_NOT)
-    {
-      not = TRUE;
-      val.op_type &= ~CS_OP_NOT;
-    }
-    s = arg_eval (parse, &val);
-    if (s == NULL || *s == '\0')
-      eval_true = 0;
-
-    if (not == TRUE)
-      eval_true = !eval_true;
-
-    if (eval_true && s)
-    {
-      err = parse->output_cb (parse->output_ctx, s);
+      char *s = arg_eval (parse, &val);
+      /* Do we set it to blank if s == NULL? */
+      if (s)
+      {
+	err = parse->output_cb (parse->output_ctx, s);
+      }
     }
   }
   if (val.alloc) free(val.s);
@@ -1982,6 +2131,8 @@
 
   err = eval_expr(parse, &(node->arg1), &val);
   if (err) return nerr_pass (err);
+  eval_true = arg_eval_bool(parse, &val);
+  /*
   if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM))
     eval_true = arg_eval_num (parse, &val);
   else
@@ -2002,6 +2153,7 @@
     if (not == TRUE)
       eval_true = !eval_true;
   }
+  */
   if (val.alloc) free(val.s);
 
   if (eval_true)
@@ -2066,7 +2218,7 @@
   return STATUS_OK;
 }
 
-static NEOERR *each_parse (CSPARSE *parse, int cmd, char *arg)
+static NEOERR *each_with_parse (CSPARSE *parse, int cmd, char *arg)
 {
   NEOERR *err;
   CSTREE *node;
@@ -2087,8 +2239,8 @@
   {
     dealloc_node(&node);
     return nerr_raise (NERR_PARSE, 
-	"%s Improperly formatted each directive: %s", 
-	find_context(parse, -1, tmp, sizeof(tmp)), arg);
+	"%s Improperly formatted %s directive: %s", 
+	find_context(parse, -1, tmp, sizeof(tmp)), Commands[cmd].cmd, arg);
   }
   if (*p != '=')
   {
@@ -2098,8 +2250,8 @@
     {
       dealloc_node(&node);
       return nerr_raise (NERR_PARSE, 
-	  "%s Improperly formatted each directive: %s", 
-	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
+	  "%s Improperly formatted %s directive: %s", 
+	  find_context(parse, -1, tmp, sizeof(tmp)), Commands[cmd].cmd, arg);
     }
     p++;
   }
@@ -2112,8 +2264,8 @@
   {
     dealloc_node(&node);
     return nerr_raise (NERR_PARSE, 
-	"%s Improperly formatted each directive: %s", 
-	find_context(parse, -1, tmp, sizeof(tmp)), arg);
+	"%s Improperly formatted %s directive: %s", 
+	find_context(parse, -1, tmp, sizeof(tmp)), Commands[cmd].cmd, arg);
   }
   node->arg1.op_type = CS_TYPE_VAR;
   node->arg1.s = lvar;
@@ -2178,6 +2330,38 @@
   return nerr_pass (err);
 }
 
+static NEOERR *with_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
+{
+  NEOERR *err = STATUS_OK;
+  CS_LOCAL_MAP with_map;
+  CSARG val;
+  HDF *var;
+
+  err = eval_expr(parse, &(node->arg2), &val);
+  if (err) return nerr_pass(err);
+
+  if (val.op_type == CS_TYPE_VAR)
+  {
+    var = var_lookup_obj (parse, val.s);
+
+    if (var != NULL)
+    {
+      /* Init and install local map */
+      with_map.type = CS_TYPE_VAR;
+      with_map.name = node->arg1.s;
+      with_map.next = parse->locals;
+      with_map.value.h = var;
+      parse->locals = &with_map;
+      err = render_node (parse, node->case_0);
+      /* Remove local map */
+      parse->locals = with_map.next;
+    }
+  } /* else WARNING */
+  if (val.alloc) free(val.s);
+
+  *next = node->next;
+  return nerr_pass (err);
+}
 static NEOERR *end_parse (CSPARSE *parse, int cmd, char *arg)
 {
   NEOERR *err;
@@ -2194,63 +2378,27 @@
 static NEOERR *include_parse (CSPARSE *parse, int cmd, char *arg)
 {
   NEOERR *err;
-  CSTREE *node;
-  char *a, *s;
-  char tmp[256];
+  char *s;
+  int flags = 0;
+  CSARG arg1, val;
 
-  err = alloc_node (&node);
-  if (err) return nerr_pass(err);
-  node->cmd = cmd;
+  memset(&arg1, 0, sizeof(CSARG));
   if (arg[0] == '!')
-    node->flags |= CSF_REQUIRED;
+    flags |= CSF_REQUIRED;
   arg++;
   /* Validate arg is a var (regex /^[#" ]$/) */
-  a = neos_strip(arg);
+  err = parse_expr (parse, arg, 0, &arg1);
+  if (err) return nerr_pass(err);
   /* ne_warn ("include: %s", a); */
-  s = strpbrk(a, "# <>");
-  if (s != NULL)
-  {
-    dealloc_node(&node);
-    return nerr_raise (NERR_PARSE, 
-	"%s Invalid character in include argument %s: %c", 
-	find_context(parse, -1, tmp, sizeof(tmp)), a, s[0]);
-  }
-
-  /* Literal string or var */
-  if (a[0] == '\"')
-  {
-    int l;
-    a++;
-    l = strlen(a);
-
-    if (a[l - 1] == '\"')
-    {
-      a[l - 1] = '\0';
-    }
-    node->arg1.op_type = CS_TYPE_STRING;
-    node->arg1.s = a;
-    s = a;
-  }
-  else
-  {
-    s = hdf_get_value (parse->hdf, a, NULL);
-    if (s == NULL) 
-    {
-      dealloc_node(&node);
-      return nerr_raise (NERR_NOT_FOUND, 
-	  "%s Unable to include empty variable %s", 
-	  find_context(parse, -1, tmp, sizeof(tmp)), a);
-    }
-    node->arg1.op_type = CS_TYPE_VAR;
-    node->arg1.s = a;
-  }
 
-  *(parse->next) = node;
-  parse->next = &(node->next);
-  parse->current = node;
+  err = eval_expr(parse, &arg1, &val);
+  if (err) return nerr_pass(err);
 
+  s = arg_eval (parse, &val);
+  if (s == NULL && !(flags & CSF_REQUIRED))
+    return STATUS_OK;
   err = cs_parse_file(parse, s);
-  if (!(node->flags & CSF_REQUIRED))
+  if (!(flags & CSF_REQUIRED))
   {
     nerr_handle(&err, NERR_NOT_FOUND);
   }
@@ -3006,6 +3154,34 @@
   return STATUS_OK;
 }
 
+static NEOERR * _builtin_name(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
+{
+  HDF *obj;
+
+  result->op_type = CS_TYPE_STRING;
+  result->s = "";
+
+  if (args->op_type & CS_TYPE_VAR)
+  {
+    obj = var_lookup_obj (parse, args->s);
+    if (obj != NULL)
+    {
+      result->s = hdf_obj_name(obj);
+    }
+    else 
+    {
+      result->s = "";
+    }
+  }
+  else if (args->op_type & CS_TYPE_STRING)
+  {
+    result->s = args->s;
+    result->alloc = args->alloc;
+    args->alloc = 0;
+  }
+  return STATUS_OK;
+}
+
 static NEOERR * _str_func_wrapper (CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
 {
   NEOERR *err;
@@ -3106,6 +3282,14 @@
     cs_destroy(&my_parse);
     return nerr_pass(err);
   }
+  err = _register_function(my_parse, "name", 1, _builtin_name);
+  if (err)
+  {
+    cs_destroy(&my_parse);
+    return nerr_pass(err);
+  }
+  my_parse->tag = hdf_get_value(hdf, "Config.TagStart", "cs");
+  my_parse->taglen = strlen(my_parse->tag);
   my_parse->hdf = hdf;
 
   *parse = my_parse;
diff -Nru clearsilver-0.8.1/cs/test.cs clearsilver-0.9.0/cs/test.cs
--- clearsilver-0.8.1/cs/test.cs	Thu Jun 21 14:56:01 2001
+++ clearsilver-0.9.0/cs/test.cs	Wed Jul  2 18:04:16 2003
@@ -27,7 +27,8 @@
   <?cs var:Blah ?>
 <?cs /if ?>
 
-<?cs include:"test2.cs" ?>
+<?cs include!"test2.cs" ?>
+<?cs linclude!"test2.cs" ?>
 
 <?cs each: x=Foo.Bar.Baz ?>
   x = <?cs var:x ?>
diff -Nru clearsilver-0.8.1/cs/test.cs.gold clearsilver-0.9.0/cs/test.cs.gold
--- clearsilver-0.8.1/cs/test.cs.gold	Fri Sep 14 16:45:36 2001
+++ clearsilver-0.9.0/cs/test.cs.gold	Wed Jul  2 18:04:16 2003
@@ -30,6 +30,12 @@
 wow2
 
 
+I'm in test2.cs
+
+
+wow2
+
+
 
   x = zero
   x.num = #0
diff -Nru clearsilver-0.8.1/cs/test.hdf clearsilver-0.9.0/cs/test.hdf
--- clearsilver-0.8.1/cs/test.hdf	Mon Mar 17 21:59:49 2003
+++ clearsilver-0.9.0/cs/test.hdf	Wed Jun 18 11:43:52 2003
@@ -133,3 +133,8 @@
 C = <?cs var:A ?>/<?cs var:B ?>
 
 Biz.Address2 = addr
+parent_id = -1
+faq.topic_id = 1
+Query.topic = -1
+
+faq.sub_topic_id = -1
diff -Nru clearsilver-0.8.1/cs/test14.cs clearsilver-0.9.0/cs/test14.cs
--- clearsilver-0.8.1/cs/test14.cs	Mon Mar 31 23:26:57 2003
+++ clearsilver-0.9.0/cs/test14.cs	Wed Jun 25 20:11:36 2003
@@ -58,7 +58,7 @@
 <?cs if:Blooey || TestIf ?>
   ERROR
 <?cs else ?>
-  Not existence test, forced to numeric which evals to 0
+  CORRECT boolean test, blooey doesn't exist, testif == 0 so its false
 <?cs /if ?>
 
 <?cs if:?Blooey || ?TestIf ?>
@@ -81,7 +81,7 @@
   Testing not one
 <?cs /if ?>
 
-<?cs if:!1 ?>
+<?cs if:!$1 ?>
   Testing not exist var one
 <?cs else ?>
   ERROR
@@ -93,7 +93,7 @@
   not expression existence test
 <?cs /if ?>
 
-<?cs if:!(#0 || TestIf) ?>
+<?cs if:!(#0 || Blooey) ?>
   not expression test
 <?cs else ?>
  ERROR
diff -Nru clearsilver-0.8.1/cs/test14.cs.gold clearsilver-0.9.0/cs/test14.cs.gold
--- clearsilver-0.8.1/cs/test14.cs.gold	Mon Mar 31 23:26:57 2003
+++ clearsilver-0.9.0/cs/test14.cs.gold	Wed Jun 25 20:11:36 2003
@@ -39,7 +39,7 @@
 
 
 
-  Not existence test, forced to numeric which evals to 0
+  CORRECT boolean test, blooey doesn't exist, testif == 0 so its false
 
 
 
diff -Nru clearsilver-0.8.1/cs/test18.cs clearsilver-0.9.0/cs/test18.cs
--- clearsilver-0.8.1/cs/test18.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test18.cs	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,35 @@
+
+<?cs set:foo["baz"].right = "dot right" ?>
+<?cs set:foo["baz"].right.label = "dot right" ?>
+
+<? cs set:foo["baz"] + right = "plus right" ?>
+<?cs set:Files.0.Funk = "bam" ?>
+
+
+<?cs def:style() ?>....<?cs /def ?>
+
+<?cs call:style() ?>
+
+with whitespace
+<?cs call:style( ) ?>
+
+with extra variable
+<?  cs call:style( foo ) ?>
+
+With whitespace in def...
+<?cs def:style2( ) ?>....<?cs /def ?>
+
+<?cs call:style2() ?>
+
+
+<?cs def:set_info(side, label, value) ?>
+   <?cs set:rows[row][side].label = label ?>
+   <?cs set:rows[row][side].value = value ?>
+   <?cs # the following test would throw a warning if enabled ?>
+   <?cs # set:side.foo = row ?>
+   <?cs set:row = row + #1 ?>
+<?cs /def ?>
+
+<?cs set:row = #0 ?>
+<?cs call:set_info("left", "phone", Days.0.Abbr) ?>
+
diff -Nru clearsilver-0.8.1/cs/test18.cs.gold clearsilver-0.9.0/cs/test18.cs.gold
--- clearsilver-0.8.1/cs/test18.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test18.cs.gold	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,36 @@
+Parsing test18.cs
+
+
+
+
+<? cs set:foo["baz"] + right = "plus right" ?>
+
+
+
+
+
+....
+
+with whitespace
+....
+
+with extra variable
+<?  cs call:style( foo ) ?>
+
+With whitespace in def...
+
+
+....
+
+
+
+
+
+
+   
+   
+   
+   
+   
+
+
diff -Nru clearsilver-0.8.1/cs/test3.cs clearsilver-0.9.0/cs/test3.cs
--- clearsilver-0.8.1/cs/test3.cs	Wed Mar 27 16:47:28 2002
+++ clearsilver-0.9.0/cs/test3.cs	Wed Jun 25 20:11:36 2003
@@ -24,7 +24,7 @@
 
 
 <?cs def:echo(wow) ?>
-  <?cs var:wow ?>
+  <?cs var:$wow ?>
 <?cs /def ?>
 
 before weekday
diff -Nru clearsilver-0.8.1/cs/test4.cs clearsilver-0.9.0/cs/test4.cs
--- clearsilver-0.8.1/cs/test4.cs	Thu Mar 28 17:40:56 2002
+++ clearsilver-0.9.0/cs/test4.cs	Wed Jun 25 20:11:36 2003
@@ -1,7 +1,7 @@
 
 Testing cs set
 
-<?cs set:Set.1 = 5 ?>
+<?cs set:Set.1 = $5 ?>
 
 <?cs var:Set.1 ?>
 
diff -Nru clearsilver-0.8.1/cs/test_chuck.cs clearsilver-0.9.0/cs/test_chuck.cs
--- clearsilver-0.8.1/cs/test_chuck.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_chuck.cs	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,18 @@
+<?cs def:set_field(card, out_field, in_field, default, color)
+?><?cs   if:in_field.changed == #1
+?><?cs     set:color="#ff0000"
+?><?cs   /if
+?><?cs   set:val = in_field
+?><?cs   if:!?val || (val == "")
+?><?cs     set:val = default
+?><?cs   /if
+?><?cs   set:card[out_field] = "<font color=" + color + ">" + val +
+"</font>"
+?><?cs /def ?>
+
+<?cs call:set_field(Biz, "Address2", Biz.Address2, "", "#888888")
+?><?cs call:set_field(Biz, "Address3", Biz.Address3, "", "#888888") ?>
+
+Biz.Address2 = <?cs var:Biz.Address2 ?>
+Biz.Address3 = <?cs var:Biz.Address3 ?>
+
diff -Nru clearsilver-0.8.1/cs/test_chuck.cs.gold clearsilver-0.9.0/cs/test_chuck.cs.gold
--- clearsilver-0.8.1/cs/test_chuck.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_chuck.cs.gold	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,8 @@
+Parsing test_chuck.cs
+
+
+
+
+Biz.Address2 = <font color=#888888>addr</font>
+Biz.Address3 = <font color=#888888></font>
+
diff -Nru clearsilver-0.8.1/cs/test_each_array.cs clearsilver-0.9.0/cs/test_each_array.cs
--- clearsilver-0.8.1/cs/test_each_array.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_each_array.cs	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,5 @@
+
+
+<?cs each:sub = Foo.Bar["Baz"] ?>
+  <?cs var:sub ?>
+<?cs /each ?>
diff -Nru clearsilver-0.8.1/cs/test_each_array.cs.gold clearsilver-0.9.0/cs/test_each_array.cs.gold
--- clearsilver-0.8.1/cs/test_each_array.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_each_array.cs.gold	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,12 @@
+Parsing test_each_array.cs
+
+
+
+  zero
+
+  one
+
+  two
+
+  three
+
diff -Nru clearsilver-0.8.1/cs/test_exists.cs clearsilver-0.9.0/cs/test_exists.cs
--- clearsilver-0.8.1/cs/test_exists.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_exists.cs	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,7 @@
+array exists test 
+<?cs var:Days[TestIf] ?>
+<?cs if:?Days[TestIf] ?>
+ PASS
+<?cs else ?>
+ ERROR
+<?cs /if ?>
diff -Nru clearsilver-0.8.1/cs/test_iter.cs clearsilver-0.9.0/cs/test_iter.cs
--- clearsilver-0.8.1/cs/test_iter.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_iter.cs	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,14 @@
+
+<?cs loop:foo = #0,#30 ?>
+  <?cs set:Loop[foo] = foo ?>
+<?cs /loop ?>
+
+<?cs set:count = #0 ?>
+<?cs set:Query.start = #10 ?>
+<?cs set:next = #20 ?>
+<?cs each:foo = Loop ?>
+  <?cs if:#count > #Query.start && #count < #next ?>
+  <?cs var:foo ?>
+  <?cs /if ?>
+  <?cs set:count = #count + #1 ?>
+<?cs /each ?>
diff -Nru clearsilver-0.8.1/cs/test_iter.cs.gold clearsilver-0.9.0/cs/test_iter.cs.gold
--- clearsilver-0.8.1/cs/test_iter.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_iter.cs.gold	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,181 @@
+Parsing test_iter.cs
+
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+  
+
+
+
+
+
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  11
+  
+  
+
+  
+  12
+  
+  
+
+  
+  13
+  
+  
+
+  
+  14
+  
+  
+
+  
+  15
+  
+  
+
+  
+  16
+  
+  
+
+  
+  17
+  
+  
+
+  
+  18
+  
+  
+
+  
+  19
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
+  
+  
+
diff -Nru clearsilver-0.8.1/cs/test_name.cs clearsilver-0.9.0/cs/test_name.cs
--- clearsilver-0.8.1/cs/test_name.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_name.cs	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,7 @@
+
+
+<?cs var:name(Wow.Foo) ?>
+
+<?cs each:count = Foo.Bar.Baz ?>
+  <?cs var:name(count) ?>
+<?cs /each ?>
diff -Nru clearsilver-0.8.1/cs/test_name.cs.gold clearsilver-0.9.0/cs/test_name.cs.gold
--- clearsilver-0.8.1/cs/test_name.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_name.cs.gold	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,14 @@
+Parsing test_name.cs
+
+
+Foo
+
+
+  0
+
+  1
+
+  2
+
+  3
+
diff -Nru clearsilver-0.8.1/cs/test_numbers.cs clearsilver-0.9.0/cs/test_numbers.cs
--- clearsilver-0.8.1/cs/test_numbers.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_numbers.cs	Wed Jul  2 17:40:06 2003
@@ -0,0 +1,56 @@
+
+<?cs var:-1 ?>
+
+<?cs if:-1 == -1 ?>
+  CORRECT: -1 == -1
+<?cs else ?>
+  ERROR: -1 should equal -1
+<?cs /if ?>
+
+<?cs if:-1 ?>
+  CORRECT: -1 is boolean true
+<?cs else ?>
+  ERROR : -1 should be boolean true
+<?cs /if ?>
+
+<?cs if:#-1 ?>
+  CORRECT: #-1 is boolean true
+<?cs else ?>
+  ERROR : #-1 should be boolean true
+<?cs /if ?>
+
+<?cs if:0 ?>
+  ERROR: 0 should be boolean false
+<?cs else ?>
+  CORRECT: 0 is boolean false
+<?cs /if ?>
+
+<?cs if:00 ?>
+  ERROR: 00 should be boolean false
+<?cs else ?>
+  CORRECT: 00 is boolean false
+<?cs /if ?>
+
+<?cs if:0x15 == 21 ?>
+  CORRECT: 0x15 (hex) == 21
+<?cs else ?>
+  ERROR: 0x15 (hex) should equal 21
+<?cs /if ?>
+
+<?cs if:0x15 ?>
+  CORRECT: 0x15 is boolean true
+<?cs else ?>
+  ERROR: 0x15 should be boolean true
+<?cs /if ?>
+
+<?cs if:(3*2)+4 == 10 ?>
+  CORRECT: (3*2)+4 does equal 10
+<?cs else ?>
+  ERROR: (3*2)+4 should equal 10
+<?cs /if ?>
+
+<?cs if:Days[0] + 2 == 2 ?>
+  CORRECT: 0 + 2 == 2
+<?cs else ?>
+  ERROR: 0 + 2 should equal 2
+<?cs /if ?>
diff -Nru clearsilver-0.8.1/cs/test_numbers.cs.gold clearsilver-0.9.0/cs/test_numbers.cs.gold
--- clearsilver-0.8.1/cs/test_numbers.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_numbers.cs.gold	Wed Jul  2 17:40:15 2003
@@ -0,0 +1,39 @@
+Parsing test_numbers.cs
+
+-1
+
+
+  CORRECT: -1 == -1
+
+
+
+  CORRECT: -1 is boolean true
+
+
+
+  CORRECT: #-1 is boolean true
+
+
+
+  CORRECT: 0 is boolean false
+
+
+
+  CORRECT: 00 is boolean false
+
+
+
+  CORRECT: 0x15 (hex) == 21
+
+
+
+  CORRECT: 0x15 is boolean true
+
+
+
+  CORRECT: (3*2)+4 does equal 10
+
+
+
+  CORRECT: 0 + 2 == 2
+
diff -Nru clearsilver-0.8.1/cs/test_paren.cs clearsilver-0.9.0/cs/test_paren.cs
--- clearsilver-0.8.1/cs/test_paren.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_paren.cs	Wed Jun 18 11:28:32 2003
@@ -0,0 +1,5 @@
+<?cs def:test(a) ?>
+VALUE:<?cs var:a ?>:
+<?cs /def ?>
+<?cs call:test("HELLO()") ?>
+
diff -Nru clearsilver-0.8.1/cs/test_paren.cs.gold clearsilver-0.9.0/cs/test_paren.cs.gold
--- clearsilver-0.8.1/cs/test_paren.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_paren.cs.gold	Wed Jun 18 11:28:32 2003
@@ -0,0 +1,6 @@
+Parsing test_paren.cs
+
+
+VALUE:HELLO():
+
+
diff -Nru clearsilver-0.8.1/cs/test_tag.cs clearsilver-0.9.0/cs/test_tag.cs
--- clearsilver-0.8.1/cs/test_tag.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_tag.cs	Wed Jun 25 20:11:36 2003
@@ -0,0 +1 @@
+<?int1 loop:x=0,2 ?><?int1 var:x ?> <?cs var:myvar ?><?int1 /loop ?>
diff -Nru clearsilver-0.8.1/cs/test_tag.cs.gold clearsilver-0.9.0/cs/test_tag.cs.gold
--- clearsilver-0.8.1/cs/test_tag.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_tag.cs.gold	Wed Jun 25 20:11:36 2003
@@ -0,0 +1,2 @@
+Parsing test_tag.cs
+0 <?cs var:myvar ?>1 <?cs var:myvar ?>2 <?cs var:myvar ?>
diff -Nru clearsilver-0.8.1/cs/test_tag.hdf clearsilver-0.9.0/cs/test_tag.hdf
--- clearsilver-0.8.1/cs/test_tag.hdf	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_tag.hdf	Wed Jun 25 20:11:36 2003
@@ -0,0 +1 @@
+Config.TagStart = int1
diff -Nru clearsilver-0.8.1/cs/test_trak1.cs clearsilver-0.9.0/cs/test_trak1.cs
--- clearsilver-0.8.1/cs/test_trak1.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_trak1.cs	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,9 @@
+<?cs if:(parent_id == #-1 && faq.topic_id == Query.topic) || (parent_id != #-1 && faq.sub_topic_id == Query.topic) ?>
+  matched
+<?cs /if ?>
+
+<?cs def:test_macro(foo) ?>
+  <?cs var:foo ?>
+<?cs /def ?>
+
+<?cs call:test_macro(len(faq)) ?>
diff -Nru clearsilver-0.8.1/cs/test_trak1.cs.gold clearsilver-0.9.0/cs/test_trak1.cs.gold
--- clearsilver-0.8.1/cs/test_trak1.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_trak1.cs.gold	Wed Jun 18 11:43:52 2003
@@ -0,0 +1,8 @@
+Parsing test_trak1.cs
+
+
+
+
+
+  2
+
diff -Nru clearsilver-0.8.1/cs/test_var.cs clearsilver-0.9.0/cs/test_var.cs
--- clearsilver-0.8.1/cs/test_var.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_var.cs	Wed Jun 18 11:28:32 2003
@@ -0,0 +1 @@
+<?cs var:Blah ?>
diff -Nru clearsilver-0.8.1/cs/test_var.cs.gold clearsilver-0.9.0/cs/test_var.cs.gold
--- clearsilver-0.8.1/cs/test_var.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_var.cs.gold	Wed Jun 18 11:28:32 2003
@@ -0,0 +1,2 @@
+Parsing test_var.cs
+wow
diff -Nru clearsilver-0.8.1/cs/test_with.cs clearsilver-0.9.0/cs/test_with.cs
--- clearsilver-0.8.1/cs/test_with.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_with.cs	Wed Jun 25 20:11:36 2003
@@ -0,0 +1,6 @@
+
+<?cs loop:x=#0,#6 ?>
+  <?cs with:abbr = Days[x].Abbr ?>
+    <?cs var:x ?> - <?cs var:abbr ?>
+  <?cs /with ?>
+<?cs /loop ?>
diff -Nru clearsilver-0.8.1/cs/test_with.cs.gold clearsilver-0.9.0/cs/test_with.cs.gold
--- clearsilver-0.8.1/cs/test_with.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/cs/test_with.cs.gold	Wed Jun 25 20:11:36 2003
@@ -0,0 +1,31 @@
+Parsing test_with.cs
+
+
+  
+    0 - Mon
+  
+
+  
+    1 - Tues
+  
+
+  
+    2 - Wed
+  
+
+  
+    3 - Thur
+  
+
+  
+    4 - Fri
+  
+
+  
+    5 - Sat
+  
+
+  
+    6 - Sun
+  
+
diff -Nru clearsilver-0.8.1/cs_config.h.in clearsilver-0.9.0/cs_config.h.in
--- clearsilver-0.8.1/cs_config.h.in	Wed Apr  2 15:07:26 2003
+++ clearsilver-0.9.0/cs_config.h.in	Mon Apr 14 16:05:07 2003
@@ -96,6 +96,12 @@
 /* Does your system have pthreads? */
 #undef HAVE_PTHREADS
 
+/* Does your system have lockf ? */
+#undef HAVE_LOCKF
+
+/* Does your system have Berkeley DB v2 ? */
+#undef HAVE_DB2
+
 /* Define if you have the drand48 function.  */
 #undef HAVE_DRAND48
 
diff -Nru clearsilver-0.8.1/imd/imd.c clearsilver-0.9.0/imd/imd.c
--- clearsilver-0.8.1/imd/imd.c	Mon Feb 11 12:16:23 2002
+++ clearsilver-0.9.0/imd/imd.c	Mon Apr 14 16:05:28 2003
@@ -24,9 +24,7 @@
 #include <time.h>
 #include <ctype.h>
 
-#include "cgi/cgi.h"
-#include "cgi/cgiwrap.h"
-#include "util/neo_misc.h"
+#include "ClearSilver.h"
 
 /* from httpd util.c : made infamous with Roy owes Rob beer. */
 static char *months[] = {
diff -Nru clearsilver-0.8.1/java-jni/Makefile clearsilver-0.9.0/java-jni/Makefile
--- clearsilver-0.8.1/java-jni/Makefile	Wed Apr  2 16:26:22 2003
+++ clearsilver-0.9.0/java-jni/Makefile	Mon Apr 14 17:13:42 2003
@@ -20,7 +20,7 @@
 DLIBS += -lneo_cgi -lneo_cs -lneo_utl 
 LIBS += -L$(LIB_DIR) $(DLIBS)
 
-TARGETS = $(NEO_UTIL_SO)
+TARGETS = org_clearsilver_HDF.h org_clearsilver_CS.h $(NEO_UTIL_SO)
 
 all: $(TARGETS) test
 
@@ -48,6 +48,11 @@
 
 $(NEO_UTIL_SO): $(NEO_UTIL_JAVA_JAR) $(NEO_UTIL_OBJ) $(DEP_LIBS)
 	$(LDSHARED) -o $@ $(LDFLAGS) $(NEO_UTIL_OBJ) $(LIBS)
+
+# I guess we'll just stick the .jar file in the lib directory
+install: all
+	$(INSTALL) $(NEO_UTIL_SO) $(DESTDIR)$(libdir)
+	$(INSTALL) $(NEO_UTIL_JAVA_JAR) $(DESTDIR)$(libdir)
 
 clean:
 	$(RM) *.o *.so
diff -Nru clearsilver-0.8.1/mod_ecs/Makefile clearsilver-0.9.0/mod_ecs/Makefile
--- clearsilver-0.8.1/mod_ecs/Makefile	Wed Apr  2 15:07:31 2003
+++ clearsilver-0.9.0/mod_ecs/Makefile	Mon Apr 14 17:13:44 2003
@@ -19,6 +19,14 @@
 $(MOD_ECS_SO): $(MOD_ECS_SRC) $(DEP_LIBS)
 	$(APXS) -c -o $@ $(MOD_ECS_SRC)
 
+install: all
+	$(NEOTONIC_ROOT)mkinstalldirs $(DESTDIR)$(libexecdir)
+	$(INSTALL) $(MOD_ECS_SO) $(DESTDIR)$(libexecdir)
+
+# Hmm, install it in the default apache place, or in with the 
+# rest of our stuff?
+#	$(APXS) -i $(MOD_ECS_SO)
+
 clean:
 	$(RM) *.o
 
diff -Nru clearsilver-0.8.1/perl/ClearSilver.pm clearsilver-0.9.0/perl/ClearSilver.pm
--- clearsilver-0.8.1/perl/ClearSilver.pm	Wed Apr  2 15:07:32 2003
+++ clearsilver-0.9.0/perl/ClearSilver.pm	Fri Apr  4 16:02:53 2003
@@ -1,6 +1,6 @@
 package ClearSilver;
 
-use 5.005;
+use 5.006;
 use strict;
 use warnings;
 
diff -Nru clearsilver-0.8.1/perl/ClearSilver.xs clearsilver-0.9.0/perl/ClearSilver.xs
--- clearsilver-0.8.1/perl/ClearSilver.xs	Wed Apr  2 15:07:32 2003
+++ clearsilver-0.9.0/perl/ClearSilver.xs	Mon Apr 14 16:05:10 2003
@@ -2,9 +2,7 @@
 #include "perl.h"
 #include "XSUB.h"
 
-#include "cs_config.h"
-#include "util/neo_hdf.h"
-#include "cs/cs.h"
+#include "ClearSilver.h"
 
 /* #define DEBUG_MODE 1
  */
diff -Nru clearsilver-0.8.1/perl/Makefile.PL clearsilver-0.9.0/perl/Makefile.PL
--- clearsilver-0.8.1/perl/Makefile.PL	Wed Apr  2 15:07:32 2003
+++ clearsilver-0.9.0/perl/Makefile.PL	Fri Apr  4 16:03:54 2003
@@ -5,9 +5,9 @@
     'NAME'		=> 'ClearSilver',
     'VERSION_FROM'	=> 'ClearSilver.pm', # finds $VERSION
     'PREREQ_PM'		=> {}, # e.g., Module::Name => 1.1
-#    ($] >= 5.005 ?    ## Add these new keywords supported since 5.005
-#      (ABSTRACT_FROM => 'ClearSilver.pm', # retrieve abstract from module
-#       AUTHOR     => 'A. U. Thor <a.u.thor@a.galaxy.far.far.away>') : ()),
+    ($] >= 5.005 ?    ## Add these new keywords supported since 5.005
+      (ABSTRACT_FROM => 'ClearSilver.pm', # retrieve abstract from module
+       AUTHOR     => 'A. U. Thor <a.u.thor@a.galaxy.far.far.away>') : ()),
     'LIBS'		=> ['-L../libs -lneo_cs -lneo_utl'], 
     'DEFINE'		=> '', # e.g., '-DHAVE_SOMETHING'
 	# Insert -I. if you add *.h files later:
diff -Nru clearsilver-0.8.1/python/Makefile clearsilver-0.9.0/python/Makefile
--- clearsilver-0.8.1/python/Makefile	Wed Apr  2 19:49:30 2003
+++ clearsilver-0.9.0/python/Makefile	Mon Apr 14 17:13:45 2003
@@ -33,6 +33,10 @@
 		--target=i386-mingw32 \
 		$(PYTHON_LIB) $(LIBS)
 
+install: all
+	$(NEOTONIC_ROOT)mkinstalldirs $(DESTDIR)$(PYTHON_SITE)
+	$(INSTALL) $(TARGETS) $(DESTDIR)$(PYTHON_SITE)
+
 clean:
 	$(RM) *.o
 
diff -Nru clearsilver-0.8.1/python/examples/CSPage.py clearsilver-0.9.0/python/examples/CSPage.py
--- clearsilver-0.8.1/python/examples/CSPage.py	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/python/examples/CSPage.py	Sun Jun 15 18:54:49 2003
@@ -0,0 +1,209 @@
+#!/neo/opt/bin/python
+
+import neo_cgi
+import sys, os, string
+import time
+from log import *
+
+# errors thrown...
+NoPageName = "NoPageName"
+NoDisplayMethod = "NoDisplayMethod"
+
+# errors signaled back to here
+Redirected = "Redirected"
+DisplayDone = "DisplayDone"
+DisplayError = "DisplayError"
+
+class Context:
+    def __init__ (self):
+        self.argv = sys.argv
+        self.stdin = sys.stdin
+        self.stdout = sys.stdout
+        self.stderr = sys.stderr
+        self.environ = os.environ
+
+class CSPage:
+    def __init__(self, context, pagename=0,readDefaultHDF=1,israwpage=0):
+	if pagename == 0:
+	    raise NoPageName, "missing pagename"
+	self.pagename = pagename
+	self.readDefaultHDF = readDefaultHDF
+        self._israwpage = israwpage
+        self.context = context
+
+        self._error_template = None
+
+        self.page_start_time = time.time()
+	neo_cgi.cgiWrap(context.stdin, context.stdout, context.environ)
+        neo_cgi.IgnoreEmptyFormVars(1)
+	self.ncgi = neo_cgi.CGI()
+        self.ncgi.parse()
+        self._path_num = 0
+	domain = self.ncgi.hdf.getValue("CGI.ServerName","")
+	domain = self.ncgi.hdf.getValue("HTTP.Host", domain)
+        self.domain = domain
+        self.subclassinit()
+        self.setPaths([self.ncgi.hdf.getValue("CGI.DocumentRoot","")])
+
+    def subclassinit(self):
+        pass
+
+    def setPaths(self, paths):
+        for path in paths:  
+            self.ncgi.hdf.setValue("hdf.loadpaths.%d" % self._path_num, path)
+            self._path_num = self._path_num + 1
+            
+    def redirectUri(self,redirectTo):
+        ncgi = self.ncgi
+        if ncgi.hdf.getIntValue("Cookie.debug",0) == 1:
+            ncgi.hdf.setValue("CGI.REDIRECT_TO",redirectTo)
+            ncgi.display("dbg/redirect.cs")
+            print "<PRE>"
+            print neo_cgi.htmlEscape(ncgi.hdf.dump())
+            print "</PRE>"
+            raise DisplayDone
+
+        self.ncgi.redirectUri(redirectTo)
+        raise Redirected, "redirected To: %s" % redirectTo
+
+    ## ----------------------------------
+    ## methods to be overridden in subclass when necessary:
+
+    def setup(self):
+        pass
+
+    def display(self):
+        raise NoDisplayMethod, "no display method present in %s" % repr(self)
+
+    def main(self):
+        self.setup()
+        self.handle_actions()
+        self.display()
+
+    ## ----------------------------------
+        
+    def handle_actions(self):
+        hdf = self.ncgi.hdf
+        hdfobj = hdf.getObj("Query.Action")
+        if hdfobj:
+            firstchild = hdfobj.child()
+            if firstchild:
+                action = firstchild.name()
+                if firstchild.next():
+                    raise "multiple actions present!!!"
+
+                method_name = "Action_%s" % action
+                method = getattr(self,method_name)
+                apply(method,[])
+
+    def start(self):
+	SHOULD_DISPLAY = 1
+        if self._israwpage:
+            SHOULD_DISPLAY = 0
+        
+	ncgi = self.ncgi
+	
+	if self.readDefaultHDF:
+            try:
+                if not self.pagename is None:
+                    ncgi.hdf.readFile("%s.hdf" % self.pagename)
+            except:
+                log("Error reading HDF file: %s.hdf" % (self.pagename))
+
+        DISPLAY_ERROR = 0
+        ERROR_MESSAGE = ""
+        # call page main function!
+        try:
+            self.main()
+        except DisplayDone:
+            SHOULD_DISPLAY = 0
+        except Redirected:
+            # catch redirect exceptions
+            SHOULD_DISPLAY = 0
+        except DisplayError, num:
+            ncgi.hdf.setValue("Query.error", str(num))
+            if self._error_template:
+                ncgi.hdf.setValue("Content", self._error_template)
+            else:
+                DISPLAY_ERROR = 1
+        except:
+            SHOULD_DISPLAY = 0
+            DISPLAY_ERROR = 1
+            
+            import handle_error
+            handle_error.handleException("Display Failed!")
+            ERROR_MESSAGE = handle_error.exceptionString()
+
+        if DISPLAY_ERROR:
+            print "Content-Type: text/html\n\n"
+
+            # print the page
+
+            print "<H1> Error in Page </H1>"
+            print "A copy of this error report has been submitted to the developers. "
+            print "The details of the error report are below."
+
+
+            print "<PRE>"
+            print neo_cgi.htmlEscape(ERROR_MESSAGE)
+            print "</PRE>\n"
+            # print debug info always on page error...
+            print "<HR>\n"
+            print "<PRE>"
+            print neo_cgi.htmlEscape(ncgi.hdf.dump())
+            print "</PRE>"
+
+
+        etime = time.time() - self.page_start_time
+        ncgi.hdf.setValue("CGI.debug.execute_time","%f" % (etime))
+
+        if SHOULD_DISPLAY and self.pagename:
+            debug_output = ncgi.hdf.getIntValue("page.debug",ncgi.hdf.getIntValue("Cookie.debug",0))
+
+            if not debug_output:
+              ncgi.hdf.setValue("Config.CompressionEnabled","1")
+
+	    # default display
+	    template_name = ncgi.hdf.getValue("Content","%s.cs" % self.pagename)
+            # ncgi.hdf.setValue ("cgiout.charset", "utf-8");
+
+	    ncgi.display(template_name)
+
+	    # debug output
+	    if debug_output:
+		print "<HR>\n"
+                print "Execution Time: %5.3f<BR><HR>" % (etime)
+		print "<PRE>"
+		print neo_cgi.htmlEscape(ncgi.hdf.dump())
+		print "</PRE>"
+		# ncgi.hdf.setValue("hdf.DEBUG",ncgi.hdf.dump())
+		# ncgi.display("debug.cs")
+                
+        script_name = ncgi.hdf.getValue("CGI.ScriptName","")
+        if script_name:
+            script_name = string.split(script_name,"/")[-1]
+            
+        log ("[%s] etime/dtime: %5.3f/%5.3f %s (%s)" % (self.domain, etime, time.time() - etime - self.page_start_time,  script_name, self.pagename))
+
+    # a protected output function to catch the output errors that occur when
+    # the server is either restarted or the user pushes the stop button on the
+    # browser
+    def output(self, str):
+        try:
+            self.context.stdout.write(str)
+        except IOError, reason:
+            log("IOError: %s" % (repr(reason)))
+            raise DisplayDone
+
+
+    def allQuery (self, s):
+        l = []
+        if self.ncgi.hdf.getValue ("Query.%s.0" % s, ""):
+          obj = self.ncgi.hdf.getChild ("Query.%s" % s)
+          while obj:
+            l.append(obj.value())
+            obj = obj.next()
+        else:
+          t = self.ncgi.hdf.getValue ("Query.%s" % s, "")
+          if t: l.append(t)
+        return l
diff -Nru clearsilver-0.8.1/python/examples/handle_error.py clearsilver-0.9.0/python/examples/handle_error.py
--- clearsilver-0.8.1/python/examples/handle_error.py	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/python/examples/handle_error.py	Sun Jun 15 18:54:49 2003
@@ -0,0 +1,91 @@
+
+import traceback, sys, string, time, socket, os
+import who_calls
+
+DUMP_DIR = "/neo/data/bugs"
+
+Warning = "handle_error.Warning"
+
+# levels
+LV_MESSAGE = "LV_MESSAGE"
+LV_WARNING = "LV_WARNING"
+LV_ERROR   = "LV_ERROR"
+
+Count = 0
+
+gErrorCount = 0
+DISABLE_DUMP = 0
+
+def exceptionReason():
+  return "%s.%s" % (str(sys.exc_type), str(sys.exc_value))
+
+def exceptionString():
+  tb_list = traceback.format_exception(sys.exc_type,sys.exc_value,sys.exc_traceback)
+  return string.join(tb_list,"")
+
+  #### old way
+  import StringIO
+  ## get the traceback message  
+  sfp = StringIO.StringIO()
+  traceback.print_exc(file=sfp)
+  exception = sfp.getvalue()
+  sfp.close()
+
+  return exception
+
+
+def handleException (msg=None, lvl=LV_ERROR, dump = 1):
+  global gErrorCount
+  gErrorCount = gErrorCount + 1
+
+  tb_list = traceback.format_exception(sys.exc_type,sys.exc_value,sys.exc_traceback)
+  if msg:
+    sys.stderr.write ("%s\n" % msg)
+  else:
+    msg = "Unhandled Exception"
+        
+  sys.stderr.write (string.join(tb_list,""))
+  try:
+    if dump: dump_bug(lvl, "handleException", msg, string.join(tb_list, ""))
+  except:
+    handleException("Unable to dump_bug", dump = 0)
+
+def handleWarning (msg=""):
+  header = "*** handleWarning: %s\n" % msg
+  sys.stderr.write(header)
+  tb = who_calls.pretty_who_calls(strip=1) + "\n"
+  sys.stderr.write(tb)
+
+  try:
+    dump_bug(LV_WARNING, "handleException", msg, tb)
+  except:
+    handleException("Unable to dump_bug", dump = 0)
+
+def dump_bug (level, etype, msg, location=None, nhdf=None):
+    global DISABLE_DUMP
+    if DISABLE_DUMP: return
+
+    now = int(time.time())
+    pid = os.getpid()
+
+    import neo_cgi, neo_util
+    hdf = neo_util.HDF()
+    hdf.setValue("Required.Level", level)
+    hdf.setValue("Required.When", str(int(time.time())))
+    hdf.setValue("Required.Type", etype)
+    hdf.setValue("Required.Title", msg)
+    hdf.setValue("Optional.Hostname", socket.gethostname())
+    if location:
+        hdf.setValue("Optional.Location", location)
+
+    for (key, value) in os.environ.items():
+        hdf.setValue ("Environ.%s" % key, value)
+
+    global Count
+    Count = Count + 1
+    fname = "%d.%d_%d.%s" % (now, pid, Count, socket.gethostname())
+    tpath = os.path.join (DUMP_DIR, "tmp", fname)
+    npath = os.path.join (DUMP_DIR, "new", fname)
+    hdf.writeFile(tpath)
+    os.rename(tpath, npath)
+
diff -Nru clearsilver-0.8.1/python/examples/log.py clearsilver-0.9.0/python/examples/log.py
--- clearsilver-0.8.1/python/examples/log.py	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/python/examples/log.py	Sun Jun 15 23:14:49 2003
@@ -0,0 +1,51 @@
+#!/neo/opt/bin/python
+
+# log.py
+
+import sys, time
+
+DEV = "development"
+DEV_UPDATE = "update queries"
+DEV_SELECT = "select queries"
+DEV_REPORT = "report log"
+
+LOGGING_STATUS = {
+   DEV : 1,
+   DEV_UPDATE : 0,
+   DEV_SELECT : 0,
+   DEV_REPORT : 0}
+
+tstart = 0
+
+def dlog(when,astr):
+    global LOGGING_STATUS
+    try:
+        if LOGGING_STATUS[when]:
+            log(astr)
+    except KeyError:
+        pass
+
+def tlog(astr):
+    global tstart
+    t = time.time()
+    if tstart == 0:
+        tstart = t
+    time_stamp = "%5.5f" % (t-tstart)
+    if len(astr):
+        if astr[-1] == "\n":
+            sys.stderr.write("[%s] %s" % (time_stamp, astr))
+        else:
+            sys.stderr.write("[%s] %s\n" % (time_stamp, astr))
+
+def log(astr):
+    if len(astr) > 1024:
+        astr = astr[:1024]
+
+    t = time.time()
+    time_stamp = time.strftime("%m/%d %T", time.localtime(t))
+    if len(astr):
+        if astr[-1] == "\n":
+            sys.stderr.write("[%s] %s" % (time_stamp, astr))
+        else:
+            sys.stderr.write("[%s] %s\n" % (time_stamp, astr))
+    # sys.stderr.flush()
diff -Nru clearsilver-0.8.1/python/examples/who_calls.py clearsilver-0.9.0/python/examples/who_calls.py
--- clearsilver-0.8.1/python/examples/who_calls.py	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/python/examples/who_calls.py	Sun Jun 15 18:54:49 2003
@@ -0,0 +1,141 @@
+
+# who_calls.py
+# by Sam Rushing for Medusa
+
+import string
+import sys
+
+from log import *
+
+whoCallsError = "whoCallsError"
+
+#--------------------------------------------------------------
+# Example use:
+#
+# import who_calls
+# log(who_calls.pretty_who_calls())
+#
+#--------------------------------------------------------------
+
+def test():
+  for i in range(1,1000):
+    pretty_who_calls()
+
+  print_top_100()
+
+def who_calls_helper():
+  tinfo = []
+  exc_info = sys.exc_info()
+
+  f = exc_info[2].tb_frame.f_back
+  while f:
+	  tinfo.append ( (
+		  f.f_code.co_filename,
+		  f.f_code.co_name,
+		  f.f_lineno )
+		  )
+	  f = f.f_back
+
+  del exc_info
+  return tinfo
+  
+
+def who_calls():
+  try:
+    raise whoCallsError
+  except whoCallsError:
+    tinfo = who_calls_helper()
+  return tinfo
+
+def pretty_who_calls(strip=0):
+	info = who_calls()
+	buf = []
+
+	for file,function,line in info[1 + strip:]:
+		buf.append("   %s(%s): %s()" % (file,line,function))
+		
+	return string.join(buf,"\n")
+
+# ---------------------------------------------------------------------------
+# used for debugging.
+# ---------------------------------------------------------------------------
+
+def compact_traceback ():
+	t,v,tb = sys.exc_info()
+	tbinfo = []
+	if tb is None:
+		# this should never happen, but then again, lots of things
+		# should never happen but do.
+		return (('','',''), str(t), str(v), 'traceback is None!!!')
+	while 1:
+		tbinfo.append (
+			tb.tb_frame.f_code.co_filename,
+			tb.tb_frame.f_code.co_name,				
+			str(tb.tb_lineno)
+			)
+		tb = tb.tb_next
+		if not tb:
+			break
+
+	# just to be safe
+	del tb
+
+	file, function, line = tbinfo[-1]
+	info = '[' + string.join (
+		map (
+			lambda x: string.join (x, '|'),
+			tbinfo
+			),
+		'] ['
+		) + ']'
+
+	return (file, function, line), str(t), str(v), info
+
+## ----------------------------------------------------
+## Refcount printing
+		
+import sys
+import types
+
+def real_get_refcounts(base = None, set_base = 0):
+    d = {}
+    sys.modules
+    # collect all classes
+    for modname,m in sys.modules.items():
+        for sym in dir(m):
+            o = getattr (m, sym)
+            if type(o) is types.ClassType:
+                name = "%s:%s" % (modname,o.__name__)
+                cnt = sys.getrefcount (o)
+                if base:
+                    if set_base:
+                        base[name] = cnt
+                    elif cnt > base.get(name, 0):
+                        d[name] = cnt - base.get(name, 0)
+                else:
+                    d[name] = cnt
+    return d
+
+def get_refcounts(base=None):
+        d = real_get_refcounts(base = base)
+        # sort by refcount
+        pairs = map (lambda x: (x[1],x[0]), d.items())
+        pairs.sort()
+        pairs.reverse()
+        return pairs
+
+REFCOUNTS = {}
+
+def set_refcount_base():
+    global REFCOUNTS
+    real_get_refcounts(REFCOUNTS, set_base = 1)
+
+def print_top_100():
+        print_top_N(100)
+
+def print_top_N(N):
+    global REFCOUNTS
+    for n, c in get_refcounts(REFCOUNTS)[:N]:
+       log('%10d %s' % (n, c))
+
+
diff -Nru clearsilver-0.8.1/python/neo_cgi.c clearsilver-0.9.0/python/neo_cgi.c
--- clearsilver-0.8.1/python/neo_cgi.c	Wed Apr  2 15:07:34 2003
+++ clearsilver-0.9.0/python/neo_cgi.c	Mon Apr 14 16:05:11 2003
@@ -9,16 +9,7 @@
  */
 
 #include <Python.h>
-
-#include "cs_config.h"
-#include "util/neo_err.h"
-#include "util/neo_misc.h"
-#include "util/neo_str.h"
-#include "util/neo_hdf.h"
-#include "cgi/cgi.h"
-#include "cgi/cgiwrap.h"
-#include "cgi/date.h"
-#include "cgi/html.h"
+#include "ClearSilver.h"
 
 #define NEO_CGI_MODULE
 #include "p_neo_util.h"
diff -Nru clearsilver-0.8.1/python/neo_cs.c clearsilver-0.9.0/python/neo_cs.c
--- clearsilver-0.8.1/python/neo_cs.c	Wed Apr  2 15:07:34 2003
+++ clearsilver-0.9.0/python/neo_cs.c	Mon Apr 14 16:05:11 2003
@@ -9,12 +9,7 @@
  */
 
 #include <Python.h>
-#include "cs_config.h"
-#include "util/neo_err.h"
-#include "util/neo_misc.h"
-#include "util/neo_str.h"
-#include "util/neo_hdf.h"
-#include "cs/cs.h"
+#include "ClearSilver.h"
 
 #define NEO_CGI_MODULE
 #include "p_neo_util.h"
diff -Nru clearsilver-0.8.1/python/neo_util.c clearsilver-0.9.0/python/neo_util.c
--- clearsilver-0.8.1/python/neo_util.c	Wed Apr  2 15:07:34 2003
+++ clearsilver-0.9.0/python/neo_util.c	Mon Apr 14 16:05:11 2003
@@ -9,12 +9,7 @@
  */
 
 #include <Python.h>
-#include "cs_config.h"
-#include "util/neo_err.h"
-#include "util/neo_misc.h"
-#include "util/neo_str.h"
-#include "util/neo_hdf.h"
-#include "util/neo_date.h"
+#include "ClearSilver.h"
 
 #define NEO_CGI_MODULE
 #include "p_neo_util.h"
diff -Nru clearsilver-0.8.1/ruby/Makefile clearsilver-0.9.0/ruby/Makefile
--- clearsilver-0.8.1/ruby/Makefile	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/ruby/Makefile	Tue Jun 17 14:20:10 2003
@@ -0,0 +1,30 @@
+
+
+ifeq ($(NEOTONIC_ROOT),)
+NEOTONIC_ROOT = ../
+endif
+
+include $(NEOTONIC_ROOT)rules.mk
+
+all: config.save ext/hdf/hdf.so test
+
+config.save: install.rb
+	$(RUBY) install.rb config
+
+ext/hdf/Makefile:
+	$(RUBY) install.rb config
+
+ext/hdf/hdf.so: config.save
+	$(RUBY) install.rb setup
+
+test: ext/hdf/hdf.so
+	$(RUBY) -Ilib -Iext/hdf test/hdftest.rb
+
+install: all
+
+clean:
+	$(RM) ext/hdf/*.o
+
+distclean:
+	$(RM) Makefile.depends config.save ext/hdf/hdf.so
+	$(RM) ext/hdf/Makefile ext/hdf/mkmf.log ext/hdf/*.o
diff -Nru clearsilver-0.8.1/ruby/ext/hdf/MANIFEST clearsilver-0.9.0/ruby/ext/hdf/MANIFEST
--- clearsilver-0.8.1/ruby/ext/hdf/MANIFEST	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/ruby/ext/hdf/MANIFEST	Tue Jun 17 14:20:12 2003
@@ -0,0 +1,4 @@
+MANIFEST
+extconf.rb
+neo_cs.c
+neo_util.c
diff -Nru clearsilver-0.8.1/ruby/ext/hdf/extconf.rb clearsilver-0.9.0/ruby/ext/hdf/extconf.rb
--- clearsilver-0.8.1/ruby/ext/hdf/extconf.rb	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/ruby/ext/hdf/extconf.rb	Tue Jun 17 14:20:12 2003
@@ -0,0 +1,9 @@
+#!/usr/bin/env ruby
+
+require 'mkmf'
+
+dir_config("hdf","../../..","../../../libs")
+
+if have_header("util/neo_hdf.h") && have_library("neo_utl","hdf_init") && have_library("neo_cs","cs_init")
+  create_makefile("hdf")
+end
diff -Nru clearsilver-0.8.1/ruby/ext/hdf/neo_cs.c clearsilver-0.9.0/ruby/ext/hdf/neo_cs.c
--- clearsilver-0.8.1/ruby/ext/hdf/neo_cs.c	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/ruby/ext/hdf/neo_cs.c	Tue Jun 17 14:20:12 2003
@@ -0,0 +1,116 @@
+/*
+ * Neotonic ClearSilver Templating System
+ *
+ * This code is made available under the terms of the 
+ * Neotonic ClearSilver License.
+ * http://www.neotonic.com/clearsilver/license.hdf
+ *
+ * Copyright (C) 2001 by Brandon Long
+ */
+
+#include <ruby.h>
+#include "ClearSilver.h"
+
+static VALUE cCs;
+extern VALUE mNeotonic;
+extern VALUE eHdfError;
+
+VALUE r_neo_error(NEOERR *err);
+
+static void c_free (CSPARSE *csd) {
+  if (csd) {
+    cs_destroy (&csd);
+  }
+}
+
+static VALUE c_init (VALUE self) {
+  return self;
+}
+
+VALUE c_new (VALUE class, VALUE oHdf) {
+  CSPARSE *cs = NULL;
+  NEOERR *err;
+  HDF *hdf;
+  VALUE r_cs;
+
+  Data_Get_Struct(oHdf, HDF, hdf);
+
+  if (hdf == NULL) rb_raise(eHdfError, "must include an Hdf object");
+
+  err = cs_init (&cs, hdf);
+
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  r_cs = Data_Wrap_Struct(class, 0, c_free, cs);
+  rb_obj_call_init(r_cs, 0, NULL);
+  return r_cs;
+}
+
+static VALUE c_parse_file (VALUE self, VALUE oPath) {
+  CSPARSE *cs = NULL;
+  NEOERR *err;
+  char *path;
+
+  Data_Get_Struct(self, CSPARSE, cs);
+  path = STR2CSTR(oPath);
+
+  err = cs_parse_file (cs, path);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE c_parse_str (VALUE self, VALUE oString)
+{
+  CSPARSE *cs = NULL;
+  NEOERR *err;
+  char *s, *ms;
+  int l;
+
+  Data_Get_Struct(self, CSPARSE, cs);
+  s = rb_str2cstr(oString, &l);
+
+  /* This should be changed to use memory from the gc */
+  ms = strdup(s);
+  if (ms == NULL) rb_raise(rb_eNoMemError, "out of memory");
+
+  err = cs_parse_string (cs, ms, l);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static NEOERR *render_cb (void *ctx, char *buf)
+{
+  STRING *str= (STRING *)ctx;
+
+  return nerr_pass(string_append(str, buf));
+}
+
+static VALUE c_render (VALUE self)
+{
+  CSPARSE *cs = NULL;
+  NEOERR *err;
+  STRING str;
+  VALUE rv;
+
+  Data_Get_Struct(self, CSPARSE, cs);
+
+  string_init(&str);
+  err = cs_render (cs, &str, render_cb);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  rv = rb_str_new2(str.buf);
+  string_clear (&str);
+  return rv;
+}
+
+void Init_Cs() {
+  cCs = rb_define_class_under(mNeotonic, "Cs", rb_cObject);
+  rb_define_singleton_method(cCs, "new", c_new, 1);
+
+  rb_define_method(cCs, "initialize", c_init, 0);
+  rb_define_method(cCs, "parse_file", c_parse_file, 1);
+  rb_define_method(cCs, "parse_string", c_parse_str, 1);
+  rb_define_method(cCs, "render", c_render, 0);
+}
diff -Nru clearsilver-0.8.1/ruby/ext/hdf/neo_util.c clearsilver-0.9.0/ruby/ext/hdf/neo_util.c
--- clearsilver-0.8.1/ruby/ext/hdf/neo_util.c	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/ruby/ext/hdf/neo_util.c	Tue Jun 17 14:20:12 2003
@@ -0,0 +1,522 @@
+/*
+ * Neotonic ClearSilver Templating System
+ *
+ * This code is made available under the terms of the 
+ * Neotonic ClearSilver License.
+ * http://www.neotonic.com/clearsilver/license.hdf
+ *
+ * Copyright (C) 2001 by Brandon Long
+ */
+
+#include <ruby.h>
+#include "ClearSilver.h"
+
+VALUE mNeotonic;
+static VALUE cHdf;
+VALUE eHdfError;
+
+
+VALUE r_neo_error (NEOERR *err)
+{
+  STRING str;
+  VALUE errstr;
+
+  string_init (&str);
+  if (nerr_match(err, NERR_PARSE)) {
+    nerr_error_string (err, &str);
+    errstr = rb_str_new2(str.buf);
+    string_clear(&str);
+    return errstr;
+  }
+  else {
+    nerr_error_traceback (err, &str);
+    errstr = rb_str_new2(str.buf);
+    string_clear(&str);
+    return errstr;
+  }
+  string_clear (&str);
+  return Qnil;
+}
+
+static void h_free(void *p) {
+  hdf_destroy(p);
+}
+
+
+static VALUE h_init (VALUE self)
+{
+  return self;
+}
+
+VALUE h_new(VALUE class)
+{
+  HDF *hdf = NULL;
+  NEOERR *err;
+  VALUE r_hdf;
+
+  err = hdf_init (&hdf);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  r_hdf = Data_Wrap_Struct(class, 0, h_free, hdf);
+  rb_obj_call_init(r_hdf, 0, NULL);
+  return r_hdf;
+}
+
+static VALUE h_get_attr (VALUE self, VALUE oName)
+{
+  HDF *hdf = NULL;
+  char *name;
+  HDF_ATTR *attr;
+  VALUE k,v;
+  VALUE rv;
+
+  Data_Get_Struct(self, HDF, hdf);
+  name = STR2CSTR(oName);
+
+  rv = rb_hash_new();
+
+  attr = hdf_get_attr(hdf, name);
+  while ( attr != NULL ) {
+    k=rb_str_new2(attr->key);
+    v=rb_str_new2(attr->value);
+    rb_hash_aset(rv, k, v);
+    attr = attr->next;
+  }
+  return rv;
+}
+
+static VALUE h_set_attr(VALUE self, VALUE oName, VALUE oKey, VALUE oValue)
+{
+  HDF *hdf= NULL;
+  char *name, *key, *value;
+  NEOERR *err;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  name = STR2CSTR(oName);
+  key = STR2CSTR(oKey);
+  if ( NIL_P(oValue) )
+    value = NULL;
+  else
+    value = STR2CSTR(oValue);
+
+  err = hdf_set_attr(hdf, name, key, value);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE h_set_value (VALUE self, VALUE oName, VALUE oValue)
+{
+  HDF *hdf = NULL;
+  char *name, *value;
+  NEOERR *err;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  name=STR2CSTR(oName);
+  value=STR2CSTR(oValue);
+
+  err = hdf_set_value (hdf, name, value);
+
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE h_get_int_value (VALUE self, VALUE oName, VALUE oDefault)
+{
+  HDF *hdf = NULL;
+  char *name;
+  int r, d = 0;
+  VALUE rv;
+
+  Data_Get_Struct(self, HDF, hdf);
+  name=STR2CSTR(oName);
+  d=NUM2INT(oDefault);
+
+  r = hdf_get_int_value (hdf, name, d);
+  rv = INT2NUM(r);
+  return rv;
+}
+
+static VALUE h_get_value (VALUE self, VALUE oName, VALUE oDefault)
+{
+  HDF *hdf = NULL;
+  char *name;
+  char *r, *d = NULL;
+  VALUE rv;
+
+  Data_Get_Struct(self, HDF, hdf);
+  name=STR2CSTR(oName);
+  d=STR2CSTR(oDefault);
+
+  r = hdf_get_value (hdf, name, d);
+  rv = rb_str_new2(r);
+  return rv;
+}
+
+static VALUE h_get_child (VALUE self, VALUE oName)
+{
+  HDF *hdf = NULL;
+  HDF *r;
+  VALUE rv;
+  char *name;
+
+  Data_Get_Struct(self, HDF, hdf);
+  name=STR2CSTR(oName);
+
+  r = hdf_get_child (hdf, name);
+  if (r == NULL) {
+    return Qnil;
+  }
+
+  rv = Data_Wrap_Struct(cHdf, 0, h_free, r);
+  return rv;
+}
+
+
+static VALUE h_obj_child (VALUE self)
+{
+  HDF *hdf = NULL;
+  HDF *r = NULL;
+  VALUE rv;
+
+  Data_Get_Struct(self, HDF, hdf);
+  
+  r = hdf_obj_child (hdf);
+  if (r == NULL) {
+    return Qnil;
+  }
+
+  rv = Data_Wrap_Struct(cHdf, 0, h_free, r);
+  return rv;
+}
+
+static VALUE h_obj_next (VALUE self)
+{
+  HDF *hdf = NULL;
+  HDF *r = NULL;
+  VALUE rv;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  r = hdf_obj_next (hdf);
+  if (r == NULL) {
+    return Qnil;
+  }
+
+  rv = Data_Wrap_Struct(cHdf, 0, h_free, r);
+  return rv;
+}
+
+static VALUE h_obj_top (VALUE self)
+{
+  HDF *hdf = NULL;
+  HDF *r = NULL;
+  VALUE rv;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  r = hdf_obj_top (hdf);
+  if (r == NULL) {
+    return Qnil;
+  }
+
+  rv = Data_Wrap_Struct(cHdf, 0, h_free, r);
+  return rv;
+}
+
+static VALUE h_obj_name (VALUE self)
+{
+  HDF *hdf = NULL;
+  VALUE rv;
+  char *r;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  r = hdf_obj_name (hdf);
+  if (r == NULL) {
+    return Qnil;
+  }
+
+  rv = rb_str_new2(r);
+  return rv;
+}
+
+static VALUE h_obj_attr (VALUE self)
+{
+  HDF *hdf = NULL;
+  HDF_ATTR *attr;
+  VALUE k,v;
+  VALUE rv;
+
+  Data_Get_Struct(self, HDF, hdf);
+  rv = rb_hash_new();
+  
+  attr = hdf_obj_attr(hdf);
+  while ( attr != NULL ) {
+    k=rb_str_new2(attr->key);
+    v=rb_str_new2(attr->value);
+    rb_hash_aset(rv, k, v);
+    attr = attr->next;
+  }
+  return rv;
+}
+
+
+static VALUE h_obj_value (VALUE self)
+{
+  HDF *hdf = NULL;
+  VALUE rv;
+  char *r;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  r = hdf_obj_value (hdf);
+  if (r == NULL) {
+    return Qnil;
+  }
+
+  rv = rb_str_new2(r);
+  return rv;
+}
+
+static VALUE h_read_file (VALUE self, VALUE oPath)
+{
+  HDF *hdf = NULL;
+  char *path;
+  NEOERR *err;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  path=STR2CSTR(oPath);
+
+  err = hdf_read_file (hdf, path);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE h_write_file (VALUE self, VALUE oPath)
+{
+  HDF *hdf = NULL;
+  char *path;
+  NEOERR *err;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  path=STR2CSTR(oPath);
+
+  err = hdf_write_file (hdf, path);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE h_write_file_atomic (VALUE self, VALUE oPath)
+{
+  HDF *hdf = NULL;
+  char *path;
+  NEOERR *err;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  path=STR2CSTR(oPath);
+
+  err = hdf_write_file_atomic (hdf, path);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE h_remove_tree (VALUE self, VALUE oName)
+{
+  HDF *hdf = NULL;
+  char *name;
+  NEOERR *err;
+
+  Data_Get_Struct(self, HDF, hdf);
+  name = STR2CSTR(oName);
+
+  err = hdf_remove_tree (hdf, name);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE h_dump (VALUE self)
+{
+  HDF *hdf = NULL;
+  VALUE rv;
+  NEOERR *err;
+  STRING str;
+
+  string_init (&str);
+  
+  Data_Get_Struct(self, HDF, hdf);
+
+  err = hdf_dump_str (hdf, NULL, 0, &str);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  rv = rb_str_new2(str.buf);
+  string_clear (&str);
+  return rv;
+}
+
+static VALUE h_write_string (VALUE self)
+{
+  HDF *hdf = NULL;
+  VALUE rv;
+  NEOERR *err;
+  char *s = NULL;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  err = hdf_write_string (hdf, &s);
+
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  rv = rb_str_new2(s);
+  if (s) free(s);
+  return rv;
+}
+
+static VALUE h_read_string (VALUE self, VALUE oString, VALUE oIgnore)
+{
+  HDF *hdf = NULL;
+  NEOERR *err;
+  char *s = NULL;
+  int ignore = 0;
+
+  Data_Get_Struct(self, HDF, hdf);
+
+  s = STR2CSTR(oString);
+  ignore = NUM2INT(oIgnore);
+
+  err = hdf_read_string_ignore (hdf, s, ignore);
+
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE h_copy (VALUE self, VALUE oName, VALUE oHdfSrc)
+{
+  HDF *hdf = NULL;
+  HDF *src = NULL;
+  char *name;
+  NEOERR *err;
+
+  Data_Get_Struct(self, HDF, hdf);
+  Data_Get_Struct(oHdfSrc, HDF, src);
+
+  name = STR2CSTR(oName);
+
+  if (src == NULL) rb_raise(eHdfError, "second argument must be an Hdf object");
+
+  err = hdf_copy (hdf, name, src);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE h_set_symlink (VALUE self, VALUE oSrc, VALUE oDest)
+{
+  HDF *hdf = NULL;
+  char *src;
+  char *dest;
+  NEOERR *err;
+
+  Data_Get_Struct(self, HDF, hdf);
+  src = STR2CSTR(oSrc);
+  dest = STR2CSTR(oDest);
+
+  err = hdf_set_symlink (hdf, src, dest);
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  return self;
+}
+
+static VALUE h_escape (VALUE self, VALUE oString, VALUE oEsc_char, VALUE oEsc)
+{
+  VALUE rv;
+  char *s;
+  char *escape;
+  char *esc_char;
+  int buflen;
+  char *ret = NULL;
+  NEOERR *err;
+
+  s = rb_str2cstr(oString,&buflen);
+  esc_char = STR2CSTR(oEsc_char);
+  escape = STR2CSTR(oEsc);
+
+  err = neos_escape(s, buflen, esc_char[0], escape, &ret);
+
+  if (err) rb_raise(eHdfError, "%s", r_neo_error(err));
+
+  rv = rb_str_new2(ret);
+  free(ret);
+  return rv;
+}
+
+static VALUE h_unescape (VALUE self, VALUE oString, VALUE oEsc_char)
+{
+  VALUE rv;
+  char *s;
+  char *copy;
+  char *esc_char;
+  int buflen;
+
+  s = rb_str2cstr(oString,&buflen);
+  esc_char = STR2CSTR(oEsc_char);
+
+  /* This should be changed to use memory from the gc */
+  copy = strdup(s);
+  if (copy == NULL) rb_raise(rb_eNoMemError, "out of memory");
+
+  neos_unescape(copy, buflen, esc_char[0]);
+
+  rv = rb_str_new2(copy);
+  free(copy);
+  return rv;
+}
+
+void Init_cs();
+
+void Init_hdf() {
+  mNeotonic = rb_define_module("Neo");
+  cHdf = rb_define_class_under(mNeotonic, "Hdf", rb_cObject);
+
+  rb_define_singleton_method(cHdf, "new", h_new, 0);
+  rb_define_method(cHdf, "initialize", h_init, 0);
+  rb_define_method(cHdf, "get_attr", h_get_attr, 1);
+  rb_define_method(cHdf, "set_attr", h_set_attr, 3);
+  rb_define_method(cHdf, "set_value", h_set_value, 2);
+  rb_define_method(cHdf, "get_int_value", h_get_int_value, 2);
+  rb_define_method(cHdf, "get_value", h_get_value, 2);
+  rb_define_method(cHdf, "get_child", h_get_child, 1);
+  rb_define_method(cHdf, "obj_child", h_obj_child, 0);
+  rb_define_method(cHdf, "obj_next", h_obj_next, 0);
+  rb_define_method(cHdf, "obj_top", h_obj_top, 0);
+  rb_define_method(cHdf, "obj_name", h_obj_name, 0);
+  rb_define_method(cHdf, "obj_attr", h_obj_attr, 0);
+  rb_define_method(cHdf, "obj_value", h_obj_value, 0);
+  rb_define_method(cHdf, "read_file", h_read_file, 1);
+  rb_define_method(cHdf, "write_file", h_write_file, 1);
+  rb_define_method(cHdf, "write_file_atomic", h_write_file_atomic, 1);
+  rb_define_method(cHdf, "remove_tree", h_remove_tree, 1);
+  rb_define_method(cHdf, "dump", h_dump, 0);
+  rb_define_method(cHdf, "write_string", h_write_string, 0);
+  rb_define_method(cHdf, "read_string", h_read_string, 2);
+  rb_define_method(cHdf, "copy", h_copy, 2);
+  rb_define_method(cHdf, "set_symlink", h_set_symlink, 2);
+
+  rb_define_singleton_method(cHdf, "escape", h_escape, 3);
+  rb_define_singleton_method(cHdf, "unescape", h_unescape, 3);
+
+  eHdfError = rb_define_class_under(mNeotonic, "HdfError", rb_eException);
+
+  Init_Cs();
+}
diff -Nru clearsilver-0.8.1/ruby/install.rb clearsilver-0.9.0/ruby/install.rb
--- clearsilver-0.8.1/ruby/install.rb	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/ruby/install.rb	Tue Jun 17 14:20:10 2003
@@ -0,0 +1,1015 @@
+#
+# This file is automatically generated. DO NOT MODIFY!
+#
+# install.rb
+#
+#   Copyright (c) 2000-2002 Minero Aoki <aamine@loveruby.net>
+#
+#   This program is free software.
+#   You can distribute/modify this program under the terms of
+#   the GNU Lesser General Public License version 2.
+#
+
+### begin compat.rb
+
+unless Enumerable.instance_methods.include? 'inject' then
+module Enumerable
+  def inject( result )
+    each do |i|
+      result = yield(result, i)
+    end
+    result
+  end
+end
+end
+
+def File.read_all( fname )
+  File.open(fname, 'rb') {|f| return f.read }
+end
+
+def File.write( fname, str )
+  File.open(fname, 'wb') {|f| f.write str }
+end
+
+### end compat.rb
+### begin config.rb
+
+if i = ARGV.index(/\A--rbconfig=/) then
+  file = $'
+  ARGV.delete_at(i)
+  require file
+else
+  require 'rbconfig'
+end
+
+
+class ConfigTable
+
+  c = ::Config::CONFIG
+
+  rubypath = c['bindir'] + '/' + c['ruby_install_name']
+
+  major = c['MAJOR'].to_i
+  minor = c['MINOR'].to_i
+  teeny = c['TEENY'].to_i
+  version = "#{major}.#{minor}"
+
+  # ruby ver. >= 1.4.4?
+  newpath_p = ((major >= 2) or
+               ((major == 1) and
+                ((minor >= 5) or
+                 ((minor == 4) and (teeny >= 4)))))
+  
+  re = Regexp.new('\A' + Regexp.quote(c['prefix']))
+  subprefix = lambda {|path|
+      re === path and path.sub(re, '$prefix')
+  }
+
+  if c['rubylibdir'] then
+    # 1.6.3 < V
+    stdruby    = subprefix.call(c['rubylibdir'])
+    siteruby   = subprefix.call(c['sitedir'])
+    versite    = subprefix.call(c['sitelibdir'])
+    sodir      = subprefix.call(c['sitearchdir'])
+  elsif newpath_p then
+    # 1.4.4 <= V <= 1.6.3
+    stdruby    = "$prefix/lib/ruby/#{version}"
+    siteruby   = subprefix.call(c['sitedir'])
+    versite    = siteruby + '/' + version
+    sodir      = "$site-ruby/#{c['arch']}"
+  else
+    # V < 1.4.4
+    stdruby    = "$prefix/lib/ruby/#{version}"
+    siteruby   = "$prefix/lib/ruby/#{version}/site_ruby"
+    versite    = siteruby
+    sodir      = "$site-ruby/#{c['arch']}"
+  end
+
+  DESCRIPTER = [
+    [ 'prefix',    [ c['prefix'],
+                     'path',
+                     'path prefix of target environment' ] ],
+    [ 'std-ruby',  [ stdruby,
+                     'path',
+                     'the directory for standard ruby libraries' ] ],
+    [ 'site-ruby-common', [ siteruby,
+                     'path',
+                     'the directory for version-independent non-standard ruby libraries' ] ],
+    [ 'site-ruby', [ versite,
+                     'path',
+                     'the directory for non-standard ruby libraries' ] ],
+    [ 'bin-dir',   [ '$prefix/bin',
+                     'path',
+                     'the directory for commands' ] ],
+    [ 'rb-dir',    [ '$site-ruby',
+                     'path',
+                     'the directory for ruby scripts' ] ],
+    [ 'so-dir',    [ sodir,
+                     'path',
+                     'the directory for ruby extentions' ] ],
+    [ 'data-dir',  [ '$prefix/share',
+                     'path',
+                     'the directory for shared data' ] ],
+    [ 'ruby-path', [ rubypath,
+                     'path',
+                     'path to set to #! line' ] ],
+    [ 'ruby-prog', [ rubypath,
+                     'name',
+                     'the ruby program using for installation' ] ],
+    [ 'make-prog', [ 'make',
+                     'name',
+                     'the make program to compile ruby extentions' ] ],
+    [ 'without-ext', [ 'no',
+                       'yes/no',
+                       'does not compile/install ruby extentions' ] ]
+  ]
+
+  SAVE_FILE = 'config.save'
+
+  def ConfigTable.each_name( &block )
+    keys().each( &block )
+  end
+
+  def ConfigTable.keys
+    DESCRIPTER.collect {|k,*dummy| k }
+  end
+
+  def ConfigTable.each_definition( &block )
+    DESCRIPTER.each( &block )
+  end
+
+  def ConfigTable.get_entry( name )
+    name, ent = DESCRIPTER.assoc(name)
+    ent
+  end
+
+  def ConfigTable.get_entry!( name )
+    get_entry(name) or raise ArgumentError, "no such config: #{name}"
+  end
+
+  def ConfigTable.add_entry( name, vals )
+    ConfigTable::DESCRIPTER.push [name,vals]
+  end
+
+  def ConfigTable.remove_entry( name )
+    get_entry name or raise ArgumentError, "no such config: #{name}"
+    DESCRIPTER.delete_if {|n,arr| n == name }
+  end
+
+  def ConfigTable.config_key?( name )
+    get_entry(name) ? true : false
+  end
+
+  def ConfigTable.bool_config?( name )
+    ent = get_entry(name) or return false
+    ent[1] == 'yes/no'
+  end
+
+  def ConfigTable.value_config?( name )
+    ent = get_entry(name) or return false
+    ent[1] != 'yes/no'
+  end
+
+  def ConfigTable.path_config?( name )
+    ent = get_entry(name) or return false
+    ent[1] == 'path'
+  end
+
+
+  class << self
+
+    alias newobj new
+
+    def new
+      c = newobj()
+      c.__send__ :init
+      c
+    end
+
+    def load
+      c = newobj()
+      File.file? SAVE_FILE or
+              raise InstallError, "#{File.basename $0} config first"
+      File.foreach( SAVE_FILE ) do |line|
+        k, v = line.split( '=', 2 )
+        c.instance_eval {
+            @table[k] = v.strip
+        }
+      end
+      c
+    end
+  
+  end
+
+  def initialize
+    @table = {}
+  end
+
+  def init
+    DESCRIPTER.each do |k, (default, vname, desc, default2)|
+      @table[k] = default
+    end
+  end
+  private :init
+
+  def save
+    File.open( SAVE_FILE, 'w' ) {|f|
+        @table.each do |k, v|
+          f.printf "%s=%s\n", k, v if v
+        end
+    }
+  end
+
+  def []=( k, v )
+    ConfigTable.config_key? k or raise InstallError, "unknown config option #{k}"
+    if ConfigTable.path_config? k then
+      @table[k] = (v[0,1] != '$') ? File.expand_path(v) : v
+    else
+      @table[k] = v
+    end
+  end
+    
+  def []( key )
+    @table[key] or return nil
+    @table[key].gsub( %r<\$([^/]+)> ) { self[$1] }
+  end
+
+  def set_raw( key, val )
+    @table[key] = val
+  end
+
+  def get_raw( key )
+    @table[key]
+  end
+
+end
+
+
+class MetaConfigEnvironment
+
+  def self.eval_file( file )
+    return unless File.file? file
+    new.instance_eval File.read_all(file), file, 1
+  end
+
+  private
+
+  def config_names
+    ConfigTable.keys
+  end
+
+  def config?( name )
+    ConfigTable.config_key? name
+  end
+
+  def bool_config?( name )
+    ConfigTable.bool_config? name
+  end
+
+  def value_config?( name )
+    ConfigTable.value_config? name
+  end
+
+  def path_config?( name )
+    ConfigTable.path_config? name
+  end
+
+  def add_config( name, argname, default, desc )
+    ConfigTable.add_entry name,[default,argname,desc]
+  end
+
+  def add_path_config( name, default, desc )
+    add_config name, 'path', default, desc
+  end
+
+  def add_bool_config( name, default, desc )
+    add_config name, 'yes/no', default ? 'yes' : 'no', desc
+  end
+
+  def set_config_default( name, default )
+    if bool_config? name then
+      ConfigTable.get_entry!(name)[0] = default ? 'yes' : 'no'
+    else
+      ConfigTable.get_entry!(name)[0] = default
+    end
+  end
+
+  def remove_config( name )
+    ent = ConfigTable.get_entry(name)
+    ConfigTable.remove_entry name
+    ent
+  end
+
+end
+
+### end config.rb
+### begin fileop.rb
+
+module FileOperations
+
+  def mkdir_p( dname, prefix = nil )
+    dname = prefix + dname if prefix
+    $stderr.puts "mkdir -p #{dname}" if verbose?
+    return if no_harm?
+
+    # does not check '/'... it's too abnormal case
+    dirs = dname.split(%r_(?=/)_)
+    if /\A[a-z]:\z/i === dirs[0] then
+      disk = dirs.shift
+      dirs[0] = disk + dirs[0]
+    end
+    dirs.each_index do |idx|
+      path = dirs[0..idx].join('')
+      Dir.mkdir path unless dir? path
+    end
+  end
+
+  def rm_f( fname )
+    $stderr.puts "rm -f #{fname}" if verbose?
+    return if no_harm?
+
+    if File.exist? fname or File.symlink? fname then
+      File.chmod 0777, fname
+      File.unlink fname
+    end
+  end
+
+  def rm_rf( dn )
+    $stderr.puts "rm -rf #{dn}" if verbose?
+    return if no_harm?
+
+    Dir.chdir dn
+    Dir.foreach('.') do |fn|
+      next if fn == '.'
+      next if fn == '..'
+      if dir? fn then
+        verbose_off {
+            rm_rf fn
+        }
+      else
+        verbose_off {
+            rm_f fn
+        }
+      end
+    end
+    Dir.chdir '..'
+    Dir.rmdir dn
+  end
+
+  def mv( src, dest )
+    rm_f dest
+    begin
+      File.link src, dest
+    rescue
+      File.write dest, File.read_all(src)
+      File.chmod File.stat(src).mode, dest
+    end
+    rm_f src
+  end
+
+  def install( from, dest, mode, prefix = nil )
+    $stderr.puts "install #{from} #{dest}" if verbose?
+    return if no_harm?
+
+    realdest = prefix + dest if prefix
+    if dir? realdest then
+      realdest += '/' + File.basename(from)
+    end
+    str = File.read_all(from)
+    if diff? str, realdest then
+      verbose_off {
+          rm_f realdest if File.exist? realdest
+      }
+      File.write realdest, str
+      File.chmod mode, realdest
+
+      File.open( objdir + '/InstalledFiles', 'a' ) {|f| f.puts realdest }
+    end
+  end
+
+  def diff?( orig, targ )
+    return true unless File.exist? targ
+    orig != File.read_all(targ)
+  end
+
+  def command( str )
+    $stderr.puts str if verbose?
+    system str or raise RuntimeError, "'system #{str}' failed"
+  end
+
+  def ruby( str )
+    command config('ruby-prog') + ' ' + str
+  end
+
+  def dir?( dname )
+    # for corrupted windows stat()
+    File.directory?( (dname[-1,1] == '/') ? dname : dname + '/' )
+  end
+
+  def all_files( dname )
+    Dir.open( dname ) {|d|
+        return d.find_all {|n| File.file? "#{dname}/#{n}" }
+    }
+  end
+
+  def all_dirs( dname )
+    Dir.open( dname ) {|d|
+        return d.find_all {|n| dir? "#{dname}/#{n}" } - %w(. ..)
+    }
+  end
+
+end
+
+### end fileop.rb
+### begin base.rb
+
+class InstallError < StandardError; end
+
+
+class Installer
+
+  Version   = '3.1.2'
+  Copyright = 'Copyright (c) 2000-2002 Minero Aoki'
+
+
+  @toplevel = nil
+
+  def self.declear_toplevel_installer( inst )
+    @toplevel and
+        raise ArgumentError, 'more than one toplevel installer decleared'
+    @toplevel = inst
+  end
+
+  def self.toplevel_installer
+    @toplevel
+  end
+
+
+  FILETYPES = %w( bin lib ext data )
+
+  include FileOperations
+
+  def initialize( config, opt, srcroot, objroot )
+    @config = config
+    @options = opt
+    @srcdir = File.expand_path(srcroot)
+    @objdir = File.expand_path(objroot)
+    @currdir = '.'
+  end
+
+  def inspect
+    "#<#{type} #{__id__}>"
+  end
+
+  #
+  # configs/options
+  #
+
+  def get_config( key )
+    @config[key]
+  end
+
+  alias config get_config
+
+  def set_config( key, val )
+    @config[key] = val
+  end
+
+  def no_harm?
+    @options['no-harm']
+  end
+
+  def verbose?
+    @options['verbose']
+  end
+
+  def verbose_off
+    save, @options['verbose'] = @options['verbose'], false
+    yield
+    @options['verbose'] = save
+  end
+
+  #
+  # srcdir/objdir
+  #
+
+  attr_reader :srcdir
+  alias srcdir_root srcdir
+  alias package_root srcdir
+
+  def curr_srcdir
+    "#{@srcdir}/#{@currdir}"
+  end
+
+  attr_reader :objdir
+  alias objdir_root objdir
+
+  def curr_objdir
+    "#{@objdir}/#{@currdir}"
+  end
+
+  def srcfile( path )
+    curr_srcdir + '/' + path
+  end
+
+  def srcexist?( path )
+    File.exist? srcfile(path)
+  end
+
+  def srcdirectory?( path )
+    dir? srcfile(path)
+  end
+  
+  def srcfile?( path )
+    File.file? srcfile(path)
+  end
+
+  def srcentries( path = '.' )
+    Dir.open( curr_srcdir + '/' + path ) {|d|
+        return d.to_a - %w(. ..) - hookfilenames
+    }
+  end
+
+  def srcfiles( path = '.' )
+    srcentries(path).find_all {|fname|
+        File.file? File.join(curr_srcdir, path, fname)
+    }
+  end
+
+  def srcdirectories( path = '.' )
+    srcentries(path).find_all {|fname|
+        dir? File.join(curr_srcdir, path, fname)
+    }
+  end
+
+  def dive_into( rel )
+    return unless dir? "#{@srcdir}/#{rel}"
+
+    dir = File.basename(rel)
+    Dir.mkdir dir unless dir? dir
+    save = Dir.pwd
+    Dir.chdir dir
+    $stderr.puts '---> ' + rel if verbose?
+    @currdir = rel
+    yield
+    Dir.chdir save
+    $stderr.puts '<--- ' + rel if verbose?
+    @currdir = File.dirname(rel)
+  end
+
+  #
+  # config
+  #
+
+  def exec_config
+    exec_task_traverse 'config'
+  end
+
+  def config_dir_bin( rel )
+  end
+
+  def config_dir_lib( rel )
+  end
+
+  def config_dir_ext( rel )
+    extconf if extdir? curr_srcdir
+  end
+
+  def extconf
+    opt = @options['config-opt'].join(' ')
+    command "#{config('ruby-prog')} #{curr_srcdir}/extconf.rb #{opt}"
+  end
+
+  def config_dir_data( rel )
+  end
+
+  #
+  # setup
+  #
+
+  def exec_setup
+    exec_task_traverse 'setup'
+  end
+
+  def setup_dir_bin( relpath )
+    all_files( curr_srcdir ).each do |fname|
+      add_rubypath "#{curr_srcdir}/#{fname}"
+    end
+  end
+
+  SHEBANG_RE = /\A\#!\s*\S*ruby\S*/
+
+  def add_rubypath( path )
+    $stderr.puts %Q<set #! line to "\#!#{config('ruby-path')}" for #{path} ...> if verbose?
+    return if no_harm?
+
+    tmpfile = File.basename(path) + '.tmp'
+    begin
+      File.open( path ) {|r|
+      File.open( tmpfile, 'w' ) {|w|
+          first = r.gets
+          return unless SHEBANG_RE === first   # reject '/usr/bin/env ruby'
+
+          w.print first.sub( SHEBANG_RE, '#!' + config('ruby-path') )
+          w.write r.read
+      } }
+      mv tmpfile, File.basename(path)
+    ensure
+      rm_f tmpfile if File.exist? tmpfile
+    end
+  end
+
+  def setup_dir_lib( relpath )
+  end
+
+  def setup_dir_ext( relpath )
+    if extdir? curr_srcdir then
+      make
+    end
+  end
+
+  def make
+    command config('make-prog')
+  end
+
+  def setup_dir_data( relpath )
+  end
+
+  #
+  # install
+  #
+
+  def exec_install
+    exec_task_traverse 'install'
+  end
+
+  def install_dir_bin( rel )
+    install_files targfiles, config('bin-dir') + '/' + rel, 0755
+  end
+
+  def install_dir_lib( rel )
+    install_files targfiles, config('rb-dir') + '/' + rel, 0644
+  end
+
+  def install_dir_ext( rel )
+    if extdir? curr_srcdir then
+      install_dir_ext_main File.dirname(rel)
+    end
+  end
+
+  def install_dir_ext_main( rel )
+    install_files allext('.'), config('so-dir') + '/' + rel, 0555
+  end
+
+  def install_dir_data( rel )
+    install_files targfiles, config('data-dir') + '/' + rel, 0644
+  end
+
+  def install_files( list, dest, mode )
+    mkdir_p dest, @options['install-prefix']
+    list.each do |fname|
+      install fname, dest, mode, @options['install-prefix']
+    end
+  end
+  
+  def targfiles
+    (targfilenames() - hookfilenames()).collect {|fname|
+        File.exist?(fname) ? fname : File.join(curr_srcdir(), fname)
+    }
+  end
+
+  def targfilenames
+    [ curr_srcdir(), '.' ].inject([]) {|ret, dir|
+        ret | all_files(dir)
+    }
+  end
+
+  def hookfilenames
+    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).collect {|fmt|
+        %w( config setup install clean ).collect {|t| sprintf fmt, t }
+    }.flatten
+  end
+
+  def allext( dir )
+    _allext(dir) or raise InstallError,
+        "no extention exists: Have you done 'ruby #{$0} setup' ?"
+  end
+
+  DLEXT = /\.#{ ::Config::CONFIG['DLEXT'] }\z/
+
+  def _allext( dir )
+    Dir.open( dir ) {|d|
+        return d.find_all {|fname| DLEXT === fname }
+    }
+  end
+
+  #
+  # clean
+  #
+
+  def exec_clean
+    exec_task_traverse 'clean'
+    rm_f 'config.save'
+    rm_f 'InstalledFiles'
+  end
+
+  def clean_dir_bin( rel )
+  end
+
+  def clean_dir_lib( rel )
+  end
+
+  def clean_dir_ext( rel )
+    clean
+  end
+  
+  def clean
+    command config('make-prog') + ' clean' if File.file? 'Makefile'
+  end
+
+  def clean_dir_data( rel )
+  end
+
+  #
+  # lib
+  #
+
+  def exec_task_traverse( task )
+    run_hook 'pre-' + task
+    FILETYPES.each do |type|
+      if config('without-ext') == 'yes' and type == 'ext' then
+        $stderr.puts 'skipping ext/* by user option' if verbose?
+        next
+      end
+      traverse task, type, task + '_dir_' + type
+    end
+    run_hook 'post-' + task
+  end
+
+  def traverse( task, rel, mid )
+    dive_into( rel ) {
+        run_hook 'pre-' + task
+        __send__ mid, rel.sub( %r_\A.*?(?:/|\z)_, '' )
+        all_dirs( curr_srcdir ).each do |d|
+          traverse task, rel + '/' + d, mid
+        end
+        run_hook 'post-' + task
+    }
+  end
+
+  def run_hook( name )
+    try_run_hook curr_srcdir + '/' + name           or
+    try_run_hook curr_srcdir + '/' + name + '.rb'
+  end
+
+  def try_run_hook( fname )
+    return false unless File.file? fname
+
+    env = self.dup
+    begin
+      env.instance_eval File.read_all(fname), fname, 1
+    rescue
+      raise InstallError, "hook #{fname} failed:\n" + $!.message
+    end
+    true
+  end
+
+  def extdir?( dir )
+    File.exist? dir + '/MANIFEST'
+  end
+
+end
+
+### end base.rb
+### begin toplevel.rb
+
+class ToplevelInstaller < Installer
+
+  TASKS = [
+    [ 'config',   'saves your configurations' ],
+    [ 'show',     'shows current configuration' ],
+    [ 'setup',    'compiles extention or else' ],
+    [ 'install',  'installs files' ],
+    [ 'clean',    "does `make clean' for each extention" ]
+  ]
+
+
+  def initialize( root )
+    super nil, {'verbose' => true}, root, '.'
+    Installer.declear_toplevel_installer self
+  end
+
+
+  def execute
+    run_metaconfigs
+
+    case task = parsearg_global()
+    when 'config'
+      @config = ConfigTable.new
+    else
+      @config = ConfigTable.load
+    end
+    parsearg_TASK task
+
+    exectask task
+  end
+
+
+  def run_metaconfigs
+    MetaConfigEnvironment.eval_file "#{srcdir_root}/#{metaconfig}"
+  end
+
+  def metaconfig
+    'metaconfig'
+  end
+
+
+  def exectask( task )
+    if task == 'show' then
+      exec_show
+    else
+      try task
+    end
+  end
+
+  def try( task )
+    $stderr.printf "#{File.basename $0}: entering %s phase...\n", task if verbose?
+    begin
+      __send__ 'exec_' + task
+    rescue
+      $stderr.printf "%s failed\n", task
+      raise
+    end
+    $stderr.printf "#{File.basename $0}: %s done.\n", task if verbose?
+  end
+
+  #
+  # processing arguments
+  #
+
+  def parsearg_global
+    task_re = /\A(?:#{TASKS.collect {|i| i[0] }.join '|'})\z/
+
+    while arg = ARGV.shift do
+      case arg
+      when /\A\w+\z/
+        task_re === arg or raise InstallError, "wrong task: #{arg}"
+        return arg
+
+      when '-q', '--quiet'
+        @options['verbose'] = false
+
+      when       '--verbose'
+        @options['verbose'] = true
+
+      when '-h', '--help'
+        print_usage $stdout
+        exit 0
+
+      when '-v', '--version'
+        puts "#{File.basename $0} version #{Version}"
+        exit 0
+      
+      when '--copyright'
+        puts Copyright
+        exit 0
+
+      else
+        raise InstallError, "unknown global option '#{arg}'"
+      end
+    end
+
+    raise InstallError, 'no task or global option given'
+  end
+
+
+  def parsearg_TASK( task )
+    mid = "parsearg_#{task}"
+    if respond_to? mid, true then
+      __send__ mid
+    else
+      ARGV.empty? or
+          raise InstallError, "#{task}:  unknown options: #{ARGV.join ' '}"
+    end
+  end
+
+  def parsearg_config
+    re = /\A--(#{ConfigTable.keys.join '|'})(?:=(.*))?\z/
+    @options['config-opt'] = []
+
+    while i = ARGV.shift do
+      if /\A--?\z/ === i then
+        @options['config-opt'] = ARGV.dup
+        break
+      end
+      m = re.match(i) or raise InstallError, "config: unknown option #{i}"
+      name, value = m.to_a[1,2]
+      if value then
+        if ConfigTable.bool_config?(name) then
+          /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i === value or raise InstallError, "config: --#{name} allows only yes/no for argument"
+          value = (/\Ay(es)?|\At(rue)/i === value) ? 'yes' : 'no'
+        end
+      else
+        ConfigTable.bool_config?(name) or raise InstallError, "config: --#{name} requires argument"
+        value = 'yes'
+      end
+      @config[name] = value
+    end
+  end
+
+  def parsearg_install
+    @options['no-harm'] = false
+    @options['install-prefix'] = ''
+    while a = ARGV.shift do
+      case a
+      when /\A--no-harm\z/
+        @options['no-harm'] = true
+      when /\A--prefix=(.*)\z/
+        path = $1
+        path = File.expand_path(path) unless path[0,1] == '/'
+        @options['install-prefix'] = path
+      else
+        raise InstallError, "install: unknown option #{a}"
+      end
+    end
+  end
+
+
+  def print_usage( out )
+    out.puts
+    out.puts 'Usage:'
+    out.puts "  ruby #{File.basename $0} <global option>"
+    out.puts "  ruby #{File.basename $0} [<global options>] <task> [<task options>]"
+
+    fmt = "  %-20s %s\n"
+    out.puts
+    out.puts 'Global options:'
+    out.printf fmt, '-q,--quiet',   'suppress message outputs'
+    out.printf fmt, '   --verbose', 'output messages verbosely'
+    out.printf fmt, '-h,--help',    'print this message'
+    out.printf fmt, '-v,--version', 'print version and quit'
+    out.printf fmt, '--copyright',  'print copyright and quit'
+
+    out.puts
+    out.puts 'Tasks:'
+    TASKS.each do |name, desc|
+      out.printf "  %-10s  %s\n", name, desc
+    end
+
+    out.puts
+    out.puts 'Options for config:'
+    ConfigTable.each_definition do |name, (default, arg, desc, default2)|
+      out.printf "  %-20s %s [%s]\n",
+                 '--'+ name + (ConfigTable.bool_config?(name) ? '' : '='+arg),
+                 desc,
+                 default2 || default
+    end
+    out.printf "  %-20s %s [%s]\n",
+        '--rbconfig=path', 'your rbconfig.rb to load', "running ruby's"
+
+    out.puts
+    out.puts 'Options for install:'
+    out.printf "  %-20s %s [%s]\n",
+        '--no-harm', 'only display what to do if given', 'off'
+
+    out.puts
+  end
+
+  #
+  # config
+  #
+
+  def exec_config
+    super
+    @config.save
+  end
+
+  #
+  # show
+  #
+
+  def exec_show
+    ConfigTable.each_name do |k|
+      v = @config.get_raw(k)
+      if not v or v.empty? then
+        v = '(not specified)'
+      end
+      printf "%-10s %s\n", k, v
+    end
+  end
+
+end
+
+### end toplevel.rb
+
+if $0 == __FILE__ then
+  begin
+    installer = ToplevelInstaller.new( File.dirname($0) )
+    installer.execute
+  rescue
+    raise if $DEBUG
+    $stderr.puts $!.message
+    $stderr.puts "try 'ruby #{$0} --help' for usage"
+    exit 1
+  end
+end
diff -Nru clearsilver-0.8.1/ruby/lib/neo.rb clearsilver-0.9.0/ruby/lib/neo.rb
--- clearsilver-0.8.1/ruby/lib/neo.rb	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/ruby/lib/neo.rb	Tue Jun 17 14:20:13 2003
@@ -0,0 +1,46 @@
+require 'hdf'
+
+module Clearsilver
+
+  class Hdf < Neo::Hdf
+    
+    def initialize
+      super
+      @level=0
+      @cpos=""
+      @position=[]
+    end
+
+    attr_reader :position, :cpos
+
+    def push name
+      @position.push(@cpos)
+      @cpos+=name+"."
+
+      if block_given?
+	yield
+	@cpos=@position.pop
+      end
+    end
+
+    def pop
+      @cpos=@position.pop
+    end
+
+    def put name, value
+      value = value.to_s unless value.is_a?(String)
+      self.set_value(@cpos+(name.to_s),value)
+    end
+
+    def get name
+      self.get_value(@cpos+name)
+    end
+
+  end
+
+  class Cs < Neo::Cs
+
+  end
+end
+
+      
diff -Nru clearsilver-0.8.1/ruby/test/hdftest.rb clearsilver-0.9.0/ruby/test/hdftest.rb
--- clearsilver-0.8.1/ruby/test/hdftest.rb	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/ruby/test/hdftest.rb	Tue Jun 17 14:20:14 2003
@@ -0,0 +1,40 @@
+#!/usr/bin/env ruby
+
+require 'neo'
+
+h=Neo::Hdf.new
+h.set_value "1","farming"
+h.set_value "2","sewing"
+h.set_value "3","bowling"
+
+h.set_value "party.1","baloons"
+h.set_value "party.2","noise makers"
+h.set_value "party.3","telling long\nstories"
+
+h.set_attr "party.1", "Drool", "True"
+h.set_attr "party.2", "Pink", "1"
+
+print h.dump
+
+q=Neo::Hdf.new
+
+q.copy "arf",h
+
+print q.dump
+
+h.get_attr("party.2").each_pair do |k,v|
+  print "party.2 attr (#{k}=#{v})\n"
+end
+
+
+s="This is a funny test. <?cs var:arf.1 ?>.
+<?cs each:p = arf.party ?>
+<?cs var:p ?>
+<?cs /each ?>"
+
+c = Neo::Cs.new q
+
+c.parse_string(s)
+
+print c.render
+
diff -Nru clearsilver-0.8.1/rules.mk.in clearsilver-0.9.0/rules.mk.in
--- clearsilver-0.8.1/rules.mk.in	Thu Apr  3 16:32:23 2003
+++ clearsilver-0.9.0/rules.mk.in	Tue Jun 17 14:20:40 2003
@@ -9,6 +9,29 @@
 
 LIB_DIR    = $(NEOTONIC_ROOT)libs/
 
+## Installation Directories
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+
+DESTDIR =
+
+cs_includedir = ${includedir}/ClearSilver
+
 ## NOTE: The wdb code in util will tickle a bug in SleepyCat 2.4.5,
 ## which ships with various versions of Linux as part of glibc.  If you
 ## are going to use that code, you should compile against SleepyCat
@@ -23,6 +46,7 @@
 
 PYTHON_INC = @PYTHON_INC@
 PYTHON_LIB = @PYTHON_LIB@
+PYTHON_SITE = @PYTHON_SITE@
 JAVA_PATH  = @JAVA_PATH@
 
 ## Programs
@@ -37,6 +61,7 @@
 JAR        = $(JAVA_PATH)/bin/jar
 APXS       = @APXS_PATH@
 PERL	   = @PERL@
+RUBY       = @RUBY@
 
 CFLAGS     = @CFLAGS@ -Wall -c -I$(NEOTONIC_ROOT) @CPPFLAGS@
 CPPFLAGS   = -I$(NEOTONIC_ROOT) @CPPFLAGS@
@@ -52,6 +77,7 @@
 XARGS      = xargs -i%
 BUILD_WRAPPERS = @BUILD_WRAPPERS@
 EXTRA_UTL_OBJS = @EXTRA_UTL_OBJS@
+EXTRA_UTL_SRC  = @EXTRA_UTL_SRC@
 
 ## --------------win32 options
 
diff -Nru clearsilver-0.8.1/scripts/cs_lint.py clearsilver-0.9.0/scripts/cs_lint.py
--- clearsilver-0.8.1/scripts/cs_lint.py	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.9.0/scripts/cs_lint.py	Wed Jul  2 18:06:12 2003
@@ -0,0 +1,283 @@
+#!/usr/bin/python
+#!/neo/opt/bin/python
+
+import sys, string, os, getopt, signal, time
+sys.path.append("../python")
+import neo_cgi, neo_util
+import cStringIO
+
+class ClearSilverChecker:
+  def __init__ (self):
+    self.context = ""
+    self.data = ""
+    self.at = 0
+    self.cmd = ""
+    self.tokens = []
+
+  def error(self, s):
+    lineno = self.lineno(self.data, self.at)
+    print "-E- [%s:%d] %s" % (self.context, lineno, s)
+    if self.cmd:
+      print "    Command is %s" % self.cmd
+    if self.tokens:
+      print "    Tokens: %s" % repr(self.tokens)
+
+  def warn(self, s):
+    lineno = self.lineno(self.data, self.at)
+    print "-W- [%s:%d] %s" % (self.context, lineno, s)
+    if self.cmd:
+      print "    Command is %s" % self.cmd
+    if self.tokens:
+      print "    Tokens: %s" % repr(self.tokens)
+
+  def check_file(self, filename):
+    print "Checking file %s" % filename
+    self.context = filename
+    try:
+      self.run_neo_cgi(filename)
+    except neo_util.ParseError, reason:
+      print "-E- %s" % str(reason)
+    self.data = open(filename, "r").read()
+    self.parse()
+
+  def run_neo_cgi(self, filename):
+    stdin = cStringIO.StringIO("")
+    stdout = cStringIO.StringIO()
+    neo_cgi.cgiWrap(stdin, stdout, {})
+    neo_cgi.IgnoreEmptyFormVars(1)
+    ncgi = neo_cgi.CGI()
+    path = os.path.dirname(filename)
+    ncgi.hdf.setValue("hdf.loadpaths.path", path)
+    ncgi.display(filename)
+    return 
+
+  def lineno(self, data, i):
+    return len(string.split(data[:i], '\n'))
+
+  def parse(self):
+    self.at = 0
+    x = string.find(self.data[self.at:], '<?cs ')
+    while x >= 0:
+      self.at = x + self.at
+      ce = string.find(self.data[self.at:], '?>')
+      if ce == -1:
+	self.error("Missing ?> in expression")
+      else:
+	ce = ce + self.at
+	self.check_command(ce)
+	
+      # reset these class variables
+      self.cmd = ""
+      self.tokens = []
+      self.at = self.at + 1
+      x = string.find(self.data[self.at:], '<?cs ')
+
+  def check_command(self, end):
+    cmd = self.data[self.at+5:end]
+    self.cmd = cmd
+    if cmd[0] == '/':
+      # handle end command
+      cmd = cmd[1:]
+      self.command_end(cmd)
+      return
+
+    pound = string.find(cmd, '#')
+    colon = string.find(cmd, ':')
+    bang = string.find(cmd, '!')
+    if colon == -1 and bang == -1:
+      if pound != -1:
+	#print "Found comment: %s" % cmd
+	pass
+      else:
+	self.command_begin(string.strip(cmd), "")
+    elif pound != -1 and bang != -1 and pound < bang:
+      # comment
+      #print "Found comment: %s" % cmd
+      pass
+    elif pound != -1 and colon != -1 and pound < colon:
+      # comment
+      #print "Found comment: %s" % cmd
+      pass
+    elif bang == -1:
+      arg = cmd[colon+1:]
+      cmd = cmd[:colon]
+      self.command_begin(cmd, arg)
+    elif colon == -1:
+      arg = cmd[bang+1:]
+      cmd = cmd[:bang]
+      self.command_begin(cmd, arg)
+
+  def command_end(self, cmd):
+    pass
+
+  def command_begin(self, cmd, args):
+    #print "%s -> %s" % (cmd, args)
+    if cmd == "alt":
+      self.check_expression(args)
+    elif cmd == "if":
+      self.check_expression(args)
+    elif cmd == "elif":
+      self.check_expression(args)
+    elif cmd == "else":
+      pass
+    elif cmd == "include":
+      self.check_expression(args)
+    elif cmd == "linclude":
+      self.check_expression(args)
+    elif cmd == "name":
+      self.check_expression(args)
+    elif cmd == "var":
+      self.check_expression(args)
+    elif cmd == "evar":
+      self.check_expression(args)
+    elif cmd == "lvar":
+      self.check_expression(args)
+    elif cmd == "def":
+      macro, args = self.split_macro(args)
+      if macro: self.check_expression(macro, lvalue=1)
+      if args:self.check_expression(args)
+    elif cmd == "call":
+      macro, args = self.split_macro(args)
+      if macro: self.check_expression(macro, lvalue=1)
+      if args:self.check_expression(args)
+    elif cmd == "with":
+      varname, args = self.split_equals(args)
+      if varname: self.check_expression(varname, lvalue=1)
+      if args: self.check_expression(args)
+    elif cmd == "each":
+      varname, args = self.split_equals(args)
+      if varname: self.check_expression(varname, lvalue=1)
+      if args: self.check_expression(args)
+    elif cmd == "loop":
+      varname, args = self.split_equals(args)
+      if varname: self.check_expression(varname, lvalue=1)
+      if args: self.check_expression(args)
+    elif cmd == "set":
+      varname, args = self.split_equals(args)
+      if varname: self.check_expression(varname, lvalue=1)
+      if args: self.check_expression(args)
+    else:
+      self.error("Unrecognized command %s" % cmd)
+
+  def split_equals(self, args):
+    x = string.find(args, '=')
+    if x == -1:
+      self.error("Missing equals")
+      return None, None
+    else:
+      return args[:x], args[x+1:]
+
+  def split_macro(self, args):
+    b = string.find(args, '(')
+    e = string.rfind(args, ')')
+    if b == -1:
+      self.error("Missing opening parenthesis")
+      return None, None
+    if e == -1:
+      self.error("Missing closing parenthesis")
+      return None, None
+    macro_name = args[:b]
+    args = args[b+1:e]
+    return macro_name, args
+
+  def check_expression(self, expr, lvalue=0):
+    tokens = self.tokenize_expression(expr)
+    #print repr(tokens)
+    if len(tokens) == 0:
+      self.error("Empty Expression")
+
+  _OP = 1
+  _VAR = 2
+  _VARN = 3
+  _STR = 4
+  _NUM = 5
+
+  _TOKEN_SEP = "\"?<>=!#-+|&,)*/%[]( \t\r\n"
+
+  def tokenize_expression(self, expr):
+    self.tokens = []
+    while expr:
+      #print "expr: '%s'" % expr
+      expr = string.lstrip(expr)
+      len_expr = len(expr)
+      if len_expr == 0: break
+      if expr[:2] in ["<=", ">=", "==", "!=", "||", "&&"]:
+	self.tokens.append((ClearSilverChecker._OP, expr[:2]))
+	expr = expr[2:]
+	continue
+      elif expr[0] in ["!", "?", "<", ">", "+", "-", "*", "/", "%", "(", ")", "[", "]", ".", ',']:
+	self.tokens.append((ClearSilverChecker._OP, expr[0]))
+	expr = expr[1:]
+	continue
+      elif expr[0] in ["#", "$"]:
+	x = 1
+	if expr[1] in ['+', '-']: x=2
+	while len_expr > x and expr[x] not in ClearSilverChecker._TOKEN_SEP: x=x+1
+	if x == 0:
+	  self.error("[1] Zero length token, unexpected character %s" % expr[0])
+	  x = 1
+	else:
+	  token = expr[1:x]
+	  if expr[0] == "#":
+	    try:
+	      n = int(token)
+	      t_type = ClearSilverChecker._NUM
+	    except ValueError:
+	      t_type = ClearSilverChecker._VARN
+	  else:
+	    t_type = ClearSilverChecker._VAR
+	  self.tokens.append((t_type, token))
+	expr = expr[x:]
+	continue
+      elif expr[0] in ['"', "'"]:
+	x = string.find(expr[1:], expr[0])
+	if x == -1:
+	  self.error("Missing end of string %s " % expr)
+	  break
+	else:
+	  x = x + 1
+	  self.tokens.append((ClearSilverChecker._STR, expr[1:x]))
+	  expr = expr[x+2:]
+	  continue
+      else:
+	x = 0
+	while len_expr > x and expr[x] not in ClearSilverChecker._TOKEN_SEP: x=x+1
+	if x == 0:
+	  self.error("[2] Zero length token, unexpected character %s" % expr[0])
+	  x = 1
+	else:
+	  token = expr[:x]
+	  try:
+	    n = int(token)
+	    t_type = ClearSilverChecker._NUM
+	    self.warn("This behavior changed in version 0.9: previously this was a variable name, now its a number: %s" % token) 
+	  except ValueError:
+	    t_type = ClearSilverChecker._VAR
+	  self.tokens.append((t_type, token))
+	expr = expr[x:]
+	continue
+    return self.tokens
+
+  # For version 0.9, we changed two things, we should check for them
+  # both
+  #  - an all numeric expression element is now considered a number and
+  #    not an HDF variable name
+  #  - we now use boolean evaluation in places that used to use either a
+  #    special case or a numeric evaluation
+
+def usage(argv0):
+  print "%s: usage info!!" % argv0
+
+def main(argv):
+  alist, args = getopt.getopt(argv[1:], "", ["help"])
+
+  for (field, val) in alist:
+    if field == "--help":
+      usage(argv[0])
+      sys.exit(-1)
+
+  for file in args:
+    ClearSilverChecker().check_file(file)
+
+if __name__ == "__main__":
+  main(sys.argv)
diff -Nru clearsilver-0.8.1/util/Makefile clearsilver-0.9.0/util/Makefile
--- clearsilver-0.8.1/util/Makefile	Wed Apr  2 15:07:36 2003
+++ clearsilver-0.9.0/util/Makefile	Mon Apr 14 17:13:46 2003
@@ -8,9 +8,10 @@
 
 UTL_LIB = $(LIB_DIR)libneo_utl.a
 UTL_SRC = neo_err.c neo_files.c neo_misc.c neo_rand.c ulist.c neo_hdf.c \
-	  neo_str.c neo_date.c wildmat.c neo_hash.c
+	  neo_str.c neo_date.c wildmat.c neo_hash.c $(EXTRA_UTL_SRC)
 
 UTL_OBJ = $(UTL_SRC:%.c=%.o) $(EXTRA_UTL_OBJS)
+UTL_HDR = $(UTL_SRC:%.c=%.h)
 
 TARGETS = $(UTL_LIB)
 
@@ -18,6 +19,11 @@
 
 $(UTL_LIB): $(UTL_OBJ)
 	$(AR) $@ $(UTL_OBJ)
+
+install: all
+	$(NEOTONIC_ROOT)mkinstalldirs $(DESTDIR)$(cs_includedir)/util
+	$(INSTALL) -m 644 $(UTL_HDR) $(DESTDIR)$(cs_includedir)/util
+	$(INSTALL) -m 644 $(UTL_LIB) $(DESTDIR)$(libdir)
 
 clean:
 	$(RM) *.o
diff -Nru clearsilver-0.8.1/util/dict.c clearsilver-0.9.0/util/dict.c
--- clearsilver-0.8.1/util/dict.c	Wed Apr  2 15:07:36 2003
+++ clearsilver-0.9.0/util/dict.c	Mon Apr 14 16:02:26 2003
@@ -51,7 +51,7 @@
 typedef UINT32 (*dictHashFunc)(const char *str);
 typedef int (*dictCompFunc)(const char *s1, const char *s2);
 
-struct dictCtx {
+struct _dictCtx {
 
   pthread_mutex_t mList;                                /* list update mutex */
   skipList list;                                                /* skip list */
@@ -557,7 +557,7 @@
 
   do {
 
-    if(! (dict = calloc(1, sizeof(struct dictCtx))))
+    if(! (dict = calloc(1, sizeof(struct _dictCtx))))
       return nerr_raise (NERR_NOMEM, "Unable to allocate memory for dictCtx");
 
     dict->useCase = useCase;
diff -Nru clearsilver-0.8.1/util/dict.h clearsilver-0.9.0/util/dict.h
--- clearsilver-0.8.1/util/dict.h	Wed Apr  2 15:07:36 2003
+++ clearsilver-0.9.0/util/dict.h	Mon Apr 14 16:02:26 2003
@@ -14,7 +14,9 @@
 #ifndef __DICT_H_
 #define __DICT_H_
 
-typedef struct dictCtx *dictCtx;
+__BEGIN_DECLS
+
+typedef struct _dictCtx *dictCtx;
 typedef BOOL (*dictCleanupFunc)(char *id, void *value, void *rock);
 typedef void (*dictFreeValueFunc)(void *value, void *rock);
 
@@ -156,5 +158,7 @@
  * Return:      None.
  * MT-Level:    Safe if <dict> thread-safe.
  */
+
+__END_DECLS
 
 #endif                                                          /* __DICT_H_ */
diff -Nru clearsilver-0.8.1/util/neo_net.c clearsilver-0.9.0/util/neo_net.c
--- clearsilver-0.8.1/util/neo_net.c	Wed Apr  2 15:07:36 2003
+++ clearsilver-0.9.0/util/neo_net.c	Thu May 22 19:32:19 2003
@@ -486,6 +486,7 @@
   NEOERR *err;
   int x = 0;
   char buf[32];
+  char *ep = NULL;
 
   while (x < sizeof(buf))
   {
@@ -506,7 +507,11 @@
     return nerr_raise(NERR_PARSE, "Format error on stream, expected '%c'", end);
 
   buf[x] = '\0';
-  *i = atoi(buf);
+  *i = strtol(buf, &ep, 10);
+  if (ep && *ep)
+  {
+    return nerr_raise(NERR_PARSE, "Format error on stream, expected number followed by '%c'", end);
+  }
 
   return STATUS_OK;
 }
