diff -Nrbu clearsilver-0.10.2/cgi/cgi_cstest.c clearsilver-0.10.3/cgi/cgi_cstest.c
--- clearsilver-0.10.2/cgi/cgi_cstest.c	1969-12-31 16:00:00.000000000 -0800
+++ clearsilver-0.10.3/cgi/cgi_cstest.c	2006-01-31 18:54:09.000000000 -0800
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2001-2004 Brandon Long
+ * All Rights Reserved.
+ *
+ * ClearSilver Templating System
+ *
+ * This code is made available under the terms of the ClearSilver License.
+ * http://www.clearsilver.net/license.hdf
+ *
+ */
+
+#include "ClearSilver.h"
+
+#include <stdio.h>
+#include <string.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;
+
+  if (argc < 3)
+  {
+    ne_warn ("Usage: cstest [-v] <file.hdf> <file.cs>");
+    return -1;
+  }
+
+  if (!strcmp(argv[1], "-v"))
+  {
+    verbose = 1;
+    if (argc < 4)
+    {
+      ne_warn ("Usage: cstest [-v] <file.hdf> <file.cs>");
+      return -1;
+    }
+    hdf_file = argv[2];
+    cs_file = argv[3];
+  }
+  else
+  {
+    hdf_file = argv[1];
+    cs_file = argv[2];
+  }
+
+  err = hdf_init(&hdf);
+  if (err != STATUS_OK)
+  {
+    nerr_log_error(err);
+    return -1;
+  }
+  err = hdf_read_file(hdf, hdf_file);
+  if (err != STATUS_OK)
+  {
+    nerr_log_error(err);
+    return -1;
+  }
+
+  printf ("Parsing %s\n", cs_file);
+  err = cs_init (&parse, hdf);
+  if (err != STATUS_OK)
+  {
+    nerr_log_error(err);
+    return -1;
+  }
+  err = cgi_register_strfuncs(parse);
+  if (err != STATUS_OK)
+  {
+    nerr_log_error(err);
+    return -1;
+  }
+
+  err = cs_parse_file (parse, cs_file);
+  if (err != STATUS_OK)
+  {
+    err = nerr_pass(err);
+    nerr_log_error(err);
+    return -1;
+  }
+
+  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);
+  }
+  hdf_destroy(&hdf);
+
+
+  return 0;
+}
diff -Nrbu clearsilver-0.10.2/cgi/cgiwrap.c clearsilver-0.10.3/cgi/cgiwrap.c
--- clearsilver-0.10.2/cgi/cgiwrap.c	2005-06-30 18:20:21.000000000 -0700
+++ clearsilver-0.10.3/cgi/cgiwrap.c	2006-01-22 15:43:00.000000000 -0800
@@ -39,12 +39,22 @@
 
 static CGIWRAPPER GlobalWrapper = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0};
 
-static void cgiwrap_init (void)
+void cgiwrap_init_std (int argc, char **argv, char **envp)
 {
-  GlobalWrapper.argc = 0;
-  GlobalWrapper.argv = NULL;
-  GlobalWrapper.envp = NULL;
+  /* Allow setting of these even after cgiwrap_init_emu is called */
+  GlobalWrapper.argc = argc;
+  GlobalWrapper.argv = argv;
+  GlobalWrapper.envp = envp;
   GlobalWrapper.env_count = 0;
+  while (envp[GlobalWrapper.env_count] != NULL) GlobalWrapper.env_count++;
+
+  /* so you can compile the same code for embedded without mods.
+   * Note that this setting is global for the lifetime of the program, so 
+   * you can never reset these values after calling cgiwrap_init_emu by
+   * calling cgiwrap_init_std, you'll have to call cgiwrap_init_emu with NULL
+   * values to reset */
+  if (GlobalWrapper.emu_init) return;
+
   GlobalWrapper.read_cb = NULL;
   GlobalWrapper.writef_cb = NULL;
   GlobalWrapper.write_cb = NULL;
@@ -54,23 +64,14 @@
   GlobalWrapper.data = NULL;
 }
 
