diff -bru clearsilver-0.2.1/cgi/cgi.c clearsilver-0.3/cgi/cgi.c
--- clearsilver-0.2.1/cgi/cgi.c	Sun Sep  9 16:58:41 2001
+++ clearsilver-0.3/cgi/cgi.c	Sat Sep 15 16:37:24 2001
@@ -951,11 +951,15 @@
   cgiwrap_writevf (fmt, ap);
   cgiwrap_writef ("\r\n\r\n");
   cgiwrap_writef ("Redirect page<br><br>\n");
+#if 0
+  /* Apparently this crashes on some computers... I don't know if its
+   * legal to reuse the va_list */
   cgiwrap_writef ("  Destination: <A HREF=\"");
   cgiwrap_writevf (fmt, ap);
   cgiwrap_writef ("\">");
   cgiwrap_writevf (fmt, ap);
   cgiwrap_writef ("</A><BR>\n<BR>\n");
+#endif
   cgiwrap_writef ("There is nothing to see here, please move along...");
 
 }
diff -bru clearsilver-0.2.1/cs/Makefile clearsilver-0.3/cs/Makefile
--- clearsilver-0.2.1/cs/Makefile	Wed Jul 18 14:59:09 2001
+++ clearsilver-0.3/cs/Makefile	Sat Sep 15 17:08:55 2001
@@ -19,11 +19,11 @@
 CSDUMP_OBJ = $(CSDUMP_SRC:%.c=%.o)
 
 CFLAGS += -I$(NEOTONIC_ROOT)
-LIBS += -L$(LIB_DIR) -lneo_cs -lneo_utl
+LIBS += -L$(LIB_DIR) -lneo_cs -lneo_utl # -lefence
 
 TARGETS = $(CS_LIB) $(CSTEST_EXE) test
 
-CS_TESTS = test.cs test2.cs test3.cs test4.cs
+CS_TESTS = test.cs test2.cs test3.cs test4.cs test5.cs test6.cs
 
 all: $(TARGETS)
 
diff -bru clearsilver-0.2.1/cs/cs.h clearsilver-0.3/cs/cs.h
--- clearsilver-0.2.1/cs/cs.h	Mon Aug  6 14:28:16 2001
+++ clearsilver-0.3/cs/cs.h	Sat Sep 15 16:38:40 2001
@@ -45,43 +45,45 @@
 
 typedef enum
 {
-  CS_TYPE_STRING = 1,
-  CS_TYPE_NUM,
-  CS_TYPE_VAR,
-  CS_TYPE_VAR_NUM,
-  CS_TYPE_MACRO
-} CSARG_TYPE;
-
-typedef enum
-{
   /* Unary operators */
-  CS_OP_EXISTS = 1,
-  CS_OP_NOT,
+  CS_OP_EXISTS = (1<<0),
+  CS_OP_NOT = (1<<1),
 
   /* Binary Operators */
-  CS_OP_EQUAL,
-  CS_OP_NEQUAL,
-  CS_OP_LT,
-  CS_OP_LTE,
-  CS_OP_GT,
-  CS_OP_GTE,
-  CS_OP_AND,
-  CS_OP_OR,
-  CS_OP_ADD,
-  CS_OP_SUB,
-  CS_OP_MULT,
-  CS_OP_DIV,
-  CS_OP_MOD
+  CS_OP_EQUAL = (1<<2),
+  CS_OP_NEQUAL = (1<<3),
+  CS_OP_LT = (1<<4),
+  CS_OP_LTE = (1<<5),
+  CS_OP_GT = (1<<6),
+  CS_OP_GTE = (1<<7),
+  CS_OP_AND = (1<<8),
+  CS_OP_OR = (1<<9),
+  CS_OP_ADD = (1<<10),
+  CS_OP_SUB = (1<<11),
+  CS_OP_MULT = (1<<12),
+  CS_OP_DIV = (1<<13),
+  CS_OP_MOD = (1<<14),
+
+  /* Types */
+  CS_TYPE_STRING = (1<<15),
+  CS_TYPE_NUM = (1<<16),
+  CS_TYPE_VAR = (1<<17),
+  CS_TYPE_VAR_NUM = (1<<18),
+  CS_TYPE_MACRO = (1<<19),
+  CS_TYPE_EXPR = (1<<20),
+  CS_TYPE_STRING_ALLOC = (1<<21)
+} CSTOKEN_TYPE;
 
-} CS_OP;
+#define CS_TYPES (CS_TYPE_STRING | CS_TYPE_NUM | CS_TYPE_VAR | CS_TYPE_VAR_NUM | CS_TYPE_STRING_ALLOC)
 
 typedef struct _arg
 {
-  CSARG_TYPE type;
-  CS_OP op;
+  CSTOKEN_TYPE op_type;
   char *s;
   long int n;
   struct _macro *macro;
+  struct _arg *expr1;
+  struct _arg *expr2;
   struct _arg *next;
 } CSARG;
 
@@ -95,7 +97,6 @@
   CSARG arg1;
   CSARG arg2;
   CSARG *vargs;
-  CS_OP op;
 
   struct _tree *case_0;
   struct _tree *case_1;
