diff -Nru clearsilver-0.7.2/cgi/cgi.c clearsilver-0.8.0/cgi/cgi.c
--- clearsilver-0.7.2/cgi/cgi.c	Wed Jul 31 16:49:41 2002
+++ clearsilver-0.8.0/cgi/cgi.c	Mon Dec  9 21:38:35 2002
@@ -68,6 +68,123 @@
   {"SERVER_ROOT", "ServerRoot"},
   {"SERVER_PROTOCOL", "ServerProtocol"},
   {"SERVER_SOFTWARE", "ServerSoftware"},
+  /* SSL Vars from mod_ssl */
+  {"HTTPS", "HTTPS"},
+  {"SSL_PROTOCOL", "SSL.Protocol"},
+  {"SSL_SESSION_ID", "SSL.SessionID"},
+  {"SSL_CIPHER", "SSL.Cipher"},
+  {"SSL_CIPHER_EXPORT", "SSL.Cipher.Export"},
+  {"SSL_CIPHER_USEKEYSIZE", "SSL.Cipher.UseKeySize"},
+  {"SSL_CIPHER_ALGKEYSIZE", "SSL.Cipher.AlgKeySize"},
+  {"SSL_VERSION_INTERFACE", "SSL.Version.Interface"},
+  {"SSL_VERSION_LIBRARY", "SSL.Version.Library"},
+  {"SSL_CLIENT_M_VERSION", "SSL.Client.M.Version"},
+  {"SSL_CLIENT_M_SERIAL", "SSL.Client.M.Serial"},
+  {"SSL_CLIENT_S_DN", "SSL.Client.S.DN"},
+  {"SSL_CLIENT_S_DN_x509", "SSL.Client.S.DN.x509"},
+  {"SSL_CLIENT_I_DN", "SSL.Client.I.DN"},
+  {"SSL_CLIENT_I_DN_x509", "SSL.Client.I.DN.x509"},
+  {"SSL_CLIENT_V_START", "SSL.Client.V.Start"},
+  {"SSL_CLIENT_V_END", "SSL.Client.V.End"},
+  {"SSL_CLIENT_A_SIG", "SSL.Client.A.SIG"},
+  {"SSL_CLIENT_A_KEY", "SSL.Client.A.KEY"},
+  {"SSL_CLIENT_CERT", "SSL.Client.CERT"},
+  {"SSL_CLIENT_CERT_CHAINn", "SSL.Client.CERT.CHAINn"},
+  {"SSL_CLIENT_VERIFY", "SSL.Client.Verify"},
+  {"SSL_SERVER_M_VERSION", "SSL.Server.M.Version"},
+  {"SSL_SERVER_M_SERIAL", "SSL.Server.M.Serial"},
+  {"SSL_SERVER_S_DN", "SSL.Server.S.DN"},
+  {"SSL_SERVER_S_DN_x509", "SSL.Server.S.DN.x509"},
+  {"SSL_SERVER_S_DN_CN", "SSL.Server.S.DN.CN"},
+  {"SSL_SERVER_S_DN_EMAIL", "SSL.Server.S.DN.Email"},
+  {"SSL_SERVER_S_DN_O", "SSL.Server.S.DN.O"},
+  {"SSL_SERVER_S_DN_OU", "SSL.Server.S.DN.OU"},
+  {"SSL_SERVER_S_DN_C", "SSL.Server.S.DN.C"},
+  {"SSL_SERVER_S_DN_SP", "SSL.Server.S.DN.SP"},
+  {"SSL_SERVER_S_DN_L", "SSL.Server.S.DN.L"},
+  {"SSL_SERVER_I_DN", "SSL.Server.I.DN"},
+  {"SSL_SERVER_I_DN_x509", "SSL.Server.I.DN.x509"},
+  {"SSL_SERVER_I_DN_CN", "SSL.Server.I.DN.CN"},
+  {"SSL_SERVER_I_DN_EMAIL", "SSL.Server.I.DN.Email"},
+  {"SSL_SERVER_I_DN_O", "SSL.Server.I.DN.O"},
+  {"SSL_SERVER_I_DN_OU", "SSL.Server.I.DN.OU"},
+  {"SSL_SERVER_I_DN_C", "SSL.Server.I.DN.C"},
+  {"SSL_SERVER_I_DN_SP", "SSL.Server.I.DN.SP"},
+  {"SSL_SERVER_I_DN_L", "SSL.Server.I.DN.L"},
+  {"SSL_SERVER_V_START", "SSL.Server.V.Start"},
+  {"SSL_SERVER_V_END", "SSL.Server.V.End"},
+  {"SSL_SERVER_A_SIG", "SSL.Server.A.SIG"},
+  {"SSL_SERVER_A_KEY", "SSL.Server.A.KEY"},
+  {"SSL_SERVER_CERT", "SSL.Server.CERT"},
+  /* SSL Vars mapped from others */
+  /* Hmm, if we're running under mod_ssl w/ +CompatEnvVars, we set these
+   * twice... */
+  {"SSL_PROTOCOL_VERSION", "SSL.Protocol"},
+  {"SSLEAY_VERSION", "SSL.Version.Library"},
+  {"HTTPS_CIPHER", "SSL.Cipher"},
+  {"HTTPS_EXPORT", "SSL.Cipher.Export"},
+  {"HTTPS_SECRETKEYSIZE", "SSL.Cipher.UseKeySize"},
+  {"HTTPS_KEYSIZE", "SSL.Cipher.AlgKeySize"},
+  {"SSL_SERVER_KEY_SIZE", "SSL.Cipher.AlgKeySize"},
+  {"SSL_SERVER_CERTIFICATE", "SSL.Server.CERT"},
+  {"SSL_SERVER_CERT_START", "SSL.Server.V.Start"},
+  {"SSL_SERVER_CERT_END", "SSL.Server.V.End"},
+  {"SSL_SERVER_CERT_SERIAL", "SSL.Server.M.Serial"},
+  {"SSL_SERVER_SIGNATURE_ALGORITHM", "SSL.Server.A.SIG"},
+  {"SSL_SERVER_DN", "SSL.Server.S.DN"},
+  {"SSL_SERVER_CN", "SSL.Server.S.DN.CN"},
+  {"SSL_SERVER_EMAIL", "SSL.Server.S.DN.Email"},
+  {"SSL_SERVER_O", "SSL.Server.S.DN.O"},
+  {"SSL_SERVER_OU", "SSL.Server.S.DN.OU"},
+  {"SSL_SERVER_C", "SSL.Server.S.DN.C"},
+  {"SSL_SERVER_SP", "SSL.Server.S.DN.SP"},
+  {"SSL_SERVER_L", "SSL.Server.S.DN.L"},
+  {"SSL_SERVER_IDN", "SSL.Server.I.DN"},
+  {"SSL_SERVER_ICN", "SSL.Server.I.DN.CN"},
+  {"SSL_SERVER_IEMAIL", "SSL.Server.I.DN.Email"},
+  {"SSL_SERVER_IO", "SSL.Server.I.DN.O"},
+  {"SSL_SERVER_IOU", "SSL.Server.I.DN.OU"},
+  {"SSL_SERVER_IC", "SSL.Server.I.DN.C"},
+  {"SSL_SERVER_ISP", "SSL.Server.I.DN.SP"},
+  {"SSL_SERVER_IL", "SSL.Server.I.DN.L"},
+  {"SSL_CLIENT_CERTIFICATE", "SSL.Client.CERT"},
+  {"SSL_CLIENT_CERT_START", "SSL.Client.V.Start"},
+  {"SSL_CLIENT_CERT_END", "SSL.Client.V.End"},
+  {"SSL_CLIENT_CERT_SERIAL", "SSL.Client.M.Serial"},
+  {"SSL_CLIENT_SIGNATURE_ALGORITHM", "SSL.Client.A.SIG"},
+  {"SSL_CLIENT_DN", "SSL.Client.S.DN"},
+  {"SSL_CLIENT_CN", "SSL.Client.S.DN.CN"},
+  {"SSL_CLIENT_EMAIL", "SSL.Client.S.DN.Email"},
+  {"SSL_CLIENT_O", "SSL.Client.S.DN.O"},
+  {"SSL_CLIENT_OU", "SSL.Client.S.DN.OU"},
+  {"SSL_CLIENT_C", "SSL.Client.S.DN.C"},
+  {"SSL_CLIENT_SP", "SSL.Client.S.DN.SP"},
+  {"SSL_CLIENT_L", "SSL.Client.S.DN.L"},
+  {"SSL_CLIENT_IDN", "SSL.Client.I.DN"},
+  {"SSL_CLIENT_ICN", "SSL.Client.I.DN.CN"},
+  {"SSL_CLIENT_IEMAIL", "SSL.Client.I.DN.Email"},
+  {"SSL_CLIENT_IO", "SSL.Client.I.DN.O"},
+  {"SSL_CLIENT_IOU", "SSL.Client.I.DN.OU"},
+  {"SSL_CLIENT_IC", "SSL.Client.I.DN.C"},
+  {"SSL_CLIENT_ISP", "SSL.Client.I.DN.SP"},
+  {"SSL_CLIENT_IL", "SSL.Client.I.DN.L"},
+  {"SSL_EXPORT", "SSL.Cipher.Export"},
+  {"SSL_KEYSIZE", "SSL.Cipher.AlgKeySize"},
+  {"SSL_SECKEYSIZE", "SSL.Cipher.UseKeySize"},
+  {"SSL_SSLEAY_VERSION", "SSL.Version.Library"},
+/* Old vars not in mod_ssl */
+  {"SSL_STRONG_CRYPTO", "SSL.Strong.Crypto"},
+  {"SSL_SERVER_KEY_EXP", "SSL.Server.Key.Exp"},
+  {"SSL_SERVER_KEY_ALGORITHM", "SSL.Server.Key.Algorithm"},
+  {"SSL_SERVER_KEY_SIZE", "SSL.Server.Key.Size"},
+  {"SSL_SERVER_SESSIONDIR", "SSL.Server.SessionDir"},
+  {"SSL_SERVER_CERTIFICATELOGDIR", "SSL.Server.CertificateLogDir"},
+  {"SSL_SERVER_CERTFILE", "SSL.Server.CertFile"},
+  {"SSL_SERVER_KEYFILE", "SSL.Server.KeyFile"},
+  {"SSL_SERVER_KEYFILETYPE", "SSL.Server.KeyFileType"},
+  {"SSL_CLIENT_KEY_EXP", "SSL.Client.Key.Exp"},
+  {"SSL_CLIENT_KEY_ALGORITHM", "SSL.Client.Key.Algorithm"},
+  {"SSL_CLIENT_KEY_SIZE", "SSL.Client.Key.Size"},
   {NULL, NULL}
 };
 