-void cgiwrap_init_std (int argc, char **argv, char **envp)
-{
-  /* so you can compile the same code for embedded without mods */
-  if (GlobalWrapper.emu_init) return;
-
-  cgiwrap_init();
-  GlobalWrapper.argc = argc;
-  GlobalWrapper.argv = argv;
-  GlobalWrapper.envp = envp;
-  while (envp[GlobalWrapper.env_count] != NULL) GlobalWrapper.env_count++;
-}
-
 void cgiwrap_init_emu (void *data, READ_FUNC read_cb, 
     WRITEF_FUNC writef_cb, WRITE_FUNC write_cb, GETENV_FUNC getenv_cb,
     PUTENV_FUNC putenv_cb, ITERENV_FUNC iterenv_cb)
 {
-  cgiwrap_init();
+  /* leave argc, argv, envp, env_count alone since we either don't use them, or
+   * they are used by the default versions if any of these are passed as NULL.
+   * Note that means that if you pass NULL for anything here, you'd better
+   * have called cgiwrap_init_std first! */
   GlobalWrapper.data = data;
   GlobalWrapper.read_cb = read_cb;
   GlobalWrapper.writef_cb = writef_cb;
diff -Nrbu clearsilver-0.10.2/cgi/Makefile clearsilver-0.10.3/cgi/Makefile
--- clearsilver-0.10.2/cgi/Makefile	2005-12-02 02:34:24.000000000 -0800
+++ clearsilver-0.10.3/cgi/Makefile	2006-01-31 18:53:23.000000000 -0800
@@ -15,9 +15,13 @@
 STATIC_OBJ = $(STATIC_SRC:%.c=%.o)
 STATIC_CSO = $(STATIC_EXE:%.cgi=%.cso)
 
+CGICSTEST_EXE = cgi_cstest
+CGICSTEST_SRC = cgi_cstest.c
+CGICSTEST_OBJ = $(CGICSTEST_SRC:%.c=%.o)
+
 DLIBS += -lneo_cgi -lneo_cs -lneo_utl # -lefence
 
-TARGETS = $(CGI_LIB) $(STATIC_EXE) $(STATIC_CSO)
+TARGETS = $(CGI_LIB) $(STATIC_EXE) $(STATIC_CSO) $(CGICSTEST_EXE)
 
 all: $(TARGETS)
 
@@ -31,6 +35,9 @@
 $(STATIC_CSO): $(STATIC_OBJ) $(DEP_LIBS)
 	$(LDSHARED) -o $@ $(STATIC_OBJ) -L$(LIB_DIR) $(DLIBS) $(LIBS)
 
+$(CGICSTEST_EXE): $(CGICSTEST_OBJ) $(DEP_LIBS)
+	$(LD) $@ $(CGICSTEST_OBJ) -L$(LIB_DIR) $(DLIBS) $(LIBS)
+
 install: all
 	$(NEOTONIC_ROOT)/mkinstalldirs $(DESTDIR)$(cs_includedir)/cgi
 	$(INSTALL) -m 644 cgi.h $(DESTDIR)$(cs_includedir)/cgi
diff -Nrbu clearsilver-0.10.2/configure.in clearsilver-0.10.3/configure.in
--- clearsilver-0.10.2/configure.in	2005-12-02 03:03:35.000000000 -0800
+++ clearsilver-0.10.3/configure.in	2006-03-12 16:05:26.000000000 -0800
@@ -245,6 +245,7 @@
 if test $cs_cv_python = yes; then
   AC_MSG_CHECKING(for python includes)
   python_inc=no
+  python_lib=no
   python_search_path="/neo/opt /usr/local /usr /c"
   python_versions="2.4 2.3 2.2 2.1 2.0 1.5 24 23 22 21 20 15"
   if test $cs_cv_python_path != "no" -a -x $cs_cv_python_path; then
@@ -259,12 +260,29 @@
       for path in $python_search_path; do
         if test -x $path/bin/python$vers; then
 	  python_bin=$path/bin/python$vers
+	  major_vers=`echo $vers | cut -b 1`
+	  if test $major_vers -ge 2; then
+	      python_base=`$python_bin -c "import sys, os; print os.path.dirname([[x for x in sys.path if x.find('site-packages') != -1]][[0]])"`
+	  else
+	      python_base=`$python_bin -c "import site, os; print os.path.dirname(site.sitedirs[[0]])"`
+	  fi
+	  if test -d $python_base; then
+	      python_lib="-L$python_base/config -lpython$vers"
+	      python_site=$python_base/site-packages
+	  fi
 	fi
 	if test -f $path/include/python$vers/Python.h; then
 	  python_inc=$path/include/python$vers
+        fi
+	if test "x$python_lib" = "xno"; then
+	    if test -d $path/lib/python$vers; then
 	  python_lib="-L$path/lib/python$vers/config -lpython$vers"
 	  python_site=$path/lib/python$vers/site-packages
-	  break 2
+	    fi
+	    if test -d $path/lib64/python$vers; then
+	      python_lib="-L$path/lib64/python$vers/config -lpython$vers"
+	      python_site=$path/lib64/python$vers/site-packages
+	    fi
 	fi
 	dnl This is currently special cased mostly for Windows
 	dnl installs, but we only use python_lib for windows anyways
@@ -274,6 +292,9 @@
 	  python_site=$path/python$vers/Lib/site-packages
 	  break 2
 	fi
+	if test "x$python_inc" != "xno" -a "x$python_lib" != "xno"; then
+	  break 2
+	fi
       done
     done
   fi
@@ -288,7 +309,7 @@
     PYTHON=$python_bin
     PYTHON_INC="-I$python_inc"
     PYTHON_LIB=$python_lib
-    if test ! $?PYTHON_SITE; then
+    if test "x$PYTHON_SITE" = "x"; then
 	PYTHON_SITE=$python_site
     fi
     BUILD_WRAPPERS="$BUILD_WRAPPERS python"
diff -Nrbu clearsilver-0.10.2/cs/cs.h clearsilver-0.10.3/cs/cs.h
--- clearsilver-0.10.2/cs/cs.h	2005-11-30 19:58:44.000000000 -0800
+++ clearsilver-0.10.3/cs/cs.h	2006-02-02 18:17:49.000000000 -0800
@@ -92,7 +92,7 @@
   CS_TYPE_FUNCTION = (1<<30)
 } CSTOKEN_TYPE;
 
-#define CS_OPS_UNARY (CS_OP_EXISTS | CS_OP_NOT | CS_OP_NUM)
+#define CS_OPS_UNARY (CS_OP_EXISTS | CS_OP_NOT | CS_OP_NUM | CS_OP_LPAREN)
 #define CS_TYPES (CS_TYPE_STRING | CS_TYPE_NUM | CS_TYPE_VAR | CS_TYPE_VAR_NUM)
 #define CS_OPS_LVALUE (CS_OP_DOT | CS_OP_LBRACKET | CS_TYPES)
 #define CS_TYPES_VAR (CS_TYPE_VAR | CS_TYPE_VAR_NUM)
@@ -354,6 +354,13 @@
  */
 NEOERR *cs_register_strfunc(CSPARSE *parse, char *funcname, CSSTRFUNC str_func);
 
+/* Testing functions for future function api.  This api may change in the
+ * future. */
+NEOERR *cs_arg_parse(CSPARSE *parse, CSARG *args, const char *fmt, ...);
+NEOERR *cs_arg_parsev(CSPARSE *parse, CSARG *args, const char *fmt, va_list ap);
+NEOERR *cs_register_function(CSPARSE *parse, const char *funcname,
+                                  int n_args, CSFUNCTION function);
+
 __END_DECLS
 
 #endif /* __CSHDF_H_ */
diff -Nrbu clearsilver-0.10.2/cs/csparse.c clearsilver-0.10.3/cs/csparse.c
--- clearsilver-0.10.2/cs/csparse.c	2005-12-02 03:04:37.000000000 -0800
+++ clearsilver-0.10.3/cs/csparse.c	2006-02-02 18:17:41.000000000 -0800
@@ -621,11 +621,24 @@
       {
 	if (c == NULL)
 	{
+          if (map->h == NULL) /* node didn't exist yet */
+            return nerr_pass (hdf_set_value (parse->hdf, map->s, value));
+          else
 	  return nerr_pass (hdf_set_value (map->h, NULL, value));
 	}
 	else
 	{
 	  *c = '.';
+          if (map->h == NULL) /* node didn't exist yet */
+          {
+            NEOERR *err;
+            char *mapped_name = sprintf_alloc("%s%s", map->s, c);
+            if (mapped_name == NULL)
+              return nerr_raise(NERR_NOMEM, "Unable to allocate memory to create mapped name");
+            err = hdf_set_value(parse->hdf, mapped_name, value);
+            free(mapped_name);
+            return nerr_pass(err);
+          }
 	  return nerr_pass (hdf_set_value (map->h, c+1, value));
 	}
       }