@@ -106,7 +107,7 @@
 
 typedef struct _local_map
 {
-  CSARG_TYPE type;
+  CSTOKEN_TYPE type;
   char *name;
   union
   {
diff -bru clearsilver-0.2.1/cs/csparse.c clearsilver-0.3/cs/csparse.c
--- clearsilver-0.2.1/cs/csparse.c	Wed Sep  5 15:08:54 2001
+++ clearsilver-0.3/cs/csparse.c	Sat Sep 15 17:22:56 2001
@@ -138,26 +138,36 @@
   return STATUS_OK;
 }
 
+static void dealloc_arg (CSARG **arg)
+{
+  CSARG *p;
+
+  if (*arg == NULL) return;
+  p = *arg;
+  if (p->expr1) dealloc_arg (&(p->expr1));
+  if (p->expr2) dealloc_arg (&(p->expr2));
+  if (p->next) dealloc_arg (&(p->next));
+  free(p);
+  *arg = NULL;
+}
+
 static void dealloc_node (CSTREE **node)
 {
   CSTREE *my_node;
-  CSARG *arg, *p;
 
   if (*node == NULL) return;
   my_node = *node;
   if (my_node->case_0) dealloc_node (&(my_node->case_0));
   if (my_node->case_1) dealloc_node (&(my_node->case_1));
   if (my_node->next) dealloc_node (&(my_node->next));
-  if (my_node->vargs)
-  {
-    arg = my_node->vargs;
-    while (arg)
-    {
-      p = arg->next;
-      free(arg);
-      arg = p;
-    }
-  }
+  if (my_node->vargs) dealloc_arg (&(my_node->vargs));
+  if (my_node->arg1.expr1) dealloc_arg (&(my_node->arg1.expr1));
+  if (my_node->arg1.expr2) dealloc_arg (&(my_node->arg1.expr2));
+  if (my_node->arg1.next) dealloc_arg (&(my_node->arg1.next));
+  if (my_node->arg2.expr1) dealloc_arg (&(my_node->arg2.expr1));
+  if (my_node->arg2.expr2) dealloc_arg (&(my_node->arg2.expr2));
+  if (my_node->arg2.next) dealloc_arg (&(my_node->arg2.next));
+
   free(my_node);
   *node = NULL;
 }
@@ -165,21 +175,11 @@
 static void dealloc_macro (CS_MACRO **macro)
 {
   CS_MACRO *my_macro;
-  CSARG *arg, *p;
 
   if (*macro == NULL) return;
   my_macro = *macro;
   if (my_macro->name) free (my_macro->name);
-  if (my_macro->args)
-  {
-    arg = my_macro->args;
-    while (arg)
-    {
-      p = arg->next;
-      free(arg);
-      arg = p;
-    }
-  }
+  if (my_macro->args) dealloc_arg (&(my_macro->args));
   if (my_macro->next) dealloc_macro (&(my_macro->next));
   free (my_macro);
   *macro = NULL;
@@ -627,18 +627,16 @@
   return hdf_get_value (parse->hdf, name, NULL);
 }
 
-static NEOERR *var_int_lookup (CSPARSE *parse, char *name, int *value)
+long int var_int_lookup (CSPARSE *parse, char *name)
 {
   char *vs;
 
   vs = var_lookup (parse, name);
 
   if (vs == NULL)
-    *value = 0;
+    return 0;
   else
-    *value = atoi(vs);
-
-  return STATUS_OK;
+    return atoi(vs);
 }
 
 static NEOERR *literal_parse (CSPARSE *parse, int cmd, char *arg)
@@ -650,7 +648,7 @@
   err = alloc_node (&node);
   if (err) return nerr_pass(err);
   node->cmd = cmd;
-  node->arg1.type = CS_TYPE_STRING;
+  node->arg1.op_type = CS_TYPE_STRING;
   node->arg1.s = arg;
   *(parse->next) = node;
   parse->next = &(node->next);
@@ -694,7 +692,7 @@
 	a, s[0]);
   }
 
-  node->arg1.type = CS_TYPE_VAR;
+  node->arg1.op_type = CS_TYPE_VAR;
   node->arg1.s = a;
   *(parse->next) = node;
   parse->next = &(node->next);
@@ -709,7 +707,7 @@
   HDF *obj;
   char *v;
 
-  if (node->arg1.type == CS_TYPE_VAR && node->arg1.s != NULL)
+  if (node->arg1.op_type == CS_TYPE_VAR && node->arg1.s != NULL)
   {
     obj = var_lookup_obj (parse, node->arg1.s);
     if (obj != NULL)
@@ -747,7 +745,7 @@
 	a, s[0]);
   }
 
-  node->arg1.type = CS_TYPE_VAR;
+  node->arg1.op_type = CS_TYPE_VAR;
   node->arg1.s = a;
   *(parse->next) = node;
   parse->next = &(node->next);
@@ -761,7 +759,7 @@
   NEOERR *err = STATUS_OK;
   char *v;
 
-  if (node->arg1.type == CS_TYPE_VAR && node->arg1.s != NULL)
+  if (node->arg1.op_type == CS_TYPE_VAR && node->arg1.s != NULL)
   {
     v = var_lookup (parse, node->arg1.s);
     if (v != NULL)
@@ -811,7 +809,7 @@
 	find_context(parse, -1, tmp, sizeof(tmp)), a);
   }
 
-  node->arg1.type = CS_TYPE_VAR;
+  node->arg1.op_type = CS_TYPE_VAR;
   node->arg1.s = a;
   *(parse->next) = node;
   parse->next = &(node->next);
@@ -828,162 +826,212 @@
   return nerr_pass (err);
 }
 
+typedef struct _token
+{
+  CSTOKEN_TYPE type;
+  char *value;
+  size_t len;
+} CSTOKEN;
 
