diff -bru clearsilver-0.2/cgi/Makefile clearsilver-0.2.1/cgi/Makefile
--- clearsilver-0.2/cgi/Makefile	Fri Jun 29 01:00:36 2001
+++ clearsilver-0.2.1/cgi/Makefile	Sun Sep  9 16:53:10 2001
@@ -14,7 +14,7 @@
 STATIC_SRC = static.c
 STATIC_OBJ = $(STATIC_SRC:%.c=%.o)
 
-CFLAGS += -I$(NEOTONIC_ROOT)
+CFLAGS += -I$(NEOTONIC_ROOT) -DHTML_COMPRESSION
 DLIBS += -lneo_cgi -lneo_cs -lneo_utl # -lefence
 LIBS += -L$(LIB_DIR) $(DLIBS)
 
diff -bru clearsilver-0.2/cgi/cgi.c clearsilver-0.2.1/cgi/cgi.c
--- clearsilver-0.2/cgi/cgi.c	Mon Aug 20 19:39:16 2001
+++ clearsilver-0.2.1/cgi/cgi.c	Sun Sep  9 16:58:41 2001
@@ -13,16 +13,18 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <stdio.h>
-#include <zlib.h>
 #include <stdarg.h>
 #include <time.h>
+#if defined(HTML_COMPRESSION)
+#include <zlib.h>
+#endif
 
-#include "cgi/cgiwrap.h"
+#include "cgiwrap.h"
 #include "util/neo_err.h"
 #include "util/neo_hdf.h"
 #include "util/neo_misc.h"
 #include "util/neo_str.h"
-#include "cgi/cgi.h"
+#include "cgi.h"
 #include "cs/cs.h"
 
 struct _cgi_vars
@@ -251,7 +253,7 @@
 {
   NEOERR *err = STATUS_OK;
   char *l, *query;
-  int len, r;
+  int len, r, o;
 
   l = hdf_get_value (cgi->hdf, "CGI.ContentLength", NULL);
   if (l == NULL) return STATUS_OK;
@@ -264,12 +266,19 @@
     return nerr_raise (NERR_NOMEM, 
 	"Unable to allocate memory to read POST input of length %d", l);
 
-  cgiwrap_read (query, len, &r);
-  if (r != len)
+  
+  o = 0;
+  while (o < len)
+  {
+    cgiwrap_read (query + o, len - o, &r);
+    if (r == 0) break;
+    o = o + r;
+  }
+  if (o != len)
   {
     free(query);
     return nerr_raise (NERR_IO, "Short read on CGI POST input (%d < %d)", 
-	r, len);
+	o, len);
   }
   query[len] = '\0';
   err = _parse_query (cgi, query);
@@ -431,7 +440,6 @@
     }
     else if (type && !strncmp (type, "multipart/form-data", 19))
     {
-      ne_warn ("found form-data");
       err = parse_rfc2388 (cgi);
       if (err != STATUS_OK) return nerr_pass (err);
     }
@@ -517,6 +525,12 @@
   return nerr_pass(err);
 }
 
+static void _destroy_tmp_file(char *filename)
+{
+  unlink(filename);
+  free(filename);
+}
+
 void cgi_destroy (CGI **cgi)
 {
   CGI *my_cgi;
@@ -529,7 +543,9 @@
   if (my_cgi->buf)
     free(my_cgi->buf);
   if (my_cgi->files)
-    uListDestroyFunc(&(my_cgi->files), fclose);
+    uListDestroyFunc(&(my_cgi->files), (void (*)(void *))fclose);
+  if (my_cgi->filenames)
+    uListDestroyFunc(&(my_cgi->filenames), (void (*)(void *))_destroy_tmp_file);
   free (*cgi);
   *cgi = NULL;
 }
@@ -600,6 +616,7 @@
   return STATUS_OK;
 }
 
+#if defined(HTML_COMPRESSION)
 /* Copy these here from zutil.h, which we aren't supposed to include */
 #define DEF_MEM_LEVEL 8
 #define OS_CODE 0x03
@@ -635,6 +652,7 @@
   err = deflateEnd(&stream);
   return STATUS_OK;
 }