@@ -103,11 +220,14 @@
 
   err = cgiwrap_getenv (env, &s);
   if (err != STATUS_OK) return nerr_pass (err);
-  err = hdf_set_buf (cgi->hdf, name, s);
-  if (err != STATUS_OK) 
+  if (s != NULL)
   {
-    free(s);
-    return nerr_pass (err);
+    err = hdf_set_buf (cgi->hdf, name, s);
+    if (err != STATUS_OK) 
+    {
+      free(s);
+      return nerr_pass (err);
+    }
   }
   return STATUS_OK;
 }
@@ -737,11 +857,11 @@
   {
     s = hdf_get_value (obj, "Status", NULL);
     if (s)
-      err = cgiwrap_writef ("Status: %s\n", s);
+      err = cgiwrap_writef ("Status: %s\r\n", s);
     if (err != STATUS_OK) return nerr_pass (err);
     s = hdf_get_value (obj, "Location", NULL);
     if (s)
-      err = cgiwrap_writef ("Location: %s\n", s);
+      err = cgiwrap_writef ("Location: %s\r\n", s);
     if (err != STATUS_OK) return nerr_pass (err);
     child = hdf_get_obj (cgi->hdf, "cgiout.other");
     if (child)
diff -Nru clearsilver-0.7.2/cgi/date.c clearsilver-0.8.0/cgi/date.c
--- clearsilver-0.7.2/cgi/date.c	Thu Sep 26 14:27:09 2002
+++ clearsilver-0.8.0/cgi/date.c	Thu Oct 17 17:17:22 2002
@@ -89,7 +89,7 @@
   if (err) return nerr_pass(err);
   err = hdf_set_int_value (obj, "wday", ttm->tm_wday);
   if (err) return nerr_pass(err);
-  tzoffset = timezone / 60;
+  tzoffset = neo_tz_offset(ttm);
   if (tzoffset < 0)
   {
     tzoffset *= -1;
diff -Nru clearsilver-0.7.2/cgi/html.c clearsilver-0.8.0/cgi/html.c
--- clearsilver-0.7.2/cgi/html.c	Fri Aug  9 16:23:38 2002
+++ clearsilver-0.8.0/cgi/html.c	Thu Jan  9 18:04:49 2003
@@ -359,7 +359,7 @@
         if (last_char == '.' || last_char == ',') { suffix=1; }
 	err = string_append (out, " <a target=\"_blank\" href=\"");
 	if (err != STATUS_OK) break;
-	if (!strncmp(src + x, "www.", 4))
+	if (!strncasecmp(src + x, "www.", 4))
 	{
 	  err = string_append (out, "http://");
 	  if (err != STATUS_OK) break;
diff -Nru clearsilver-0.7.2/cgi/rfc2388.c clearsilver-0.8.0/cgi/rfc2388.c
--- clearsilver-0.7.2/cgi/rfc2388.c	Tue Sep 10 15:23:28 2002
+++ clearsilver-0.8.0/cgi/rfc2388.c	Tue Jan  7 15:12:17 2003
@@ -2,8 +2,9 @@
 /*
  * Neotonic ClearSilver Templating System
  *
- * This code is made available under the terms of the FSF's
- * Library Gnu Public License (LGPL).
+ * 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
  */
@@ -119,7 +120,7 @@
   return STATUS_OK;
 }
 
-static NEOERR * _read_line (CGI *cgi, char **s, int *l)
+static NEOERR * _read_line (CGI *cgi, char **s, int *l, int *done)
 {
   int ofs = 0;
   char *p;
@@ -152,6 +153,15 @@
     memmove(cgi->buf, cgi->buf + cgi->nl, ofs);
   }
   cgiwrap_read (cgi->buf + ofs, cgi->buflen - ofs, &(cgi->readlen));
+  if (cgi->readlen < 0)
+  {
+    return nerr_raise_errno (NERR_IO, "POST Read Error");
+  }
+  if (cgi->readlen == 0)
+  {
+    *done = 1;
+    return STATUS_OK;
+  }
   cgi->data_read += cgi->readlen;
   if (cgi->upload_cb)
   {
@@ -174,15 +184,15 @@
   return STATUS_OK;
 }
 
-static NEOERR * _read_header_line (CGI *cgi, STRING *line)
+static NEOERR * _read_header_line (CGI *cgi, STRING *line, int *done)
 {
   NEOERR *err;
   char *s, *p;
   int l;
 
-  err = _read_line (cgi, &s, &l);
+  err = _read_line (cgi, &s, &l, done);
   if (err) return nerr_pass (err);
-  if (l == 0) return STATUS_OK;
+  if (*done || (l == 0)) return STATUS_OK;
   if (isspace (s[0])) return STATUS_OK;
   while (l && isspace(s[l-1])) l--;
   err = string_appendn (line, s, l);
@@ -190,9 +200,10 @@
 
   while (1)
   {
-    err = _read_line (cgi, &s, &l);
+    err = _read_line (cgi, &s, &l, done);
     if (err) break;
     if (l == 0) break;
+    if (*done) break;
     if (!(s[0] == ' ' || s[0] == '\t'))
     {
       cgi->unget = TRUE;
@@ -253,9 +264,9 @@
   *done = 0;
   while (1)
   {
-    err = _read_line (cgi, &s, &l);
+    err = _read_line (cgi, &s, &l, done);
     if (err) return nerr_pass (err);
-    if (l == 0) {
+    if ((l == 0) || (*done)) {
       *done = 1;
       return STATUS_OK;
     }
@@ -344,7 +355,7 @@
 
   while (1)
   {
-    err = _read_header_line (cgi, &str);
+    err = _read_header_line (cgi, &str, done);
     if (err) break;
     if (str.buf == NULL || str.buf[0] == '\0') break;
     p = strchr (str.buf, ':');
@@ -402,7 +413,7 @@
       char *s;
       int l, w;
 
-      err = _read_line (cgi, &s, &l);
+      err = _read_line (cgi, &s, &l, done);
       if (err) break;
       if (l == 0) break;
       if (_is_boundary(boundary, s, l, done)) break;
diff -Nru clearsilver-0.7.2/cs/Makefile clearsilver-0.8.0/cs/Makefile
--- clearsilver-0.7.2/cs/Makefile	Thu Oct 17 13:54:23 2002
+++ clearsilver-0.8.0/cs/Makefile	Wed Nov 27 09:49:52 2002
@@ -23,7 +23,7 @@
 
 TARGETS = $(CS_LIB) $(CSTEST_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
+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
 
 all: $(TARGETS)
 
@@ -31,7 +31,7 @@
 	$(AR) $@ $(CS_OBJ)
 
 $(CSTEST_EXE): $(CSTEST_OBJ) $(CS_LIB)
-	$(LD) $@ $(CSTEST_OBJ) $(LIBS)
+	$(LD) $@ $(CSTEST_OBJ) $(LIBS) # -lefence
 
 $(CSDUMP_EXE): $(CSDUMP_OBJ) $(CS_LIB)
 	$(LD) $@ $(CSDUMP_OBJ) $(LIBS)
diff -Nru clearsilver-0.7.2/cs/cs.h clearsilver-0.8.0/cs/cs.h
--- clearsilver-0.7.2/cs/cs.h	Mon Jun 10 18:46:23 2002
+++ clearsilver-0.8.0/cs/cs.h	Fri Feb 21 14:44:46 2003
@@ -76,19 +76,22 @@
   CS_OP_LBRACKET = (1<<19),
   CS_OP_RBRACKET = (1<<20),
 
+  CS_OP_DOT = (1<<21),
+
   /* Types */
-  CS_TYPE_STRING = (1<<21),
-  CS_TYPE_NUM = (1<<22),
-  CS_TYPE_VAR = (1<<23),
-  CS_TYPE_VAR_NUM = (1<<24),
+  CS_TYPE_STRING = (1<<25),
+  CS_TYPE_NUM = (1<<26),
+  CS_TYPE_VAR = (1<<27),
+  CS_TYPE_VAR_NUM = (1<<28),
 
   /* Not real types... */
-  CS_TYPE_MACRO = (1<<25),
-  CS_TYPE_FUNCTION = (1<<26)
+  CS_TYPE_MACRO = (1<<29),
+  CS_TYPE_FUNCTION = (1<<30)
 } CSTOKEN_TYPE;
 
 #define CS_OPS_UNARY (CS_OP_EXISTS | CS_OP_NOT | CS_OP_NUM)
 #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)
 #define CS_TYPES_CONST (CS_TYPE_STRING | CS_TYPE_NUM)
 #define CS_ASSOC (CS_OP_RPAREN | CS_OP_RBRACKET)
diff -Nru clearsilver-0.7.2/cs/csparse.c clearsilver-0.8.0/cs/csparse.c
--- clearsilver-0.7.2/cs/csparse.c	Tue Aug 20 16:46:25 2002
+++ clearsilver-0.8.0/cs/csparse.c	Fri Feb 21 14:44:46 2003
@@ -684,6 +684,7 @@
   { FALSE, ")", CS_OP_RPAREN },
   { FALSE, "[", CS_OP_LBRACKET },
   { FALSE, "]", CS_OP_RBRACKET },
+  { FALSE, ".", CS_OP_DOT },
   { FALSE, NULL, 0 }
 };
 
@@ -789,7 +790,7 @@
    CS_OP_EQUAL | CS_OP_NEQUAL,
    CS_OP_GT | CS_OP_GTE | CS_OP_LT | CS_OP_LTE,
    CS_OP_ADD | CS_OP_SUB, 
-   CS_OP_MULT | CS_OP_DIV | CS_OP_MOD,
+   CS_OP_MULT | CS_OP_DIV | CS_OP_MOD | CS_OP_DOT,
    CS_OP_LBRACKET,
    0
 };
@@ -818,6 +819,7 @@
     case CS_OP_RPAREN: return ")";
     case CS_OP_LBRACKET: return "[";
     case CS_OP_RBRACKET: return "]";
+    case CS_OP_DOT : return ".";
     case CS_TYPE_STRING: return more ? "STRING" : "s";
     case CS_TYPE_NUM: return more ? "NUM" : "n";
     case CS_TYPE_VAR: return more ? "VAR" : "v";
@@ -827,8 +829,7 @@
   return "u";
 }
 
-static NEOERR *parse_expr2 (CSPARSE *parse, CSTOKEN *tokens, int ntokens, 
-    CSARG *arg)
+static NEOERR *parse_expr2 (CSPARSE *parse, CSTOKEN *tokens, int ntokens, int lvalue, CSARG *arg)
 {
   NEOERR *err;
   char tmp[256];
@@ -843,6 +844,12 @@
   fprintf(stderr, "\n");
 #endif
 
+  /* Not quite sure what to do with this case... */
+  if (ntokens == 0)
+  {
+    return nerr_raise (NERR_PARSE, "%s Bad Expression",
+	find_context(parse, -1, tmp, sizeof(tmp)));
+  }
   if (ntokens == 1)
   {
     x = 0;
@@ -873,7 +880,7 @@
       return nerr_raise (NERR_NOMEM, 
 	  "%s Unable to allocate memory for expression", 
 	  find_context(parse, -1, tmp, sizeof(tmp)));
-    err = parse_expr2(parse, tokens + 1, 1, arg->expr1);
+    err = parse_expr2(parse, tokens + 1, 1, lvalue, arg->expr1);
     return nerr_pass(err);
   }
 
@@ -928,6 +935,13 @@
 	    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, 
+	    "%s Invalid op '%s' in lvalue",
+	    find_context(parse, -1, tmp, sizeof(tmp)), 
+	    expand_token_type(tokens[x].type, 0));
+      }
       if (tokens[x].type & BinaryOpOrder[op])
       {
 	arg->op_type = tokens[x].type;
@@ -939,14 +953,15 @@
 	      find_context(parse, -1, tmp, sizeof(tmp)));
 	if (tokens[x].type == CS_OP_LBRACKET)
 	{
-	  err = parse_expr2(parse, tokens + x, ntokens-x, arg->expr2);
+	  /* Inside of brackets, we don't limit to valid lvalue ops */
+	  err = parse_expr2(parse, tokens + x, ntokens-x, 0, arg->expr2);
 	}
 	else
 	{
-	  err = parse_expr2(parse, tokens + x + 1, ntokens-x-1, arg->expr2);
+	  err = parse_expr2(parse, tokens + x + 1, ntokens-x-1, lvalue, arg->expr2);
 	}
 	if (err) return nerr_pass (err);
-	err = parse_expr2(parse, tokens, x, arg->expr1);
+	err = parse_expr2(parse, tokens, x, lvalue, arg->expr1);
 	if (err) return nerr_pass (err);
 	return STATUS_OK;
       }
@@ -960,7 +975,7 @@
       (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, arg));
+    return nerr_pass(parse_expr2(parse, tokens + 1, ntokens-2, lvalue, arg));
   }
 
   /* Unary op against an entire expression */
@@ -973,7 +988,7 @@
       return nerr_raise (NERR_NOMEM, 
 	  "%s Unable to allocate memory for expression", 
 	  find_context(parse, -1, tmp, sizeof(tmp)));
-    err = parse_expr2(parse, tokens + 2, ntokens-3, arg->expr1);
+    err = parse_expr2(parse, tokens + 2, ntokens-3, lvalue, arg->expr1);
     return nerr_pass(err);
   }
   if (tokens[0].type & CS_OPS_UNARY)