@@ -811,6 +824,7 @@
     {
       if (*arg == '#')
       {
+        /* TODO: make # an operator and not syntax */
 	arg++;
 	tokens[ntokens].type = CS_TYPE_NUM;
 	tokens[ntokens].value = arg;
@@ -858,6 +872,7 @@
       }
       else if (*arg == '$')
       {
+        /* TODO: make $ an operator and not syntax */
 	arg++;
 	tokens[ntokens].type = CS_TYPE_VAR;
 	tokens[ntokens].value = arg;
@@ -922,7 +937,7 @@
   CS_OP_ADD | CS_OP_SUB, 
   CS_OP_MULT | CS_OP_DIV | CS_OP_MOD,
   CS_OP_NOT | CS_OP_EXISTS,
-  CS_OP_LBRACKET | CS_OP_DOT,
+  CS_OP_LBRACKET | CS_OP_DOT | CS_OP_LPAREN,
   0
 };
 
@@ -1071,8 +1086,10 @@
 	  return nerr_raise (NERR_PARSE, 
 	      "%s Missing left parenthesis in expression",
 	      find_context(parse, -1, tmp, sizeof(tmp)));
-	if (x == 0) break;
-	x--;
+	/* if (x == 0) break; */
+	/* x--; */
+	/* we don't do an x-- here, because we are special casing the
+	 * left bracket to be both an operator and an associative */
       }
       if (tokens[x].type & CS_OP_RBRACKET)
       {
@@ -1093,13 +1110,6 @@
 	/* we don't do an x-- here, because we are special casing the
 	 * left bracket to be both an operator and an associative */
       }
-      else if (tokens[x].type & (CS_OP_LBRACKET | CS_OP_LPAREN))
-      {
-	return nerr_raise (NERR_PARSE, 
-	    "%s Missing right %s in expression",
-	    find_context(parse, -1, tmp, sizeof(tmp)), 
-	    (tokens[x].type == CS_OP_LBRACKET) ? "bracket" : "parenthesis");
-      }
       if (lvalue && !(tokens[x].type & CS_OPS_LVALUE))
       {
 	return nerr_raise (NERR_PARSE, 
@@ -1109,7 +1119,7 @@
       }
       if (tokens[x].type & OperatorOrder[op])
       {
-	if (OperatorOrder[op] & CS_OPS_UNARY)
+	if (tokens[x].type & CS_OPS_UNARY)
 	{
 	  if (x == 0)
 	  {
@@ -1119,7 +1129,22 @@
 	      return nerr_raise (NERR_NOMEM, 
 		  "%s Unable to allocate memory for expression", 
 		  find_context(parse, -1, tmp, sizeof(tmp)));
+            if (tokens[x].type & CS_OP_LPAREN)
+            {
+              if (!(tokens[ntokens-1].type & CS_OP_RPAREN))
+              {
+                return nerr_raise (NERR_PARSE, 
+                                   "%s Missing right parenthesis in expression",
+                                   find_context(parse, -1, tmp, sizeof(tmp)));
+              }
+              /* XXX: we might want to set lvalue to 0 here */
+              /* -2 since we strip the RPAREN as well */
+              err = parse_expr2(parse, tokens + 1, ntokens-2, lvalue, arg->expr1);
+            }
+            else
+            {
 	    err = parse_expr2(parse, tokens + 1, ntokens-1, lvalue, arg->expr1);
+            }
 	    return nerr_pass(err);
 	  }
 	}
@@ -1152,10 +1177,17 @@
 	    return nerr_raise (NERR_NOMEM, 
 		"%s Unable to allocate memory for expression", 
 		find_context(parse, -1, tmp, sizeof(tmp)));
-	  if (tokens[x].type == CS_OP_LBRACKET)
+	  if (tokens[x].type & CS_OP_LBRACKET)
+	  {
+            if (!(tokens[ntokens-1].type & CS_OP_RBRACKET))
 	  {
+              return nerr_raise (NERR_PARSE, 
+                                 "%s Missing right bracket in expression",
+                                 find_context(parse, -1, tmp, sizeof(tmp)));
+            }
 	    /* Inside of brackets, we don't limit to valid lvalue ops */
-	    err = parse_expr2(parse, tokens + x, ntokens-x, 0, arg->expr2);
+            /* -2 since we strip the RBRACKET as well */
+	    err = parse_expr2(parse, tokens + x + 1, ntokens-x-2, 0, arg->expr2);
 	  }
 	  else
 	  {
@@ -1171,18 +1203,10 @@
     }
     op++;
   }
-  /* ah, this expression just contains enclosing associatives, strip them */
-  x = ntokens-1;
-  if ((tokens[0].type == CS_OP_LPAREN && tokens[x].type == CS_OP_RPAREN) ||
-      (tokens[0].type == CS_OP_LBRACKET && tokens[x].type == CS_OP_RBRACKET))
-  {
-    /* parens don't do anything, just strip them and pass */
-    return nerr_pass(parse_expr2(parse, tokens + 1, ntokens-2, lvalue, arg));
-  }
 
   /* Unary op against an entire expression */
   if ((tokens[0].type & CS_OPS_UNARY) && tokens[1].type == CS_OP_LPAREN && 
-      tokens[x].type == CS_OP_RPAREN)
+      tokens[ntokens-1].type == CS_OP_RPAREN)
   {
     arg->op_type = tokens[0].type;
     arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG));
@@ -1207,7 +1231,7 @@
 
   /* function call */
   if ((tokens[0].type & CS_TYPE_VAR) && tokens[1].type == CS_OP_LPAREN && 
-      tokens[x].type == CS_OP_RPAREN)
+      tokens[ntokens-1].type == CS_OP_RPAREN)
   {
     CS_FUNCTION *csf;
     int nargs;
@@ -1851,19 +1875,13 @@
 
 static NEOERR *eval_expr (CSPARSE *parse, CSARG *expr, CSARG *result)
 {
-  CSARG arg1, arg2;
   NEOERR *err;
-  long int n2;
-  char *s1, *s2;
 
   if (expr == NULL)
     return nerr_raise (NERR_ASSERT, "expr is NULL");
   if (result == NULL)
     return nerr_raise (NERR_ASSERT, "result is NULL");
 
-  arg1.alloc = 0;
-  arg2.alloc = 0;
-
 #if DEBUG_EXPR_EVAL
   _depth++;
   expand_arg(parse, _depth, "expr", expr);
@@ -1882,11 +1900,11 @@
     return STATUS_OK;
   }
 
-  err = eval_expr (parse, expr->expr1, &arg1);
-  if (err) return nerr_pass(err);
-#if DEBUG_EXPR_EVAL
-  expand_arg(parse, _depth, "arg1", &arg1);
-#endif
+  if (expr->op_type & CS_OP_LPAREN)
+  {
+    /* lparen is a no-op, just skip */
+    return nerr_pass(eval_expr(parse, expr->expr1, result));
+  }
   if (expr->op_type & CS_TYPE_FUNCTION)
   {
     if (expr->function == NULL || expr->function->function == NULL)
@@ -1894,10 +1912,23 @@
           "Function is NULL in attempt to evaluate function call %s", 
           (expr->function) ? expr->function->name : "");
 
-    err = expr->function->function(parse, expr->function, &arg1, result);
+    /* The function evaluates all the arguments, so don't pre-evaluate
+     * argument1 */
+    err = expr->function->function(parse, expr->function, expr->expr1, result);
     if (err) return nerr_pass(err);
   }