+#endif
 
 static NEOERR *cgi_output (CGI *cgi, STRING *str)
 {
@@ -656,6 +674,7 @@
   if (!strcasecmp(s, "text/html"))
     is_html = 1;
 
+#if defined(HTML_COMPRESSION)
   /* Determine whether or not we can compress the output */
   if (is_html && hdf_get_int_value (cgi->hdf, "Config.CompressionEnabled", 0))
   {
@@ -716,6 +735,7 @@
     }
     if (err != STATUS_OK) return nerr_pass(err);
   }
+#endif
 
   err = cgi_headers(cgi);
   if (err != STATUS_OK) return nerr_pass(err);
@@ -754,6 +774,7 @@
     }
   }
 
+#if defined(HTML_COMPRESSION)
   if (is_html && (use_deflate || use_gzip))
   {
     char *dest;
@@ -799,6 +820,7 @@
     }
   }
   else
+#endif
   {
     err = cgiwrap_write(str->buf, str->len);
   }
diff -bru clearsilver-0.2/cgi/cgi.h clearsilver-0.2.1/cgi/cgi.h
--- clearsilver-0.2/cgi/cgi.h	Mon Aug 20 19:39:16 2001
+++ clearsilver-0.2.1/cgi/cgi.h	Sun Sep  9 16:53:10 2001
@@ -47,11 +47,19 @@
   int readlen;
   BOOL found_nl;
   BOOL unget;
+  char *last_start;
+  int last_length;
   int nl;
 
   /* this is a list of filepointers pointing at files that were uploaded */
   /* Use cgi_filehandle to access these */
   ULIST *files;
+
+  /* By default, cgi_parse unlinks uploaded files as it opens them. */
+  /* If Config.Upload.Unlink is set to 0, the files are not unlinked */
+  /* and there names are stored in this list. */
+  /* Use Query.*.FileName to access these */
+  ULIST *filenames;
 
   /* keep track of the time between cgi_init and cgi_render */
   double time_start;
diff -bru clearsilver-0.2/cgi/html.c clearsilver-0.2.1/cgi/html.c
--- clearsilver-0.2/cgi/html.c	Fri Aug 10 20:19:25 2001
+++ clearsilver-0.2.1/cgi/html.c	Fri Sep 14 18:23:03 2001
@@ -418,7 +418,7 @@
     else
     {
       int nl = has_long_lines (src, slen);
-      err = split_and_convert(src, slen, &out_s, !nl | formatting, formatting);
+      err = split_and_convert(src, slen, &out_s, 1, formatting);
     }
   } while (0);
   if (err != STATUS_OK) 