@@ -984,7 +999,7 @@
       return nerr_raise (NERR_NOMEM, 
 	  "%s Unable to allocate memory for expression", 
 	  find_context(parse, -1, tmp, sizeof(tmp)));
-    err = parse_expr2(parse, tokens + 1, ntokens-1, arg->expr1);
+    err = parse_expr2(parse, tokens + 1, ntokens-1, lvalue, arg->expr1);
     return nerr_pass(err);
   }
 
@@ -1018,7 +1033,7 @@
       return nerr_raise (NERR_NOMEM, 
 	  "%s Unable to allocate memory for expression", 
 	  find_context(parse, -1, tmp, sizeof(tmp)));
-    err = parse_expr2(parse, tokens + 2, ntokens-3, arg->expr1);
+    err = parse_expr2(parse, tokens + 2, ntokens-3, lvalue, arg->expr1);
     return nerr_pass(err);
   }
 
@@ -1026,7 +1041,7 @@
       find_context(parse, -1, tmp, sizeof(tmp)));
 }
 
-static NEOERR *parse_expr (CSPARSE *parse, char *arg, CSARG *expr)
+static NEOERR *parse_expr (CSPARSE *parse, char *arg, int lvalue, CSARG *expr)
 {
   NEOERR *err;
   CSTOKEN tokens[MAX_TOKENS];
@@ -1035,7 +1050,7 @@
   memset(tokens, 0, sizeof(CSTOKEN) * MAX_TOKENS);
   err = parse_tokens (parse, arg, tokens, &ntokens);
   if (err) return nerr_pass(err);
-  err = parse_expr2 (parse, tokens, ntokens, expr);
+  err = parse_expr2 (parse, tokens, ntokens, lvalue, expr);
   if (err) return nerr_pass(err);
   return STATUS_OK;
 }