-static NEOERR *parse_arg (CSPARSE *parse, char *buf, CSARG *arg, char **remain)
+struct _simple_tokens
+{
+  BOOL two_chars;
+  char *token;
+  CSTOKEN_TYPE type;
+} SimpleTokens[] = {
+  { TRUE, "<=", CS_OP_LTE },
+  { TRUE, ">=", CS_OP_GTE },
+  { TRUE, "==", CS_OP_EQUAL },
+  { TRUE, "!=", CS_OP_NEQUAL },
+  { TRUE, "||", CS_OP_OR },
+  { TRUE, "&&", CS_OP_AND },
+  { FALSE, "<", CS_OP_LT },
+  { FALSE, ">", CS_OP_GT },
+  { FALSE, "!", CS_OP_NOT },
+  { FALSE, "+", CS_OP_ADD },
+  { FALSE, "-", CS_OP_SUB },
+  { FALSE, "*", CS_OP_MULT },
+  { FALSE, "/", CS_OP_DIV },
+  { FALSE, "%", CS_OP_MOD },
+  { FALSE, NULL, 0 }
+};
+
+#define MAX_TOKENS 256
+
+static NEOERR *parse_tokens (CSPARSE *parse, char *arg, CSTOKEN *tokens, 
+    int *used_tokens)
 {
-  char *p;
   char tmp[256];
+  int ntokens = 0;
+  int x;
+  BOOL found;
+  char *p;
+  char *expr = arg;
 
-  while (*buf && isspace(*buf)) buf++;
-  if (buf[0] == '#')
+  while (arg && *arg != '\0')
   {
-    arg->type = CS_TYPE_NUM;
-    arg->n = strtol(buf+1, remain, 0);
-    if (*remain == buf+1)
-    {
-      arg->type = CS_TYPE_VAR_NUM;
-      arg->s = buf+1;
-      *remain = strpbrk(buf+1, "?<>=!#-+|&,) ");
-      if (*remain == buf+1)
-	return nerr_raise (NERR_PARSE, "%s Missing arg after #: %s",
-	    find_context(parse, -1, tmp, sizeof(tmp)), buf);
+    while (*arg && isspace(*arg)) arg++;
+    if (*arg == '\0') break;
+    x = 0;
+    found = FALSE;
+    while ((found == FALSE) && SimpleTokens[x].token)
+    {
+      if (((SimpleTokens[x].two_chars == TRUE) && 
+	    (*arg == SimpleTokens[x].token[0]) &&
+	    (*(arg + 1) == SimpleTokens[x].token[1])) ||
+	  ((SimpleTokens[x].two_chars == FALSE) && 
+	   (*arg == SimpleTokens[x].token[0])))
+      {
+	tokens[ntokens++].type = SimpleTokens[x].type;
+	found = TRUE;
+	arg++;
+	if (SimpleTokens[x].two_chars) arg++;
+      }
+      x++;
+    }
 
+    if (found == FALSE)
+    {
+      if (*arg == '#')
+      {
+	arg++;
+	tokens[ntokens].type = CS_TYPE_NUM;
+	tokens[ntokens].value = arg;
+	strtol(arg, &p, 0);
+	if (p == arg)
+	{
+	  tokens[ntokens].type = CS_TYPE_VAR_NUM;
+	  p = strpbrk(arg, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
+	  if (p == arg)
+	    return nerr_raise (NERR_PARSE, "%s Missing arg after #: %s",
+		find_context(parse, -1, tmp, sizeof(tmp)), arg);
     }
+	if (p == NULL)
+	  tokens[ntokens].len = strlen(arg);
+	else
+	  tokens[ntokens].len = p - arg;
+	ntokens++;
+	arg = p;
   }
-  else if (buf[0] == '"')
+      else if (*arg == '"')
   {
-    arg->type = CS_TYPE_STRING;
-    arg->s = buf + 1;
-    p = strchr (buf+1, '"');
+	arg++;
+	tokens[ntokens].type = CS_TYPE_STRING;
+	tokens[ntokens].value = arg;
+	p = strchr (arg, '"');
     if (p == NULL)
       return nerr_raise (NERR_PARSE, "%s Missing end of string: %s", 
-	  find_context(parse, -1, tmp, sizeof(tmp)), buf);
-    *p = '\0';
-    *remain = p+1;
+	      find_context(parse, -1, tmp, sizeof(tmp)), arg);
+	tokens[ntokens].len = p - arg;
+	ntokens++;
+	arg = p + 1;
   }
   else
   {
-    arg->type = CS_TYPE_VAR;
-    arg->s = buf;
-    *remain = strpbrk(buf, "?<>=!#-+|&,) ");
-    if (*remain == buf)
-      return nerr_raise (NERR_PARSE, "%s Var arg specified with no varname: %s",
-	  find_context(parse, -1, tmp, sizeof(tmp)), buf);
+	tokens[ntokens].type = CS_TYPE_VAR;
+	tokens[ntokens].value = arg;
+	p = strpbrk(arg, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
+	if (p == arg)
+	  return nerr_raise (NERR_PARSE, 
+	      "%s Var arg specified with no varname: %s",
+	      find_context(parse, -1, tmp, sizeof(tmp)), arg);
+	if (p == NULL)
+	  tokens[ntokens].len = strlen(arg);
+	else
+	  tokens[ntokens].len = p - arg;
+	ntokens++;
+	arg = p;
+      }
+    }
+    if (ntokens >= MAX_TOKENS)
+	return nerr_raise (NERR_PARSE, 
+	    "%s Expression exceeds maximum number of tokens of %d: %s",
+	    find_context(parse, -1, tmp, sizeof(tmp)), MAX_TOKENS, expr);
   }
+  *used_tokens = ntokens;
   return STATUS_OK;
 }
 
-static NEOERR *parse_expr (CSPARSE *parse, char *arg, CSTREE *node)
+CSTOKEN_TYPE BinaryOpOrder[] = {
+   CS_OP_OR,
+   CS_OP_AND,
+   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,
+   0
+};
+
+static NEOERR *parse_expr2 (CSPARSE *parse, CSTOKEN *tokens, int ntokens, 
+    CSARG *arg)
 {
   NEOERR *err;
-  int x;
-  char *r;
   char tmp[256];
+  int x, op = 0;
 
-  arg = neos_strip(arg);
-  if (arg[0] == '\0')
-    return nerr_raise (NERR_PARSE, "%s No expression", 
-	  find_context(parse, -1, tmp, sizeof(tmp)));
-  if (arg[0] == '!')
-  {
-    node->op = CS_OP_NOT;
-    arg++;
-  }
-
-  err = parse_arg(parse, arg, &(node->arg1), &r);
-  if (err != STATUS_OK) return nerr_pass(err);
-
-  /* Unary operators */
-  if (r == NULL || r[0] == '\0')
-  {
-    if (node->op != CS_OP_NOT)
-      node->op = CS_OP_EXISTS;
-  }
-  else
+  if (ntokens == 1 || (ntokens == 2 && tokens[0].type == CS_OP_NOT))
   {
-    if (node->op == CS_OP_NOT)
-      return nerr_raise (NERR_PARSE, "%s No expression", 
-	  find_context(parse, -1, tmp, sizeof(tmp)));
     x = 0;
-    while (r[x] && isspace(r[x])) x++;
-    if (r[x] == '=' && r[x+1] == '=')
-    {
-      node->op = CS_OP_EQUAL;
-      x+=2;
-    }
-    else if (r[x] == '!' && r[x+1] == '=')
-    {
-      node->op = CS_OP_NEQUAL;
-      x+=2;
-    }
-    else if (r[x] == '<' && r[x+1] == '=')
+    if (tokens[0].type == CS_OP_NOT) x = 1;
+    if (tokens[x].type & CS_TYPES)
     {
-      node->op = CS_OP_LTE;
-      x+=2;
-    }
-    else if (r[x] == '>' && r[x+1] == '=')
-    {
-      node->op = CS_OP_GTE;
-      x+=2;
-    }
-    else if (r[x] == '&' && r[x+1] == '&')
-    {
-      node->op = CS_OP_AND;
-      x+=2;
-    }
-    else if (r[x] == '|' && r[x+1] == '|')
-    {
-      node->op = CS_OP_OR;
-      x+=2;
-    }
-    else if (r[x] == '<')
-    {
-      node->op = CS_OP_LT;
-      x++;
-    }
-    else if (r[x] == '>')
-    {
-      node->op = CS_OP_GT;
-      x++;
+      arg->s = tokens[x].value;
+      if (tokens[x].len >= 0)
+	arg->s[tokens[x].len] = '\0';
+      arg->op_type = tokens[x].type;
+
+      if (tokens[x].type == CS_TYPE_NUM)
+	arg->n = strtol(arg->s, NULL, 0);
+      if (tokens[0].type == CS_OP_NOT) arg->op_type |= CS_OP_NOT;
+      return STATUS_OK;
     }
-    else if (r[x] == '+')
+    else
     {
-      node->op = CS_OP_ADD;
-      x++;
+      return nerr_raise (NERR_PARSE, 
+	  "%s Terminal token is not an argument, type is %d",
+	  find_context(parse, -1, tmp, sizeof(tmp)), tokens[0].type);
     }
-    else if (r[x] == '-')
-    {
-      node->op = CS_OP_SUB;
-      x++;
     }
-    else if (r[x] == '*')
+
+  while (BinaryOpOrder[op])
     {
-      node->op = CS_OP_MULT;
-      x++;
-    }
-    else if (r[x] == '/')
+    x = ntokens-1;
+    while (x >= 0)
     {
-      node->op = CS_OP_DIV;
-      x++;
-    }
-    else if (r[x] == '%')
+      if (tokens[x].type & BinaryOpOrder[op])
     {
-      node->op = CS_OP_MOD;
-      x++;
+	arg->op_type = tokens[x].type;
+	arg->expr2 = (CSARG *) calloc (1, sizeof (CSARG));
+	arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG));
+	if (arg->expr1 == NULL || arg->expr2 == NULL)
+	  return nerr_raise (NERR_NOMEM, 
+	      "%s Unable to allocate memory for expression", 
+	      find_context(parse, -1, tmp, sizeof(tmp)));
+	err = parse_expr2(parse, tokens + x + 1, ntokens-x-1, arg->expr2);
+	if (err) return nerr_pass (err);
+	err = parse_expr2(parse, tokens, x, arg->expr1);
+	if (err) return nerr_pass (err);
+	return STATUS_OK;
     }
-    else
-    {
-      return nerr_raise (NERR_PARSE, "%s Unrecognized operand in if expr: %s",
-	  find_context(parse, -1, tmp, sizeof(tmp)), &r[x]);
+      x--;
     }
-    /* HACK: There might not have been room to NULL terminate the var
-     * arg1, so we do it here after we've parsed the op */
-    r[0] = '\0';
-    r += x;
-    while (*r && isspace(*r)) r++;
-    err = parse_arg(parse, r, &(node->arg2), &r);
-    if (err != STATUS_OK) return nerr_pass(err);
+    op++;
   }
+  return nerr_raise (NERR_PARSE, "%s Bad Expression",
+      find_context(parse, -1, tmp, sizeof(tmp)));
+}
+
+static NEOERR *parse_expr (CSPARSE *parse, char *arg, CSARG *expr)
+{
+  NEOERR *err;
+  CSTOKEN tokens[MAX_TOKENS];
+  int ntokens = 0;
+
+  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);
+  if (err) return nerr_pass(err);
   return STATUS_OK;
 }
 