diff -bru clearsilver-0.2/cgi/rfc2388.c clearsilver-0.2.1/cgi/rfc2388.c
--- clearsilver-0.2/cgi/rfc2388.c	Mon Aug 20 19:39:16 2001
+++ clearsilver-0.2.1/cgi/rfc2388.c	Sun Sep  9 16:53:10 2001
@@ -134,41 +134,22 @@
   if (cgi->unget)
   {
     cgi->unget = FALSE;
-    *s = cgi->buf;
-    if (cgi->found_nl)
-      *l = cgi->nl;
-    else
-      *l = cgi->readlen;
+    *s = cgi->last_start;
+    *l = cgi->last_length;
     return STATUS_OK;
   }
   if (cgi->found_nl)
   {
-    if (cgi->readlen < cgi->buflen)
-    {
-      ofs = cgi->readlen - cgi->nl;
-    }
-    else
-    {
-      ofs = cgi->buflen - cgi->nl;
-    }
-    memmove (cgi->buf, cgi->buf + cgi->nl, ofs);
-    if (cgi->readlen < cgi->buflen)
-    {
-      cgi->readlen = ofs;
-      p = memchr (cgi->buf, '\n', cgi->readlen);
-      if (!p)
-      {
-	cgi->found_nl = FALSE;
-	*s = cgi->buf;
-	*l = cgi->readlen;
-	return STATUS_OK;
-      }
-      *s = cgi->buf;
-      *l = p - cgi->buf + 1;
+    p = memchr (cgi->buf + cgi->nl, '\n', cgi->readlen - cgi->nl);
+    if (p) {
+      cgi->last_start = *s = cgi->buf + cgi->nl;
+      cgi->last_length = *l = p - (cgi->buf + cgi->nl) + 1;
       cgi->found_nl = TRUE;
-      cgi->nl = *l;
+      cgi->nl = p - cgi->buf + 1;
       return STATUS_OK;
     }
+    ofs = cgi->readlen - cgi->nl;
+    memmove(cgi->buf, cgi->buf + cgi->nl, ofs);
   }
   cgiwrap_read (cgi->buf + ofs, cgi->buflen - ofs, &(cgi->readlen));
   cgi->data_read += cgi->readlen;
@@ -182,12 +163,12 @@
   if (!p)
   {
     cgi->found_nl = FALSE;
-    *s = cgi->buf;
-    *l = cgi->readlen;
+    cgi->last_start = *s = cgi->buf;
+    cgi->last_length = *l = cgi->readlen;
     return STATUS_OK;
   }
-  *s = cgi->buf;
-  *l = p - cgi->buf + 1;
+  cgi->last_start = *s = cgi->buf;
+  cgi->last_length = *l = p - cgi->buf + 1;
   cgi->found_nl = TRUE;
   cgi->nl = *l;
   return STATUS_OK;
@@ -289,6 +270,7 @@
   char *name = NULL, *filename = NULL;
   char *type = NULL, *tmp = NULL;
   char *last = NULL;
+  int unlink_files = hdf_get_int_value(cgi->hdf, "Config.Upload.Unlink", 1);
 
   string_init (&str);
 
@@ -345,7 +327,8 @@
       char path[_POSIX_PATH_MAX];
       int fd;
 
-      snprintf (path, sizeof(path), "/tmp/cgi_upload.XXXXXX");
+      snprintf (path, sizeof(path), "%s/cgi_upload.XXXXXX", 
+                hdf_get_value(cgi->hdf, "Config.Upload.TmpDir", "/var/tmp"));
 
       fd = mkstemp(path);
       if (fd == -1)
@@ -362,7 +345,7 @@
 	err = nerr_raise_errno (NERR_SYSTEM, "Unable to fdopen file %s", path);
 	break;
       }
-      unlink (path);
+      if (unlink_files) unlink(path);
       if (cgi->files == NULL)
       {
 	err = uListInit (&(cgi->files), 10, 0);
@@ -378,6 +361,23 @@
 	fclose (fp);
 	break;
       }
+      if (!unlink_files) {
+        if (cgi->filenames == NULL)
+        {
+	  err = uListInit (&(cgi->filenames), 10, 0);
+	  if (err)
+	  {
+	    fclose(fp);
+	    break;
+	  }
+        }
+        err = uListAppend (cgi->filenames, strdup(path));
+        if (err)
+        {
+	  fclose (fp);
+	  break;
+        }
+      }
     }
     string_set(&str, "");
     while (1)
@@ -437,6 +437,14 @@
       {
 	snprintf (buf, sizeof(buf), "Query.%s.FileHandle", name);
 	err = hdf_set_int_value (cgi->hdf, buf, uListLength(cgi->files));
+      }
+      if (!err && !unlink_files)
+      {
+        char *path;
+	snprintf (buf, sizeof(buf), "Query.%s.FileName", name);
+        err = uListGet(cgi->filenames, uListLength(cgi->filenames)-1, 
+                       (void **)&path);
+	if (!err) err = hdf_set_value (cgi->hdf, buf, path);
       }
     }
     else
Only in clearsilver-0.2.1/cs: csgrammer.y
diff -bru clearsilver-0.2/cs/csparse.c clearsilver-0.2.1/cs/csparse.c
--- clearsilver-0.2/cs/csparse.c	Mon Aug  6 14:28:16 2001
+++ clearsilver-0.2.1/cs/csparse.c	Wed Sep  5 15:08:54 2001
@@ -356,6 +356,25 @@
   return buf;
 }
 