@@ -1134,7 +1149,7 @@
     node->flags |= CSF_REQUIRED;
   arg++;
   /* Validate arg is a var (regex /^[#" ]$/) */
-  err = parse_expr (parse, arg, &(node->arg1));
+  err = parse_expr (parse, arg, 0, &(node->arg1));
   if (err)
   {
     dealloc_node(&node);
@@ -1161,7 +1176,7 @@
     node->flags |= CSF_REQUIRED;
   arg++;
   /* Validate arg is a var (regex /^[#" ]$/) */
-  err = parse_expr (parse, arg, &(node->arg1));
+  err = parse_expr (parse, arg, 0, &(node->arg1));
   if (err)
   {
     dealloc_node(&node);
@@ -1188,7 +1203,7 @@
     node->flags |= CSF_REQUIRED;
   arg++;
   /* Validate arg is a var (regex /^[#" ]$/) */
-  err = parse_expr (parse, arg, &(node->arg1));
+  err = parse_expr (parse, arg, 0, &(node->arg1));
   if (err)
   {
     dealloc_node(&node);
@@ -1215,7 +1230,7 @@
     node->flags |= CSF_REQUIRED;
   arg++;
   /* Validate arg is a var (regex /^[#" ]$/) */
-  err = parse_expr (parse, arg, &(node->arg1));
+  err = parse_expr (parse, arg, 0, &(node->arg1));
   if (err)
   {
     dealloc_node(&node);
@@ -1297,7 +1312,7 @@
   node->cmd = cmd;
   arg++;
 
-  err = parse_expr (parse, arg, &(node->arg1));
+  err = parse_expr (parse, arg, 0, &(node->arg1));
   if (err != STATUS_OK)
   {
     dealloc_node(&node);
@@ -1472,7 +1487,7 @@
       if (expr->op_type == CS_OP_LBRACKET)
       {
 	/* the bracket op is essentially hdf array lookups, which just
-	 * means appending .0 */
+	 * means appending the value of arg2, .0 */
 	result->op_type = CS_TYPE_VAR;
 	result->alloc = 1;
 	if (arg2.op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM))
@@ -1499,6 +1514,45 @@
 	  }
 	}
       }
+      else if (expr->op_type == CS_OP_DOT)
+      {
+	/* the dot op is essentially extending the hdf name, which just
+	 * means appending the string .0 */
+	result->op_type = CS_TYPE_VAR;
+	result->alloc = 1;
+	if (arg2.op_type & CS_TYPES_VAR)
+	{
+	  result->s = sprintf_alloc("%s.%s", arg1.s, arg2.s);
+	  if (result->s == NULL)
+	    return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %s", arg1.s, arg2.s);
+	}
+	else
+	{
+	  if (arg2.op_type & CS_TYPE_NUM)
+	  {
+	    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);
+	    if (s2 && s2[0])
+	    {
+	      result->s = sprintf_alloc("%s.%s", arg1.s, s2);
+	      if (result->s == NULL)
+		return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %s", arg1.s, s2);
+	    }
+	    else
+	    {
+	      /* if s2 doesn't match anything, then the whole thing is empty */
+	      result->s = "";
+	      result->alloc = 0;
+	    }
+	  }
+	}
+      }
       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)))