@@ -998,7 +1046,7 @@
   node->cmd = cmd;
   arg++;
 
-  err = parse_expr (parse, arg, node);
+  err = parse_expr (parse, arg, &(node->arg1));
   if (err != STATUS_OK)
   {
     dealloc_node(&node);
@@ -1012,224 +1060,255 @@
   return STATUS_OK;
 }
 
-static NEOERR *arg_eval (CSPARSE *parse, CSARG *arg, char **value)
+char *arg_eval (CSPARSE *parse, CSARG *arg)
 {
-  switch (arg->type)
+  if (arg->op_type & CS_OP_NOT)
+  {
+    ne_warn ("String eval shouldn't have a NOT op");
+    return NULL;
+  }
+  else
+  {
+    switch ((arg->op_type & CS_TYPES))
   {
     case CS_TYPE_STRING:
-      *value = arg->s;
-      break;
+      case CS_TYPE_STRING_ALLOC:
+	return arg->s;
     case CS_TYPE_VAR:
-      {
-	/* err = hdf_get_value (parse->hdf, arg->s, value, 0); */
-	*value = var_lookup (parse, arg->s);
-      }
-      break;
+	return var_lookup (parse, arg->s);
     case CS_TYPE_NUM:
     case CS_TYPE_VAR_NUM:
       /* These types should force numeric evaluation... so nothing
        * should get here */
     default:
-      ne_warn ("Unsupported type %s in arg_eval_num", arg->type);
-      *value = 0;
-      break;
+	ne_warn ("Unsupported type %s in arg_eval", arg->op_type);
+	return NULL;
+    }
   }
-  return STATUS_OK;
 }
 
-static NEOERR *arg_eval_num (CSPARSE *parse, CSARG *arg, long int *value)
+long int arg_eval_num (CSPARSE *parse, CSARG *arg)
 {
-  NEOERR *err;
-  switch (arg->type)
+  long int v = 0;
+
+  switch ((arg->op_type & CS_TYPES))
   {
     case CS_TYPE_STRING:
-      *value = strtol(arg->s, NULL, 0);
+    case CS_TYPE_STRING_ALLOC:
+      v = strtol(arg->s, NULL, 0);
       break;
     case CS_TYPE_NUM:
-      *value = arg->n;
+      v = arg->n;
       break;
 
     case CS_TYPE_VAR:
     case CS_TYPE_VAR_NUM:
-      {
-	int v;
-	/* err = hdf_get_int_value (parse->hdf, arg->s, &v, 0); */
-	err = var_int_lookup (parse, arg->s, &v);
-	if (err != STATUS_OK) return nerr_pass (err);
-	*value = v;
-      }
+      v = var_int_lookup (parse, arg->s);
       break;
     default:
-      ne_warn ("Unsupported type %s in arg_eval_num", arg->type);
-      *value = 0;
+      ne_warn ("Unsupported type %s in arg_eval_num", arg->op_type);
+      v = 0;
       break;
   }
-  return STATUS_OK;
+  if (arg->op_type & CS_OP_NOT)
+    v = !v;
+  return v;
 }
 