+static char *expand_state (CS_STATE state)
+{
+  static char buf[256];
+
+  if (state & ST_GLOBAL)
+    return "GLOBAL";
+  else if (state & ST_IF)
+    return "IF";
+  else if (state & ST_ELSE)
+    return "ELSE";
+  else if (state & ST_EACH)
+    return "EACH";
+  else if (state & ST_DEF)
+    return "DEF";
+
+  snprintf(buf, sizeof(buf), "Unknown state %d", state);
+  return buf;
+}
+
 NEOERR *cs_parse_string (CSPARSE *parse, char *ibuf, size_t ibuf_len)
 {
   NEOERR *err = STATUS_OK;
@@ -423,9 +442,9 @@
 	      if (!(Commands[i].allowed_state & entry->state))
 	      {
 		return nerr_raise (NERR_PARSE, 
-		    "%s Command %s not allowed in %d", Commands[i].cmd, 
+		    "%s Command %s not allowed in %s", Commands[i].cmd, 
 		    find_context(parse, -1, tmp, sizeof(tmp)), 
-		    entry->state);
+		    expand_state(entry->state));
 	      }
 	      if (Commands[i].has_arg)
 	      {
@@ -1755,6 +1774,7 @@
   node->cmd = cmd;
   arg++;
   s = arg;
+  while (*s && isspace(*s)) s++;
   while (x < 256 && *s && *s != ' ' && *s != '#' && *s != '=')
   {
     name[x++] = *s;
@@ -1803,6 +1823,7 @@
     {
       if (op != CS_OP_NOT)
 	op = CS_OP_EXISTS;
+      break;
     }
     else
     {
Only in clearsilver-0.2.1/cs: lemon.c
Only in clearsilver-0.2.1/cs: lempar.c
diff -bru clearsilver-0.2/cs/test.cs.gold clearsilver-0.2.1/cs/test.cs.gold
--- clearsilver-0.2/cs/test.cs.gold	Fri Jul  6 00:29:42 2001
+++ clearsilver-0.2.1/cs/test.cs.gold	Fri Sep 14 16:45:36 2001
@@ -86,6 +86,10 @@
 
   Outside 2
   
+    Inside = 2
+  
+    Inside = 3
+  
 
   Outside 3
   
diff -bru clearsilver-0.2/cs/test.hdf clearsilver-0.2.1/cs/test.hdf
--- clearsilver-0.2/cs/test.hdf	Tue Aug  7 14:58:46 2001
+++ clearsilver-0.2.1/cs/test.hdf	Fri Sep 14 18:23:23 2001
@@ -30,8 +30,7 @@
       3 = 3
     }
   }
-  2 {
-  }
+  2 : Outside.1
   3 {
   }
 }
@@ -56,3 +55,6 @@
 }
 
 Neg = -1
+
+My.Test : Days.0.Abbr
+My.Test2 : Days.0
diff -bru clearsilver-0.2/python/neo_cgi.c clearsilver-0.2.1/python/neo_cgi.c
--- clearsilver-0.2/python/neo_cgi.c	Mon Aug 20 19:39:17 2001
+++ clearsilver-0.2.1/python/neo_cgi.c	Fri Aug 31 15:19:48 2001
@@ -791,6 +791,21 @@
   return Py_None; 
 }
 
+static PyObject * p_update (PyObject *self, PyObject *args)
+{
+  PyObject *dict;
+  int i = 0;
+
+  if (_PyImport_FindExtension("neo_util","neo_util") == NULL)
+    initneo_util();
+
+  if (_PyImport_FindExtension("neo_cs","neo_cs") == NULL)
+    initneo_cs();
+
+  Py_INCREF(Py_None);
+  return Py_None; 
+}
+
 static PyMethodDef ModuleMethods[] =
 {
   {"CGI", p_cgi_init, METH_VARARGS, NULL},
@@ -800,6 +815,7 @@
   {"cgiWrap", cgiwrap, METH_VARARGS, cgiwrap_doc},
   {"IgnoreEmptyFormVars", p_ignore, METH_VARARGS, NULL},
   {"exportDate", p_export_date, METH_VARARGS, NULL},
+  {"update", p_update, METH_VARARGS, NULL},
   {NULL, NULL}
 };
 
@@ -808,7 +824,10 @@
   PyObject *m, *d;
 
   initneo_util();