@@ -1710,6 +1764,21 @@
     if (s)
     {
       CSPARSE *cs = NULL;
+
+      /* Ok, we need our own copy of the string to pass to
+       * cs_parse_string... */
+      if (val.alloc) {
+	val.alloc = 0;
+      }
+      else 
+      {
+	s = strdup(s);
+	if (s == NULL)
+	{
+	  return nerr_raise(NERR_NOMEM, "Unable to allocate memory for lvar_eval");
+	}
+      }
+
       do {
 	err = cs_init(&cs, parse->hdf);
 	if (err) break;
@@ -1977,7 +2046,7 @@
   node->arg1.op_type = CS_TYPE_VAR;
   node->arg1.s = lvar;
 
-  err = parse_expr(parse, p, &(node->arg2));
+  err = parse_expr(parse, p, 0, &(node->arg2));
   if (err) 
   {
     dealloc_node(&node);
@@ -2176,25 +2245,6 @@
 
   while (*s)
   {
-    carg = (CSARG *) calloc (1, sizeof(CSARG));
-    if (carg == NULL)
-    {
-      err = nerr_raise (NERR_NOMEM, 
-	  "%s Unable to allocate memory for CSARG in def %s",
-	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
-      break;
-    }
-    if (larg == NULL)
-    {
-      macro->args = carg;
-      larg = carg;
-    }
-    else
-    {
-      larg->next = carg;
-      larg = carg;
-    }
-    macro->n_args++;
     while (*s && isspace(*s)) s++;
     a = strpbrk(s, ",)");
     if (a == NULL)
@@ -2217,6 +2267,34 @@
 	  find_context(parse, -1, tmp, sizeof(tmp)), arg, *p);
       break;
     }
+    /* No argument case */
+    if (*s == '\0' && macro->n_args == 0) break;
+    if (*s == '\0')
+    {
+      err = nerr_raise (NERR_PARSE, 
+	  "%s Missing argument name or extra comma in def %s",
+	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
+      break;
+    }
+    carg = (CSARG *) calloc (1, sizeof(CSARG));
+    if (carg == NULL)
+    {
+      err = nerr_raise (NERR_NOMEM, 
+	  "%s Unable to allocate memory for CSARG in def %s",
+	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
+      break;
+    }
+    if (larg == NULL)
+    {
+      macro->args = carg;
+      larg = carg;
+    }
+    else
+    {
+      larg->next = carg;
+      larg = carg;
+    }
+    macro->n_args++;
     carg->s = s;
     if (last == TRUE) break;
     s = a+1;
@@ -2317,7 +2395,7 @@
   {
     dealloc_node(&node);
     return nerr_raise (NERR_PARSE, 
-	"%s Missing right paren in def %s",
+	"%s Missing right paren in call %s",
 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
   }
   *a = '\0';
@@ -2325,6 +2403,26 @@
   x = 0;
   while (*s)
   {
+    while (*s && isspace(*s)) s++;
+    /* No arguments case */
+    if (*s == '\0' && x == 0) break;
+    /* Empty argument case */
+    if (*s == '\0')
+    {
+      err =nerr_raise (NERR_PARSE, 
+	"%s Missing argument in call %s",
+	find_context(parse, -1, tmp, sizeof(tmp)), arg);
+      break;
+    }
+    a = get_arg(s);
+    if (a == NULL)
+    {
+      last = TRUE;
+    }
+    else
+    {
+      *a = '\0';
+    }
     carg = (CSARG *) calloc (1, sizeof(CSARG));
     if (carg == NULL)
     {
@@ -2344,16 +2442,7 @@
       larg = carg;
     }
     x++;
-    a = get_arg(s);
-    if (a == NULL)
-    {
-      last = TRUE;
-    }
-    else
-    {
-      *a = '\0';
-    }
-    err = parse_expr (parse, s, carg);
+    err = parse_expr (parse, s, 0, carg);
     if (err) break;
     if (last == TRUE) break;
     s = a+1;
@@ -2495,14 +2584,14 @@
   }
   *s = '\0';
   s++;
-  err = parse_expr(parse, arg, &(node->arg1));
+  err = parse_expr(parse, arg, 1, &(node->arg1));
   if (err)
   {
     dealloc_node(&node);
     return nerr_pass(err);
   }
 
-  err = parse_expr(parse, s, &(node->arg2));
+  err = parse_expr(parse, s, 0, &(node->arg2));
   if (err)
   {
     dealloc_node(&node);
@@ -2541,15 +2630,32 @@
 
       n_val = arg_eval_num (parse, &val);
       snprintf (buf, sizeof(buf), "%ld", n_val);
-      err = var_set_value (parse, set.s, buf);
+      if (set.s)
+      {
+	err = var_set_value (parse, set.s, buf);
+      }
+      else
+      {
+	err = nerr_raise(NERR_ASSERT, 
+	    "lvalue is NULL/empty in attempt to evaluate set to '%s'", buf);
+      }
     }
     else
     {
       char *s = arg_eval (parse, &val);
       /* Do we set it to blank if s == NULL? */
-      if (s)
+      if (set.s)
+      {
+	if (s)
+	{
+	  err = var_set_value (parse, set.s, s);
+	}
+      }
+      else
       {
-	err = var_set_value (parse, set.s, s);
+	err = nerr_raise(NERR_ASSERT, 
+	    "lvalue is NULL/empty in attempt to evaluate set to '%s'", 
+	    (s) ? s : "");
       }
     }
   } /* else WARNING */
@@ -2640,7 +2746,7 @@
     a = strpbrk(p, ",");
     if (a == NULL) last = TRUE;
     else *a = '\0';
-    err = parse_expr (parse, p, carg);
+    err = parse_expr (parse, p, 0, carg);
     if (err) break;
     if (last == TRUE) break;
     p = a+1;
diff -Nru clearsilver-0.7.2/cs/test.hdf clearsilver-0.8.0/cs/test.hdf
--- clearsilver-0.7.2/cs/test.hdf	Tue Apr 30 19:57:02 2002
+++ clearsilver-0.8.0/cs/test.hdf	Wed Nov 27 09:49:52 2002
@@ -127,3 +127,7 @@
 
 CS_START = <?cs
 CS_END = ?>
+
+A = HELLO
+B = WORLD
+C = <?cs var:A ?>/<?cs var:B ?>
diff -Nru clearsilver-0.7.2/cs/test16.cs clearsilver-0.8.0/cs/test16.cs
--- clearsilver-0.7.2/cs/test16.cs	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.8.0/cs/test16.cs	Wed Nov 27 09:49:52 2002
@@ -0,0 +1,3 @@
+<?cs lvar:C ?>
+<?cs lvar:C ?>
+<?cs lvar:C ?>
diff -Nru clearsilver-0.7.2/cs/test16.cs.gold clearsilver-0.8.0/cs/test16.cs.gold
--- clearsilver-0.7.2/cs/test16.cs.gold	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.8.0/cs/test16.cs.gold	Wed Nov 27 09:49:52 2002
@@ -0,0 +1,4 @@
+Parsing test16.cs
+HELLO/WORLD
+HELLO/WORLD
+HELLO/WORLD
diff -Nru clearsilver-0.7.2/java-jni/README-bin.txt clearsilver-0.8.0/java-jni/README-bin.txt
--- clearsilver-0.7.2/java-jni/README-bin.txt	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.8.0/java-jni/README-bin.txt	Fri Oct 18 11:57:28 2002
@@ -0,0 +1,33 @@
+---------------------------------
+Clearsilver JavaJNI wrapper
+by David Jeske
+Distributed under the Neotonic ClearSilver License
+----------------------------------
+
+This is a binary compile of a Java JNI wrapper for the ClearSilver
+templating library. This version is compiled on:
+
+  x86 Linux (Linux 2.2.x - RedHat 6.2)
+
+INSTALLING
+
+You must put the native library (libclearsilver-jni.so) into a standard 
+library location (i.e. like /lib), or make sure that Java can 
+find it by using the java command line directive: 
+
+  -Djava.library.path=/somewhere/else
+
+Then you must put the clearsilver.jar file into your java 
+CLASSPATH.
+
+USING
+
+See the example CSTest.java for an example of how to import
+and use the clearsilver objects. 
+
+USING in a servlet
+
+Since the most common usage of Clearsilver is in a servlet, 
+we've provided some examples of how to use it in the servlet/
+directory.
+-
diff -Nru clearsilver-0.7.2/python/Makefile clearsilver-0.8.0/python/Makefile
--- clearsilver-0.7.2/python/Makefile	Thu Oct 17 13:54:27 2002
+++ clearsilver-0.8.0/python/Makefile	Wed Nov 13 17:45:55 2002
@@ -22,7 +22,7 @@
 DLIBS += -lneo_cgi -lneo_cs -lneo_utl 
 LIBS += -L$(LIB_DIR) $(DLIBS) $(DB2_LIB)
 
-ifeq ($(OSNAME),WindowsNT 0)
+ifeq ($(OSTYPE),WindowsNT)
 TARGETS = $(NEO_UTIL_PYD)
 PYTHONLIBS=-LC:/python22/Libs -lpython22 
 else
diff -Nru clearsilver-0.7.2/python/neo_cgi.c clearsilver-0.8.0/python/neo_cgi.c
--- clearsilver-0.7.2/python/neo_cgi.c	Thu Oct 17 14:06:11 2002
+++ clearsilver-0.8.0/python/neo_cgi.c	Mon Nov 25 12:08:35 2002
@@ -581,6 +581,8 @@
 
   memcpy (ptr, s, len);
 
+  Py_DECREF(buf);
+
   PyErr_Clear();
   return len;
 }
diff -Nru clearsilver-0.7.2/python/neo_util.c clearsilver-0.8.0/python/neo_util.c
--- clearsilver-0.7.2/python/neo_util.c	Thu Oct  3 15:39:28 2002
+++ clearsilver-0.8.0/python/neo_util.c	Mon Feb  3 14:27:00 2003
@@ -551,6 +551,24 @@
   return rv;
 }
 
+static PyObject * p_hdf_search_path (PyObject *self, PyObject *args)
+{
+  HDFObject *ho = (HDFObject *)self;
+  PyObject *rv;
+  char *path;
+  char full[_POSIX_PATH_MAX];
+  NEOERR *err;
+
+  if (!PyArg_ParseTuple(args, "s:searchPath(path)", &path))
+    return NULL;
+
+  err = hdf_search_path (ho->data, path, full);
+  if (err) return p_neo_error(err); 
+
+  rv = PyString_FromString(full);
+  return rv;
+}
+
 static PyMethodDef HDFMethods[] =
 {
   {"getIntValue", p_hdf_get_int_value, METH_VARARGS, NULL},
@@ -575,6 +593,7 @@
   {"dump", p_hdf_dump, METH_VARARGS, NULL},
   {"copy", p_hdf_copy, METH_VARARGS, NULL},
   {"setSymLink", p_hdf_set_symlink, METH_VARARGS, NULL},
+  {"searchPath", p_hdf_search_path, METH_VARARGS, NULL},
   {NULL, NULL}
 };
 
diff -Nru clearsilver-0.7.2/rules.mk clearsilver-0.8.0/rules.mk
--- clearsilver-0.7.2/rules.mk	Thu Oct 17 13:54:22 2002
+++ clearsilver-0.8.0/rules.mk	Wed Nov 13 16:58:02 2002
@@ -45,11 +45,11 @@
 
 ## --------------win32 options
 
-ifeq ($(OSNAME),WindowsNT 0)
+ifeq ($(OSTYPE),WindowsNT)
 CFLAGS += -D__WINDOWS_GCC__
 USE_DB2 = 0
 USE_ZLIB = 0
-SHELL=cmd.exe
+# SHELL=cmd.exe
 LS = ls
 PYTHON_INC = -Ic:/Python22/include
 LDSHARED= NEED_TO_USE_DLLWRAP
@@ -85,6 +85,7 @@
 Makefile.depends: $(NEOTONIC_ROOT)/rules.mk Makefile
 	@echo "*******************************************"
 	@echo "** Building Dependencies "
+	@echo "** OSNAME: $(OSTYPE)"
 	@rm -f Makefile.depends
 	@touch Makefile.depends
 	@for II in `$(LS) -1 *.c`; do \
diff -Nru clearsilver-0.7.2/scripts/ChangeLog.py clearsilver-0.8.0/scripts/ChangeLog.py
--- clearsilver-0.7.2/scripts/ChangeLog.py	Wed Dec 31 16:00:00 1969
+++ clearsilver-0.8.0/scripts/ChangeLog.py	Wed Oct 30 14:06:50 2002
@@ -0,0 +1,245 @@
+#!/neo/opt/bin/python
+
+import sys, os, string, re, getopt, pwd, socket, time
+
+def warn(*args):
+  t = time.time()
+  log_line = "[" + time.strftime("%m/%d %T", time.localtime(t)) + "] "
+  l = []
+  for arg in args:
+    l.append(str(arg))
+  log_line = log_line + string.join(l, " ") + "\n"
+  sys.stderr.write(log_line)
+
+class ChangeLog:
+  def __init__ (self, module, release_from, release_to, copydir = None, cvsroot=None):
+    self._module = module
+    self._releaseFrom = release_from
+    self._releaseTo = release_to
+    self._cvsroot = cvsroot
+    if cvsroot is None:
+      self._cvsroot = os.environ.get("CVSROOT", None)
+
+    self._copydir = copydir
+    if copydir is None: 
+      self._copydir = os.getcwd()
+    self._names = {}
+
+  def changeInfo (self):
+    cmd = self.cvsCmd ("-q", "rdiff", "-s -r%s -r%s %s" % (self._releaseFrom, self._releaseTo, self._module))
+    warn (cmd)
+    fpi = os.popen (cmd)
+    data = fpi.readlines()
+    r = fpi.close()
+    if r is None: r = 0
+    if r != 0:
+      warn ("Return code from command is %d\n" % r)
+      return
+
+    self.oldfiles = {}
+    self.newfiles = []
+    self.delfiles = []
+    old_re = re.compile ("File (.*) changed from revision (.*) to (.*)")
+    new_re = re.compile ("File (.*) is new; current revision (.*)")
+    del_re = re.compile ("File (.*) is removed;")
+    for line in data:
+      m = old_re.match (line)
+      if m:
+        file = m.group(1)
+        if file[:len(self._module)+1] == "%s/" % self._module:
+          file = file[len(self._module)+1:]
+        self.oldfiles[file] = (m.group(2), m.group(3))
+        continue
+      m = new_re.match (line)
+      if m:
+        file = m.group(1)
+        if file[:len(self._module)+1] == "%s/" % self._module:
+          file = file[len(self._module)+1:]
+        self.newfiles.append(file)
+        continue
+      m = del_re.match (line)
+      if m: 
+        file = m.group(1)
+        if file[:len(self._module)+1] == "%s/" % self._module:
+          file = file[len(self._module)+1:]
+        self.delfiles.append(file)
+        continue
+      warn ("Unknown response from changeInfo request:\n  %s" % line)
+
+  def parselog (self, log):
+    lines = string.split (log, '\n')
+    in_header = 1
+    x = 0
+    num = len(lines)
+    revisions = {}
+    revision = None
+    comment = []
+    info_re = re.compile ("date: ([^; ]*) ([^;]*);  author: ([^;]*);")
+    while (x < num):
+      line = string.strip(lines[x])
+      if line:
+        if (x + 1 < num):
+          nline = string.strip(lines[x+1])
+        else:
+          nline = None
+        if in_header:
+          (key, value) = string.split (line, ':', 1)
+          if key == "Working file":
+            filename = string.strip (value)
+          elif key == "description":
+            in_header = 0
+        else:
+          if (line == "----------------------------") and (nline[:9] == "revision "):
+            if revision is not None:
+              key = (date, author, string.join (comment, '\n'))
+              try:
+                revisions[key].append((filename, revision))
+              except KeyError:
+                revisions[key] = [(filename, revision)]
+              comment = []
+          elif line == "=" * 77:
+            key = (date, author, string.join (comment, '\n'))
+            try:
+              revisions[key].append((filename, revision))
+            except KeyError:
+              revisions[key] = [(filename, revision)]
+            in_header = 1
+            revision = None
+            comment = []
+          elif line[:9] == "revision ":
+            (rev, revision) = string.split (lines[x])
+          else:
+            m = info_re.match (lines[x])
+            if m:
+              date = m.group(1)
+              author = m.group(3)
+            else:
+              comment.append (lines[x])
+      x = x + 1
+    return revisions
+
+  def rcs2log (self):
+    cwd = os.getcwd()
+    os.chdir(self._copydir)
+    files = string.join (self.oldfiles.keys(), ' ')
+    cmd = 'rcs2log -v -r "-r%s:%s" %s' % (self._releaseFrom, self._releaseTo, files)
+    fpi = os.popen (cmd)
+    data = fpi.read()
+    r = fpi.close()
+    os.chdir(cwd)
+    if r is None: r = 0
+    if r != 0:
+      warn (cmd)
+      warn ("Return code from command is %d\n" % r)
+      return
+
+    fpo = open ("ChangeLog.%s" % self._releaseTo, 'w')
+    fpo.write(data)
+    fpo.close()
+
+  def runCmd (self, cmd):
+    cwd = os.getcwd()
+    os.chdir(self._copydir)
+    warn (cmd)
+    fpi = os.popen (cmd)
+    data = fpi.read()
+    r = fpi.close()
+    os.chdir(cwd)
+    if r is None: r = 0
+    if r != 0:
+      warn ("Return code from command is %d\n" % r)
+      return None
+    return data
+
+  def rcslog (self):
+    inverted_log = {}
+    if len(self.newfiles):
+      cmd = self.cvsCmd ("", "log", "-N %s" % string.join(self.newfiles,' '))
+      data = self.runCmd (cmd)
+      if data is None: return
+      revisions = self.parselog (data)
+      for (key, value) in revisions.items():
+        try:
+          inverted_log[key] = inverted_log[key] + value
+        except KeyError:
+          inverted_log[key] = value
+
+    filenames = string.join (self.oldfiles.keys(), ' ')
+    if filenames:
+      cmd = self.cvsCmd ("", "log", "-N -r%s:%s %s" % (self._releaseFrom, self._releaseTo, filenames))
+      data = self.runCmd (cmd)
+      if data is not None: 
+        revisions = self.parselog (data)
+        for (key, value) in revisions.items():
+          for (filename, revision) in value:
+            (rev1, rev2) = self.oldfiles[filename]
+            if revision != rev1:
+              try:
+                inverted_log[key].append((filename, revision))
+              except KeyError:
+                inverted_log[key] = [(filename, revision)]
+
+    fpo = open ("ChangeLog.%s" % self._releaseTo, 'w')
+    fpo.write ("ChangeLog from %s to %s\n" % (self._releaseFrom, self._releaseTo))
+    fpo.write ("=" * 72 + "\n")
+    changes = inverted_log.items()
+    changes.sort()
+    changes.reverse()
+    last_stamp = ""
+    for (key, value) in changes:
+      (date, author, comment) = key
+      new_stamp = "%s  %s" % (date, self.fullname(author))
+      if new_stamp != last_stamp:
+        fpo.write ("%s\n\n" % new_stamp)
+        last_stamp = new_stamp
+      for (filename, revision) in value:
+        fpo.write ("  * %s:%s\n" % (filename, revision))
+      fpo.write ("    %s\n\n" % comment)
+      
+    fpo.close()
+
+  def cvsCmd (self, cvsargs, cmd, cmdargs):
+    root = ""
+    if self._cvsroot is not None:
+      root = "-d %s" % self._cvsroot
+
+    cmd = "cvs -z3 %s %s %s %s" % (root, cvsargs, cmd, cmdargs)
+    return cmd
+
+  def fullname (self, author):
+    try:
+      return self._names[author]
+    except KeyError:
+      try:
+        (name, passwd, uid, gid, gecos, dir, shell) = pwd.getpwnam(author)
+        fullname = "%s  <%s@%s>" % (gecos, name, socket.gethostname())
+      except KeyError:
+        fullname = author
+
+      self._names[author] = fullname
+      return fullname
+      
+
+def usage (argv0):
+  print "usage: %s [--help] module release1 release2" % argv0
+  print __doc__
+
+def main (argv, stdout, environ):
+  list, args = getopt.getopt(argv[1:], "", ["help"])
+
+  for (field, val) in list:
+    if field == "--help":
+      usage (argv[0])
+      return
+
+  if len (args) < 3:
+    usage (argv[0])
+    return
+
+  cl = ChangeLog (args[0], args[1], args[2])
+  cl.changeInfo()
+  cl.rcslog()
+  
+
+if __name__ == "__main__":
+  main (sys.argv, sys.stdout, os.environ)
diff -Nru clearsilver-0.7.2/scripts/commitlog.py clearsilver-0.8.0/scripts/commitlog.py
--- clearsilver-0.7.2/scripts/commitlog.py	Tue Jul 24 19:52:18 2001
+++ clearsilver-0.8.0/scripts/commitlog.py	Sun Jan 26 22:53:45 2003
@@ -16,6 +16,7 @@
 
 def main(argv):
   PATH = argv[1]
+  module = argv[2]
 
   body = sys.stdin.read()
   body_lines = string.split(body,"\n")
@@ -54,7 +55,7 @@
 
   log_summary = "%10s %16s %s\n" % (CVS_USER,DATE,string.join(log_lines," ")[:60])
 
-  filename = os.path.join(PATH,"neotonic.summary")
+  filename = os.path.join(PATH,"%s.summary" % module)
   os.system('co -f -q -l %s %s,v' % (filename,filename))
 
   # check to see if the log line is already there
@@ -69,7 +70,7 @@
 
   log_data = "----------------\n" + "USER: %s\n" % CVS_USER + "DATE: %s\n" % DATE + body
 
-  filename = os.path.join(PATH,"neotonic")
+  filename = os.path.join(PATH,"%s" % module)
   os.system('co -f -q -l %s %s,v' % (filename,filename))
   fp = open(filename,"a+")
   fp.write(log_data)
diff -Nru clearsilver-0.7.2/util/Makefile clearsilver-0.8.0/util/Makefile
--- clearsilver-0.7.2/util/Makefile	Thu Oct 17 13:54:29 2002
+++ clearsilver-0.8.0/util/Makefile	Wed Nov 13 16:58:04 2002
@@ -10,18 +10,23 @@
 UTL_SRC = neo_err.c neo_files.c neo_misc.c neo_test.c ulist.c neo_hdf.c \
 	  neo_str.c neo_date.c wildmat.c 
 
-ifneq ($(OSNAME),WindowsNT 0)
-UTL_SRC += ulocks.c skiplist.c dict.c filter.c rcfs.c neo_net.c neo_server.c
+ifeq ($(OSTYPE),WindowsNT)
+
+CFLAGS += -Ios_win
+UTL_SRC += snprintf.c os_win/regex.c os_win/mkstemp.c
+
+else 
 
+UTL_SRC += ulocks.c skiplist.c dict.c filter.c rcfs.c neo_net.c neo_server.c
+CFLAGS += -DHAVE_GMTOFF
 ifeq ($(USE_DB2),1)
 UTL_SRC += wdb.c
 endif
 
-else 
-CFLAGS += -Ios_win
-UTL_SRC += snprintf.c os_win/regex.c os_win/mkstemp.c
-
 endif
+
+# Eventually, this should be in a configure script somewhere...
+# This version is portable enough (linux/freebsd) for now
 
 
 UTL_OBJ = $(UTL_SRC:%.c=%.o)
diff -Nru clearsilver-0.7.2/util/neo_date.c clearsilver-0.8.0/util/neo_date.c
--- clearsilver-0.7.2/util/neo_date.c	Wed Jul 31 16:49:42 2002
+++ clearsilver-0.8.0/util/neo_date.c	Thu Oct 17 17:17:23 2002
@@ -54,3 +54,29 @@
   ttm->tm_isdst = save_isdst;
   return r;
 }
+
+/* Hefted from NCSA HTTPd src/util.c -- What a pain in the ass. */
+long neo_tz_offset(struct tm *ttm) {
+#if defined(HAVE_GMTOFF)
+  return ttm->tm_gmtoff;
+#elif defined(HAVE_TIMEZONE)
+  long tz;
+  tz = - timezone;
+  if(ttm->tm_isdst)
+    tz += 3600;
+  return tz;
+#else
+  long tz;
+  struct tm loc_tm, gmt_tm;
+  time_t tt; 
+
+  /* We probably shouldn't use the _r versions here since this
+   * is for older platforms... */
+  tt = time(NULL);
+  localtime_r(&tt, &loc_tm);
+  gmtime_r(&tt, &gmt_tm);
+  tz = mktime(&loc_tm) - mktime(&gmt_tm);
+  return tz;
+#endif /* GMT OFFSet Crap */
+}
+
diff -Nru clearsilver-0.7.2/util/neo_date.h clearsilver-0.8.0/util/neo_date.h
--- clearsilver-0.7.2/util/neo_date.h	Sat Oct  5 12:29:04 2002
+++ clearsilver-0.8.0/util/neo_date.h	Thu Oct 17 17:17:23 2002
@@ -22,6 +22,9 @@
 /* local timezone struct tm -> time_t UTC */
 time_t neo_time_compact (struct tm *ttm, char *timezone);
 
+/* To be portable... in seconds */
+long neo_tz_offset(struct tm *ttm);
+
 __END_DECLS
 
 #endif /* _NEO_DATE_H_ */
diff -Nru clearsilver-0.7.2/util/neo_err.c clearsilver-0.8.0/util/neo_err.c
--- clearsilver-0.7.2/util/neo_err.c	Tue Mar 12 23:46:03 2002
+++ clearsilver-0.8.0/util/neo_err.c	Thu Feb 20 17:51:50 2003
@@ -72,8 +72,8 @@
   return 0;
 }
 
-NEOERR *nerr_raisef (char *func, char *file, int lineno, int error, 
-                    char *fmt, ...)
+NEOERR *nerr_raisef (const char *func, const char *file, int lineno, int error, 
+                    const char *fmt, ...)
 {
   NEOERR *err;
   va_list ap;
@@ -94,8 +94,8 @@
   return err;
 }
 
-NEOERR *nerr_raise_errnof (char *func, char *file, int lineno, int error, 
-                    char *fmt, ...)
+NEOERR *nerr_raise_errnof (const char *func, const char *file, int lineno, 
+    			   int error, const char *fmt, ...)
 {
   NEOERR *err;
   va_list ap;
@@ -121,7 +121,7 @@
   return err;
 }
 
-NEOERR *nerr_passf (char *func, char *file, int lineno, NEOERR *err)
+NEOERR *nerr_passf (const char *func, const char *file, int lineno, NEOERR *err)
 {
   NEOERR *nerr;
 
@@ -141,8 +141,8 @@
   return nerr;
 }
 
-NEOERR *nerr_pass_ctxf (char *func, char *file, int lineno, NEOERR *err,
-    char *fmt, ...)
+NEOERR *nerr_pass_ctxf (const char *func, const char *file, int lineno, 
+			NEOERR *err, const char *fmt, ...)
 {
   NEOERR *nerr;
   va_list ap;
@@ -386,11 +386,11 @@
   return 0;
 }
 
-NEOERR *nerr_register (int *val, char *name)
+NEOERR *nerr_register (int *val, const char *name)
 {
   NEOERR *err;
 
-  err = uListAppend (Errors, name);
+  err = uListAppend (Errors, (void *) name);
   if (err != STATUS_OK) return nerr_pass(err);
 
   *val = uListLength(Errors);
diff -Nru clearsilver-0.7.2/util/neo_err.h clearsilver-0.8.0/util/neo_err.h
--- clearsilver-0.7.2/util/neo_err.h	Wed Jul 31 16:49:42 2002
+++ clearsilver-0.8.0/util/neo_err.h	Thu Feb 20 17:51:50 2003
@@ -43,8 +43,8 @@
   int err_stack;
   int flags;
   char desc[256];
-  char *file;
-  char *func;
+  const char *file;
+  const char *func;
   int lineno;
   /* internal use only */
   struct _neo_err *next;
@@ -66,14 +66,14 @@
 #define nerr_raise(e,f,a...) \
    nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
 
-NEOERR *nerr_raisef (char *func, char *file, int lineno, NERR_TYPE error, 
-                    char *fmt, ...);
+NEOERR *nerr_raisef (const char *func, const char *file, int lineno, NERR_TYPE error, 
+                    const char *fmt, ...);
 
 #define nerr_raise_errno(e,f,a...) \
    nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
 
-NEOERR *nerr_raise_errnof (char *func, char *file, int lineno, int error, 
-                    char *fmt, ...);
+NEOERR *nerr_raise_errnof (const char *func, const char *file, int lineno, int error, 
+                    const char *fmt, ...);
 /* function: nerr_pass
  * description: this function is used to pass an error up a level in the
  *              call chain (ie, if the error isn't handled at the
@@ -85,7 +85,7 @@
  */
 #define nerr_pass(e) \
    nerr_passf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e)
-NEOERR *nerr_passf (char *func, char *file, int lineno, NEOERR *err);
+NEOERR *nerr_passf (const char *func, const char *file, int lineno, NEOERR *err);
 
 /* function: nerr_pass_ctx
  * description: this function is used to pass an error up a level in the
@@ -102,8 +102,8 @@
  */
 #define nerr_pass_ctx(e,f,a...) \
    nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
-NEOERR *nerr_pass_ctxf (char *func, char *file, int lineno, NEOERR *err, 
-                       char *fmt, ...);
+NEOERR *nerr_pass_ctxf (const char *func, const char *file, int lineno, NEOERR *err, 
+                       const char *fmt, ...);
 
 /* function: nerr_log_error
  * description: currently, this prints out the error to stderr, and
@@ -121,7 +121,7 @@
  */
 void nerr_ignore (NEOERR **err);
 
-NEOERR *nerr_register (NERR_TYPE *err, char *name);
+NEOERR *nerr_register (NERR_TYPE *err, const char *name);
 
 NEOERR *nerr_init (void);
 
diff -Nru clearsilver-0.7.2/util/neo_hdf.c clearsilver-0.8.0/util/neo_hdf.c
--- clearsilver-0.7.2/util/neo_hdf.c	Mon Oct 14 15:59:53 2002
+++ clearsilver-0.8.0/util/neo_hdf.c	Mon Nov 11 16:11:55 2002
@@ -1321,8 +1321,9 @@
   char *name, *value;
   HDF_ATTR *attr = NULL;
 
-  while (_copy_line_alloc(str, &buf) != 0)
+  while (**str != '\0')
   {
+    _copy_line_alloc(str, &buf);
     attr = NULL;
     (*line)++;
     s = buf;
@@ -1468,6 +1469,7 @@
       }
     }
     if (buf != NULL) free(buf);