-static NEOERR *if_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
+static NEOERR *eval_expr (CSPARSE *parse, CSARG *expr, CSARG *result)
 {
-  NEOERR *err = STATUS_OK;
-  int eval_true = 0;
-
-  if ((node->op == CS_OP_EXISTS) || (node->op == CS_OP_NOT))
-  {
-    char *vs;
-    int vn;
-    if (node->arg1.type == CS_TYPE_STRING)
-      eval_true = 1;
-    else if (node->arg1.type == CS_TYPE_NUM)
-      eval_true = (node->arg1.n) ? 1 : 0;
-    else if (node->arg1.type == CS_TYPE_VAR)
-    {
-      /* err = hdf_get_value (parse->hdf, node->arg1.s, &vs, NULL); */
-      vs = var_lookup (parse, node->arg1.s);
-      if (!((vs == NULL) || (vs[0] == '\0')))
-      {
-	eval_true = 1;
-      }
-    }
-    else if (node->arg1.type == CS_TYPE_VAR_NUM)
+  if (expr->op_type & CS_TYPES)
     {
-      /* err = hdf_get_int_value (parse->hdf, node->arg1.s, &vn, 0); */
-      err = var_int_lookup (parse, node->arg1.s, &vn);
-      if (err != STATUS_OK) return nerr_pass(err);
-      eval_true = (vn) ? 1 : 0;
-    }
-    if (node->op == CS_OP_NOT) eval_true = eval_true ? 0 : 1;
+    *result = *expr;
+    return STATUS_OK;
   }
   else
   {
-    if ((node->arg1.type == CS_TYPE_NUM) || 
-	(node->arg2.type == CS_TYPE_NUM) ||
-	(node->arg1.type == CS_TYPE_VAR_NUM) || 
-	(node->arg2.type == CS_TYPE_VAR_NUM) ||
-	(node->op == CS_OP_AND) ||
-	(node->op == CS_OP_OR) ||
-	(node->op == CS_OP_ADD) ||
-	(node->op == CS_OP_SUB) || 
-	(node->op == CS_OP_MULT) ||
-	(node->op == CS_OP_DIV) ||
-	(node->op == CS_OP_MOD))
+    CSARG arg1, arg2;
+    NEOERR *err;
+
+    err = eval_expr (parse, expr->expr1, &arg1);
+    if (err) return nerr_pass(err);
+    err = eval_expr (parse, expr->expr2, &arg2);
+    if (err) return nerr_pass(err);
+    /* Check for type conversion */
+    if ((arg1.op_type & (CS_OP_NOT | CS_TYPE_NUM | CS_TYPE_VAR_NUM)) ||
+	(arg2.op_type & (CS_OP_NOT | 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)))
     {
-      /* Numeric evaluation */
+      /* eval as num */
       long int n1, n2;
-      err = arg_eval_num (parse, &(node->arg1), &n1);
-      err = arg_eval_num (parse, &(node->arg2), &n2);
-      switch (node->op)
+
+      result->op_type = CS_TYPE_NUM;
+      n1 = arg_eval_num (parse, &arg1);
+      n2 = arg_eval_num (parse, &arg2);
+
+      switch (expr->op_type)
       {
 	case CS_OP_EQUAL:
-	  eval_true = (n1 == n2) ? 1 : 0;
+	  result->n = (n1 == n2) ? 1 : 0;
 	  break;
 	case CS_OP_NEQUAL:
-	  eval_true = (n1 != n2) ? 1 : 0;
+	  result->n = (n1 != n2) ? 1 : 0;
 	  break;
 	case CS_OP_LT:
-	  eval_true = (n1 < n2) ? 1 : 0;
+	  result->n = (n1 < n2) ? 1 : 0;
 	  break;
 	case CS_OP_LTE:
-	  eval_true = (n1 <= n2) ? 1 : 0;
+	  result->n = (n1 <= n2) ? 1 : 0;
 	  break;
 	case CS_OP_GT:
-	  eval_true = (n1 > n2) ? 1 : 0;
+	  result->n = (n1 > n2) ? 1 : 0;
 	  break;
 	case CS_OP_GTE:
-	  eval_true = (n1 >= n2) ? 1 : 0;
+	  result->n = (n1 >= n2) ? 1 : 0;
 	  break;
 	case CS_OP_AND:
-	  eval_true = (n1 && n2) ? 1 : 0;
+	  result->n = (n1 && n2) ? 1 : 0;
 	  break;
 	case CS_OP_OR:
-	  eval_true = (n1 || n2) ? 1 : 0;
+	  result->n = (n1 || n2) ? 1 : 0;
 	  break;
 	case CS_OP_ADD:
-	  eval_true = (n1 + n2) ? 1 : 0;
+	  result->n = (n1 + n2);
 	  break;
 	case CS_OP_SUB:
-	  eval_true = (n1 - n2) ? 1 : 0;
+	  result->n = (n1 - n2);
 	  break;
 	case CS_OP_MULT:
-	  eval_true = (n1 * n2) ? 1 : 0;
+	  result->n = (n1 * n2);
 	  break;
 	case CS_OP_DIV:
-	  if (n2 == 0) eval_true = 1;
-	  else eval_true = (n1 / n2) ? 1 : 0;
+	  if (n2 == 0) result->n = UINT_MAX;
+	  else result->n = (n1 / n2);
 	  break;
 	case CS_OP_MOD:
-	  if (n2 == 0) eval_true = 1;
-	  else eval_true = (n1 % n2) ? 1 : 0;
+	  if (n2 == 0) result->n = 0;
+	  else result->n = (n1 % n2);
 	  break;
 	default:
-	  ne_warn ("Unsupported op %d in if_eval", node->op);
+	  ne_warn ("Unsupported op %d in eval_expr", expr->op_type);
 	  break;
       }
     }
-    else
+    else /* eval as string */
     {
       char *s1, *s2;
       int out;
-      err = arg_eval (parse, &(node->arg1), &s1);
-      err = arg_eval (parse, &(node->arg2), &s2);
-      /* ne_warn("arg1 = %s, arg2 = %s", s1, s2); */
+
+      result->op_type = CS_TYPE_NUM;
+      s1 = arg_eval (parse, &arg1);
+      s2 = arg_eval (parse, &arg2);
+
       if ((s1 == NULL) || (s2 == NULL))
       {
-	switch (node->op)
+	switch (expr->op_type)
 	{
 	  case CS_OP_EQUAL:
-	    eval_true = (s1 == s2) ? 1 : 0;
+	    result->n = (s1 == s2) ? 1 : 0;
 	    break;
 	  case CS_OP_NEQUAL:
-	    eval_true = (s1 != s2) ? 1 : 0;
+	    result->n = (s1 != s2) ? 1 : 0;
 	    break;
 	  case CS_OP_LT:
-	    eval_true = ((s1 == NULL) && (s2 != NULL)) ? 1 : 0;
+	    result->n = ((s1 == NULL) && (s2 != NULL)) ? 1 : 0;
 	    break;
 	  case CS_OP_LTE:
-	    eval_true = (s1 == NULL) ? 1 : 0;
+	    result->n = (s1 == NULL) ? 1 : 0;
 	    break;
 	  case CS_OP_GT:
-	    eval_true = ((s1 != NULL) && (s2 == NULL)) ? 1 : 0;
+	    result->n = ((s1 != NULL) && (s2 == NULL)) ? 1 : 0;
 	    break;
 	  case CS_OP_GTE:
-	    eval_true = (s2 == NULL) ? 1 : 0;
+	    result->n = (s2 == NULL) ? 1 : 0;
+	    break;
+	  case CS_OP_ADD:
+	    result->op_type = CS_TYPE_STRING;
+	    if (s1 == NULL) 
+	      result->s = s2;
+	    else
+	      result->s = s1;
 	    break;
 	  default:
-	    ne_warn ("Unsupported op %d in if_eval", node->op);
+	    ne_warn ("Unsupported op %d in eval_expr", expr->op_type);
 	    break;
 	}
       }
       else
       {
 	out = strcmp (s1, s2);
-	switch (node->op)
+	switch (expr->op_type)
 	{
 	  case CS_OP_EQUAL:
-	    eval_true = (!out) ? 1 : 0;
+	    result->n = (!out) ? 1 : 0;
 	    break;
 	  case CS_OP_NEQUAL:
-	    eval_true = (out) ? 1 : 0;
+	    result->n = (out) ? 1 : 0;
 	    break;
 	  case CS_OP_LT:
-	    eval_true = (out < 0) ? 1 : 0;
+	    result->n = (out < 0) ? 1 : 0;
 	    break;
 	  case CS_OP_LTE:
-	    eval_true = (out <= 0) ? 1 : 0;
+	    result->n = (out <= 0) ? 1 : 0;
 	    break;
 	  case CS_OP_GT:
-	    eval_true = (out > 0) ? 1 : 0;
+	    result->n = (out > 0) ? 1 : 0;
 	    break;
 	  case CS_OP_GTE:
-	    eval_true = (out >= 0) ? 1 : 0;
+	    result->n = (out >= 0) ? 1 : 0;
+	    break;
+	  case CS_OP_ADD:
+	    result->op_type = CS_TYPE_STRING_ALLOC;
+	    result->s = (char *) calloc ((strlen(s1) + strlen(s2) + 1), sizeof(char));
+	    if (result->s == NULL)
+	      return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate strings in expression: %s + %s", s1, s2);
+	    strcat(result->s, s1);
+	    strcat(result->s, s2);
 	    break;
-	  case CS_OP_AND:
-	  case CS_OP_OR:
 	  default:
-	    ne_warn ("Unsupported op %d in if_eval", node->op);
+	    ne_warn ("Unsupported op %d in expr_eval", expr->op_type);
 	    break;
 	}
       }
     }
+    if (arg1.op_type == CS_TYPE_STRING_ALLOC)
+      free(arg1.s);
+    if (arg2.op_type == CS_TYPE_STRING_ALLOC)
+      free(arg2.s);
   }
+  return STATUS_OK;
+}
+
+static NEOERR *if_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
+{
+  NEOERR *err = STATUS_OK;
+  int eval_true = 0;
+  CSARG val;
+
+  err = eval_expr(parse, &(node->arg1), &val);
+  if (err) return nerr_pass (err);
+  if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM))
+    eval_true = arg_eval_num (parse, &val);
+  else
+  {
+    char *s;
+    BOOL not = FALSE;
+    if (val.op_type & CS_OP_NOT)
+    {
+      not = TRUE;
+      val.op_type &= ~CS_OP_NOT;
+    }
+    s = arg_eval (parse, &val);
+    if (s == NULL || *s == '\0')
+      eval_true = 0;
+    else
+      eval_true = 1;
+
+    if (not == TRUE)
+      eval_true = !eval_true;
+  }
+  if (val.op_type == CS_TYPE_STRING_ALLOC)
+    free(val.s);
 
   if (eval_true)
   {
@@ -1342,10 +1421,10 @@
 	"%s Improperly formatted each directive: %s", 
 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
   }