-  else if (expr->op_type & CS_OPS_UNARY)
+  else 
+  {
+    CSARG arg1, arg2;
+    arg1.alloc = 0;
+    arg2.alloc = 0;
+
+    err = eval_expr (parse, expr->expr1, &arg1);
+    if (err) return nerr_pass(err);
+#if DEBUG_EXPR_EVAL
+    expand_arg(parse, _depth, "arg1", &arg1);
+#endif
+    if (expr->op_type & CS_OPS_UNARY)
   {
     result->op_type = CS_TYPE_NUM;
     switch (expr->op_type) {
@@ -1907,8 +1938,7 @@
       case CS_OP_EXISTS:
         if (arg1.op_type & (CS_TYPE_VAR | CS_TYPE_VAR_NUM))
         {
-          s1 = arg_eval (parse, &arg1);
-          if (s1 == NULL)
+            if (arg_eval(parse, &arg1) == NULL)
             result->n = 0;
           else
             result->n = 1;
@@ -1922,6 +1952,8 @@
       case CS_OP_NUM:
         result->n = arg_eval_num (parse, &arg1);
         break;
+        case CS_OP_LPAREN:
+          return nerr_raise(NERR_ASSERT, "LPAREN should be handled above");
       default:
         result->n = 0;
         ne_warn ("Unsupported op %s in eval_expr", expand_token_type(expr->op_type, 1));
@@ -1967,14 +1999,14 @@
       result->alloc = 1;
       if (arg2.op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM))
       {
-        n2 = arg_eval_num (parse, &arg2);
+          long int n2 = arg_eval_num (parse, &arg2);
         result->s = sprintf_alloc("%s.%d", arg1.s, n2);
         if (result->s == NULL)
           return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %d", arg1.s, n2);
       }
       else
       {
-        s2 = arg_eval (parse, &arg2);
+          char *s2 = arg_eval (parse, &arg2);
         if (s2 && s2[0])
         {
           result->s = sprintf_alloc("%s.%s", arg1.s, s2);
@@ -2005,14 +2037,14 @@
       {
         if (arg2.op_type & CS_TYPE_NUM)
         {
-          n2 = arg_eval_num (parse, &arg2);
+            long int n2 = arg_eval_num (parse, &arg2);
           result->s = sprintf_alloc("%s.%d", arg1.s, n2);
           if (result->s == NULL)
             return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %d", arg1.s, n2);
         }
         else
         {
-          s2 = arg_eval (parse, &arg2);
+            char *s2 = arg_eval (parse, &arg2);
           if (s2 && s2[0])
           {
             result->s = sprintf_alloc("%s.%s", arg1.s, s2);
@@ -2039,16 +2071,15 @@
     {
       /* eval as num */
       err = eval_expr_num(parse, &arg1, &arg2, expr->op_type, result);
-
     }
     else /* eval as string */
     {
       err = eval_expr_string(parse, &arg1, &arg2, expr->op_type, result);
     }
-
   }
   if (arg1.alloc) free(arg1.s);
   if (arg2.alloc) free(arg2.s);
+  }
 
 #if DEBUG_EXPR_EVAL
   expand_arg(parse, _depth, "result", result);
@@ -2853,6 +2884,11 @@
 	var = var_lookup_obj (parse, val.s);
 	map->h = var;
 	map->type = CS_TYPE_VAR;
+        /* Bring across the name we're mapping to, in case h doesn't exist and
+         * we need to set it. */
+        map->s = val.s;
+        map->map_alloc = val.alloc;
+        val.alloc = 0;
       }
     }
     else
@@ -3199,7 +3235,7 @@
 
 /* **** Functions ******************************************** */
 
-static NEOERR *_register_function(CSPARSE *parse, const char *funcname,
+NEOERR *cs_register_function(CSPARSE *parse, const char *funcname,
                                   int n_args, CSFUNCTION function)
 {
   CS_FUNCTION *csf;
@@ -3240,7 +3276,7 @@
  *   i - int
  *   A - arg ptr (maybe later)
  */
-static NEOERR * cs_arg_parsev(CSPARSE *parse, CSARG *args, char *fmt, 
+NEOERR * cs_arg_parsev(CSPARSE *parse, CSARG *args, const char *fmt,
     va_list ap) 
 {
   NEOERR *err = STATUS_OK;
@@ -3287,7 +3323,7 @@
   return STATUS_OK;
 }
 
-static NEOERR * cs_arg_parse(CSPARSE *parse, CSARG *args, char *fmt, ...)
+NEOERR * cs_arg_parse(CSPARSE *parse, CSARG *args, const char *fmt, ...)
 {
   NEOERR *err;
   va_list ap;
@@ -3300,16 +3336,22 @@
 
 static NEOERR * _builtin_subcount(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
 {
+  NEOERR *err;
   HDF *obj;
   int count = 0;
+  CSARG val;
+
+  memset(&val, 0, sizeof(val));
+  err = eval_expr(parse, args, &val);
+  if (err) return nerr_pass(err);
 
   /* default for non-vars is 0 children */
   result->op_type = CS_TYPE_NUM;
   result->n = 0;
 
-  if (args->op_type & CS_TYPE_VAR)
+  if (val.op_type & CS_TYPE_VAR)
   {
-    obj = var_lookup_obj (parse, args->s);
+    obj = var_lookup_obj (parse, val.s);
     if (obj != NULL)
     {
       obj = hdf_obj_child(obj);
@@ -3321,61 +3363,60 @@
     }
     result->n = count;
   }
+  if (val.alloc) free(val.s);
 
   return STATUS_OK;
 }
 
 static NEOERR * _builtin_str_length(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
 {
-  HDF *obj;
+  NEOERR *err;
+  CSARG val;
+
+  memset(&val, 0, sizeof(val));
+  err = eval_expr(parse, args, &val);
+  if (err) return nerr_pass(err);
 
   /* non var/string objects have 0 length */
   result->op_type = CS_TYPE_NUM;
   result->n = 0;
 
-  if (args->op_type & CS_TYPE_VAR)
+  if (val.op_type & (CS_TYPE_VAR | CS_TYPE_STRING))
   {
-    obj = var_lookup_obj (parse, args->s);
-    if (obj) {
-      char *s = hdf_obj_value(obj);
-      if (s) {
-	result->n = strlen(s);
-      }
-    }
-  }
-  else if (args->op_type & CS_TYPE_STRING)
-  {
-    result->n = strlen(args->s);
+    char *s = arg_eval(parse, &val);
+    if (s) result->n = strlen(s);
   }
+  if (val.alloc) free(val.s);
   return STATUS_OK;
 }
 
 
 static NEOERR * _builtin_name(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
 {
+  NEOERR *err;
   HDF *obj;
+  CSARG val;
+
+  memset(&val, 0, sizeof(val));
+  err = eval_expr(parse, args, &val);
+  if (err) return nerr_pass(err);
 
   result->op_type = CS_TYPE_STRING;
   result->s = "";
 
-  if (args->op_type & CS_TYPE_VAR)
+  if (val.op_type & CS_TYPE_VAR)
   {
-    obj = var_lookup_obj (parse, args->s);
+    obj = var_lookup_obj (parse, val.s);
     if (obj != NULL)
-    {
       result->s = hdf_obj_name(obj);
     }
-    else 
+  else if (val.op_type & CS_TYPE_STRING)
     {
-      result->s = "";
-    }
-  }
-  else if (args->op_type & CS_TYPE_STRING)
-  {
-    result->s = args->s;
-    result->alloc = args->alloc;
-    args->alloc = 0;
+    result->s = val.s;
+    result->alloc = val.alloc;
+    val.alloc = 0;
   }
+  if (val.alloc) free(val.s);
   return STATUS_OK;
 }
 
@@ -3383,20 +3424,27 @@
 static NEOERR * _builtin_first(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
                                CSARG *result)
 {
+  NEOERR *err;
   CS_LOCAL_MAP *map;
   char *c;
+  CSARG val;
+
+  memset(&val, 0, sizeof(val));
+  err = eval_expr(parse, args, &val);
+  if (err) return nerr_pass(err);
 
   /* default is "not first" */
   result->op_type = CS_TYPE_NUM;
   result->n = 0;
 
   /* Only applies to possible local vars */
-  if ((args->op_type & CS_TYPE_VAR) && !strchr(args->s, '.'))
+  if ((val.op_type & CS_TYPE_VAR) && !strchr(val.s, '.'))
   {
-    map = lookup_map (parse, args->s, &c);
+    map = lookup_map (parse, val.s, &c);
     if (map && map->first)
       result->n = 1;
   }
+  if (val.alloc) free(val.s);
   return STATUS_OK;
 }
 
@@ -3405,17 +3453,23 @@
 static NEOERR * _builtin_last(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
                                CSARG *result)
 {
+  NEOERR *err;
   CS_LOCAL_MAP *map;
   char *c;
+  CSARG val;
+
+  memset(&val, 0, sizeof(val));
+  err = eval_expr(parse, args, &val);
+  if (err) return nerr_pass(err);
 
   /* default is "not last" */
   result->op_type = CS_TYPE_NUM;
   result->n = 0;
 
   /* Only applies to possible local vars */
-  if ((args->op_type & CS_TYPE_VAR) && !strchr(args->s, '.'))
+  if ((val.op_type & CS_TYPE_VAR) && !strchr(val.s, '.'))
   {
-    map = lookup_map (parse, args->s, &c);
+    map = lookup_map (parse, val.s, &c);
     if (map) {
       if (map->last) {
         result->n = 1;
@@ -3426,6 +3480,7 @@
       }
     }
   }
+  if (val.alloc) free(val.s);
   return STATUS_OK;
 }
 
@@ -3433,14 +3488,19 @@
 static NEOERR * _builtin_abs (CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
                               CSARG *result)
 {
+  NEOERR *err;
   int n1 = 0;
+  CSARG val;
 
-  result->op_type = CS_TYPE_NUM;
-  result->n = 0;
+  memset(&val, 0, sizeof(val));
+  err = eval_expr(parse, args, &val);
+  if (err) return nerr_pass(err);
 
-  n1 = arg_eval_num(parse, args);
+  result->op_type = CS_TYPE_NUM;
+  n1 = arg_eval_num(parse, &val);
   result->n = abs(n1);
 
+  if (val.alloc) free(val.s);
   return STATUS_OK;
 }
 
@@ -3531,29 +3591,26 @@
 #ifdef ENABLE_GETTEXT
 static NEOERR * _builtin_gettext(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
 {
-  HDF *obj;
+  NEOERR *err;
+  char *s;
+  CSARG val;
+
+  memset(&val, 0, sizeof(val));
+  err = eval_expr(parse, args, &val);
+  if (err) return nerr_pass(err);
 
   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)
+  if (val.op_type & (CS_TYPE_VAR | CS_TYPE_STRING))
     {
-      result->s = gettext(hdf_obj_value(obj));
-    }
-    else 
+    s = arg_eval(parse, &val);
+    if (s)
     {
-      result->s = "";
+      result->s = gettext(s);
     }
   }
-  else if (args->op_type & CS_TYPE_STRING)
-  {
-    result->s = gettext(args->s);
-    result->alloc = args->alloc;
-    args->alloc = 0;
-  }
+  if (val.alloc) free(val.s);
   return STATUS_OK;
 }
 #endif
@@ -3562,13 +3619,18 @@
 {
   NEOERR *err;
   char *s;
+  CSARG val;
+
+  memset(&val, 0, sizeof(val));
+  err = eval_expr(parse, args, &val);
+  if (err) return nerr_pass(err);
 
-  if (args->op_type & (CS_TYPE_VAR | CS_TYPE_STRING))
+  if (val.op_type & (CS_TYPE_VAR | CS_TYPE_STRING))
   {
     result->op_type = CS_TYPE_STRING;
     result->n = 0;
 
-    s = arg_eval(parse, args);
+    s = arg_eval(parse, &val);
     if (s)
     {
       err = csf->str_func(s, &(result->s));
@@ -3578,12 +3640,13 @@
   }
   else
   {
-    result->op_type = args->op_type;
-    result->n = args->n;
-    result->s = args->s;
-    result->alloc = args->alloc;
-    args->alloc = 0;
+    result->op_type = val.op_type;
+    result->n = val.n;
+    result->s = val.s;
+    result->alloc = val.alloc;
+    val.alloc = 0;
   }
+  if (val.alloc) free(val.s);
   return STATUS_OK;
 }
 
@@ -3591,7 +3654,7 @@
 {
   NEOERR *err;
 
-  err = _register_function(parse, funcname, 1, _str_func_wrapper);
+  err = cs_register_function(parse, funcname, 1, _str_func_wrapper);
   if (err) return nerr_pass(err);
   parse->functions->str_func = str_func;
 
@@ -3682,7 +3745,7 @@
     };
     int x = 0;
     while (Builtins[x].name != NULL) {
-      err = _register_function(my_parse, Builtins[x].name, Builtins[x].nargs,
+      err = cs_register_function(my_parse, Builtins[x].name, Builtins[x].nargs,
                                Builtins[x].function);
       if (err)
       {
diff -Nrbu clearsilver-0.10.2/cs/cstest.c clearsilver-0.10.3/cs/cstest.c
--- clearsilver-0.10.2/cs/cstest.c	2005-06-30 11:51:49.000000000 -0700
+++ clearsilver-0.10.3/cs/cstest.c	2006-03-12 15:54:15.000000000 -0800
@@ -13,6 +13,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 #include "util/neo_misc.h"
 #include "util/neo_hdf.h"
 #include "cs.h"
@@ -23,6 +24,23 @@
   return STATUS_OK;
 }
 
+NEOERR *test_strfunc(const char *str, char **ret)
+{
+  char *s = strdup(str);
+  int x = 0;
+
+  if (s == NULL)
+    return nerr_raise(NERR_NOMEM, "Unable to duplicate string in test_strfunc");
+
+  while (s[x]) {
+    s[x] = tolower(s[x]);
+    x++;
+  }
+  *ret = s;
+  return STATUS_OK;
+}
+
+
 int main (int argc, char *argv[])
 {
   NEOERR *err;
@@ -75,6 +93,14 @@
     return -1;
   }
 
+  /* register a test strfunc */
+  err = cs_register_strfunc(parse, "test_strfunc", test_strfunc);
+  if (err != STATUS_OK) 
+  {
+    nerr_log_error(err);
+    return -1;
+  }
+
   err = cs_parse_file (parse, cs_file);
   if (err != STATUS_OK)
   {
diff -Nrbu clearsilver-0.10.2/cs/Makefile clearsilver-0.10.3/cs/Makefile
--- clearsilver-0.10.2/cs/Makefile	2005-12-02 02:34:47.000000000 -0800
+++ clearsilver-0.10.3/cs/Makefile	2006-02-01 18:20:49.000000000 -0800
@@ -28,10 +28,12 @@
 
 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 \
+	   test14.cs test15.cs test16.cs test17.cs test18.cs test19.cs \
+	   test_var.cs test_paren.cs test_chuck.cs test_trak1.cs test_iter.cs \
 	   test_each_array.cs test_name.cs test_with.cs test_numbers.cs \
-	   test_splice.cs test_joo.cs test_first_last.cs test_abs_max_min.cs
+	   test_splice.cs test_joo.cs test_first_last.cs test_abs_max_min.cs \
+	   test_comma.cs test_macro_set.cs test_func.cs
+
 
 all: $(TARGETS)
 
diff -Nrbu clearsilver-0.10.2/cs/test19.cs clearsilver-0.10.3/cs/test19.cs
--- clearsilver-0.10.2/cs/test19.cs	1969-12-31 16:00:00.000000000 -0800
+++ clearsilver-0.10.3/cs/test19.cs	2006-01-04 16:36:39.000000000 -0800
@@ -0,0 +1,21 @@
+
+<?cs loop:a=0,1,1 ?>
+<?cs loop:b=0,1,1 ?>
+a: <?cs var:a ?>  b: <?cs var:b ?>
+
+!a || b: <?cs var:!a || b ?>
+
+!(a || b): <?cs var:!(a || b) ?>
+<?cs /loop ?>
+<?cs /loop ?>
+
+<?cs if:?Wow["Foo"] ?>
+ Wow.Foo exists <?cs var:Wow.Foo ?>
+<?cs /if ?>
+
+<?cs if:?Wow["Bar"] ?>
+ Wow.Bar exists <?cs var:Wow.Bar ?>
+<?cs /if ?>
+
+3: <?cs var:max((1,3),2) ?>
+2: <?cs var:max((3,1),2) ?>
diff -Nrbu clearsilver-0.10.2/cs/test19.cs.gold clearsilver-0.10.3/cs/test19.cs.gold
--- clearsilver-0.10.2/cs/test19.cs.gold	1969-12-31 16:00:00.000000000 -0800
+++ clearsilver-0.10.3/cs/test19.cs.gold	2006-02-01 16:23:35.000000000 -0800
@@ -0,0 +1,40 @@
+Parsing test19.cs
+
+
+
+a: 0  b: 0
+
+!a || b: 1
+
+!(a || b): 1
+
+a: 0  b: 1
+
+!a || b: 1
+
+!(a || b): 0
+
+
+
+a: 1  b: 0
+
+!a || b: 0
+
+!(a || b): 0
+
+a: 1  b: 1
+
+!a || b: 1
+
+!(a || b): 0
+
+
+
+
+ Wow.Foo exists 3
+
+
+
+
+3: 3
+2: 2
diff -Nrbu clearsilver-0.10.2/cs/test_comma.cs clearsilver-0.10.3/cs/test_comma.cs
--- clearsilver-0.10.2/cs/test_comma.cs	1969-12-31 16:00:00.000000000 -0800
+++ clearsilver-0.10.3/cs/test_comma.cs	2006-01-26 19:06:57.000000000 -0800
@@ -0,0 +1,11 @@
+
+Comma tests, evalute both but pass right most as expression result
+
+4: <?cs var:2,4 ?>
+
+also, "do nothing" lparen operator
+4: <?cs var:(2,4) ?>
+
+2: <?cs var:(4,2) ?>
+
+3: <?cs var:max((1,3),2) ?>
diff -Nrbu clearsilver-0.10.2/cs/test_comma.cs.gold clearsilver-0.10.3/cs/test_comma.cs.gold
--- clearsilver-0.10.2/cs/test_comma.cs.gold	1969-12-31 16:00:00.000000000 -0800
+++ clearsilver-0.10.3/cs/test_comma.cs.gold	2006-02-01 16:23:41.000000000 -0800
@@ -0,0 +1,12 @@
+Parsing test_comma.cs
+
+Comma tests, evalute both but pass right most as expression result
+
+4: 4
+
+also, "do nothing" lparen operator
+4: 4
+
+2: 2
+
+3: 3
diff -Nrbu clearsilver-0.10.2/cs/test_func.cs clearsilver-0.10.3/cs/test_func.cs
--- clearsilver-0.10.2/cs/test_func.cs	1969-12-31 16:00:00.000000000 -0800
+++ clearsilver-0.10.3/cs/test_func.cs	2006-02-01 16:19:54.000000000 -0800
@@ -0,0 +1,30 @@
+testing func calls
+
+Testing register strfunc
+<?cs var:test_strfunc(Foo) ?>
+<?cs var:test_strfunc("Foo" + Foo) ?>
+
+
+<?cs var:test_strfunc((5,2)) ?>
+<?cs var:test_strfunc((5,2) + 2) ?>
+
+testing passing expressions to builtins
+<?cs loop:x = 0, 20, 2 ?>
+ <?cs var:abs(x - 5) ?>
+<?cs /loop ?>
+
+25: <?cs var:max(20-5, 20+5) ?>
+15: <?cs var:min(20-5, 20+5) ?>
+
+6: <?cs var:string.length("foo" + "bar") ?>
+
+25: <?cs var:max(20-5, 20+5) ?>
+
+4: <?cs var:subcount(Foo.Bar["Baz"]) ?>
+Baz: <?cs var:name(Foo.Bar["Baz"]) ?>
+
+oba: <?cs var:string.slice("foo" + "bar", 5-3, 2+3) ?>
+
+first/last only run on local vars, which can't be created by expressions
+
+
diff -Nrbu clearsilver-0.10.2/cs/test_func.cs.gold clearsilver-0.10.3/cs/test_func.cs.gold
--- clearsilver-0.10.2/cs/test_func.cs.gold	1969-12-31 16:00:00.000000000 -0800
+++ clearsilver-0.10.3/cs/test_func.cs.gold	2006-02-01 16:23:41.000000000 -0800
@@ -0,0 +1,51 @@
+Parsing test_func.cs
+testing func calls
+
+Testing register strfunc
+worn out
+fooworn out
+
+
+2
+4
+
+testing passing expressions to builtins
+
+ 5
+
+ 3
+
+ 1
+
+ 1
+
+ 3
+
+ 5
+
+ 7
+
+ 9
+
+ 11
+
+ 13
+
+ 15
+
+
+25: 25
+15: 15
+
+6: 6
+
+25: 25
+
+4: 4
+Baz: Baz
+
+oba: oba
+
+first/last only run on local vars, which can't be created by expressions
+
+
diff -Nrbu clearsilver-0.10.2/cs/test_macro_set.cs clearsilver-0.10.3/cs/test_macro_set.cs
--- clearsilver-0.10.2/cs/test_macro_set.cs	1969-12-31 16:00:00.000000000 -0800
+++ clearsilver-0.10.3/cs/test_macro_set.cs	2006-01-26 16:48:45.000000000 -0800
@@ -0,0 +1,22 @@
+<?cs def:getWidthStyle(width, output) ?>
+  <?cs set:output = "style='width:" + width + "px;'" ?>
+<?cs /def ?>
+
+Testing "pass by reference" to macro calls so they can "return" data
+
+Testing non-existant var
+<?cs call:getWidthStyle(100, attr) ?>
+<?cs var:attr ?>
+
+Testing non-existant var sub var
+<?cs call:getWidthStyle(300, attr2.foo) ?>
+<?cs var:attr2.foo ?>
+
+Testing non-existant sub var
+<?cs call:getWidthStyle(400, attr.foo) ?>
+<?cs var:attr.foo ?>
+
+Testing existant var
+<?cs set:attr3 = "" ?>
+<?cs call:getWidthStyle(200, attr3) ?>
+<?cs var:attr3 ?>
diff -Nrbu clearsilver-0.10.2/cs/test_macro_set.cs.gold clearsilver-0.10.3/cs/test_macro_set.cs.gold
--- clearsilver-0.10.2/cs/test_macro_set.cs.gold	1969-12-31 16:00:00.000000000 -0800
+++ clearsilver-0.10.3/cs/test_macro_set.cs.gold	2006-02-01 16:23:41.000000000 -0800
@@ -0,0 +1,29 @@
+Parsing test_macro_set.cs
+
+
+Testing "pass by reference" to macro calls so they can "return" data
+
+Testing non-existant var
+
+  
+
+style='width:100px;'
+
+Testing non-existant var sub var
+
+  
+
+style='width:300px;'
+
+Testing non-existant sub var
+
+  
+
+style='width:400px;'
+
+Testing existant var
+
+
+  
+
+style='width:200px;'
Binary files clearsilver-0.10.2/java-jni/libclearsilver-jni.so and clearsilver-0.10.3/java-jni/libclearsilver-jni.so differ
diff -Nrbu clearsilver-0.10.2/Makefile clearsilver-0.10.3/Makefile
--- clearsilver-0.10.2/Makefile	2005-12-02 02:33:25.000000000 -0800
+++ clearsilver-0.10.3/Makefile	2006-03-12 15:42:06.000000000 -0800
@@ -108,8 +108,8 @@
 		mkdir -p $$mdir; \
 	done
 
-CS_DISTDIR = clearsilver-0.10.2
-CS_LABEL = CLEARSILVER-0_10_2
+CS_DISTDIR = clearsilver-0.10.3
+CS_LABEL = CLEARSILVER-0_10_3
 CS_FILES = README README.python INSTALL LICENSE CS_LICENSE rules.mk.in Makefile acconfig.h autogen.sh config.guess config.sub configure.in cs_config.h.in mkinstalldirs install-sh ClearSilver.h
 CS_DIRS = util cs cgi python scripts mod_ecs imd java-jni perl ruby dso csharp ports contrib m4
 
diff -Nrbu clearsilver-0.10.2/mod_ecs/mod_ecs.c clearsilver-0.10.3/mod_ecs/mod_ecs.c
--- clearsilver-0.10.2/mod_ecs/mod_ecs.c	2005-07-02 17:17:45.000000000 -0700
+++ clearsilver-0.10.3/mod_ecs/mod_ecs.c	2006-03-12 16:08:07.000000000 -0800
@@ -104,7 +104,7 @@
   request_rec *r;
 } WRAPPER_DATA;
 
-static int buf_getline (char *idata, int ilen, char *odata, int olen, int *nonl)
+static int buf_getline (const char *idata, int ilen, char *odata, int olen, int *nonl)
 {
   char *eol;
   int len;
@@ -143,7 +143,7 @@
   return ret;
 }
 
-static int header_write (HEADER_BUF *hbuf, char *data, int dlen)
+static int header_write (HEADER_BUF *hbuf, const char *data, int dlen)
 {
   char buf[1024];
   int done, len;
diff -Nrbu clearsilver-0.10.2/ports/rpm/clearsilver.spec clearsilver-0.10.3/ports/rpm/clearsilver.spec
--- clearsilver-0.10.2/ports/rpm/clearsilver.spec	2005-10-21 16:03:41.000000000 -0700
+++ clearsilver-0.10.3/ports/rpm/clearsilver.spec	2006-03-12 15:43:17.000000000 -0800
@@ -53,11 +53,11 @@
 
 Summary: Neotonic ClearSilver
 Name: clearsilver
-Version: 0.10.2
+Version: 0.10.3
 Release: 1
 Copyright: Open Source - Neotonic ClearSilver License (Apache 1.1 based)
 Group: Development/Libraries
-Source: http://www.clearsilver.net/downloads/clearsilver-0.10.2.tar.gz
+Source: http://www.clearsilver.net/downloads/clearsilver-0.10.3.tar.gz
 URL: http://www.clearsilver.net/
 Vendor: Neotonic Software Corporation, Inc.
 Packager: Brandon Long <blong@neotonic.com>
diff -Nrbu clearsilver-0.10.2/python/setup.py clearsilver-0.10.3/python/setup.py
--- clearsilver-0.10.2/python/setup.py	2005-10-21 16:19:30.000000000 -0700
+++ clearsilver-0.10.3/python/setup.py	2006-03-12 16:15:48.000000000 -0800
@@ -1,9 +1,19 @@
 
 import os, string, re, sys
-from distutils.core import setup, Extension
+
+# Check to see if the Egg system is installed (ie, setuptools)
+# See http://peak.telecommunity.com/DevCenter/PythonEggs
+USE_EGGS=1
+try:
+  from setuptools import setup
+except ImportError:
+  from distutils.core import setup
+  USE_EGGS=0
+
+from distutils.core import Extension
 from distutils import sysconfig
 
-VERSION = "0.10.2"
+VERSION = "0.10.3"
 INC_DIRS = ["../"]
 LIBRARIES = ["neo_cgi", "neo_cs", "neo_utl"]
 LIB_DIRS = ["../libs"]
@@ -95,17 +105,23 @@
   except AttributeError:
     pass
 
-setup(name="clearsilver",
-      version=VERSION,
-      description="Python ClearSilver Wrapper",
-      author="Brandon Long",
-      author_email="blong@fiction.net",
-      url="http://www.clearsilver.net/",
-      ext_modules=[Extension(
+setup_args = {
+    'name': "clearsilver",
+    'version': VERSION,
+    'description': "Python ClearSilver Wrapper",
+    'author': "Brandon Long",
+    'author_email': "blong@fiction.net",
+    'url': "http://www.clearsilver.net/",
+    'ext_modules': [Extension(
         name="neo_cgi",
 	sources=["neo_cgi.c", "neo_cs.c", "neo_util.c"],
 	include_dirs=INC_DIRS,
 	library_dirs=LIB_DIRS,
 	libraries=LIBRARIES,
 	)]
-      )
+  }
+
+if USE_EGGS:
+  setup_args['zip_safe'] = 0
+
+apply(setup, [], setup_args)
diff -Nrbu clearsilver-0.10.2/util/neo_date.c clearsilver-0.10.3/util/neo_date.c
--- clearsilver-0.10.2/util/neo_date.c	2005-11-30 20:04:27.000000000 -0800
+++ clearsilver-0.10.3/util/neo_date.c	2006-03-12 15:35:17.000000000 -0800
@@ -32,20 +32,20 @@
  * than this */
 static char TzBuf[_POSIX_PATH_MAX + 4];
 
-static int time_set_tz (const char *timezone)
+static int time_set_tz (const char *mytimezone)
 {
-  snprintf (TzBuf, sizeof(TzBuf), "TZ=%s", timezone);
+  snprintf (TzBuf, sizeof(TzBuf), "TZ=%s", mytimezone);
   putenv(TzBuf);
   tzset();
   return 0;
 }
 
-void neo_time_expand (const time_t tt, const char *timezone, struct tm *ttm)
+void neo_time_expand (const time_t tt, const char *mytimezone, struct tm *ttm)
 {
   const char *cur_tz = getenv("TZ");
   int change_back = 0;
-  if (cur_tz == NULL || strcmp(timezone, cur_tz)) {
-    time_set_tz (timezone);
+  if (cur_tz == NULL || strcmp(mytimezone, cur_tz)) {
+    time_set_tz (mytimezone);
     change_back = 1;
   }
   localtime_r (&tt, ttm);
@@ -54,15 +54,15 @@
   }
 }
 
-time_t neo_time_compact (struct tm *ttm, const char *timezone)
+time_t neo_time_compact (struct tm *ttm, const char *mytimezone)
 {
   time_t r;
   int save_isdst = ttm->tm_isdst;
 
   const char *cur_tz = getenv("TZ");
   int change_back = 0;
-  if (cur_tz == NULL || strcmp(timezone, cur_tz)) {
-    time_set_tz (timezone);
+  if (cur_tz == NULL || strcmp(mytimezone, cur_tz)) {
+    time_set_tz (mytimezone);
     change_back = 1;
   }
   ttm->tm_isdst = -1;
@@ -83,7 +83,11 @@
   return ttm->tm_gmtoff;
 #elif defined(HAVE_TZNAME)
   long tz;
+#ifndef __CYGWIN__
   tz = - timezone;
+#else
+  tz = - _timezone;
+#endif
   if(ttm->tm_isdst)
     tz += 3600;
   return tz;
diff -Nrbu clearsilver-0.10.2/util/neo_err.c clearsilver-0.10.3/util/neo_err.c
--- clearsilver-0.10.2/util/neo_err.c	2005-06-30 11:51:59.000000000 -0700
+++ clearsilver-0.10.3/util/neo_err.c	2006-03-07 12:43:17.000000000 -0800
@@ -20,6 +20,7 @@
 #include "neo_misc.h"
 #include "neo_err.h"
 #include "ulist.h"
+#include "ulocks.h"
 
 int NERR_PASS = -1;
 int NERR_ASSERT = 0;
@@ -37,6 +38,10 @@
 static NEOERR *FreeList = NULL;
 static ULIST *Errors = NULL;
 static int Inited = 0;
+#ifdef HAVE_PTHREADS
+/* In multi-threaded environments, we have to init thread safely */
+static pthread_mutex_t InitLock = PTHREAD_MUTEX_INITIALIZER;
+#endif
 
 /* Set this to 1 to enable non-thread safe re-use of NEOERR data
  * structures.  This was a premature performance optimization that isn't
@@ -420,6 +425,14 @@
 
   if (Inited == 0)
   {
+#ifdef HAVE_PTHREADS
+    /* In threaded environments, we have to mutex lock to do this init, but
+     * we don't want to use a mutex every time to check that it was Inited.
+     * So, we only lock if our first test of Inited was false */
+    err = mLock(&InitLock);
+    if (err != STATUS_OK) return nerr_pass(err);
+    if (Inited == 0) {
+#endif
     err = uListInit (&Errors, 10, 0);
     if (err != STATUS_OK) return nerr_pass(err);
 
@@ -449,6 +462,11 @@
     if (err != STATUS_OK) return nerr_pass(err);
 
     Inited = 1;
+#ifdef HAVE_PTHREADS
+    }
+    err = mUnlock(&InitLock);
+    if (err != STATUS_OK) return nerr_pass(err);
+#endif
   }
   return STATUS_OK;
 }
diff -Nrbu clearsilver-0.10.2/util/neo_err.h clearsilver-0.10.3/util/neo_err.h
--- clearsilver-0.10.2/util/neo_err.h	2005-11-21 18:51:19.000000000 -0800
+++ clearsilver-0.10.3/util/neo_err.h	2005-12-15 14:17:36.000000000 -0800
@@ -13,7 +13,7 @@
 #define __NEO_ERR_H_ 1
 
 /* For compilers (well, cpp actually) which don't define __PRETTY_FUNCTION__ */
-#ifndef __PRETTY_FUNCTION__
+#ifndef __GNUC__
 #define __PRETTY_FUNCTION__ "unknown_function"
 #endif
 