+    buf = NULL;
   }
   if (buf != NULL) free(buf);
   return STATUS_OK;
diff -Nru clearsilver-0.7.2/util/neo_misc.h clearsilver-0.8.0/util/neo_misc.h
--- clearsilver-0.7.2/util/neo_misc.h	Wed Jul 31 16:49:42 2002
+++ clearsilver-0.8.0/util/neo_misc.h	Wed Nov 13 17:45:57 2002
@@ -26,7 +26,9 @@
 typedef char INT8;
 typedef char BOOL;
 
+#ifndef MIN
 #define MIN(x,y)        (((x) < (y)) ? (x) : (y))
+#endif
 
 #ifndef TRUE
 #define TRUE 1
diff -Nru clearsilver-0.7.2/util/neo_net.c clearsilver-0.8.0/util/neo_net.c
--- clearsilver-0.7.2/util/neo_net.c	Sun Sep  1 19:00:46 2002
+++ clearsilver-0.8.0/util/neo_net.c	Wed Oct 23 18:13:21 2002
@@ -26,6 +26,13 @@
 #include "neo_net.h"
 #include "neo_str.h"
 
+static int ShutdownAccept = 0;
+
+void net_shutdown()
+{
+  ShutdownAccept = 1;
+}
+
 /* Server side */
 NEOERR *net_listen(int port, int *fd)
 {
@@ -105,10 +112,18 @@
   int len;
 
   len = sizeof(struct sockaddr_in);
-  while ((fd = accept(sfd, (struct sockaddr *)&client_addr, &len)) == -1)
+  while (1)
   {
-    if (errno == EINTR) continue;
-    return nerr_raise_errno(NERR_IO, "accept() returned error");
+    fd = accept(sfd, (struct sockaddr *)&client_addr, &len);
+    if (fd >= 0) break;
+    if (ShutdownAccept || errno != EINTR)
+    {
+      return nerr_raise_errno(NERR_IO, "accept() returned error");
+    }
+    if (errno == EINTR)
+    {
+      ne_warn("accept received EINTR");
+    }
   }
 
   my_sock = (NSOCK *) calloc(1, sizeof(NSOCK));
diff -Nru clearsilver-0.7.2/util/neo_net.h clearsilver-0.8.0/util/neo_net.h
--- clearsilver-0.7.2/util/neo_net.h	Sun Sep  1 19:00:46 2002
+++ clearsilver-0.8.0/util/neo_net.h	Wed Oct 23 18:13:21 2002
@@ -48,6 +48,7 @@
 NEOERR *net_write_str(NSOCK *sock, char *s);
 NEOERR *net_write_int(NSOCK *sock, int i);
 NEOERR *net_flush(NSOCK *sock);
+void net_shutdown();
 
 __END_DECLS
 
diff -Nru clearsilver-0.7.2/util/neo_server.c clearsilver-0.8.0/util/neo_server.c
--- clearsilver-0.7.2/util/neo_server.c	Fri Sep  6 17:59:59 2002
+++ clearsilver-0.8.0/util/neo_server.c	Wed Oct 23 18:13:21 2002
@@ -102,6 +102,7 @@
 static void sig_term(int sig)
 {
   ShutdownPending = 1;
+  net_shutdown();
 }
 
 static void setup_term(void)
diff -Nru clearsilver-0.7.2/util/neo_str.c clearsilver-0.8.0/util/neo_str.c
--- clearsilver-0.7.2/util/neo_str.c	Mon May  6 16:16:24 2002
+++ clearsilver-0.8.0/util/neo_str.c	Thu Dec  5 12:41:25 2002
@@ -86,6 +86,7 @@
     if (str->buf == NULL)
       return nerr_raise (NERR_NOMEM, "Unable to allocate render buf of size %d",
 	  str->max);
+   /*  ne_warn("Creating string %x at %d (%5.2fK)", str, str->max, (str->max / 1024.0)); */
   }
   else if (str->len + l >= str->max)
   {
@@ -97,6 +98,7 @@
     if (str->buf == NULL)
       return nerr_raise (NERR_NOMEM, "Unable to allocate STRING buf of size %d",
 	  str->max);
+    /* ne_warn("Growing string %x to %d (%5.2fK)", str, str->max, (str->max / 1024.0)); */
   }
   return STATUS_OK;
 }