+  _PyImport_FixupExtension("neo_util", "neo_util");
+
   initneo_cs();
+  _PyImport_FixupExtension("neo_cs", "neo_cs");
 
   m = Py_InitModule("neo_cgi", ModuleMethods);
   p_cgiwrap_init (m);
diff -bru clearsilver-0.2/util/neo_hdf.c clearsilver-0.2.1/util/neo_hdf.c
--- clearsilver-0.2/util/neo_hdf.c	Tue Aug  7 14:58:46 2001
+++ clearsilver-0.2.1/util/neo_hdf.c	Fri Sep 14 17:21:30 2001
@@ -21,7 +21,7 @@
 #include "neo_str.h"
 
 static NEOERR *_alloc_hdf (HDF **hdf, char *name, size_t nlen, char *value, 
-    int dup, int wf)
+    int dup, int wf, HDF *top)
 {
   *hdf = calloc (1, sizeof (HDF));
   if (*hdf == NULL)
@@ -29,6 +29,8 @@
     return nerr_raise (NERR_NOMEM, "Unable to allocate memory for hdf element");
   }
 
+  (*hdf)->top = top;
+
   if (name != NULL)
   {
     (*hdf)->name_len = nlen;
@@ -100,11 +102,11 @@
   if (err != STATUS_OK)
     return nerr_pass (err);
 
-  err = _alloc_hdf (&my_hdf, NULL, 0, NULL, 0, 0);
+  err = _alloc_hdf (&my_hdf, NULL, 0, NULL, 0, 0, NULL);
   if (err != STATUS_OK)
     return nerr_pass (err);
 
-  my_hdf->top = 1;
+  my_hdf->top = my_hdf;
 
   *hdf = my_hdf;
 
@@ -114,7 +116,7 @@
 void hdf_destroy (HDF **hdf)
 {
   if (*hdf == NULL) return;
-  if ((*hdf)->top)
+  if ((*hdf)->top == (*hdf))
     _dealloc_hdf(hdf);
 }
 
@@ -124,12 +126,22 @@
   int x = 0;
   char *s = name;
   char *n = name;
+  int r;
 
   *node = NULL;
 
   if (hdf == NULL) return -1;
 
+  if (hdf->link)
+  {
+    r = _walk_hdf (hdf->top, hdf->value, &hp);
+    if (r) return r;
+    if (hp) hp = hp->child;
+  }
+  else
+  {
   hp = hdf->child;
+  }
   if (hp == NULL)
   {
     return -1;
@@ -158,11 +170,23 @@
     }
     if (s == NULL) break;
    
+    if (hp->link)
+    {
+      r = _walk_hdf (hp->top, hp->value, &hp);
+      if (r) return r;
     hp = hp->child;
+    }
+    else
+    {
+      hp = hp->child;
+    }
     n = s + 1;
     s = strchr (n, '.');
     x = (s == NULL) ? strlen(n) : s - n;
   } 
+  if (hp->link)
+    return _walk_hdf (hp->top, hp->value, node);
+
   *node = hp;
   return 0;
 }
@@ -239,7 +263,14 @@
 
 HDF* hdf_obj_child (HDF *hdf)
 {
+  HDF *obj;
   if (hdf == NULL) return NULL;
+  if (hdf->link)
+  {
+    if (_walk_hdf(hdf->top, hdf->value, &obj))
+      return NULL;
+    return obj->child;
+  }
   return hdf->child;
 }
 
@@ -261,7 +292,7 @@
   return hdf->value;
 }
 
-NEOERR* _set_value (HDF *hdf, char *name, char *value, int dup, int wf)
+NEOERR* _set_value (HDF *hdf, char *name, char *value, int dup, int wf, int link)
 {
   NEOERR *err;
   HDF *hn, *hp, *hs;
@@ -325,11 +356,12 @@
     {
       if (s != NULL)
       {
-	err = _alloc_hdf (&hp, n, x, NULL, 0, 0);
+	err = _alloc_hdf (&hp, n, x, NULL, 0, 0, hdf->top);
       }
       else
       {
-	err = _alloc_hdf (&hp, n, x, value, dup, wf);
+	err = _alloc_hdf (&hp, n, x, value, dup, wf, hdf->top);
+	if (link) hp->link = 1;
       }
       if (err != STATUS_OK)
 	return nerr_pass (err);
@@ -358,6 +390,7 @@
 	hp->alloc_value = wf;
 	hp->value = value;
       }
+      if (link) hp->link = 1;
     }
     if (s == NULL)
       break;