-  node->arg1.type = CS_TYPE_VAR;
+  node->arg1.op_type = CS_TYPE_VAR;
   node->arg1.s = lvar;
 
-  node->arg2.type = CS_TYPE_VAR;
+  node->arg2.op_type = CS_TYPE_VAR;
   node->arg2.s = p;
 
   /* ne_warn ("each %s %s", lvar, p); */
@@ -1443,7 +1522,7 @@
     {
       a[l - 1] = '\0';
     }
-    node->arg1.type = CS_TYPE_STRING;
+    node->arg1.op_type = CS_TYPE_STRING;
     node->arg1.s = a;
     s = a;
   }
@@ -1457,7 +1536,7 @@
 	  "%s Unable to include empty variable %s", 
 	  find_context(parse, -1, tmp, sizeof(tmp)), a);
     }
-    node->arg1.type = CS_TYPE_VAR;
+    node->arg1.op_type = CS_TYPE_VAR;
     node->arg1.s = a;
   }
 
@@ -1474,10 +1553,11 @@
   CSTREE *node;
   CS_MACRO *macro;
   CSARG *carg, *larg = NULL;
-  char *a = NULL, *s;
+  char *a = NULL, *p = NULL, *s;
   char tmp[256];
   char name[256];
   int x = 0;
+  BOOL last = FALSE;
 
   err = alloc_node (&node);
   if (err) return nerr_pass(err);
@@ -1545,22 +1625,32 @@
       larg = carg;
     }
     macro->n_args++;
-    err = parse_arg (parse, s, carg, &s);
-    if (err) break;
-    a = s;
-    while (*s && isspace(*s)) s++;
-    if (*s == ')') break;
-    if (*s == ',') s++;
-    *a = '\0';
     while (*s && isspace(*s)) s++;
-  }
-  if (!err && *s != ')')
+    a = strpbrk(s, ",)");
+    if (a == NULL)
   {
     err = nerr_raise (NERR_PARSE, 
 	"%s Missing right paren in def %s",
 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
+      break;
+    }
+    if (*a == ')') last = TRUE;
+    *a = '\0';
+    /* cut out ending whitespace */
+    p = strpbrk(s, " \t\r\n");
+    if (p != NULL) *p = '\0';
+    p = strpbrk(s, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
+    if (p != NULL)
+    {
+      err = nerr_raise (NERR_PARSE, 
+	  "%s Invalid character in def %s argument: %c",
+	  find_context(parse, -1, tmp, sizeof(tmp)), arg, *p);
+      break;
+    }
+    carg->s = s;
+    if (last == TRUE) break;
+    s = a+1;
   }
-  if (a) *a = '\0';
   if (err)
   {
     dealloc_node(&node);
@@ -1605,6 +1695,7 @@
   char tmp[256];
   char name[256];
   int x = 0;
+  BOOL last = FALSE;
 
   err = alloc_node (&node);
   if (err) return nerr_pass(err);
@@ -1640,7 +1731,7 @@
 	"%s Undefined macro called: %s", 
 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
   }
-  node->arg1.type = CS_TYPE_MACRO;
+  node->arg1.op_type = CS_TYPE_MACRO;
   node->arg1.macro = macro;
 
   x = 0;
@@ -1665,20 +1756,20 @@
       larg = carg;
     }
     x++;
-    err = parse_arg (parse, s, carg, &s);
-    if (err) break;
-    a = s;
-    while (*s && isspace(*s)) s++;
-    if (*s == ')') break;
-    if (*s == ',') s++;
-    *a = '\0';
-    while (*s && isspace(*s)) s++;
-  }
-  if (!err && *s != ')')
+    a = strpbrk(s, ",)");
+    if (a == NULL)
   {
     err = nerr_raise (NERR_PARSE, 
 	"%s Missing right paren in def %s",
 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
+      break;
+    }
+    if (*a == ')') last = TRUE;
+    *a = '\0';
+    err = parse_expr (parse, s, carg);
+    if (err) break;
+    if (last == TRUE) break;
+    s = a+1;
   }
   if (!err && x != macro->n_args)
   {
@@ -1692,7 +1783,6 @@
     dealloc_node(&node);
     return nerr_pass(err);
   }
-  if (a) *a = '\0';
 
   *(parse->next) = node;
   parse->next = &(node->next);
@@ -1726,12 +1816,12 @@
     if (x) call_map[x-1].next = map;
 
     map->name = darg->s;
-    if (carg->type == CS_TYPE_STRING)
+    if (carg->op_type == CS_TYPE_STRING)
     {
       map->value.s = carg->s;
       map->type = CS_TYPE_STRING;
     }