diff -Nru clearsilver-0.7.2/util/osdep.h clearsilver-0.8.0/util/osdep.h
--- clearsilver-0.7.2/util/osdep.h	Wed Jul 31 16:49:42 2002
+++ clearsilver-0.8.0/util/osdep.h	Wed Nov 13 17:45:57 2002
@@ -15,9 +15,14 @@
 #define	S_IXGRP         S_IXUSR
 #define	S_IWGRP         S_IWUSR
 #define	S_IRGRP         S_IRUSR
+#define S_IROTH         S_IRUSR
+#define S_IWOTH         S_IWUSR
 
 #define HAVE_STDARG_H 1
 #define HAVE_STRING_H 1
+#undef HAVE_GMTOFF
+
+
 
 int snprintf (char *str, size_t count, const char *fmt, ...);
 int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
@@ -26,9 +31,11 @@
 
 #define os_random rand
 
-#else // __WINDOWS_GCC__
+#else // UNIX......
 
 #define os_random random
+
+#define HAVE_PTHREAD 1
 
 #endif 
 
diff -Nru clearsilver-0.7.2/util/test/Makefile clearsilver-0.8.0/util/test/Makefile
--- clearsilver-0.7.2/util/test/Makefile	Mon Oct 14 15:59:55 2002
+++ clearsilver-0.8.0/util/test/Makefile	Mon Nov 11 16:11:56 2002
@@ -44,7 +44,7 @@
 	$(LD) $@ $(LISTDIRTEST_OBJ) $(LIBS)
 
 $(HDFCOPYTEST_EXE): $(HDFCOPYTEST_OBJ) $(NTR_LIB)