@@ -375,7 +408,12 @@
 
 NEOERR* hdf_set_value (HDF *hdf, char *name, char *value)
 {
-  return nerr_pass(_set_value (hdf, name, value, 1, 1));
+  return nerr_pass(_set_value (hdf, name, value, 1, 1, 0));
+}
+
+NEOERR* hdf_set_symlink (HDF *hdf, char *src, char *dest)
+{
+  return nerr_pass(_set_value (hdf, src, dest, 1, 1, 1));
 }
 
 NEOERR* hdf_set_int_value (HDF *hdf, char *name, int value)
@@ -383,12 +421,12 @@
   char buf[256];
 
   snprintf (buf, sizeof(buf), "%d", value);
-  return nerr_pass(_set_value (hdf, name, buf, 1, 1));
+  return nerr_pass(_set_value (hdf, name, buf, 1, 1, 0));
 }
 
 NEOERR* hdf_set_buf (HDF *hdf, char *name, char *value)
 {
-  return nerr_pass(_set_value (hdf, name, value, 0, 1));
+  return nerr_pass(_set_value (hdf, name, value, 0, 1, 0));
 }
 
 NEOERR* hdf_set_copy (HDF *hdf, char *dest, char *src)
@@ -396,7 +434,7 @@
   HDF *node;
   if ((_walk_hdf(hdf, src, &node) == 0) && (node->value != NULL))
   {
-    return nerr_pass(_set_value (hdf, dest, node->value, 0, 0));
+    return nerr_pass(_set_value (hdf, dest, node->value, 0, 0, 0));
   }
   return nerr_raise (NERR_NOT_FOUND, "Unable to find %s", src);
 }
@@ -477,7 +515,7 @@
     dt = dest->child;
     if (dt == NULL)
     {
-      err = _alloc_hdf (&(dest->child), st->name, st->name_len, st->value, 1, 0);
+      err = _alloc_hdf (&(dest->child), st->name, st->name_len, st->value, 1, 0, dest->top);
       dt = dest->child;
     }
     else 
@@ -511,7 +549,7 @@
       }
       if (alloc == FALSE)
       {
-	err = _alloc_hdf (&(dt->next), st->name, st->name_len, st->value, 1, 0);
+	err = _alloc_hdf (&(dt->next), st->name, st->name_len, st->value, 1, 0, dest->top);
 	dt = dt->next;
       }
     }