-    else if (carg->type == CS_TYPE_NUM)
+    else if (carg->op_type == CS_TYPE_NUM)
     {
       map->value.n = carg->n;
       map->type = CS_TYPE_NUM;
@@ -1762,9 +1852,7 @@
 {
   NEOERR *err;
   CSTREE *node;
-  CS_OP op = CS_OP_EXISTS;
-  CSARG *carg, *larg = NULL;
-  char *s, *a = NULL;
+  char *s;
   char tmp[256];
   char name[256];
   int x = 0;
@@ -1790,131 +1878,15 @@
 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
   }
   s++;
-  node->arg1.type = CS_TYPE_VAR;
+  node->arg1.op_type = CS_TYPE_VAR;
   node->arg1.s = strdup(name);
 
-  while (*s)
-  {
-    carg = (CSARG *) calloc (1, sizeof(CSARG));
-    if (carg == NULL)
-    {
-      err = nerr_raise (NERR_NOMEM, 
-	  "%s Unable to allocate memory for CSARG in set %s",
-	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
-      break;
-    }
-    carg->op = op;
-    op = CS_OP_EXISTS;
-    if (larg == NULL)
-    {
-      node->vargs = carg;
-      larg = carg;
-    }
-    else
-    {
-      larg->next = carg;
-      larg = carg;
-    }
-    err = parse_arg (parse, s, carg, &s);
-    a = s;
-    if (err) break;
-    /* Unary operators */
-    if (s == NULL || s[0] == '\0')
-    {
-      if (op != CS_OP_NOT)
-	op = CS_OP_EXISTS;
-      break;
-    }
-    else
-    {
-      if (op == CS_OP_NOT)
-	return nerr_raise (NERR_PARSE, "%s No expression", 
-	    find_context(parse, -1, tmp, sizeof(tmp)));
-      x = 0;
-      while (s[x] && isspace(s[x])) x++;
-      if (s[x] == '=' && s[x+1] == '=')
-      {
-	op = CS_OP_EQUAL;
-	x+=2;
-      }
-      else if (s[x] == '!' && s[x+1] == '=')
-      {
-	op = CS_OP_NEQUAL;
-	x+=2;
-      }
-      else if (s[x] == '<' && s[x+1] == '=')
-      {
-	op = CS_OP_LTE;
-	x+=2;
-      }
-      else if (s[x] == '>' && s[x+1] == '=')
-      {
-	op = CS_OP_GTE;
-	x+=2;
-      }
-      else if (s[x] == '&' && s[x+1] == '&')
-      {
-	op = CS_OP_AND;
-	x+=2;
-      }
-      else if (s[x] == '|' && s[x+1] == '|')
-      {
-	op = CS_OP_OR;
-	x+=2;
-      }
-      else if (s[x] == '<')
-      {
-	op = CS_OP_LT;
-	x++;
-      }
-      else if (s[x] == '>')
-      {
-	op = CS_OP_LT;
-	x++;
-      }
-      else if (s[x] == '+')
-      {
-	op = CS_OP_ADD;
-	x++;
-      }
-      else if (s[x] == '-')
-      {
-	op = CS_OP_SUB;
-	x++;
-      }
-      else if (s[x] == '*')
-      {
-	op = CS_OP_MULT;
-	x++;
-      }
-      else if (s[x] == '/')
-      {
-	op = CS_OP_DIV;
-	x++;
-      }
-      else if (s[x] == '%')
-      {
-	op = CS_OP_MOD;
-	x++;
-      }
-      else if (s[x])
-      {
-	return nerr_raise (NERR_PARSE, "%s Unrecognized operand in set expr: %s",
-	    find_context(parse, -1, tmp, sizeof(tmp)), &s[x]);
-      }
-      /* HACK: There might not have been room to NULL terminate the var
-       * arg1, so we do it here after we've parsed the op */
-      *a = '\0';
-      s += x;
-    }
-    while (*s && isspace(*s)) s++;
-  }
+  err = parse_expr(parse, s, &(node->arg2));
   if (err)
   {
     dealloc_node(&node);
     return nerr_pass(err);
   }
-  if (a) *a = '\0';
 
   *(parse->next) = node;
   parse->next = &(node->next);
@@ -1926,223 +1898,31 @@
 static NEOERR *set_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
 {
   NEOERR *err = STATUS_OK;
-  CSARG *arg;
-  STRING s_val;
-  long int n_val = 0;
-  BOOL is_num = FALSE;
-
-  string_init (&s_val);
-  arg = node->vargs;
-  while (arg)
-  {
-    /* This should only happen on the first arg */
-    if ((arg->op == CS_OP_EXISTS) || (arg->op == CS_OP_NOT))
-    {
-      char *vs;
-      int vn;
-      if (arg->type == CS_TYPE_STRING)
-      {
-	err = string_set (&s_val, arg->s);
-      }
-      else if (arg->type == CS_TYPE_NUM)
-      {
-	is_num = TRUE;
-	n_val = arg->n;
-      }
-      else if (arg->type == CS_TYPE_VAR)
-      {
-	vs = var_lookup (parse, arg->s);
-	if (vs == NULL)
-	{
-	  err = string_set (&s_val, "");
-	}
-	else
-	{
-	  err = string_set (&s_val, vs);
-	}
-      }
-      else if (arg->type == CS_TYPE_VAR_NUM)
-      {
-	is_num = TRUE;
-	err = var_int_lookup (parse, arg->s, &vn);
-	if (err != STATUS_OK) return nerr_pass(err);
-	n_val = vn;
-      }
-    }
-    else
-    {
-      if (is_num ||
-	  (arg->type == CS_TYPE_NUM) || 
-	  (arg->type == CS_TYPE_VAR_NUM) || 
-	  (arg->op == CS_OP_AND) ||
-	  (arg->op == CS_OP_OR) ||
-	  (arg->op == CS_OP_SUB) || 
-	  (arg->op == CS_OP_MULT) ||
-	  (arg->op == CS_OP_DIV) ||
-	  (arg->op == CS_OP_MOD))
-      {
-	/* Numeric evaluation */
-	long int n;
-
-	if (is_num == FALSE)
-	{
-	  /* we have to convert the existing s_val to a number */
-	  if (s_val.buf == NULL)
-	    n_val = 0;
-	  else
-	    n_val = strtol(s_val.buf, NULL, 0);
-	  is_num = TRUE;
-	}
+  CSARG val;
 
-	err = arg_eval_num (parse, arg, &n);
-	switch (arg->op)
-	{
-	  case CS_OP_EQUAL:
-	    n_val = (n_val == n) ? 1 : 0;
-	    break;
-	  case CS_OP_NEQUAL:
-	    n_val = (n_val != n) ? 1 : 0;
-	    break;
-	  case CS_OP_LT:
-	    n_val = (n_val < n) ? 1 : 0;
-	    break;
-	  case CS_OP_LTE:
-	    n_val = (n_val <= n) ? 1 : 0;
-	    break;
-	  case CS_OP_GT:
-	    n_val = (n_val > n) ? 1 : 0;
-	    break;
-	  case CS_OP_GTE:
-	    n_val = (n_val >= n) ? 1 : 0;
-	    break;
-	  case CS_OP_AND:
-	    n_val = (n_val && n) ? 1 : 0;
-	    break;
-	  case CS_OP_OR:
-	    n_val = (n_val || n) ? 1 : 0;
-	    break;
-	  case CS_OP_ADD:
-	    n_val = (n_val + n);
-	    break;
-	  case CS_OP_SUB:
-	    n_val = (n_val - n);
-	    break;
-	  case CS_OP_MULT:
-	    n_val = (n_val * n);
-	    break;
-	  case CS_OP_DIV:
-	    if (n == 0) n_val = UINT_MAX;
-	    else n_val = (n_val / n);
-	    break;
-	  case CS_OP_MOD:
-	    if (n == 0) n_val = UINT_MAX;
-	    else n_val = (n_val % n);
-	    break;
-	  default:
-	    ne_warn ("Unsupported op %d in set_eval", arg->op);
-	    break;
-	}
-      }
-      else
-      {
-	char *s, *vs;
-	int out;
-	err = arg_eval (parse, arg, &s);
-	/* ne_warn("arg1 = %s, arg2 = %s", s_val, s); */
-	if ((s_val.buf == NULL) || (s == NULL))
-	{
-	  switch (arg->op)
-	  {
-	    case CS_OP_EQUAL:
-	      vs = (s_val.buf == s) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_NEQUAL:
-	      vs = (s_val.buf != s) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_LT:
-	      vs = ((s_val.buf == NULL) && (s != NULL)) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_LTE:
-	      vs = (s_val.buf == NULL) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_GT:
-	      vs = ((s_val.buf != NULL) && (s == NULL)) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_GTE:
-	      vs = (s == NULL) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_ADD:
-	      if (s_val.buf == NULL) 
-		err = string_set (&s_val, s);
-	      break;
-	    default:
-	      ne_warn ("Unsupported op %d in set_eval", arg->op);
-	      break;
-	  }
-	}
-	else
-	{
-	  out = strcmp (s_val.buf, s);
-	  switch (arg->op)
-	  {
-	    case CS_OP_EQUAL:
-	      vs = (!out) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_NEQUAL:
-	      vs = (out) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_LT:
-	      vs = (out < 0) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_LTE:
-	      vs = (out <= 0) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_GT:
-	      vs = (out > 0) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_GTE:
-	      vs = (out >= 0) ? "1" : "0";
-	      err = string_set (&s_val, vs);
-	      break;
-	    case CS_OP_ADD:
-	      err = string_append (&s_val, s);
-	      break;
-	    default:
-	      ne_warn ("Unsupported op %d in set_eval", arg->op);
-	      break;
-	  }
-	}
-      }
-    }
-    if (err != STATUS_OK) return nerr_pass(err);
-    arg = arg->next;
-  }
+  err = eval_expr(parse, &(node->arg2), &val);
+  if (err) return nerr_pass (err);
 
-  if (is_num)
+  if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM))
   { 
     char buf[256];
+    long int n_val;
+
+    n_val = arg_eval_num (parse, &val);
     snprintf (buf, sizeof(buf), "%ld", n_val);
     err = var_set_value (parse, node->arg1.s, buf);
   }
   else
   {
-    if (s_val.buf)
+    char *s = arg_eval (parse, &val);
+    /* Do we set it to blank if s == NULL? */
+    if (s)
     {
-      err = var_set_value (parse, node->arg1.s, s_val.buf);
+      err = var_set_value (parse, node->arg1.s, s);
     }
   }
-  if (s_val.buf) string_clear (&s_val);
+  if (val.op_type == CS_TYPE_STRING_ALLOC)
+    free(val.s);
 
   *next = node->next;
   return nerr_pass (err);
@@ -2192,13 +1972,13 @@
     if (err) return nerr_pass (err);
     if (node->cmd)
     {
-      if (node->arg1.type)
+      if (node->arg1.op_type)
       {
-	if (node->arg1.type == CS_TYPE_NUM)
+	if (node->arg1.op_type == CS_TYPE_NUM)
 	{
 	  snprintf (buf, blen, "%ld ", node->arg1.n);
 	}
-	else if (node->arg1.type == CS_TYPE_MACRO)
+	else if (node->arg1.op_type == CS_TYPE_MACRO)
 	{
 	  snprintf (buf, blen, "%s ", node->arg1.macro->name);
 	}
@@ -2209,9 +1989,9 @@
 	err = cb (ctx, buf);
 	if (err) return nerr_pass (err);
       }
-      if (node->arg2.type)
+      if (node->arg2.op_type)
       {
-	if (node->arg2.type == CS_TYPE_NUM)
+	if (node->arg2.op_type == CS_TYPE_NUM)
 	{
 	  snprintf (buf, blen, "%ld", node->arg2.n);
 	}
@@ -2228,7 +2008,7 @@
 	arg = node->vargs;
 	while (arg)
 	{
-	  if (arg->type == CS_TYPE_NUM)
+	  if (arg->op_type == CS_TYPE_NUM)
 	  {
 	    snprintf (buf, blen, "%ld ", arg->n);
 	  }
@@ -2277,6 +2057,7 @@
   return nerr_pass (dump_node (parse, node, 0, ctx, cb, buf, sizeof(buf)));
 }
 
+#if 0
 static char *node_name (CSTREE *node)
 {
   static char buf[256];
@@ -2397,12 +2178,12 @@
     s = repr_string_alloc (node->arg1.s);
     if (s == NULL)
       return nerr_raise(NERR_NOMEM, "Unable to allocate space for repr");
-    fprintf (fp, "\n\t  { %d, %s, %ld }, ", node->arg1.type, s, node->arg1.n);
+    fprintf (fp, "\n\t  { %d, %s, %ld }, ", node->arg1.op_type, s, node->arg1.n);
     free(s);
     s = repr_string_alloc (node->arg2.s);
     if (s == NULL)
       return nerr_raise(NERR_NOMEM, "Unable to allocate space for repr");
-    fprintf (fp, "\n\t  { %d, %s, %ld }, ", node->arg2.type, s, node->arg2.n);
+    fprintf (fp, "\n\t  { %d, %s, %ld }, ", node->arg2.op_type, s, node->arg2.n);
     free(s);
     if (node->case_0)
       fprintf (fp, "\n\t%d, &%s, ", node->op, node_name(node->case_0));
@@ -2458,4 +2239,5 @@
   fclose(fp);
   return nerr_pass (err);
 }
+#endif
 
diff -bru clearsilver-0.2.1/cs/test.hdf clearsilver-0.3/cs/test.hdf
--- clearsilver-0.2.1/cs/test.hdf	Fri Sep 14 18:23:23 2001
+++ clearsilver-0.3/cs/test.hdf	Sat Sep 15 17:08:55 2001
@@ -58,3 +58,5 @@
 
 My.Test : Days.0.Abbr
 My.Test2 : Days.0
+
+Color = #fffff
diff -bru clearsilver-0.2.1/cs/test4.cs.gold clearsilver-0.3/cs/test4.cs.gold
--- clearsilver-0.2.1/cs/test4.cs.gold	Fri Jul  6 00:29:42 2001
+++ clearsilver-0.3/cs/test4.cs.gold	Sat Sep 15 16:38:40 2001
@@ -8,7 +8,7 @@
 
 
 
-50
+30
 
 
 Worn Out wow
Only in clearsilver-0.3/cs: test5.cs
Only in clearsilver-0.3/cs: test5.cs.gold
Only in clearsilver-0.3/cs: test6.cs
Only in clearsilver-0.3/cs: test6.cs.gold