-	$(LD) $@ $(HDFCOPYTEST_OBJ) $(LIBS) -lefence
+	$(LD) $@ $(HDFCOPYTEST_OBJ) $(LIBS) # -lefence
 
 $(NETTEST_EXE): $(NETTEST_OBJ) $(NTR_LIB)
 	$(LD) $@ $(NETTEST_OBJ) $(LIBS)
diff -Nru clearsilver-0.7.2/util/ulocks.h clearsilver-0.8.0/util/ulocks.h
--- clearsilver-0.7.2/util/ulocks.h	Mon Aug  6 14:28:17 2001
+++ clearsilver-0.8.0/util/ulocks.h	Wed Nov 13 17:45:57 2002
@@ -11,7 +11,6 @@
 #ifndef _ULOCKS_H_
 #define _ULOCKS_H_
 
-#include <pthread.h>
 
 NEOERR *fCreate(int *plock, char *file);
 /*
@@ -73,6 +72,11 @@
  * MT-Level:    Safe.
  */
 
+#ifdef HAVE_PTHREAD
+
+#include <pthread.h>
+
+
 NEOERR *mCreate(pthread_mutex_t *mutex);
 /*
  * Function:    mCreate - initialize a mutex.
@@ -175,5 +179,7 @@
  *              NERR_LOCK on failure
  * MT-Level:    Safe.
  */
+
+#endif /* HAVE_PTHREAD */
 
 #endif                                                         /* _ULOCKS_H_ */