@@ -530,7 +568,7 @@
 
   if (_walk_hdf(dest, name, &node) == -1)
   {
-    err = _set_value (dest, name, NULL, 0, 0);
+    err = _set_value (dest, name, NULL, 0, 0, 0);
     if (err) return nerr_pass (err);
     if (_walk_hdf(dest, name, &node) == -1)
       return nerr_raise(NERR_ASSERT, "Um, this shouldn't happen");
@@ -541,16 +579,18 @@
 NEOERR* hdf_dump(HDF *hdf, char *prefix)
 {
   char *p;
+  char op = '=';
 
   if (hdf->value)
   {
+    if (hdf->link) op = ':';
     if (prefix)
     {
-      printf("%s.%s = %s\n", prefix, hdf->name, hdf->value);
+      printf("%s.%s %c %s\n", prefix, hdf->name, op, hdf->value);
     }
     else
     {
-      printf("%s = %s\n", hdf->name, hdf->value);
+      printf("%s %c %s\n", hdf->name, op, hdf->value);
     }
   }
   if (hdf->child)
@@ -578,9 +618,11 @@
 {
   NEOERR *err;
   char *p;
+  char op = '=';
 
   if (hdf->value)
   {
+    if (hdf->link) op = ':';
     if (prefix && !compact)
     {
       err = string_appendf (str, "%s.%s", prefix, hdf->name);
@@ -599,7 +641,7 @@
     }
     else
     {
-      err = string_appendf (str, " = %s\n", hdf->value);
+      err = string_appendf (str, " %c %s\n", op, hdf->value);
     }
     if (err) return nerr_pass (err);
   }
@@ -640,6 +682,7 @@
 NEOERR* hdf_dump_format (HDF *hdf, int lvl, FILE *fp)
 {
   char prefix[256];
+  char op = '=';
 
   memset(prefix, ' ', 256);
   if (lvl > 127)
@@ -648,6 +691,7 @@
 
   if (hdf->value)
   {
+    if (hdf->link) op = ':';
     if (strchr (hdf->value, '\n'))
     {
       if (hdf->value[strlen(hdf->value)-1] != '\n')
@@ -657,7 +701,7 @@
     }
     else
     {
-      fprintf(fp, "%s%s = %s\n", prefix, hdf->name, hdf->value);
+      fprintf(fp, "%s%s %c %s\n", prefix, hdf->name, op, hdf->value);
     }
   }
   if (hdf->child)
@@ -790,13 +834,13 @@
 	if (err != STATUS_OK)
 	  return nerr_pass_ctx(err, "In String %d", *line);
       }
-      else if (s[0] == ':') /* copy */
+      else if (s[0] == ':') /* link */
       {
 	*s = '\0';
 	name = neos_strip(name);
 	s++;
 	value = neos_strip(s);
-	err = hdf_set_copy (hdf, name, value);
+	err = hdf_set_symlink (hdf, name, value);
 	if (err != STATUS_OK)
 	  return nerr_pass_ctx(err, "In string %d", *line);
       }
@@ -945,13 +989,13 @@
 	if (err != STATUS_OK)
 	  return nerr_pass_ctx(err, "In file %s:%d", path, *line);
       }
-      else if (s[0] == ':') /* copy */
+      else if (s[0] == ':') /* link */
       {
 	*s = '\0';
 	name = neos_strip(name);
 	s++;
 	value = neos_strip(s);
-	err = hdf_set_copy (hdf, name, value);
+	err = hdf_set_symlink (hdf, name, value);
 	if (err != STATUS_OK)
 	  return nerr_pass_ctx(err, "In file %s:%d", path, *line);
       }
diff -bru clearsilver-0.2/util/neo_hdf.h clearsilver-0.2.1/util/neo_hdf.h
--- clearsilver-0.2/util/neo_hdf.h	Tue Aug  7 14:58:46 2001
+++ clearsilver-0.2.1/util/neo_hdf.h	Fri Sep 14 16:45:46 2001
@@ -19,11 +19,12 @@
 
 typedef struct _hdf
 {
-  int top;
+  int link;
   int alloc_value;
   char *name;
   int name_len;
   char *value;
+  struct _hdf *top;
   struct _hdf *next;
   struct _hdf *child;
 } HDF;
@@ -46,6 +47,8 @@
 NEOERR* hdf_set_int_value (HDF *hdf, char *name, int value);
 NEOERR* hdf_set_copy (HDF *hdf, char *dest, char *src);
 NEOERR* hdf_set_buf (HDF *hdf, char *name, char *value);
+
+NEOERR *hdf_set_symlink (HDF *hdf, char *src, char *dest);
 
 NEOERR* hdf_read_file (HDF *hdf, char *path);
 NEOERR* hdf_write_file (HDF *hdf, char *path);
diff -bru clearsilver-0.2/util/ulocks.c clearsilver-0.2.1/util/ulocks.c
--- clearsilver-0.2/util/ulocks.c	Mon Aug  6 14:28:17 2001
+++ clearsilver-0.2.1/util/ulocks.c	Thu Sep  6 13:10:56 2001
@@ -68,7 +68,9 @@
   *plock = -1;
 
   if((lock = open(file, O_WRONLY|O_NDELAY|O_APPEND, 0600)) < 0) {
-    return nerr_raise_errno (NERR_IO, "Unable to find lock file %s", file);
+    if (errno == ENOENT)
+      nerr_raise (NERR_NOT_FOUND, "Unable to find lock file %s", file);
+    return nerr_raise_errno (NERR_IO, "Unable to open lock file %s", file);
   }
 
   *plock = lock;
