• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2001-2004 Brandon Long
3  * All Rights Reserved.
4  *
5  * ClearSilver Templating System
6  *
7  * This code is made available under the terms of the ClearSilver License.
8  * http://www.clearsilver.net/license.hdf
9  *
10  */
11 
12 /*
13  * TODO: there is some really ugly pseudo reference counting in here
14  * for allocation of temporary strings (and passing references).  See the alloc
15  * member of various structs for details.  We should move this to an arena
16  * allocator so we can just allocate whenever we need to and just clean up
17  * all the allocation at the end (may require two arenas: one for parese and
18  * one for render)
19  */
20 
21 #include "cs_config.h"
22 
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <limits.h>
33 #include <stdarg.h>
34 
35 #ifdef ENABLE_GETTEXT
36 #include <libintl.h>
37 #endif
38 
39 #include "util/neo_misc.h"
40 #include "util/neo_err.h"
41 #include "util/neo_files.h"
42 #include "util/neo_str.h"
43 #include "util/ulist.h"
44 #include "cs.h"
45 
46 /* turn on some debug output for expressions */
47 #define DEBUG_EXPR_PARSE 0
48 #define DEBUG_EXPR_EVAL 0
49 
50 typedef enum
51 {
52   ST_SAME = 0,
53   ST_GLOBAL = 1<<0,
54   ST_IF = 1<<1,
55   ST_ELSE = 1<<2,
56   ST_EACH = 1<<3,
57   ST_WITH = 1<<4,
58   ST_POP = 1<<5,
59   ST_DEF = 1<<6,
60   ST_LOOP =  1<<7,
61   ST_ALT = 1<<8,
62   ST_ESCAPE = 1<<9,
63 } CS_STATE;
64 
65 #define ST_ANYWHERE (ST_EACH | ST_WITH | ST_ELSE | ST_IF | ST_GLOBAL | ST_DEF | ST_LOOP | ST_ALT | ST_ESCAPE)
66 
67 typedef struct _stack_entry
68 {
69   CS_STATE state;
70   NEOS_ESCAPE escape;
71   CSTREE *tree;
72   CSTREE *next_tree;
73   int num_local;
74   int location;
75 } STACK_ENTRY;
76 
77 static NEOERR *literal_parse (CSPARSE *parse, int cmd, char *arg);
78 static NEOERR *literal_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
79 static NEOERR *name_parse (CSPARSE *parse, int cmd, char *arg);
80 static NEOERR *name_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
81 static NEOERR *var_parse (CSPARSE *parse, int cmd, char *arg);
82 static NEOERR *var_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
83 static NEOERR *evar_parse (CSPARSE *parse, int cmd, char *arg);
84 static NEOERR *lvar_parse (CSPARSE *parse, int cmd, char *arg);
85 static NEOERR *lvar_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
86 static NEOERR *if_parse (CSPARSE *parse, int cmd, char *arg);
87 static NEOERR *if_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
88 static NEOERR *else_parse (CSPARSE *parse, int cmd, char *arg);
89 static NEOERR *elif_parse (CSPARSE *parse, int cmd, char *arg);
90 static NEOERR *endif_parse (CSPARSE *parse, int cmd, char *arg);
91 static NEOERR *each_with_parse (CSPARSE *parse, int cmd, char *arg);
92 static NEOERR *each_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
93 static NEOERR *with_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
94 static NEOERR *end_parse (CSPARSE *parse, int cmd, char *arg);
95 static NEOERR *include_parse (CSPARSE *parse, int cmd, char *arg);
96 static NEOERR *linclude_parse (CSPARSE *parse, int cmd, char *arg);
97 static NEOERR *linclude_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
98 static NEOERR *def_parse (CSPARSE *parse, int cmd, char *arg);
99 static NEOERR *skip_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
100 static NEOERR *call_parse (CSPARSE *parse, int cmd, char *arg);
101 static NEOERR *call_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
102 static NEOERR *set_parse (CSPARSE *parse, int cmd, char *arg);
103 static NEOERR *set_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
104 static NEOERR *loop_parse (CSPARSE *parse, int cmd, char *arg);
105 static NEOERR *loop_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
106 static NEOERR *alt_parse (CSPARSE *parse, int cmd, char *arg);
107 static NEOERR *alt_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
108 static NEOERR *escape_parse (CSPARSE *parse, int cmd, char *arg);
109 static NEOERR *escape_eval (CSPARSE *parse, CSTREE *node, CSTREE **next);
110 
111 static NEOERR *render_node (CSPARSE *parse, CSTREE *node);
112 static NEOERR *cs_init_internal (CSPARSE **parse, HDF *hdf, CSPARSE *parent);
113 static int rearrange_for_call(CSARG **args);
114 
115 typedef struct _cmds
116 {
117   char *cmd;
118   int cmdlen;
119   CS_STATE allowed_state;
120   CS_STATE next_state;
121   NEOERR* (*parse_handler)(CSPARSE *parse, int cmd, char *arg);
122   NEOERR* (*eval_handler)(CSPARSE *parse, CSTREE *node, CSTREE **next);
123   int has_arg;
124 } CS_CMDS;
125 
126 CS_CMDS Commands[] = {
127   {"literal", sizeof("literal")-1, ST_ANYWHERE,     ST_SAME,
128     literal_parse, literal_eval, 0},
129   {"name",     sizeof("name")-1,     ST_ANYWHERE,     ST_SAME,
130     name_parse, name_eval,     1},
131   {"var",     sizeof("var")-1,     ST_ANYWHERE,     ST_SAME,
132     var_parse, var_eval,     1},
133   {"uvar",     sizeof("uvar")-1,     ST_ANYWHERE,     ST_SAME,
134     var_parse, var_eval,     1},
135   {"evar",    sizeof("evar")-1,    ST_ANYWHERE,     ST_SAME,
136     evar_parse, skip_eval,    1},
137   {"lvar",    sizeof("lvar")-1,    ST_ANYWHERE,     ST_SAME,
138     lvar_parse, lvar_eval,    1},
139   {"if",      sizeof("if")-1,      ST_ANYWHERE,     ST_IF,
140     if_parse, if_eval,      1},
141   {"else",    sizeof("else")-1,    ST_IF,           ST_POP | ST_ELSE,
142     else_parse, skip_eval,    0},
143   {"elseif",  sizeof("elseif")-1,  ST_IF,           ST_SAME,
144     elif_parse, if_eval,   1},
145   {"elif",    sizeof("elif")-1,    ST_IF,           ST_SAME,
146     elif_parse, if_eval,   1},
147   {"/if",     sizeof("/if")-1,     ST_IF | ST_ELSE, ST_POP,
148     endif_parse, skip_eval,   0},
149   {"each",    sizeof("each")-1,    ST_ANYWHERE,     ST_EACH,
150     each_with_parse, each_eval,    1},
151   {"/each",   sizeof("/each")-1,   ST_EACH,         ST_POP,
152     end_parse, skip_eval, 0},
153   {"with",    sizeof("each")-1,    ST_ANYWHERE,     ST_WITH,
154     each_with_parse, with_eval,    1},
155   {"/with",   sizeof("/with")-1,   ST_WITH,         ST_POP,
156     end_parse, skip_eval, 0},
157   {"include", sizeof("include")-1, ST_ANYWHERE,     ST_SAME,
158     include_parse, skip_eval, 1},
159   {"linclude", sizeof("linclude")-1, ST_ANYWHERE,     ST_SAME,
160     linclude_parse, linclude_eval, 1},
161   {"def",     sizeof("def")-1,     ST_ANYWHERE,     ST_DEF,
162     def_parse, skip_eval, 1},
163   {"/def",    sizeof("/def")-1,    ST_DEF,          ST_POP,
164     end_parse, skip_eval, 0},
165   {"call",    sizeof("call")-1,    ST_ANYWHERE,     ST_SAME,
166     call_parse, call_eval, 1},
167   {"set",    sizeof("set")-1,    ST_ANYWHERE,     ST_SAME,
168     set_parse, set_eval, 1},
169   {"loop",    sizeof("loop")-1,    ST_ANYWHERE,     ST_LOOP,
170     loop_parse, loop_eval, 1},
171   {"/loop",    sizeof("/loop")-1,    ST_LOOP,     ST_POP,
172     end_parse, skip_eval, 1},
173   {"alt",    sizeof("alt")-1,    ST_ANYWHERE,     ST_ALT,
174     alt_parse, alt_eval, 1},
175   {"/alt",    sizeof("/alt")-1,    ST_ALT,     ST_POP,
176     end_parse, skip_eval, 1},
177   {"escape",    sizeof("escape")-1,    ST_ANYWHERE,     ST_ESCAPE,
178     escape_parse, escape_eval, 1},
179   {"/escape",    sizeof("/escape")-1,    ST_ESCAPE,     ST_POP,
180     end_parse, skip_eval, 1},
181   {NULL},
182 };
183 
184 /* Possible Config.VarEscapeMode values */
185 typedef struct _escape_modes
186 {
187   char *mode; /* Add space for NUL */
188   NEOS_ESCAPE context; /* Context of the name */
189 } CS_ESCAPE_MODES;
190 
191 CS_ESCAPE_MODES EscapeModes[] = {
192   {"none", NEOS_ESCAPE_NONE},
193   {"html", NEOS_ESCAPE_HTML},
194   {"js",   NEOS_ESCAPE_SCRIPT},
195   {"url",  NEOS_ESCAPE_URL},
196   {NULL},
197 };
198 
199 
200 /* **** CS alloc/dealloc ******************************************** */
201 
202 static int NodeNumber = 0;
203 
init_node_pos(CSTREE * node,CSPARSE * parse)204 static void init_node_pos(CSTREE *node, CSPARSE *parse)
205 {
206   CS_POSITION *pos = &parse->pos;
207   char *data;
208 
209   if (parse->offset < pos->cur_offset) {
210     /* Oops, we went backwards in file, is this an error? */
211     node->linenum = -1;
212     node->colnum = parse->offset;
213     return;
214   }
215 
216   /* Start counting from 1 not 0 */
217   if (pos->line == 0) pos->line = 1;
218   if (pos->col == 0) pos->col = 1;
219 
220   if (parse->context == NULL) {
221     /* Not in a file */
222     node->fname = NULL;
223   }
224   else {
225     node->fname = strdup(parse->context);
226     if (node->fname == NULL) {
227       /* malloc error, cannot proceed */
228       node->linenum = -1;
229       return;
230     }
231   }
232 
233   data = parse->context_string;
234   if (data == NULL) {
235     node->linenum = -1;
236     return;
237   }
238 
239   while (pos->cur_offset < parse->offset) {
240     if (data[pos->cur_offset] == '\n') {
241       pos->line++;
242       pos->col = 1;
243     }
244     else {
245       pos->col++;
246     }
247 
248     pos->cur_offset++;
249   }
250 
251   node->linenum = pos->line;
252   node->colnum = pos->col;
253 
254   return;
255 
256 }
257 
alloc_node(CSTREE ** node,CSPARSE * parse)258 static NEOERR *alloc_node (CSTREE **node, CSPARSE *parse)
259 {
260   CSTREE *my_node;
261 
262   *node = NULL;
263   my_node = (CSTREE *) calloc (1, sizeof (CSTREE));
264   if (my_node == NULL)
265     return nerr_raise (NERR_NOMEM, "Unable to allocate memory for node");
266 
267   my_node->cmd = 0;
268   my_node->node_num = NodeNumber++;
269 
270   *node = my_node;
271 
272   if (parse->audit_mode) {
273     init_node_pos(my_node, parse);
274   }
275   return STATUS_OK;
276 }
277 
278 /* TODO: make these deallocations linear and not recursive */
dealloc_arg(CSARG ** arg)279 static void dealloc_arg (CSARG **arg)
280 {
281   CSARG *p;
282 
283   if (*arg == NULL) return;
284   p = *arg;
285   if (p->expr1) dealloc_arg (&(p->expr1));
286   if (p->expr2) dealloc_arg (&(p->expr2));
287   if (p->next) dealloc_arg (&(p->next));
288 
289   if (p->argexpr) free(p->argexpr);
290 
291   free(p);
292   *arg = NULL;
293 }
294 
dealloc_node(CSTREE ** node)295 static void dealloc_node (CSTREE **node)
296 {
297   CSTREE *my_node;
298 
299   if (*node == NULL) return;
300   my_node = *node;
301   if (my_node->case_0) dealloc_node (&(my_node->case_0));
302   if (my_node->case_1) dealloc_node (&(my_node->case_1));
303   if (my_node->next) dealloc_node (&(my_node->next));
304   if (my_node->vargs) dealloc_arg (&(my_node->vargs));
305   if (my_node->arg1.expr1) dealloc_arg (&(my_node->arg1.expr1));
306   if (my_node->arg1.expr2) dealloc_arg (&(my_node->arg1.expr2));
307   if (my_node->arg1.next) dealloc_arg (&(my_node->arg1.next));
308   if (my_node->arg2.expr1) dealloc_arg (&(my_node->arg2.expr1));
309   if (my_node->arg2.expr2) dealloc_arg (&(my_node->arg2.expr2));
310   if (my_node->arg2.next) dealloc_arg (&(my_node->arg2.next));
311 
312   if (my_node->arg1.argexpr) free(my_node->arg1.argexpr);
313   if (my_node->arg2.argexpr) free(my_node->arg2.argexpr);
314   if (my_node->fname) free(my_node->fname);
315 
316   free(my_node);
317   *node = NULL;
318 }
319 
dealloc_macro(CS_MACRO ** macro)320 static void dealloc_macro (CS_MACRO **macro)
321 {
322   CS_MACRO *my_macro;
323 
324   if (*macro == NULL) return;
325   my_macro = *macro;
326   if (my_macro->name) free (my_macro->name);
327   if (my_macro->args) dealloc_arg (&(my_macro->args));
328   if (my_macro->next) dealloc_macro (&(my_macro->next));
329   free (my_macro);
330   *macro = NULL;
331 }
332 
dealloc_function(CS_FUNCTION ** csf)333 static void dealloc_function (CS_FUNCTION **csf)
334 {
335   CS_FUNCTION *my_csf;
336 
337   if (*csf == NULL) return;
338   my_csf = *csf;
339   if (my_csf->name) free (my_csf->name);
340   if (my_csf->next) dealloc_function (&(my_csf->next));
341   free (my_csf);
342   *csf = NULL;
343 }
344 
find_open_delim(CSPARSE * parse,char * buf,int x,int len)345 static int find_open_delim (CSPARSE *parse, char *buf, int x, int len)
346 {
347   char *p;
348   int ws_index = 2+parse->taglen;
349 
350   while (x < len)
351   {
352     p = strchr (&(buf[x]), '<');
353     if (p == NULL) return -1;
354     if (p[1] == '?' && !strncasecmp(&p[2], parse->tag, parse->taglen) &&
355 	(p[ws_index] == ' ' || p[ws_index] == '\n' || p[ws_index] == '\t' || p[ws_index] == '\r'))
356       /*
357     if (p[1] && p[1] == '?' &&
358 	p[2] && (p[2] == 'C' || p[2] == 'c') &&
359 	p[3] && (p[3] == 'S' || p[3] == 's') &&
360 	p[4] && (p[4] == ' ' || p[4] == '\n' || p[4] == '\t' || p[4] == '\r'))
361 	*/
362     {
363       return p - buf;
364     }
365     x = p - buf + 1;
366   }
367   return -1;
368 }
369 
_store_error(CSPARSE * parse,NEOERR * err)370 static NEOERR *_store_error (CSPARSE *parse, NEOERR *err)
371 {
372   CS_ERROR *ptr;
373   CS_ERROR *node;
374 
375   node = (CS_ERROR *) calloc(1, sizeof(CS_ERROR));
376   if (node == NULL)
377   {
378     return nerr_raise (NERR_NOMEM,
379         "Unable to allocate memory for error entry");
380   }
381 
382   node->err = err;
383 
384   if (parse->err_list == NULL)
385   {
386     parse->err_list = node;
387     return STATUS_OK;
388   }
389 
390   ptr = parse->err_list;
391   while (ptr->next != NULL)
392     ptr = ptr->next;
393 
394   ptr->next = node;
395   return STATUS_OK;
396 
397 }
398 
cs_parse_file(CSPARSE * parse,const char * path)399 NEOERR *cs_parse_file (CSPARSE *parse, const char *path)
400 {
401   NEOERR *err;
402   char *ibuf;
403   const char *save_context;
404   int save_infile;
405   char fpath[_POSIX_PATH_MAX];
406   CS_POSITION pos;
407 
408   if (path == NULL)
409     return nerr_raise (NERR_ASSERT, "path is NULL");
410 
411   if (parse->fileload)
412   {
413     err = parse->fileload(parse->fileload_ctx, parse->hdf, path, &ibuf);
414   }
415   else
416   {
417     if (path[0] != '/')
418     {
419       err = hdf_search_path (parse->hdf, path, fpath);
420       if (parse->global_hdf && nerr_handle(&err, NERR_NOT_FOUND))
421         err = hdf_search_path(parse->global_hdf, path, fpath);
422       if (err != STATUS_OK) return nerr_pass(err);
423       path = fpath;
424     }
425 
426     err = ne_load_file (path, &ibuf);
427   }
428   if (err) return nerr_pass (err);
429 
430   save_context = parse->context;
431   parse->context = path;
432   save_infile = parse->in_file;
433   parse->in_file = 1;
434 
435   if (parse->audit_mode) {
436     /* Save previous position before parsing the new file */
437     memcpy(&pos, &parse->pos, sizeof(CS_POSITION));
438 
439     parse->pos.line = 0;
440     parse->pos.col = 0;
441     parse->pos.cur_offset = 0;
442   }
443 
444   err = cs_parse_string(parse, ibuf, strlen(ibuf));
445 
446   if (parse->audit_mode) {
447     memcpy(&parse->pos, &pos, sizeof(CS_POSITION));
448   }
449 
450   parse->in_file = save_infile;
451   parse->context = save_context;
452 
453   return nerr_pass(err);
454 }
455 
find_context(CSPARSE * parse,int offset,char * buf,size_t blen)456 static char *find_context (CSPARSE *parse, int offset, char *buf, size_t blen)
457 {
458   FILE *fp;
459   int dump_err = 1;
460   char line[256];
461   int count = 0;
462   int lineno = 0;
463   char *data;
464 
465   if (offset == -1) offset = parse->offset;
466 
467   do
468   {
469     if (parse->in_file && parse->context)
470     {
471       /* Open the file and find which line we're on */
472 
473       fp = fopen(parse->context, "r");
474       if (fp == NULL) {
475 	ne_warn("Unable to open context %s", parse->context);
476 	break;
477       }
478       while (fgets(line, sizeof(line), fp) != NULL)
479       {
480 	count += strlen(line);
481 	if (strchr(line, '\n') != NULL)
482 	  lineno++;
483 	if (count > offset) break;
484       }
485       fclose (fp);
486       snprintf (buf, blen, "[%s:%d]", parse->context, lineno);
487     }
488     else
489     {
490       data = parse->context_string;
491       if (data != NULL)
492       {
493 	lineno = 1;
494 	while (count < offset)
495 	{
496 	  if (data[count++] == '\n') lineno++;
497 	}
498 	if (parse->context)
499 	  snprintf (buf, blen, "[%s:~%d]", parse->context, lineno);
500 	else
501 	  snprintf (buf, blen, "[lineno:~%d]", lineno);
502       }
503       else
504       {
505 	if (parse->context)
506 	  snprintf (buf, blen, "[%s:%d]", parse->context, offset);
507 	else
508 	  snprintf (buf, blen, "[offset:%d]", offset);
509       }
510     }
511     dump_err = 0;
512   } while (0);
513   if (dump_err)
514   {
515     if (parse->context)
516       snprintf (buf, blen, "[-E- %s:%d]", parse->context, offset);
517     else
518       snprintf (buf, blen, "[-E- offset:%d]", offset);
519   }
520 
521   return buf;
522 }
523 
expand_state(CS_STATE state)524 static char *expand_state (CS_STATE state)
525 {
526   static char buf[256];
527 
528   if (state & ST_GLOBAL)
529     return "GLOBAL";
530   else if (state & ST_IF)
531     return "IF";
532   else if (state & ST_ELSE)
533     return "ELSE";
534   else if (state & ST_EACH)
535     return "EACH";
536   else if (state & ST_WITH)
537     return "WITH";
538   else if (state & ST_DEF)
539     return "DEF";
540   else if (state & ST_LOOP)
541     return "LOOP";
542   else if (state & ST_ALT)
543     return "ALT";
544   else if (state & ST_ESCAPE)
545     return "ESCAPE";
546 
547   snprintf(buf, sizeof(buf), "Unknown state %d", state);
548   return buf;
549 }
550 
cs_parse_string(CSPARSE * parse,char * ibuf,size_t ibuf_len)551 NEOERR *cs_parse_string (CSPARSE *parse, char *ibuf, size_t ibuf_len)
552 {
553   NEOERR *err = STATUS_OK;
554   STACK_ENTRY *entry, *current_entry;
555   char *p;
556   char *token;
557   int done = 0;
558   int i, n;
559   char *arg;
560   int initial_stack_depth;
561   int initial_offset;
562   char *initial_context;
563   char tmp[256];
564 
565   err = uListAppend(parse->alloc, ibuf);
566   if (err)
567   {
568     free (ibuf);
569     return nerr_pass (err);
570   }
571 
572   initial_stack_depth = uListLength(parse->stack);
573   initial_offset = parse->offset;
574   initial_context = parse->context_string;
575 
576   parse->offset = 0;
577   parse->context_string = ibuf;
578   while (!done)
579   {
580     /* Stage 1: Find <?cs starter */
581     i = find_open_delim (parse, ibuf, parse->offset, ibuf_len);
582     if (i >= 0)
583     {
584       ibuf[i] = '\0';
585       /* Create literal with data up until start delim */
586       /* ne_warn ("literal -> %d-%d", parse->offset, i);  */
587       err = (*(Commands[0].parse_handler))(parse, 0, &(ibuf[parse->offset]));
588       /* skip delim */
589       token = &(ibuf[i+3+parse->taglen]);
590       while (*token && isspace(*token)) token++;
591 
592       p = strstr (token, "?>");
593       if (p == NULL)
594       {
595 	return nerr_raise (NERR_PARSE, "%s Missing end ?> at %s",
596 	    find_context(parse, i, tmp, sizeof(tmp)), &(ibuf[parse->offset]));
597       }
598       *p = '\0';
599       if (strstr (token, "<?") != NULL)
600       {
601 	return nerr_raise (NERR_PARSE, "%s Missing end ?> at %s",
602 	    find_context(parse, i, tmp, sizeof(tmp)),
603 	    token);
604       }
605       parse->offset = p - ibuf + 2;
606       if (token[0] != '#') /* handle comments */
607       {
608 	for (i = 1; Commands[i].cmd; i++)
609 	{
610 	  n = Commands[i].cmdlen;
611 	  if (!strncasecmp(token, Commands[i].cmd, n))
612 	  {
613 	    if ((Commands[i].has_arg && ((token[n] == ':') || (token[n] == '!')))
614 		|| (token[n] == ' ' || token[n] == '\0' || token[n] == '\r' || token[n] == '\n'))
615 	    {
616 	      err = uListGet (parse->stack, -1, (void *)&entry);
617 	      if (err != STATUS_OK) goto cs_parse_done;
618 	      if (!(Commands[i].allowed_state & entry->state))
619 	      {
620 		return nerr_raise (NERR_PARSE,
621 		    "%s Command %s not allowed in %s", Commands[i].cmd,
622 		    find_context(parse, -1, tmp, sizeof(tmp)),
623 		    expand_state(entry->state));
624 	      }
625 	      if (Commands[i].has_arg)
626 	      {
627 		/* Need to parse out arg */
628 		arg = &token[n];
629 		err = (*(Commands[i].parse_handler))(parse, i, arg);
630 	      }
631 	      else
632 	      {
633 		err = (*(Commands[i].parse_handler))(parse, i, NULL);
634 	      }
635 	      if (err != STATUS_OK) goto cs_parse_done;
636 	      if (Commands[i].next_state & ST_POP)
637 	      {
638                 void *ptr;
639 		err = uListPop(parse->stack, &ptr);
640 		if (err != STATUS_OK) goto cs_parse_done;
641                 entry = (STACK_ENTRY *)ptr;
642 		if (entry->next_tree)
643 		  parse->current = entry->next_tree;
644 		else
645 		  parse->current = entry->tree;
646 		free(entry);
647 	      }
648 	      if ((Commands[i].next_state & ~ST_POP) != ST_SAME)
649 	      {
650 		entry = (STACK_ENTRY *) calloc (1, sizeof (STACK_ENTRY));
651 		if (entry == NULL)
652 		  return nerr_raise (NERR_NOMEM,
653 		      "%s Unable to allocate memory for stack entry",
654 		      find_context(parse, -1, tmp, sizeof(tmp)));
655 		entry->state = Commands[i].next_state;
656 		entry->tree = parse->current;
657 		entry->location = parse->offset;
658 		/* Set the new stack escape context to the parent one */
659 		err = uListGet (parse->stack, -1, (void *)&current_entry);
660 		if (err != STATUS_OK) {
661 		  free (entry);
662 		  goto cs_parse_done;
663 		}
664 		entry->escape = current_entry->escape;
665 		/* Get the future escape context from parse because when
666 		 * we parse "escape", the new stack has not yet been established.
667 		 */
668 		entry->escape = parse->escaping.next_stack;
669 		parse->escaping.next_stack = parse->escaping.global_ctx;
670 		err = uListAppend(parse->stack, entry);
671 		if (err != STATUS_OK) {
672 		  free (entry);
673 		  goto cs_parse_done;
674 		}
675 	      }
676 	      break;
677 	    }
678 	  }
679 	}
680 	if (Commands[i].cmd == NULL)
681 	{
682 	  return nerr_raise (NERR_PARSE, "%s Unknown command %s",
683 	      find_context(parse, -1, tmp, sizeof(tmp)), token);
684 	}
685       }
686     }
687     else
688     {
689       /* Create literal with all remaining data */
690       err = (*(Commands[0].parse_handler))(parse, 0, &(ibuf[parse->offset]));
691       done = 1;
692     }
693   }
694   /* Should we check the parse stack here? */
695   while (uListLength(parse->stack) > initial_stack_depth)
696   {
697     err = uListPop(parse->stack, (void *)&entry);
698     if (err != STATUS_OK) goto cs_parse_done;
699     if (entry->state & ~(ST_GLOBAL | ST_POP))
700       return nerr_raise (NERR_PARSE, "%s Non-terminted %s clause",
701 	  find_context(parse, entry->location, tmp, sizeof(tmp)),
702           expand_state(entry->state));
703   }
704 
705 cs_parse_done:
706   parse->offset = initial_offset;
707   parse->context_string = initial_context;
708   parse->escaping.current = NEOS_ESCAPE_NONE;
709   return nerr_pass(err);
710 }
711 
lookup_map(CSPARSE * parse,char * name,char ** rest)712 static CS_LOCAL_MAP * lookup_map (CSPARSE *parse, char *name, char **rest)
713 {
714   CS_LOCAL_MAP *map;
715   char *c;
716 
717   /* This shouldn't happen, but it did once... */
718   if (name == NULL) return NULL;
719   map = parse->locals;
720   c = strchr (name, '.');
721   if (c != NULL) *c = '\0';
722   *rest = c;
723   while (map != NULL)
724   {
725     if (!strcmp (map->name, name))
726     {
727       if (c != NULL) *c = '.';
728       return map;
729     }
730     map = map->next;
731   }
732   if (c != NULL) *c = '.';
733   return NULL;
734 }
735 
var_lookup_obj(CSPARSE * parse,char * name)736 static HDF *var_lookup_obj (CSPARSE *parse, char *name)
737 {
738   CS_LOCAL_MAP *map;
739   char *c;
740   HDF *ret_hdf;
741 
742   map = lookup_map (parse, name, &c);
743   if (map && map->type == CS_TYPE_VAR)
744   {
745     if (c == NULL)
746     {
747       return map->h;
748     }
749     else
750     {
751       return hdf_get_obj (map->h, c+1);
752     }
753   }
754   /* smarti:  Added support for global hdf under local hdf */
755   /* return hdf_get_obj (parse->hdf, name); */
756   ret_hdf = hdf_get_obj (parse->hdf, name);
757   if (ret_hdf == NULL && parse->global_hdf != NULL) {
758     ret_hdf = hdf_get_obj (parse->global_hdf, name);
759   }
760   return ret_hdf;
761 }
762 
763 /* Ugh, I have to write the same walking code because I can't grab the
764  * object for writing, as it might not exist... */
var_set_value(CSPARSE * parse,char * name,char * value)765 static NEOERR *var_set_value (CSPARSE *parse, char *name, char *value)
766 {
767   CS_LOCAL_MAP *map;
768   char *c;
769 
770   map = parse->locals;
771   c = strchr (name, '.');
772   if (c != NULL) *c = '\0';
773   while (map != NULL)
774   {
775     if (!strcmp (map->name, name))
776     {
777       if (map->type == CS_TYPE_VAR)
778       {
779 	if (c == NULL)
780 	{
781           if (map->h == NULL) /* node didn't exist yet */
782             return nerr_pass (hdf_set_value (parse->hdf, map->s, value));
783           else
784             return nerr_pass (hdf_set_value (map->h, NULL, value));
785 	}
786 	else
787 	{
788 	  *c = '.';
789           if (map->h == NULL) /* node didn't exist yet */
790           {
791             NEOERR *err;
792             char *mapped_name = sprintf_alloc("%s%s", map->s, c);
793             if (mapped_name == NULL)
794               return nerr_raise(NERR_NOMEM, "Unable to allocate memory to create mapped name");
795             err = hdf_set_value(parse->hdf, mapped_name, value);
796             free(mapped_name);
797             return nerr_pass(err);
798           }
799 	  return nerr_pass (hdf_set_value (map->h, c+1, value));
800 	}
801       }
802       else
803       {
804 	if (c == NULL)
805 	{
806 	  char *tmp = NULL;
807 	  /* If this is a string, it might be what we're setting,
808 	   * ie <?cs set:value = value ?>
809 	   */
810 	  if (map->type == CS_TYPE_STRING && map->map_alloc)
811 	    tmp = map->s;
812 	  map->type = CS_TYPE_STRING;
813 	  map->map_alloc = 1;
814 	  map->s = strdup(value);
815 	  if (tmp != NULL) free(tmp);
816 	  if (map->s == NULL && value != NULL)
817 	    return nerr_raise(NERR_NOMEM,
818 		"Unable to allocate memory to set var");
819 
820 	  return STATUS_OK;
821 	}
822 	else {
823 	  ne_warn("WARNING!! Trying to set sub element '%s' of local variable '%s' which doesn't map to an HDF variable, ignoring", c+1, map->name);
824 	  return STATUS_OK;
825 	}
826       }
827     }
828     map = map->next;
829   }
830   if (c != NULL) *c = '.';
831   return nerr_pass (hdf_set_value (parse->hdf, name, value));
832 }
833 
var_lookup(CSPARSE * parse,char * name)834 static char *var_lookup (CSPARSE *parse, char *name)
835 {
836   CS_LOCAL_MAP *map;
837   char *c;
838   char* retval;
839 
840   map = lookup_map (parse, name, &c);
841   if (map)
842   {
843     if (map->type == CS_TYPE_VAR)
844     {
845       if (c == NULL)
846       {
847 	return hdf_obj_value (map->h);
848       }
849       else
850       {
851 	return hdf_get_value (map->h, c+1, NULL);
852       }
853     }
854     /* Hmm, if c != NULL, they are asking for a sub member of something
855      * which isn't a var... right now we ignore them, I don't know what
856      * the right thing is */
857     /* hmm, its possible now that they are getting a reference to a
858      * string that will be deleted... where is it used? */
859     else if (map->type == CS_TYPE_STRING)
860     {
861       return map->s;
862     }
863     else if (map->type == CS_TYPE_NUM)
864     {
865       char buf[40];
866       if (map->s) return map->s;
867       snprintf (buf, sizeof(buf), "%ld", map->n);
868       map->s = strdup(buf);
869       map->map_alloc = 1;
870       return map->s;
871     }
872   }
873   /* smarti:  Added support for global hdf under local hdf */
874   /* return hdf_get_value (parse->hdf, name, NULL); */
875   retval = hdf_get_value (parse->hdf, name, NULL);
876   if (retval == NULL && parse->global_hdf != NULL) {
877     retval = hdf_get_value (parse->global_hdf, name, NULL);
878   }
879   return retval;
880 }
881 
var_int_lookup(CSPARSE * parse,char * name)882 long int var_int_lookup (CSPARSE *parse, char *name)
883 {
884   char *vs;
885 
886   vs = var_lookup (parse, name);
887 
888   if (vs == NULL)
889     return 0;
890   else
891     return atoi(vs);
892 }
893 
894 typedef struct _token
895 {
896   CSTOKEN_TYPE type;
897   char *value;
898   size_t len;
899 } CSTOKEN;
900 
901 struct _simple_tokens
902 {
903   BOOL two_chars;
904   char *token;
905   CSTOKEN_TYPE type;
906 } SimpleTokens[] = {
907   { TRUE, "<=", CS_OP_LTE },
908   { TRUE, ">=", CS_OP_GTE },
909   { TRUE, "==", CS_OP_EQUAL },
910   { TRUE, "!=", CS_OP_NEQUAL },
911   { TRUE, "||", CS_OP_OR },
912   { TRUE, "&&", CS_OP_AND },
913   { FALSE, "!", CS_OP_NOT },
914 /* For now, we are still treating this special instead of as an op
915  * If we make this an op, then we'd have to determine how to handle
916  * NUM types without doing something like #"5" */
917 /*  { FALSE, "#", CS_OP_NUM }, */
918   { FALSE, "?", CS_OP_EXISTS },
919   { FALSE, "<", CS_OP_LT },
920   { FALSE, ">", CS_OP_GT },
921   { FALSE, "+", CS_OP_ADD },
922   { FALSE, "-", CS_OP_SUB },
923   { FALSE, "*", CS_OP_MULT },
924   { FALSE, "/", CS_OP_DIV },
925   { FALSE, "%", CS_OP_MOD },
926   { FALSE, "(", CS_OP_LPAREN },
927   { FALSE, ")", CS_OP_RPAREN },
928   { FALSE, "[", CS_OP_LBRACKET },
929   { FALSE, "]", CS_OP_RBRACKET },
930   { FALSE, ".", CS_OP_DOT },
931   { FALSE, ",", CS_OP_COMMA },
932   { FALSE, NULL, 0 }
933 };
934 
935 #define MAX_TOKENS 256
936 
parse_tokens(CSPARSE * parse,char * arg,CSTOKEN * tokens,int * used_tokens)937 static NEOERR *parse_tokens (CSPARSE *parse, char *arg, CSTOKEN *tokens,
938     int *used_tokens)
939 {
940   char tmp[256];
941   int ntokens = 0;
942   int x;
943   BOOL found;
944   BOOL last_is_op = 1;
945   char *p, *p2;
946   char *expr = arg;
947 
948   while (arg && *arg != '\0')
949   {
950     while (*arg && isspace(*arg)) arg++;
951     if (*arg == '\0') break;
952     x = 0;
953     found = FALSE;
954 
955     /* If we already saw an operator, and this is a +/-, assume its
956      * a number */
957     if (!(last_is_op && (*arg == '+' || *arg == '-')))
958     {
959       while ((found == FALSE) && SimpleTokens[x].token)
960       {
961 	if (((SimpleTokens[x].two_chars == TRUE) &&
962 	      (*arg == SimpleTokens[x].token[0]) &&
963 	      (*(arg + 1) == SimpleTokens[x].token[1])) ||
964 	    ((SimpleTokens[x].two_chars == FALSE) &&
965 	     (*arg == SimpleTokens[x].token[0])))
966 	{
967 	  tokens[ntokens++].type = SimpleTokens[x].type;
968 	  found = TRUE;
969 	  arg++;
970 	  if (SimpleTokens[x].two_chars) arg++;
971 	}
972 	x++;
973       }
974       /* Another special case: RPAREN and RBRACKET can have another op
975        * after it */
976       if (found && !(tokens[ntokens-1].type == CS_OP_RPAREN || tokens[ntokens-1].type == CS_OP_RBRACKET))
977 	last_is_op = 1;
978     }
979 
980     if (found == FALSE)
981     {
982       if (*arg == '#')
983       {
984         /* TODO: make # an operator and not syntax */
985 	arg++;
986 	tokens[ntokens].type = CS_TYPE_NUM;
987 	tokens[ntokens].value = arg;
988 	strtol(arg, &p, 0);
989 	if (p == arg)
990 	{
991 	  tokens[ntokens].type = CS_TYPE_VAR_NUM;
992 	  p = strpbrk(arg, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
993 	  if (p == arg)
994 	    return nerr_raise (NERR_PARSE, "%s Missing varname/number after #: %s",
995 		find_context(parse, -1, tmp, sizeof(tmp)), arg);
996 	}
997 	if (p == NULL)
998 	  tokens[ntokens].len = strlen(arg);
999 	else
1000 	  tokens[ntokens].len = p - arg;
1001 	ntokens++;
1002 	arg = p;
1003       }
1004       else if (*arg == '"')
1005       {
1006 	arg++;
1007 	tokens[ntokens].type = CS_TYPE_STRING;
1008 	tokens[ntokens].value = arg;
1009 	p = strchr (arg, '"');
1010 	if (p == NULL)
1011 	  return nerr_raise (NERR_PARSE, "%s Missing end of string: %s",
1012 	      find_context(parse, -1, tmp, sizeof(tmp)), arg);
1013 	tokens[ntokens].len = p - arg;
1014 	ntokens++;
1015 	arg = p + 1;
1016       }
1017       else if (*arg == '\'')
1018       {
1019 	arg++;
1020 	tokens[ntokens].type = CS_TYPE_STRING;
1021 	tokens[ntokens].value = arg;
1022 	p = strchr (arg, '\'');
1023 	if (p == NULL)
1024 	  return nerr_raise (NERR_PARSE, "%s Missing end of string: %s",
1025 	      find_context(parse, -1, tmp, sizeof(tmp)), arg);
1026 	tokens[ntokens].len = p - arg;
1027 	ntokens++;
1028 	arg = p + 1;
1029       }
1030       else if (*arg == '$')
1031       {
1032         /* TODO: make $ an operator and not syntax */
1033 	arg++;
1034 	tokens[ntokens].type = CS_TYPE_VAR;
1035 	tokens[ntokens].value = arg;
1036 	p = strpbrk(arg, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
1037 	if (p == arg)
1038 	  return nerr_raise (NERR_PARSE, "%s Missing varname after $: %s",
1039 	      find_context(parse, -1, tmp, sizeof(tmp)), arg);
1040 	if (p == NULL)
1041 	  tokens[ntokens].len = strlen(arg);
1042 	else
1043 	  tokens[ntokens].len = p - arg;
1044 	ntokens++;
1045 	arg = p;
1046       }
1047       else
1048       {
1049 	tokens[ntokens].type = CS_TYPE_VAR;
1050 	tokens[ntokens].value = arg;
1051 	/* Special case for Dave: If this is entirely a number, treat it
1052 	 * as one */
1053 	strtol(arg, &p2, 0);
1054 	p = strpbrk(arg, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
1055 	/* This is complicated because +/- is valid in a number, but not
1056 	 * in a varname */
1057 	if (p2 != arg && (p <= p2 || (p == NULL && *p2 == '\0')))
1058 	{
1059 	  tokens[ntokens].type = CS_TYPE_NUM;
1060 	  tokens[ntokens].len = p2 - arg;
1061 	  arg = p2;
1062 	}
1063 	else
1064 	{
1065 	  if (p == arg)
1066 	    return nerr_raise (NERR_PARSE,
1067 		"%s Var arg specified with no varname: %s",
1068 		find_context(parse, -1, tmp, sizeof(tmp)), arg);
1069 	  if (p == NULL)
1070 	    tokens[ntokens].len = strlen(arg);
1071 	  else
1072 	    tokens[ntokens].len = p - arg;
1073 	  arg = p;
1074 	}
1075 	ntokens++;
1076       }
1077       last_is_op = 0;
1078     }
1079     if (ntokens >= MAX_TOKENS)
1080 	return nerr_raise (NERR_PARSE,
1081 	    "%s Expression exceeds maximum number of tokens of %d: %s",
1082 	    find_context(parse, -1, tmp, sizeof(tmp)), MAX_TOKENS, expr);
1083   }
1084   *used_tokens = ntokens;
1085   return STATUS_OK;
1086 }
1087 
1088 CSTOKEN_TYPE OperatorOrder[] = {
1089   CS_OP_COMMA,
1090   CS_OP_OR,
1091   CS_OP_AND,
1092   CS_OP_EQUAL | CS_OP_NEQUAL,
1093   CS_OP_GT | CS_OP_GTE | CS_OP_LT | CS_OP_LTE,
1094   CS_OP_ADD | CS_OP_SUB,
1095   CS_OP_MULT | CS_OP_DIV | CS_OP_MOD,
1096   CS_OP_NOT | CS_OP_EXISTS,
1097   CS_OP_LBRACKET | CS_OP_DOT | CS_OP_LPAREN,
1098   0
1099 };
1100 
expand_token_type(CSTOKEN_TYPE t_type,int more)1101 static char *expand_token_type(CSTOKEN_TYPE t_type, int more)
1102 {
1103   switch (t_type)
1104   {
1105     case CS_OP_EXISTS: return "?";
1106     case CS_OP_NOT: return "!";
1107     case CS_OP_NUM: return "#";
1108     case CS_OP_EQUAL: return "==";
1109     case CS_OP_NEQUAL: return "!=";
1110     case CS_OP_LT: return "<";
1111     case CS_OP_LTE: return "<=";
1112     case CS_OP_GT: return ">";
1113     case CS_OP_GTE: return ">=";
1114     case CS_OP_AND: return "&&";
1115     case CS_OP_OR: return "||";
1116     case CS_OP_ADD: return "+";
1117     case CS_OP_SUB: return "-";
1118     case CS_OP_MULT: return "*";
1119     case CS_OP_DIV: return "/";
1120     case CS_OP_MOD: return "%";
1121     case CS_OP_LPAREN: return "(";
1122     case CS_OP_RPAREN: return ")";
1123     case CS_OP_LBRACKET: return "[";
1124     case CS_OP_RBRACKET: return "]";
1125     case CS_OP_DOT : return ".";
1126     case CS_OP_COMMA : return ",";
1127     case CS_TYPE_STRING: return more ? "STRING" : "s";
1128     case CS_TYPE_NUM: return more ? "NUM" : "n";
1129     case CS_TYPE_VAR: return more ? "VAR" : "v";
1130     case CS_TYPE_VAR_NUM: return more ? "VARNUM" : "vn";
1131     case CS_TYPE_MACRO: return more ? "MACRO" : "m";
1132     case CS_TYPE_FUNCTION: return more ? "FUNC" : "f";
1133     default: return "u";
1134   }
1135   return "u";
1136 }
1137 
token_list(CSTOKEN * tokens,int ntokens,char * buf,size_t buflen)1138 static char *token_list (CSTOKEN *tokens, int ntokens, char *buf, size_t buflen)
1139 {
1140   char *p = buf;
1141   int i, t;
1142   char save;
1143 
1144   for (i = 0; i < ntokens && buflen > 0; i++)
1145   {
1146     if (tokens[i].value)
1147     {
1148       save = tokens[i].value[tokens[i].len];
1149       tokens[i].value[tokens[i].len] = '\0';
1150       t = snprintf(p, buflen, "%s%d:%s:'%s'", i ? "  ":"", i, expand_token_type(tokens[i].type, 0), tokens[i].value);
1151       tokens[i].value[tokens[i].len] = save;
1152     }
1153     else
1154     {
1155       t = snprintf(p, buflen, "%s%d:%s", i ? "  ":"", i, expand_token_type(tokens[i].type, 0));
1156     }
1157     if (t == -1 || t >= buflen) return buf;
1158     buflen -= t;
1159     p += t;
1160   }
1161   return buf;
1162 }
1163 
parse_expr2(CSPARSE * parse,CSTOKEN * tokens,int ntokens,int lvalue,CSARG * arg)1164 static NEOERR *parse_expr2 (CSPARSE *parse, CSTOKEN *tokens, int ntokens, int lvalue, CSARG *arg)
1165 {
1166   NEOERR *err = STATUS_OK;
1167   char tmp[256];
1168   char tmp2[256];
1169   int x, op;
1170   int m;
1171 
1172 #if DEBUG_EXPR_PARSE
1173   fprintf(stderr, "%s\n", token_list(tokens, ntokens, tmp, sizeof(tmp)));
1174   for (x = 0; x < ntokens; x++)
1175   {
1176     fprintf (stderr, "%s ", expand_token_type(tokens[x].type, 0));
1177   }
1178   fprintf(stderr, "\n");
1179 #endif
1180 
1181   /* Not quite sure what to do with this case... */
1182   if (ntokens == 0)
1183   {
1184     return nerr_raise (NERR_PARSE, "%s Bad Expression",
1185 	find_context(parse, -1, tmp, sizeof(tmp)));
1186   }
1187   if (ntokens == 1)
1188   {
1189     x = 0;
1190     if (tokens[0].type & CS_TYPES)
1191     {
1192       arg->s = tokens[0].value;
1193       if (tokens[0].len >= 0)
1194 	arg->s[tokens[0].len] = '\0';
1195       arg->op_type = tokens[0].type;
1196 
1197       if (tokens[x].type == CS_TYPE_NUM)
1198 	arg->n = strtol(arg->s, NULL, 0);
1199       return STATUS_OK;
1200     }
1201     else
1202     {
1203       return nerr_raise (NERR_PARSE,
1204 	  "%s Terminal token is not an argument, type is %s",
1205 	  find_context(parse, -1, tmp, sizeof(tmp)), expand_token_type(tokens[0].type, 0));
1206     }
1207   }
1208 
1209   /*
1210   if (ntokens == 2 && (tokens[0].type & CS_OPS_UNARY))
1211   {
1212     arg->op_type = tokens[0].type;
1213     arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG));
1214     if (arg->expr1 == NULL)
1215       return nerr_raise (NERR_NOMEM,
1216 	  "%s Unable to allocate memory for expression",
1217 	  find_context(parse, -1, tmp, sizeof(tmp)));
1218     err = parse_expr2(parse, tokens + 1, 1, lvalue, arg->expr1);
1219     return nerr_pass(err);
1220   }
1221   */
1222 
1223   op = 0;
1224   while (OperatorOrder[op])
1225   {
1226     x = ntokens-1;
1227     while (x >= 0)
1228     {
1229       /* handle associative ops by skipping through the entire set here,
1230        * ie the whole thing is an expression that can't match a binary op */
1231       if (tokens[x].type & CS_OP_RPAREN)
1232       {
1233 	m = 1;
1234 	x--;
1235 	while (x >= 0)
1236 	{
1237 	  if (tokens[x].type & CS_OP_RPAREN) m++;
1238 	  if (tokens[x].type & CS_OP_LPAREN) m--;
1239 	  if (m == 0) break;
1240 	  x--;
1241 	}
1242 	if (m)
1243 	  return nerr_raise (NERR_PARSE,
1244 	      "%s Missing left parenthesis in expression",
1245 	      find_context(parse, -1, tmp, sizeof(tmp)));
1246 	/* if (x == 0) break; */
1247 	/* x--; */
1248 	/* we don't do an x-- here, because we are special casing the
1249 	 * left bracket to be both an operator and an associative */
1250       }
1251       if (tokens[x].type & CS_OP_RBRACKET)
1252       {
1253 	m = 1;
1254 	x--;
1255 	while (x >= 0)
1256 	{
1257 	  if (tokens[x].type & CS_OP_RBRACKET) m++;
1258 	  if (tokens[x].type & CS_OP_LBRACKET) m--;
1259 	  if (m == 0) break;
1260 	  x--;
1261 	}
1262 	if (m)
1263 	  return nerr_raise (NERR_PARSE,
1264 	      "%s Missing left bracket in expression",
1265 	      find_context(parse, -1, tmp, sizeof(tmp)));
1266 	if (x == 0) break;
1267 	/* we don't do an x-- here, because we are special casing the
1268 	 * left bracket to be both an operator and an associative */
1269       }
1270       if (lvalue && !(tokens[x].type & CS_OPS_LVALUE))
1271       {
1272 	return nerr_raise (NERR_PARSE,
1273 	    "%s Invalid op '%s' in lvalue",
1274 	    find_context(parse, -1, tmp, sizeof(tmp)),
1275 	    expand_token_type(tokens[x].type, 0));
1276       }
1277       if (tokens[x].type & OperatorOrder[op])
1278       {
1279 	if (tokens[x].type & CS_OPS_UNARY)
1280 	{
1281 	  if (x == 0)
1282 	  {
1283 	    arg->op_type = tokens[x].type;
1284 	    arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG));
1285 	    if (arg->expr1 == NULL)
1286 	      return nerr_raise (NERR_NOMEM,
1287 		  "%s Unable to allocate memory for expression",
1288 		  find_context(parse, -1, tmp, sizeof(tmp)));
1289             if (tokens[x].type & CS_OP_LPAREN)
1290             {
1291               if (!(tokens[ntokens-1].type & CS_OP_RPAREN))
1292               {
1293                 return nerr_raise (NERR_PARSE,
1294                                    "%s Missing right parenthesis in expression",
1295                                    find_context(parse, -1, tmp, sizeof(tmp)));
1296               }
1297               /* XXX: we might want to set lvalue to 0 here */
1298               /* -2 since we strip the RPAREN as well */
1299               err = parse_expr2(parse, tokens + 1, ntokens-2, lvalue, arg->expr1);
1300             }
1301             else
1302             {
1303               err = parse_expr2(parse, tokens + 1, ntokens-1, lvalue, arg->expr1);
1304             }
1305 	    return nerr_pass(err);
1306 	  }
1307 	}
1308 	else if (tokens[x].type == CS_OP_COMMA)
1309 	{
1310 	  /* Technically, comma should be a left to right, not right to
1311 	   * left, so we're going to build up the arguments in reverse
1312 	   * order... */
1313 	  arg->op_type = tokens[x].type;
1314 	  /* The actual argument is expr1 */
1315 	  arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG));
1316 	  /* The previous argument is next */
1317 	  arg->next = (CSARG *) calloc (1, sizeof (CSARG));
1318 	  if (arg->expr1 == NULL || arg->next == NULL)
1319 	    return nerr_raise (NERR_NOMEM,
1320 		"%s Unable to allocate memory for expression",
1321 		find_context(parse, -1, tmp, sizeof(tmp)));
1322 	  err = parse_expr2(parse, tokens + x + 1, ntokens-x-1, lvalue, arg->expr1);
1323 	  if (err) return nerr_pass (err);
1324 	  err = parse_expr2(parse, tokens, x, lvalue, arg->next);
1325 	  if (err) return nerr_pass (err);
1326 	  return STATUS_OK;
1327 	}
1328 	else
1329 	{
1330 	  arg->op_type = tokens[x].type;
1331 	  arg->expr2 = (CSARG *) calloc (1, sizeof (CSARG));
1332 	  arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG));
1333 	  if (arg->expr1 == NULL || arg->expr2 == NULL)
1334 	    return nerr_raise (NERR_NOMEM,
1335 		"%s Unable to allocate memory for expression",
1336 		find_context(parse, -1, tmp, sizeof(tmp)));
1337 	  if (tokens[x].type & CS_OP_LBRACKET)
1338 	  {
1339             if (!(tokens[ntokens-1].type & CS_OP_RBRACKET))
1340             {
1341               return nerr_raise (NERR_PARSE,
1342                                  "%s Missing right bracket in expression",
1343                                  find_context(parse, -1, tmp, sizeof(tmp)));
1344             }
1345 	    /* Inside of brackets, we don't limit to valid lvalue ops */
1346             /* -2 since we strip the RBRACKET as well */
1347 	    err = parse_expr2(parse, tokens + x + 1, ntokens-x-2, 0, arg->expr2);
1348 	  }
1349 	  else
1350 	  {
1351 	    err = parse_expr2(parse, tokens + x + 1, ntokens-x-1, lvalue, arg->expr2);
1352 	  }
1353 	  if (err) return nerr_pass (err);
1354 	  err = parse_expr2(parse, tokens, x, lvalue, arg->expr1);
1355 	  if (err) return nerr_pass (err);
1356 	  return STATUS_OK;
1357 	}
1358       }
1359       x--;
1360     }
1361     op++;
1362   }
1363 
1364   /* Unary op against an entire expression */
1365   if ((tokens[0].type & CS_OPS_UNARY) && tokens[1].type == CS_OP_LPAREN &&
1366       tokens[ntokens-1].type == CS_OP_RPAREN)
1367   {
1368     arg->op_type = tokens[0].type;
1369     arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG));
1370     if (arg->expr1 == NULL)
1371       return nerr_raise (NERR_NOMEM,
1372 	  "%s Unable to allocate memory for expression",
1373 	  find_context(parse, -1, tmp, sizeof(tmp)));
1374     err = parse_expr2(parse, tokens + 2, ntokens-3, lvalue, arg->expr1);
1375     return nerr_pass(err);
1376   }
1377   if (tokens[0].type & CS_OPS_UNARY)
1378   {
1379     arg->op_type = tokens[0].type;
1380     arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG));
1381     if (arg->expr1 == NULL)
1382       return nerr_raise (NERR_NOMEM,
1383 	  "%s Unable to allocate memory for expression",
1384 	  find_context(parse, -1, tmp, sizeof(tmp)));
1385     err = parse_expr2(parse, tokens + 1, ntokens-1, lvalue, arg->expr1);
1386     return nerr_pass(err);
1387   }
1388 
1389   /* function call */
1390   if ((tokens[0].type & CS_TYPE_VAR) && tokens[1].type == CS_OP_LPAREN &&
1391       tokens[ntokens-1].type == CS_OP_RPAREN)
1392   {
1393     CS_FUNCTION *csf;
1394     int nargs;
1395 
1396     if (tokens[0].len >= 0)
1397       tokens[0].value[tokens[0].len] = '\0';
1398 
1399     arg->op_type = CS_TYPE_FUNCTION;
1400     csf = parse->functions;
1401     while (csf != NULL)
1402     {
1403       if (!strcmp(tokens[0].value, csf->name))
1404       {
1405 	arg->function = csf;
1406 	break;
1407       }
1408       csf = csf->next;
1409     }
1410     if (csf == NULL)
1411     {
1412       return nerr_raise (NERR_PARSE, "%s Unknown function %s called",
1413 	  find_context(parse, -1, tmp, sizeof(tmp)), tokens[0].value);
1414     }
1415     arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG));
1416     if (arg->expr1 == NULL)
1417       return nerr_raise (NERR_NOMEM,
1418 	  "%s Unable to allocate memory for expression",
1419 	  find_context(parse, -1, tmp, sizeof(tmp)));
1420     if (ntokens-3 > 0) {
1421       err = parse_expr2(parse, tokens + 2, ntokens-3, lvalue, arg->expr1);
1422       if (err) return nerr_pass(err);
1423     } else {
1424       free(arg->expr1);
1425       arg->expr1 = NULL;
1426     }
1427     nargs = rearrange_for_call(&(arg->expr1));
1428     if (nargs != arg->function->n_args)
1429     {
1430       return nerr_raise (NERR_PARSE,
1431 	  "%s Incorrect number of arguments in call to %s, expected %d, got %d",
1432 	  find_context(parse, -1, tmp, sizeof(tmp)), tokens[0].value,
1433 	  arg->function->n_args, nargs);
1434     }
1435     return nerr_pass(err);
1436   }
1437 
1438   return nerr_raise (NERR_PARSE, "%s Bad Expression:%s",
1439       find_context(parse, -1, tmp, sizeof(tmp)),
1440       token_list(tokens, ntokens, tmp2, sizeof(tmp2)));
1441 }
1442 
parse_expr(CSPARSE * parse,char * arg,int lvalue,CSARG * expr)1443 static NEOERR *parse_expr (CSPARSE *parse, char *arg, int lvalue, CSARG *expr)
1444 {
1445   NEOERR *err;
1446   CSTOKEN tokens[MAX_TOKENS];
1447   int ntokens = 0;
1448 
1449   memset(tokens, 0, sizeof(CSTOKEN) * MAX_TOKENS);
1450   err = parse_tokens (parse, arg, tokens, &ntokens);
1451   if (err) return nerr_pass(err);
1452 
1453   if (parse->audit_mode) {
1454     /* Save the complete expression string for future reference */
1455     expr->argexpr = strdup(arg);
1456   }
1457 
1458   err = parse_expr2 (parse, tokens, ntokens, lvalue, expr);
1459   if (err) return nerr_pass(err);
1460   return STATUS_OK;
1461 }
1462 
literal_parse(CSPARSE * parse,int cmd,char * arg)1463 static NEOERR *literal_parse (CSPARSE *parse, int cmd, char *arg)
1464 {
1465   NEOERR *err;
1466   CSTREE *node;
1467 
1468   /* ne_warn ("literal: %s", arg); */
1469   err = alloc_node (&node, parse);
1470   if (err) return nerr_pass(err);
1471   node->cmd = cmd;
1472   node->arg1.op_type = CS_TYPE_STRING;
1473   node->arg1.s = arg;
1474   *(parse->next) = node;
1475   parse->next = &(node->next);
1476   parse->current = node;
1477 
1478   return STATUS_OK;
1479 }
1480 
literal_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)1481 static NEOERR *literal_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
1482 {
1483   NEOERR *err = STATUS_OK;
1484 
1485   if (node->arg1.s != NULL)
1486     err = parse->output_cb (parse->output_ctx, node->arg1.s);
1487   *next = node->next;
1488   return nerr_pass(err);
1489 }
1490 
name_parse(CSPARSE * parse,int cmd,char * arg)1491 static NEOERR *name_parse (CSPARSE *parse, int cmd, char *arg)
1492 {
1493   NEOERR *err;
1494   CSTREE *node;
1495   char *a, *s;
1496   char tmp[256];
1497 
1498   /* ne_warn ("name: %s", arg); */
1499   err = alloc_node (&node, parse);
1500   if (err) return nerr_pass(err);
1501   node->cmd = cmd;
1502   if (arg[0] == '!')
1503     node->flags |= CSF_REQUIRED;
1504   arg++;
1505   /* Validate arg is a var (regex /^[#" ]$/) */
1506   a = neos_strip(arg);
1507   s = strpbrk(a, "#\" <>");
1508   if (s != NULL)
1509   {
1510     dealloc_node(&node);
1511     return nerr_raise (NERR_PARSE, "%s Invalid character in var name %s: %c",
1512 	find_context(parse, -1, tmp, sizeof(tmp)),
1513 	a, s[0]);
1514   }
1515 
1516   node->arg1.op_type = CS_TYPE_VAR;
1517   node->arg1.s = a;
1518   *(parse->next) = node;
1519   parse->next = &(node->next);
1520   parse->current = node;
1521 
1522   return STATUS_OK;
1523 }
1524 
escape_parse(CSPARSE * parse,int cmd,char * arg)1525 static NEOERR *escape_parse (CSPARSE *parse, int cmd, char *arg)
1526 {
1527   NEOERR *err;
1528   char *a = NULL;
1529   char tmp[256];
1530   CS_ESCAPE_MODES *esc_cursor;
1531   CSTREE *node;
1532 
1533   /* ne_warn ("escape: %s", arg); */
1534   err = alloc_node (&node, parse);
1535   if (err) return nerr_pass(err);
1536   node->cmd = cmd;
1537   /* Since this throws an error always if there's a problem
1538    * this flag seems pointless, but following convention,
1539    * here it is. */
1540   if (arg[0] == '!')
1541     node->flags |= CSF_REQUIRED;
1542   arg++; /* ignore colon, space, etc */
1543 
1544   /* Parse the arg - we're expecting a string */
1545   err = parse_expr (parse, arg, 0, &(node->arg1));
1546   if (err)
1547   {
1548     dealloc_node(&node);
1549     return nerr_pass(err);
1550   }
1551   if (node->arg1.op_type != CS_TYPE_STRING)
1552   {
1553     dealloc_node(&node);
1554     return nerr_raise (NERR_PARSE, "%s Invalid argument for escape: %s",
1555       find_context(parse, -1, tmp, sizeof(tmp)), arg);
1556   }
1557 
1558   a = neos_strip(node->arg1.s); /* Strip spaces for testing */
1559 
1560   /* Ensure the mode specified is allowed */
1561   for (esc_cursor = &EscapeModes[0];
1562        esc_cursor->mode != NULL;
1563        esc_cursor++)
1564     if (!strncasecmp(a, esc_cursor->mode, strlen(esc_cursor->mode)))
1565     {
1566       if (err != STATUS_OK) return nerr_pass(err);
1567       parse->escaping.next_stack = esc_cursor->context;
1568       break;
1569     }
1570   /* Didn't find an acceptable value we were looking for */
1571   if (esc_cursor->mode == NULL)
1572   {
1573     dealloc_node(&node);
1574     return nerr_raise (NERR_PARSE, "%s Invalid argument for escape: %s",
1575       find_context(parse, -1, tmp, sizeof(tmp)), a);
1576   }
1577 
1578   *(parse->next) = node;
1579   parse->next = &(node->case_0);
1580   parse->current = node;
1581   return STATUS_OK;
1582 }
1583 
name_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)1584 static NEOERR *name_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
1585 {
1586   NEOERR *err = STATUS_OK;
1587   HDF *obj;
1588   char *v;
1589 
1590   if (node->arg1.op_type == CS_TYPE_VAR && node->arg1.s != NULL)
1591   {
1592     obj = var_lookup_obj (parse, node->arg1.s);
1593     if (obj != NULL)
1594     {
1595       v = hdf_obj_name(obj);
1596       err = parse->output_cb (parse->output_ctx, v);
1597     }
1598   }
1599   *next = node->next;
1600   return nerr_pass(err);
1601 }
1602 
var_parse(CSPARSE * parse,int cmd,char * arg)1603 static NEOERR *var_parse (CSPARSE *parse, int cmd, char *arg)
1604 {
1605   NEOERR *err;
1606   CSTREE *node;
1607   STACK_ENTRY *entry;
1608 
1609   err = uListGet (parse->stack, -1, (void *)&entry);
1610   if (err != STATUS_OK) return nerr_pass(err);
1611 
1612   /* ne_warn ("var: %s", arg); */
1613   err = alloc_node (&node, parse);
1614   if (err) return nerr_pass(err);
1615   node->cmd = cmd;
1616 
1617   /* Default escape the variable based on
1618    * current stack's escape context except for
1619    * uvar:
1620    */
1621   if (!strcmp(Commands[cmd].cmd, "uvar"))
1622     node->escape = NEOS_ESCAPE_NONE;
1623   else
1624     node->escape = entry->escape;
1625 
1626 
1627   if (arg[0] == '!')
1628     node->flags |= CSF_REQUIRED;
1629   arg++;
1630   /* Validate arg is a var (regex /^[#" ]$/) */
1631   err = parse_expr (parse, arg, 0, &(node->arg1));
1632   if (err)
1633   {
1634     dealloc_node(&node);
1635     return nerr_pass(err);
1636   }
1637 
1638   *(parse->next) = node;
1639   parse->next = &(node->next);
1640   parse->current = node;
1641 
1642   return STATUS_OK;
1643 }
1644 
lvar_parse(CSPARSE * parse,int cmd,char * arg)1645 static NEOERR *lvar_parse (CSPARSE *parse, int cmd, char *arg)
1646 {
1647   NEOERR *err;
1648   CSTREE *node;
1649 
1650   /* ne_warn ("lvar: %s", arg); */
1651   err = alloc_node (&node, parse);
1652   if (err) return nerr_pass(err);
1653   node->cmd = cmd;
1654   if (arg[0] == '!')
1655     node->flags |= CSF_REQUIRED;
1656   arg++;
1657   /* Validate arg is a var (regex /^[#" ]$/) */
1658   err = parse_expr (parse, arg, 0, &(node->arg1));
1659   if (err)
1660   {
1661     dealloc_node(&node);
1662     return nerr_pass(err);
1663   }
1664 
1665   *(parse->next) = node;
1666   parse->next = &(node->next);
1667   parse->current = node;
1668 
1669   return STATUS_OK;
1670 }
1671 
linclude_parse(CSPARSE * parse,int cmd,char * arg)1672 static NEOERR *linclude_parse (CSPARSE *parse, int cmd, char *arg)
1673 {
1674   NEOERR *err;
1675   CSTREE *node;
1676 
1677   /* ne_warn ("linclude: %s", arg); */
1678   err = alloc_node (&node, parse);
1679   if (err) return nerr_pass(err);
1680   node->cmd = cmd;
1681   if (arg[0] == '!')
1682     node->flags |= CSF_REQUIRED;
1683   arg++;
1684   /* Validate arg is a var (regex /^[#" ]$/) */
1685   err = parse_expr (parse, arg, 0, &(node->arg1));
1686   if (err)
1687   {
1688     dealloc_node(&node);
1689     return nerr_pass(err);
1690   }
1691 
1692   *(parse->next) = node;
1693   parse->next = &(node->next);
1694   parse->current = node;
1695 
1696   return STATUS_OK;
1697 }
1698 
alt_parse(CSPARSE * parse,int cmd,char * arg)1699 static NEOERR *alt_parse (CSPARSE *parse, int cmd, char *arg)
1700 {
1701   NEOERR *err;
1702   CSTREE *node;
1703 
1704   /* ne_warn ("var: %s", arg); */
1705   err = alloc_node (&node, parse);
1706   if (err) return nerr_pass(err);
1707   node->cmd = cmd;
1708   if (arg[0] == '!')
1709     node->flags |= CSF_REQUIRED;
1710   arg++;
1711   /* Validate arg is a var (regex /^[#" ]$/) */
1712   err = parse_expr (parse, arg, 0, &(node->arg1));
1713   if (err)
1714   {
1715     dealloc_node(&node);
1716     return nerr_pass(err);
1717   }
1718 
1719   *(parse->next) = node;
1720   parse->next = &(node->case_0);
1721   parse->current = node;
1722 
1723   return STATUS_OK;
1724 }
1725 
evar_parse(CSPARSE * parse,int cmd,char * arg)1726 static NEOERR *evar_parse (CSPARSE *parse, int cmd, char *arg)
1727 {
1728   NEOERR *err;
1729   CSTREE *node;
1730   char *a, *s;
1731   const char *save_context;
1732   int save_infile;
1733   char tmp[256];
1734 
1735   /* ne_warn ("evar: %s", arg); */
1736   err = alloc_node (&node, parse);
1737   if (err) return nerr_pass(err);
1738   node->cmd = cmd;
1739   if (arg[0] == '!')
1740     node->flags |= CSF_REQUIRED;
1741   arg++;
1742   /* Validate arg is a var (regex /^[#" ]$/) */
1743   a = neos_strip(arg);
1744   s = strpbrk(a, "#\" <>");
1745   if (s != NULL)
1746   {
1747     dealloc_node(&node);
1748     return nerr_raise (NERR_PARSE, "%s Invalid character in var name %s: %c",
1749 	find_context(parse, -1, tmp, sizeof(tmp)),
1750 	a, s[0]);
1751   }
1752 
1753   err = hdf_get_copy (parse->hdf, a, &s, NULL);
1754   if (err)
1755   {
1756     dealloc_node(&node);
1757     return nerr_pass (err);
1758   }
1759   if (node->flags & CSF_REQUIRED && s == NULL)
1760   {
1761     dealloc_node(&node);
1762     return nerr_raise (NERR_NOT_FOUND, "%s Unable to evar empty variable %s",
1763 	find_context(parse, -1, tmp, sizeof(tmp)), a);
1764   }
1765 
1766   node->arg1.op_type = CS_TYPE_VAR;
1767   node->arg1.s = a;
1768   *(parse->next) = node;
1769   parse->next = &(node->next);
1770   parse->current = node;
1771 
1772   save_context = parse->context;
1773   save_infile = parse->in_file;
1774   parse->context = a;
1775   parse->in_file = 0;
1776   if (s) err = cs_parse_string (parse, s, strlen(s));
1777   parse->context = save_context;
1778   parse->in_file = save_infile;
1779 
1780   return nerr_pass (err);
1781 }
1782 
if_parse(CSPARSE * parse,int cmd,char * arg)1783 static NEOERR *if_parse (CSPARSE *parse, int cmd, char *arg)
1784 {
1785   NEOERR *err;
1786   CSTREE *node;
1787 
1788   /* ne_warn ("if: %s", arg); */
1789   err = alloc_node (&node, parse);
1790   if (err != STATUS_OK) return nerr_pass(err);
1791   node->cmd = cmd;
1792   arg++;
1793 
1794   err = parse_expr (parse, arg, 0, &(node->arg1));
1795   if (err != STATUS_OK)
1796   {
1797     dealloc_node(&node);
1798     return nerr_pass(err);
1799   }
1800 
1801   *(parse->next) = node;
1802   parse->next = &(node->case_0);
1803   parse->current = node;
1804 
1805   return STATUS_OK;
1806 }
1807 
arg_eval(CSPARSE * parse,CSARG * arg)1808 char *arg_eval (CSPARSE *parse, CSARG *arg)
1809 {
1810   switch ((arg->op_type & CS_TYPES))
1811   {
1812     case CS_TYPE_STRING:
1813       return arg->s;
1814     case CS_TYPE_VAR:
1815       return var_lookup (parse, arg->s);
1816     case CS_TYPE_NUM:
1817     case CS_TYPE_VAR_NUM:
1818     default:
1819       ne_warn ("Unsupported type %s in arg_eval", expand_token_type(arg->op_type, 1));
1820       return NULL;
1821   }
1822 }
1823 
1824 /* This coerces everything to numbers */
arg_eval_num(CSPARSE * parse,CSARG * arg)1825 long int arg_eval_num (CSPARSE *parse, CSARG *arg)
1826 {
1827   long int v = 0;
1828 
1829   switch ((arg->op_type & CS_TYPES))
1830   {
1831     case CS_TYPE_STRING:
1832       v = strtol(arg->s, NULL, 0);
1833       break;
1834     case CS_TYPE_NUM:
1835       v = arg->n;
1836       break;
1837 
1838     case CS_TYPE_VAR:
1839     case CS_TYPE_VAR_NUM:
1840       v = var_int_lookup (parse, arg->s);
1841       break;
1842     default:
1843       ne_warn ("Unsupported type %s in arg_eval_num", expand_token_type(arg->op_type, 1));
1844       v = 0;
1845       break;
1846   }
1847   return v;
1848 }
1849 
1850 /* This is different from arg_eval_num because we don't force strings to
1851  * numbers, a string is either a number (if it is all numeric) or we're
1852  * testing existance.  At least, that's what perl does and what dave
1853  * wants */
arg_eval_bool(CSPARSE * parse,CSARG * arg)1854 long int arg_eval_bool (CSPARSE *parse, CSARG *arg)
1855 {
1856   long int v = 0;
1857   char *s, *r;
1858 
1859   switch ((arg->op_type & CS_TYPES))
1860   {
1861     case CS_TYPE_STRING:
1862     case CS_TYPE_VAR:
1863       if (arg->op_type == CS_TYPE_VAR)
1864 	s = var_lookup(parse, arg->s);
1865       else
1866 	s = arg->s;
1867       if (!s || *s == '\0') return 0; /* non existance or empty is false(0) */
1868       v = strtol(s, &r, 0);
1869       if (*r == '\0') /* entire string converted, treat as number */
1870 	return v;
1871       /* if the entire string didn't convert, then its non-numeric and
1872        * exists, so its true (1) */
1873       return 1;
1874     case CS_TYPE_NUM:
1875       return arg->n;
1876     case CS_TYPE_VAR_NUM: /* this implies forced numeric evaluation */
1877       return var_int_lookup (parse, arg->s);
1878       break;
1879     default:
1880       ne_warn ("Unsupported type %s in arg_eval_bool", expand_token_type(arg->op_type, 1));
1881       v = 0;
1882       break;
1883   }
1884   return v;
1885 }
1886 
arg_eval_str_alloc(CSPARSE * parse,CSARG * arg)1887 char *arg_eval_str_alloc (CSPARSE *parse, CSARG *arg)
1888 {
1889   char *s = NULL;
1890   char buf[256];
1891   long int n_val;
1892 
1893   switch ((arg->op_type & CS_TYPES))
1894   {
1895     case CS_TYPE_STRING:
1896       s = arg->s;
1897       break;
1898     case CS_TYPE_VAR:
1899       s = var_lookup (parse, arg->s);
1900       break;
1901     case CS_TYPE_NUM:
1902     case CS_TYPE_VAR_NUM:
1903       s = buf;
1904       n_val = arg_eval_num (parse, arg);
1905       snprintf (buf, sizeof(buf), "%ld", n_val);
1906       break;
1907     default:
1908       ne_warn ("Unsupported type %s in arg_eval_str_alloc",
1909 	  expand_token_type(arg->op_type, 1));
1910       s = NULL;
1911       break;
1912   }
1913   if (s) return strdup(s);
1914   return NULL;
1915 }
1916 
1917 #if DEBUG_EXPR_EVAL
expand_arg(CSPARSE * parse,int depth,char * where,CSARG * arg)1918 static void expand_arg (CSPARSE *parse, int depth, char *where, CSARG *arg)
1919 {
1920   int x;
1921 
1922   for (x=0; x<depth; x++)
1923     fputc(' ', stderr);
1924 
1925   fprintf(stderr, "%s op: %s alloc: %d value: ", where, expand_token_type(arg->op_type, 0), arg->alloc);
1926   if (arg->op_type & CS_OP_NOT)
1927     fprintf(stderr, "!");
1928   if (arg->op_type & CS_OP_NUM)
1929     fprintf(stderr, "#");
1930   if (arg->op_type & CS_OP_EXISTS)
1931     fprintf(stderr, "?");
1932   if (arg->op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM))
1933     fprintf(stderr, "#");
1934   if (arg->op_type & CS_TYPE_NUM)
1935     fprintf(stderr, "%ld\n", arg->n);
1936   else if (arg->op_type & CS_TYPE_STRING)
1937     fprintf(stderr, "'%s'\n", arg->s);
1938   else if (arg->op_type & CS_TYPE_VAR)
1939     fprintf(stderr, "%s = %s\n", arg->s, var_lookup(parse, arg->s));
1940   else if (arg->op_type & CS_TYPE_VAR_NUM)
1941     fprintf(stderr, "%s = %ld\n", arg->s, var_int_lookup(parse, arg->s));
1942   else
1943     fprintf(stderr, "\n");
1944 }
1945 #endif
1946 
eval_expr_string(CSPARSE * parse,CSARG * arg1,CSARG * arg2,CSTOKEN_TYPE op,CSARG * result)1947 static NEOERR *eval_expr_string(CSPARSE *parse, CSARG *arg1, CSARG *arg2, CSTOKEN_TYPE op, CSARG *result)
1948 {
1949   char *s1, *s2;
1950   int out;
1951 
1952   result->op_type = CS_TYPE_NUM;
1953   s1 = arg_eval (parse, arg1);
1954   s2 = arg_eval (parse, arg2);
1955 
1956   if ((s1 == NULL) || (s2 == NULL))
1957   {
1958     switch (op)
1959     {
1960       case CS_OP_EQUAL:
1961 	result->n = (s1 == s2) ? 1 : 0;
1962 	break;
1963       case CS_OP_NEQUAL:
1964 	result->n = (s1 != s2) ? 1 : 0;
1965 	break;
1966       case CS_OP_LT:
1967 	result->n = ((s1 == NULL) && (s2 != NULL)) ? 1 : 0;
1968 	break;
1969       case CS_OP_LTE:
1970 	result->n = (s1 == NULL) ? 1 : 0;
1971 	break;
1972       case CS_OP_GT:
1973 	result->n = ((s1 != NULL) && (s2 == NULL)) ? 1 : 0;
1974 	break;
1975       case CS_OP_GTE:
1976 	result->n = (s2 == NULL) ? 1 : 0;
1977 	break;
1978       case CS_OP_ADD:
1979 	/* be sure to transfer ownership of the string here */
1980 	result->op_type = CS_TYPE_STRING;
1981 	if (s1 == NULL)
1982 	{
1983 	  result->s = s2;
1984 	  result->alloc = arg2->alloc;
1985 	  arg2->alloc = 0;
1986 	}
1987 	else
1988 	{
1989 	  result->s = s1;
1990 	  result->alloc = arg1->alloc;
1991 	  arg1->alloc = 0;
1992 	}
1993 	break;
1994       default:
1995 	ne_warn ("Unsupported op %s in eval_expr", expand_token_type(op, 1));
1996 	break;
1997     }
1998   }
1999   else
2000   {
2001     out = strcmp (s1, s2);
2002     switch (op)
2003     {
2004       case CS_OP_EQUAL:
2005 	result->n = (!out) ? 1 : 0;
2006 	break;
2007       case CS_OP_NEQUAL:
2008 	result->n = (out) ? 1 : 0;
2009 	break;
2010       case CS_OP_LT:
2011 	result->n = (out < 0) ? 1 : 0;
2012 	break;
2013       case CS_OP_LTE:
2014 	result->n = (out <= 0) ? 1 : 0;
2015 	break;
2016       case CS_OP_GT:
2017 	result->n = (out > 0) ? 1 : 0;
2018 	break;
2019       case CS_OP_GTE:
2020 	result->n = (out >= 0) ? 1 : 0;
2021 	break;
2022       case CS_OP_ADD:
2023 	result->op_type = CS_TYPE_STRING;
2024 	result->alloc = 1;
2025 	result->s = (char *) calloc ((strlen(s1) + strlen(s2) + 1), sizeof(char));
2026 	if (result->s == NULL)
2027 	  return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate strings in expression: %s + %s", s1, s2);
2028 	strcpy(result->s, s1);
2029 	strcat(result->s, s2);
2030 	break;
2031       default:
2032 	ne_warn ("Unsupported op %s in eval_expr_string", expand_token_type(op, 1));
2033 	break;
2034     }
2035   }
2036   return STATUS_OK;
2037 }
2038 
eval_expr_num(CSPARSE * parse,CSARG * arg1,CSARG * arg2,CSTOKEN_TYPE op,CSARG * result)2039 static NEOERR *eval_expr_num(CSPARSE *parse, CSARG *arg1, CSARG *arg2, CSTOKEN_TYPE op, CSARG *result)
2040 {
2041   long int n1, n2;
2042 
2043   result->op_type = CS_TYPE_NUM;
2044   n1 = arg_eval_num (parse, arg1);
2045   n2 = arg_eval_num (parse, arg2);
2046 
2047   switch (op)
2048   {
2049     case CS_OP_EQUAL:
2050       result->n = (n1 == n2) ? 1 : 0;
2051       break;
2052     case CS_OP_NEQUAL:
2053       result->n = (n1 != n2) ? 1 : 0;
2054       break;
2055     case CS_OP_LT:
2056       result->n = (n1 < n2) ? 1 : 0;
2057       break;
2058     case CS_OP_LTE:
2059       result->n = (n1 <= n2) ? 1 : 0;
2060       break;
2061     case CS_OP_GT:
2062       result->n = (n1 > n2) ? 1 : 0;
2063       break;
2064     case CS_OP_GTE:
2065       result->n = (n1 >= n2) ? 1 : 0;
2066       break;
2067     case CS_OP_ADD:
2068       result->n = (n1 + n2);
2069       break;
2070     case CS_OP_SUB:
2071       result->n = (n1 - n2);
2072       break;
2073     case CS_OP_MULT:
2074       result->n = (n1 * n2);
2075       break;
2076     case CS_OP_DIV:
2077       if (n2 == 0) result->n = UINT_MAX;
2078       else result->n = (n1 / n2);
2079       break;
2080     case CS_OP_MOD:
2081       if (n2 == 0) result->n = 0;
2082       else result->n = (n1 % n2);
2083       break;
2084     default:
2085       ne_warn ("Unsupported op %s in eval_expr_num", expand_token_type(op, 1));
2086       break;
2087   }
2088   return STATUS_OK;
2089 }
2090 
eval_expr_bool(CSPARSE * parse,CSARG * arg1,CSARG * arg2,CSTOKEN_TYPE op,CSARG * result)2091 static NEOERR *eval_expr_bool(CSPARSE *parse, CSARG *arg1, CSARG *arg2, CSTOKEN_TYPE op, CSARG *result)
2092 {
2093   long int n1, n2;
2094 
2095   result->op_type = CS_TYPE_NUM;
2096   n1 = arg_eval_bool (parse, arg1);
2097   n2 = arg_eval_bool (parse, arg2);
2098 
2099   switch (op)
2100   {
2101     case CS_OP_AND:
2102       result->n = (n1 && n2) ? 1 : 0;
2103       break;
2104     case CS_OP_OR:
2105       result->n = (n1 || n2) ? 1 : 0;
2106       break;
2107     default:
2108       ne_warn ("Unsupported op %s in eval_expr_bool", expand_token_type(op, 1));
2109       break;
2110   }
2111   return STATUS_OK;
2112 }
2113 
2114 #if DEBUG_EXPR_EVAL
2115 static int _depth = 0;
2116 #endif
2117 
eval_expr(CSPARSE * parse,CSARG * expr,CSARG * result)2118 static NEOERR *eval_expr (CSPARSE *parse, CSARG *expr, CSARG *result)
2119 {
2120   NEOERR *err;
2121 
2122   if (expr == NULL)
2123     return nerr_raise (NERR_ASSERT, "expr is NULL");
2124   if (result == NULL)
2125     return nerr_raise (NERR_ASSERT, "result is NULL");
2126 
2127 #if DEBUG_EXPR_EVAL
2128   _depth++;
2129   expand_arg(parse, _depth, "expr", expr);
2130 #endif
2131 
2132   memset(result, 0, sizeof(CSARG));
2133   if (expr->op_type & CS_TYPES)
2134   {
2135     *result = *expr;
2136     /* we transfer ownership of the string here.. ugh */
2137     if (expr->alloc) expr->alloc = 0;
2138 #if DEBUG_EXPR_EVAL
2139     expand_arg(parse, _depth, "result", result);
2140     _depth--;
2141 #endif
2142     return STATUS_OK;
2143   }
2144 
2145   if (expr->op_type & CS_OP_LPAREN)
2146   {
2147     /* lparen is a no-op, just skip */
2148     return nerr_pass(eval_expr(parse, expr->expr1, result));
2149   }
2150   if (expr->op_type & CS_TYPE_FUNCTION)
2151   {
2152     if (expr->function == NULL || expr->function->function == NULL)
2153       return nerr_raise(NERR_ASSERT,
2154           "Function is NULL in attempt to evaluate function call %s",
2155           (expr->function) ? expr->function->name : "");
2156 
2157     /* The function evaluates all the arguments, so don't pre-evaluate
2158      * argument1 */
2159     err = expr->function->function(parse, expr->function, expr->expr1, result);
2160     if (err) return nerr_pass(err);
2161     /* Indicate whether or not an explicit escape call was made by
2162      * setting the mode (usually NONE or FUNCTION). This is ORed to
2163      * ensure that escaping calls within other functions do not get
2164      * double-escaped. E.g. slice(html_escape(foo), 10, 20) */
2165     parse->escaping.current |= expr->function->escape;
2166   }
2167   else
2168   {
2169     CSARG arg1, arg2;
2170     arg1.alloc = 0;
2171     arg2.alloc = 0;
2172 
2173     err = eval_expr (parse, expr->expr1, &arg1);
2174     if (err) return nerr_pass(err);
2175 #if DEBUG_EXPR_EVAL
2176     expand_arg(parse, _depth, "arg1", &arg1);
2177 #endif
2178     if (expr->op_type & CS_OPS_UNARY)
2179     {
2180       result->op_type = CS_TYPE_NUM;
2181       switch (expr->op_type) {
2182         case CS_OP_NOT:
2183           result->n = arg_eval_bool(parse, &arg1) ? 0 : 1;
2184           break;
2185         case CS_OP_EXISTS:
2186           if (arg1.op_type & (CS_TYPE_VAR | CS_TYPE_VAR_NUM))
2187           {
2188             if (arg_eval(parse, &arg1) == NULL)
2189               result->n = 0;
2190             else
2191               result->n = 1;
2192           }
2193           else
2194           {
2195             /* All numbers/strings exist */
2196             result->n = 1;
2197           }
2198           break;
2199         case CS_OP_NUM:
2200           result->n = arg_eval_num (parse, &arg1);
2201           break;
2202         case CS_OP_LPAREN:
2203           return nerr_raise(NERR_ASSERT, "LPAREN should be handled above");
2204         default:
2205           result->n = 0;
2206           ne_warn ("Unsupported op %s in eval_expr", expand_token_type(expr->op_type, 1));
2207           break;
2208       }
2209     }
2210     else if (expr->op_type == CS_OP_COMMA)
2211     {
2212       /* The comma operator, like in C, we return the value of the right
2213        * most argument, in this case that's expr1, but we still need to
2214        * evaluate the other stuff */
2215       if (expr->next)
2216       {
2217         err = eval_expr (parse, expr->next, &arg2);
2218 #if DEBUG_EXPR_EVAL
2219         expand_arg(parse, _depth, "arg2", &arg2);
2220 #endif
2221         if (err) return nerr_pass(err);
2222         if (arg2.alloc) free(arg2.s);
2223       }
2224       *result = arg1;
2225       /* we transfer ownership of the string here.. ugh */
2226       if (arg1.alloc) arg1.alloc = 0;
2227 #if DEBUG_EXPR_EVAL
2228       expand_arg(parse, _depth, "result", result);
2229       _depth--;
2230 #endif
2231       return STATUS_OK;
2232     }
2233     else
2234     {
2235       err = eval_expr (parse, expr->expr2, &arg2);
2236 #if DEBUG_EXPR_EVAL
2237       expand_arg(parse, _depth, "arg2", &arg2);
2238 #endif
2239       if (err) return nerr_pass(err);
2240 
2241       if (expr->op_type == CS_OP_LBRACKET)
2242       {
2243         /* the bracket op is essentially hdf array lookups, which just
2244          * means appending the value of arg2, .0 */
2245         result->op_type = CS_TYPE_VAR;
2246         result->alloc = 1;
2247         if (arg2.op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM))
2248         {
2249           long int n2 = arg_eval_num (parse, &arg2);
2250           result->s = sprintf_alloc("%s.%ld", arg1.s, n2);
2251           if (result->s == NULL)
2252             return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %ld", arg1.s, n2);
2253         }
2254         else
2255         {
2256           char *s2 = arg_eval (parse, &arg2);
2257           if (s2 && s2[0])
2258           {
2259             result->s = sprintf_alloc("%s.%s", arg1.s, s2);
2260             if (result->s == NULL)
2261               return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %s", arg1.s, s2);
2262           }
2263           else
2264           {
2265             /* if s2 doesn't match anything, then the whole thing is empty */
2266             result->s = "";
2267             result->alloc = 0;
2268           }
2269         }
2270       }
2271       else if (expr->op_type == CS_OP_DOT)
2272       {
2273         /* the dot op is essentially extending the hdf name, which just
2274          * means appending the string .0 */
2275         result->op_type = CS_TYPE_VAR;
2276         result->alloc = 1;
2277         if (arg2.op_type & CS_TYPES_VAR)
2278         {
2279           result->s = sprintf_alloc("%s.%s", arg1.s, arg2.s);
2280           if (result->s == NULL)
2281             return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %s", arg1.s, arg2.s);
2282         }
2283         else
2284         {
2285           if (arg2.op_type & CS_TYPE_NUM)
2286           {
2287             long int n2 = arg_eval_num (parse, &arg2);
2288             result->s = sprintf_alloc("%s.%ld", arg1.s, n2);
2289             if (result->s == NULL)
2290               return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %ld", arg1.s, n2);
2291           }
2292           else
2293           {
2294             char *s2 = arg_eval (parse, &arg2);
2295             if (s2 && s2[0])
2296             {
2297               result->s = sprintf_alloc("%s.%s", arg1.s, s2);
2298               if (result->s == NULL)
2299                 return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %s", arg1.s, s2);
2300             }
2301             else
2302             {
2303               /* if s2 doesn't match anything, then the whole thing is empty */
2304               result->s = "";
2305               result->alloc = 0;
2306             }
2307           }
2308         }
2309       }
2310       else if (expr->op_type & (CS_OP_AND | CS_OP_OR))
2311       {
2312         /* eval as bool */
2313         err = eval_expr_bool (parse, &arg1, &arg2, expr->op_type, result);
2314       }
2315       else if ((arg1.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) ||
2316                (arg2.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) ||
2317                (expr->op_type & (CS_OP_AND | CS_OP_OR | CS_OP_SUB | CS_OP_MULT | CS_OP_DIV | CS_OP_MOD | CS_OP_GT | CS_OP_GTE | CS_OP_LT | CS_OP_LTE)))
2318       {
2319         /* eval as num */
2320         err = eval_expr_num(parse, &arg1, &arg2, expr->op_type, result);
2321       }
2322       else /* eval as string */
2323       {
2324         err = eval_expr_string(parse, &arg1, &arg2, expr->op_type, result);
2325       }
2326     }
2327     if (arg1.alloc) free(arg1.s);
2328     if (arg2.alloc) free(arg2.s);
2329   }
2330 
2331 #if DEBUG_EXPR_EVAL
2332   expand_arg(parse, _depth, "result", result);
2333   _depth--;
2334 #endif
2335   return STATUS_OK;
2336 }
2337 
var_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)2338 static NEOERR *var_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
2339 {
2340   NEOERR *err = STATUS_OK;
2341   CSARG val;
2342 
2343   parse->escaping.current = NEOS_ESCAPE_NONE;
2344   err = eval_expr(parse, &(node->arg1), &val);
2345   if (err) return nerr_pass(err);
2346   if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM))
2347   {
2348     char buf[256];
2349     long int n_val;
2350 
2351     n_val = arg_eval_num (parse, &val);
2352     snprintf (buf, sizeof(buf), "%ld", n_val);
2353     err = parse->output_cb (parse->output_ctx, buf);
2354   }
2355   else
2356   {
2357     char *s = arg_eval (parse, &val);
2358     /* Determine if the node has been escaped by an explicit function. If not
2359      * call to escape. node->escape should contain the default escaping from
2360      * Config.VarEscapeMode and parse->escaping.current will have a non-zero
2361      * value if an explicit escape call was made sooooo.
2362      */
2363     if (s && parse->escaping.current == NEOS_ESCAPE_NONE) /* no explicit escape */
2364     {
2365       char *escaped = NULL;
2366       /* Use default escape if escape is UNDEF */
2367       if (node->escape == NEOS_ESCAPE_UNDEF)
2368         err = neos_var_escape(parse->escaping.when_undef, s, &escaped);
2369       else
2370         err = neos_var_escape(node->escape, s, &escaped);
2371 
2372       if (escaped)
2373       {
2374         err = parse->output_cb (parse->output_ctx, escaped);
2375         free(escaped);
2376       }
2377     }
2378     else if (s)
2379     { /* already explicitly escaped */
2380       err = parse->output_cb (parse->output_ctx, s);
2381     }
2382     /* Do we set it to blank if s == NULL? */
2383   }
2384   if (val.alloc) free(val.s);
2385 
2386   *next = node->next;
2387   return nerr_pass(err);
2388 }
2389 
lvar_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)2390 static NEOERR *lvar_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
2391 {
2392   NEOERR *err = STATUS_OK;
2393   CSARG val;
2394 
2395   err = eval_expr(parse, &(node->arg1), &val);
2396   if (err) return nerr_pass(err);
2397   if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM))
2398   {
2399     char buf[256];
2400     long int n_val;
2401 
2402     n_val = arg_eval_num (parse, &val);
2403     snprintf (buf, sizeof(buf), "%ld", n_val);
2404     err = parse->output_cb (parse->output_ctx, buf);
2405   }
2406   else
2407   {
2408     char *s = arg_eval (parse, &val);
2409 
2410     if (s)
2411     {
2412       CSPARSE *cs = NULL;
2413 
2414       /* Ok, we need our own copy of the string to pass to
2415        * cs_parse_string... */
2416       if (val.alloc && (val.op_type & CS_TYPE_STRING)) {
2417 	val.alloc = 0;
2418       }
2419       else
2420       {
2421 	s = strdup(s);
2422 	if (s == NULL)
2423 	{
2424 	  return nerr_raise(NERR_NOMEM, "Unable to allocate memory for lvar_eval");
2425 	}
2426       }
2427 
2428       do {
2429 	err = cs_init_internal(&cs, parse->hdf, parse);
2430 	if (err) break;
2431 	err = cs_parse_string(cs, s, strlen(s));
2432 	if (err) break;
2433 	err = cs_render(cs, parse->output_ctx, parse->output_cb);
2434 	if (err) break;
2435       } while (0);
2436       cs_destroy(&cs);
2437     }
2438   }
2439   if (val.alloc) free(val.s);
2440 
2441   *next = node->next;
2442   return nerr_pass(err);
2443 }
2444 
linclude_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)2445 static NEOERR *linclude_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
2446 {
2447   NEOERR *err = STATUS_OK;
2448   CSARG val;
2449 
2450   err = eval_expr(parse, &(node->arg1), &val);
2451   if (err) return nerr_pass(err);
2452   if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM))
2453   {
2454     char buf[256];
2455     long int n_val;
2456 
2457     n_val = arg_eval_num (parse, &val);
2458     snprintf (buf, sizeof(buf), "%ld", n_val);
2459     err = parse->output_cb (parse->output_ctx, buf);
2460   }
2461   else
2462   {
2463     char *s = arg_eval (parse, &val);
2464 
2465     if (s)
2466     {
2467       CSPARSE *cs = NULL;
2468       do {
2469 	err = cs_init_internal(&cs, parse->hdf, parse);
2470 	if (err) break;
2471 	err = cs_parse_file(cs, s);
2472 	if (!(node->flags & CSF_REQUIRED))
2473 	{
2474 	  nerr_handle(&err, NERR_NOT_FOUND);
2475 	}
2476 	if (err) break;
2477 	err = cs_render(cs, parse->output_ctx, parse->output_cb);
2478 	if (err) break;
2479       } while (0);
2480       cs_destroy(&cs);
2481     }
2482   }
2483   if (val.alloc) free(val.s);
2484 
2485   *next = node->next;
2486   return nerr_pass(err);
2487 }
2488 
2489 /* if the expr evaluates to true, display it, else render the alternate */
alt_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)2490 static NEOERR *alt_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
2491 {
2492   NEOERR *err = STATUS_OK;
2493   CSARG val;
2494   int eval_true = 1;
2495 
2496   err = eval_expr(parse, &(node->arg1), &val);
2497   if (err) return nerr_pass(err);
2498   eval_true = arg_eval_bool(parse, &val);
2499   if (eval_true)
2500   {
2501     if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM))
2502     {
2503       char buf[256];
2504       long int n_val;
2505 
2506       n_val = arg_eval_num (parse, &val);
2507       snprintf (buf, sizeof(buf), "%ld", n_val);
2508       err = parse->output_cb (parse->output_ctx, buf);
2509     }
2510     else
2511     {
2512       char *s = arg_eval (parse, &val);
2513       /* Do we set it to blank if s == NULL? */
2514       if (s)
2515       {
2516 	err = parse->output_cb (parse->output_ctx, s);
2517       }
2518     }
2519   }
2520   if (val.alloc) free(val.s);
2521 
2522   if (eval_true == 0)
2523   {
2524     err = render_node (parse, node->case_0);
2525   }
2526 
2527   *next = node->next;
2528   return nerr_pass(err);
2529 }
2530 
2531 /* just calls through to the child nodes */
escape_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)2532 static NEOERR *escape_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
2533 {
2534   NEOERR *err = STATUS_OK;
2535   /* TODO(wad): Should I set a eval-time value here? */
2536   err = render_node (parse, node->case_0);
2537   *next = node->next;
2538   return nerr_pass(err);
2539 }
2540 
2541 
if_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)2542 static NEOERR *if_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
2543 {
2544   NEOERR *err = STATUS_OK;
2545   int eval_true = 0;
2546   CSARG val;
2547 
2548   err = eval_expr(parse, &(node->arg1), &val);
2549   if (err) return nerr_pass (err);
2550   eval_true = arg_eval_bool(parse, &val);
2551   if (val.alloc) free(val.s);
2552 
2553   if (eval_true)
2554   {
2555     err = render_node (parse, node->case_0);
2556   }
2557   else if (node->case_1 != NULL)
2558   {
2559     err = render_node (parse, node->case_1);
2560   }
2561   *next = node->next;
2562   return nerr_pass (err);
2563 }
2564 
else_parse(CSPARSE * parse,int cmd,char * arg)2565 static NEOERR *else_parse (CSPARSE *parse, int cmd, char *arg)
2566 {
2567   NEOERR *err;
2568   STACK_ENTRY *entry;
2569 
2570   /* ne_warn ("else"); */
2571   err = uListGet (parse->stack, -1, (void *)&entry);
2572   if (err != STATUS_OK) return nerr_pass(err);
2573 
2574   parse->next = &(entry->tree->case_1);
2575   parse->current = entry->tree;
2576   return STATUS_OK;
2577 }
2578 
elif_parse(CSPARSE * parse,int cmd,char * arg)2579 static NEOERR *elif_parse (CSPARSE *parse, int cmd, char *arg)
2580 {
2581   NEOERR *err;
2582   STACK_ENTRY *entry;
2583 
2584   /* ne_warn ("elif: %s", arg); */
2585   err = uListGet (parse->stack, -1, (void *)&entry);
2586   if (err != STATUS_OK) return nerr_pass(err);
2587 
2588   if (entry->next_tree == NULL)
2589     entry->next_tree = entry->tree;
2590 
2591   parse->next = &(entry->tree->case_1);
2592 
2593   err = if_parse(parse, cmd, arg);
2594   entry->tree = parse->current;
2595   return nerr_pass(err);
2596 }
2597 
endif_parse(CSPARSE * parse,int cmd,char * arg)2598 static NEOERR *endif_parse (CSPARSE *parse, int cmd, char *arg)
2599 {
2600   NEOERR *err;
2601   STACK_ENTRY *entry;
2602 
2603   /* ne_warn ("endif"); */
2604   err = uListGet (parse->stack, -1, (void *)&entry);
2605   if (err != STATUS_OK) return nerr_pass(err);
2606 
2607   if (entry->next_tree)
2608     parse->next = &(entry->next_tree->next);
2609   else
2610     parse->next = &(entry->tree->next);
2611   parse->current = entry->tree;
2612   return STATUS_OK;
2613 }
2614 
each_with_parse(CSPARSE * parse,int cmd,char * arg)2615 static NEOERR *each_with_parse (CSPARSE *parse, int cmd, char *arg)
2616 {
2617   NEOERR *err;
2618   CSTREE *node;
2619   char *lvar;
2620   char *p;
2621   char tmp[256];
2622 
2623   err = alloc_node (&node, parse);
2624   if (err) return nerr_pass(err);
2625   node->cmd = cmd;
2626   if (arg[0] == '!')
2627     node->flags |= CSF_REQUIRED;
2628   arg++;
2629 
2630   p = lvar = neos_strip(arg);
2631   while (*p && !isspace(*p) && *p != '=') p++;
2632   if (*p == '\0')
2633   {
2634     dealloc_node(&node);
2635     return nerr_raise (NERR_PARSE,
2636 	"%s Improperly formatted %s directive: %s",
2637 	find_context(parse, -1, tmp, sizeof(tmp)), Commands[cmd].cmd, arg);
2638   }
2639   if (*p != '=')
2640   {
2641     *p++ = '\0';
2642     while (*p && *p != '=') p++;
2643     if (*p == '\0')
2644     {
2645       dealloc_node(&node);
2646       return nerr_raise (NERR_PARSE,
2647 	  "%s Improperly formatted %s directive: %s",
2648 	  find_context(parse, -1, tmp, sizeof(tmp)), Commands[cmd].cmd, arg);
2649     }
2650     p++;
2651   }
2652   else
2653   {
2654     *p++ = '\0';
2655   }
2656   while (*p && isspace(*p)) p++;
2657   if (*p == '\0')
2658   {
2659     dealloc_node(&node);
2660     return nerr_raise (NERR_PARSE,
2661 	"%s Improperly formatted %s directive: %s",
2662 	find_context(parse, -1, tmp, sizeof(tmp)), Commands[cmd].cmd, arg);
2663   }
2664   node->arg1.op_type = CS_TYPE_VAR;
2665   node->arg1.s = lvar;
2666 
2667   err = parse_expr(parse, p, 0, &(node->arg2));
2668   if (err)
2669   {
2670     dealloc_node(&node);
2671     return nerr_pass(err);
2672   }
2673   /* ne_warn ("each %s %s", lvar, p); */
2674 
2675   *(parse->next) = node;
2676   parse->next = &(node->case_0);
2677   parse->current = node;
2678 
2679   return STATUS_OK;
2680 }
2681 
each_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)2682 static NEOERR *each_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
2683 {
2684   NEOERR *err = STATUS_OK;
2685   CS_LOCAL_MAP each_map;
2686   CSARG val;
2687   HDF *var, *child;
2688 
2689   memset(&each_map, 0, sizeof(each_map));
2690 
2691   err = eval_expr(parse, &(node->arg2), &val);
2692   if (err) return nerr_pass(err);
2693 
2694   if (val.op_type == CS_TYPE_VAR)
2695   {
2696     var = var_lookup_obj (parse, val.s);
2697 
2698     if (var != NULL)
2699     {
2700       /* Init and install local map */
2701       each_map.type = CS_TYPE_VAR;
2702       each_map.name = node->arg1.s;
2703       each_map.next = parse->locals;
2704       each_map.first = 1;
2705       each_map.last = 0;
2706       parse->locals = &each_map;
2707 
2708       do
2709       {
2710 	child = hdf_obj_child (var);
2711 	while (child != NULL)
2712 	{
2713           /* We don't explicitly set each_map.last here since checking
2714            * requires a function call, so we move the check to _builtin_last
2715            * so it only makes the call if last() is being used */
2716 	  each_map.h = child;
2717 	  err = render_node (parse, node->case_0);
2718           if (each_map.map_alloc) {
2719             free(each_map.s);
2720             each_map.s = NULL;
2721           }
2722           if (each_map.first) each_map.first = 0;
2723 	  if (err != STATUS_OK) break;
2724 	  child = hdf_obj_next (child);
2725 	}
2726 
2727       } while (0);
2728 
2729       /* Remove local map */
2730       parse->locals = each_map.next;
2731     }
2732   } /* else WARNING */
2733   if (val.alloc) free(val.s);
2734 
2735   *next = node->next;
2736   return nerr_pass (err);
2737 }
2738 
with_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)2739 static NEOERR *with_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
2740 {
2741   NEOERR *err = STATUS_OK;
2742   CS_LOCAL_MAP with_map;
2743   CSARG val;
2744   HDF *var;
2745 
2746   memset(&with_map, 0, sizeof(with_map));
2747 
2748   err = eval_expr(parse, &(node->arg2), &val);
2749   if (err) return nerr_pass(err);
2750 
2751   if (val.op_type == CS_TYPE_VAR)
2752   {
2753     var = var_lookup_obj (parse, val.s);
2754 
2755     if (var != NULL)
2756     {
2757       /* Init and install local map */
2758       with_map.type = CS_TYPE_VAR;
2759       with_map.name = node->arg1.s;
2760       with_map.next = parse->locals;
2761       with_map.h = var;
2762       parse->locals = &with_map;
2763       err = render_node (parse, node->case_0);
2764       /* Remove local map */
2765       if (with_map.map_alloc) free(with_map.s);
2766       parse->locals = with_map.next;
2767     }
2768   }
2769   else
2770   {
2771     /* else WARNING */
2772     ne_warn("Invalid op_type for with: %s", expand_token_type(val.op_type, 1));
2773   }
2774   if (val.alloc) free(val.s);
2775 
2776   *next = node->next;
2777   return nerr_pass (err);
2778 }
end_parse(CSPARSE * parse,int cmd,char * arg)2779 static NEOERR *end_parse (CSPARSE *parse, int cmd, char *arg)
2780 {
2781   NEOERR *err;
2782   STACK_ENTRY *entry;
2783 
2784   err = uListGet (parse->stack, -1, (void *)&entry);
2785   if (err != STATUS_OK) return nerr_pass(err);
2786 
2787   parse->next = &(entry->tree->next);
2788   parse->current = entry->tree;
2789   return STATUS_OK;
2790 }
2791 
include_parse(CSPARSE * parse,int cmd,char * arg)2792 static NEOERR *include_parse (CSPARSE *parse, int cmd, char *arg)
2793 {
2794   NEOERR *err;
2795   char *s;
2796   int flags = 0;
2797   CSARG arg1, val;
2798 
2799   memset(&arg1, 0, sizeof(CSARG));
2800   if (arg[0] == '!')
2801     flags |= CSF_REQUIRED;
2802   arg++;
2803   /* Validate arg is a var (regex /^[#" ]$/) */
2804   err = parse_expr (parse, arg, 0, &arg1);
2805   if (err) return nerr_pass(err);
2806   /* ne_warn ("include: %s", a); */
2807 
2808   err = eval_expr(parse, &arg1, &val);
2809   if (err) return nerr_pass(err);
2810 
2811   s = arg_eval (parse, &val);
2812   if (s == NULL && !(flags & CSF_REQUIRED))
2813     return STATUS_OK;
2814   err = cs_parse_file(parse, s);
2815   if (!(flags & CSF_REQUIRED))
2816   {
2817     nerr_handle(&err, NERR_NOT_FOUND);
2818   }
2819   if (val.alloc) free(val.s);
2820 
2821   return nerr_pass (err);
2822 }
2823 
def_parse(CSPARSE * parse,int cmd,char * arg)2824 static NEOERR *def_parse (CSPARSE *parse, int cmd, char *arg)
2825 {
2826   NEOERR *err;
2827   CSTREE *node;
2828   CS_MACRO *macro;
2829   CSARG *carg, *larg = NULL;
2830   char *a = NULL, *p = NULL, *s;
2831   char tmp[256];
2832   char name[256];
2833   int x = 0;
2834   BOOL last = FALSE;
2835 
2836   /* Since def doesn't get a new stack entry until after this is run,
2837    * setup a dumb var on the parse object to hold the future setting.
2838    */
2839   parse->escaping.next_stack = NEOS_ESCAPE_UNDEF;
2840 
2841   err = alloc_node (&node, parse);
2842   if (err) return nerr_pass(err);
2843   node->cmd = cmd;
2844   arg++;
2845   s = arg;
2846   while (*s && *s != ' ' && *s != '#' && *s != '(')
2847   {
2848     name[x++] = *s;
2849     s++;
2850   }
2851   name[x] = '\0';
2852   while (*s && isspace(*s)) s++;
2853   if (*s == '\0' || *s != '(')
2854   {
2855     dealloc_node(&node);
2856     return nerr_raise (NERR_PARSE,
2857 	"%s Missing left paren in macro def %s",
2858 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
2859   }
2860   s++;
2861   /* Check to see if this is a redefinition */
2862   macro = parse->macros;
2863   while (macro != NULL)
2864   {
2865     if (!strcmp(macro->name, name))
2866     {
2867       dealloc_node(&node);
2868       return nerr_raise (NERR_PARSE,
2869 	  "%s Duplicate macro def for %s",
2870 	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
2871     }
2872     macro = macro->next;
2873   }
2874 
2875   macro = (CS_MACRO *) calloc (1, sizeof (CS_MACRO));
2876   if (macro) macro->name = strdup(name);
2877   if (macro == NULL || macro->name == NULL)
2878   {
2879     dealloc_node(&node);
2880     dealloc_macro(&macro);
2881     return nerr_raise (NERR_NOMEM,
2882 	"%s Unable to allocate memory for CS_MACRO in def %s",
2883 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
2884   }
2885 
2886   while (*s)
2887   {
2888     while (*s && isspace(*s)) s++;
2889     a = strpbrk(s, ",)");
2890     if (a == NULL)
2891     {
2892       err = nerr_raise (NERR_PARSE,
2893 	  "%s Missing right paren in def %s",
2894 	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
2895       break;
2896     }
2897     if (*a == ')') last = TRUE;
2898     *a = '\0';
2899     /* cut out ending whitespace */
2900     p = strpbrk(s, " \t\r\n");
2901     if (p != NULL) *p = '\0';
2902     p = strpbrk(s, "\"?<>=!#-+|&,)*/%[]( \t\r\n");
2903     if (p != NULL)
2904     {
2905       err = nerr_raise (NERR_PARSE,
2906 	  "%s Invalid character in def %s argument: %c",
2907 	  find_context(parse, -1, tmp, sizeof(tmp)), arg, *p);
2908       break;
2909     }
2910     /* No argument case */
2911     if (*s == '\0' && macro->n_args == 0) break;
2912     if (*s == '\0')
2913     {
2914       err = nerr_raise (NERR_PARSE,
2915 	  "%s Missing argument name or extra comma in def %s",
2916 	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
2917       break;
2918     }
2919     carg = (CSARG *) calloc (1, sizeof(CSARG));
2920     if (carg == NULL)
2921     {
2922       err = nerr_raise (NERR_NOMEM,
2923 	  "%s Unable to allocate memory for CSARG in def %s",
2924 	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
2925       break;
2926     }
2927     if (larg == NULL)
2928     {
2929       macro->args = carg;
2930       larg = carg;
2931     }
2932     else
2933     {
2934       larg->next = carg;
2935       larg = carg;
2936     }
2937     macro->n_args++;
2938     carg->s = s;
2939     if (last == TRUE) break;
2940     s = a+1;
2941   }
2942   if (err)
2943   {
2944     dealloc_node(&node);
2945     dealloc_macro(&macro);
2946     return nerr_pass(err);
2947   }
2948 
2949   macro->tree = node;
2950   if (parse->macros)
2951   {
2952     macro->next = parse->macros;
2953   }
2954   parse->macros = macro;
2955 
2956   *(parse->next) = node;
2957   parse->next = &(node->case_0);
2958   parse->current = node;
2959 
2960   return STATUS_OK;
2961 }
2962 
rearrange_for_call(CSARG ** args)2963 static int rearrange_for_call(CSARG **args)
2964 {
2965   CSARG *larg = NULL;
2966   CSARG *carg = *args;
2967   CSARG *vargs = NULL;
2968   int nargs = 0;
2969 
2970   /* multiple argument case, we have to walk the args and reverse
2971    * them. Also handles single arg case since its the same as the
2972    * last arg */
2973   while (carg)
2974   {
2975     nargs++;
2976     if (carg->op_type != CS_OP_COMMA)
2977     {
2978       /* last argument */
2979       if (vargs)
2980 	carg->next = vargs;
2981       vargs = carg;
2982       break;
2983     }
2984     if (vargs)
2985       carg->expr1->next = vargs;
2986     vargs = carg->expr1;
2987     larg = carg;
2988     carg = carg->next;
2989     /* dealloc comma, but not its descendents */
2990     larg->next = NULL;
2991     larg->expr1 = NULL;
2992     dealloc_arg(&larg);
2993   }
2994   *args = vargs;
2995 
2996   return nargs;
2997 }
2998 
call_parse(CSPARSE * parse,int cmd,char * arg)2999 static NEOERR *call_parse (CSPARSE *parse, int cmd, char *arg)
3000 {
3001   NEOERR *err;
3002   CSTREE *node;
3003   CS_MACRO *macro;
3004   CSARG *carg;
3005   char *s, *a = NULL;
3006   char tmp[256];
3007   char name[256];
3008   int x = 0;
3009   int nargs = 0;
3010   STACK_ENTRY *entry;
3011 
3012   err = uListGet (parse->stack, -1, (void *)&entry);
3013   if (err != STATUS_OK) return nerr_pass(err);
3014 
3015   err = alloc_node (&node, parse);
3016   if (err) return nerr_pass(err);
3017   node->cmd = cmd;
3018   node->escape = entry->escape;
3019   arg++;
3020   s = arg;
3021   while (x < sizeof(name) && *s && *s != ' ' && *s != '#' && *s != '(')
3022   {
3023     name[x++] = *s;
3024     s++;
3025   }
3026   name[x] = '\0';
3027   while (*s && isspace(*s)) s++;
3028   if (*s == '\0' || *s != '(')
3029   {
3030     dealloc_node(&node);
3031     return nerr_raise (NERR_PARSE,
3032 	"%s Missing left paren in call %s",
3033 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
3034   }
3035   s++;
3036   /* Check to see if this macro exists */
3037   macro = parse->macros;
3038   while (macro != NULL)
3039   {
3040     if (!strcmp(macro->name, name)) break;
3041     macro = macro->next;
3042   }
3043   if (macro == NULL)
3044   {
3045     dealloc_node(&node);
3046     err = nerr_raise (NERR_PARSE, "%s Undefined macro called: %s",
3047           find_context(parse, -1, tmp, sizeof(tmp)), arg);
3048     if (parse->audit_mode) {
3049       /* Ignore macros that cannot be found */
3050       return _store_error(parse, err);
3051     }
3052     else {
3053       return err;
3054     }
3055   }
3056   node->arg1.op_type = CS_TYPE_MACRO;
3057   node->arg1.macro = macro;
3058 
3059   a = strrchr(s, ')');
3060   if (a == NULL)
3061   {
3062     dealloc_node(&node);
3063     return nerr_raise (NERR_PARSE,
3064 	"%s Missing right paren in call %s",
3065 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
3066   }
3067   *a = '\0';
3068 
3069   while (*s && isspace(*s)) s++;
3070   /* No arguments case */
3071   if (*s == '\0')
3072   {
3073     nargs = 0;
3074   }
3075   else
3076   {
3077     /* Parse arguments case */
3078     do
3079     {
3080       carg = (CSARG *) calloc (1, sizeof(CSARG));
3081       if (carg == NULL)
3082       {
3083 	err = nerr_raise (NERR_NOMEM,
3084 	    "%s Unable to allocate memory for CSARG in call %s",
3085 	    find_context(parse, -1, tmp, sizeof(tmp)), arg);
3086 	break;
3087       }
3088       err = parse_expr (parse, s, 0, carg);
3089       if (err) break;
3090       nargs = rearrange_for_call(&carg);
3091       node->vargs = carg;
3092     } while (0);
3093   }
3094   if (!err && nargs != macro->n_args)
3095   {
3096     err = nerr_raise (NERR_PARSE,
3097 	"%s Incorrect number of arguments, expected %d, got %d in call to macro %s: %s",
3098 	find_context(parse, -1, tmp, sizeof(tmp)), macro->n_args, nargs,
3099 	macro->name, arg);
3100   }
3101   if (err)
3102   {
3103     dealloc_node(&node);
3104     return nerr_pass(err);
3105   }
3106 
3107   *(parse->next) = node;
3108   parse->next = &(node->next);
3109   parse->current = node;
3110 
3111   return STATUS_OK;
3112 }
3113 
call_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)3114 static NEOERR *call_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
3115 {
3116   NEOERR *err = STATUS_OK;
3117   CS_LOCAL_MAP *call_map, *map;
3118   CS_MACRO *macro;
3119   CSARG *carg, *darg;
3120   HDF *var;
3121   int x;
3122 
3123   /* Reset the value of when_undef for the coming call evaluation.
3124    * This is only used here so it there's no need to reset its value after
3125    * the call. If this call is nested (escape == NEOS_ESCAPE_UNDEF), then
3126    * leave the when_undef variable alone. The parent call_eval should have
3127    * already defined it.
3128    */
3129   if (node->escape != NEOS_ESCAPE_UNDEF)
3130     parse->escaping.when_undef = node->escape;
3131 
3132   macro = node->arg1.macro;
3133   if (macro->n_args)
3134   {
3135     call_map = (CS_LOCAL_MAP *) calloc (macro->n_args, sizeof(CS_LOCAL_MAP));
3136     if (call_map == NULL)
3137       return nerr_raise (NERR_NOMEM,
3138                 "Unable to allocate memory for call_map in call_eval of %s",
3139                          macro->name);
3140   }
3141   else
3142   {
3143     call_map = NULL;
3144   }
3145 
3146   darg = macro->args;
3147   carg = node->vargs;
3148 
3149   for (x = 0; x < macro->n_args; x++)
3150   {
3151     CSARG val;
3152     map = &call_map[x];
3153     if (x) call_map[x-1].next = map;
3154 
3155     map->name = darg->s;
3156     err = eval_expr(parse, carg, &val);
3157     if (err) break;
3158     if (val.op_type & CS_TYPE_STRING)
3159     {
3160       map->s = val.s;
3161       map->type = val.op_type;
3162       map->map_alloc = val.alloc;
3163       val.alloc = 0;
3164     }
3165     else if (val.op_type & CS_TYPE_NUM)
3166     {
3167       map->n = val.n;
3168       map->type = CS_TYPE_NUM;
3169     }
3170     else if (val.op_type & (CS_TYPE_VAR | CS_TYPE_VAR_NUM))
3171     {
3172       CS_LOCAL_MAP *lmap;
3173       char *c;
3174       lmap = lookup_map (parse, val.s, &c);
3175       if (lmap != NULL && (lmap->type != CS_TYPE_VAR && lmap->type != CS_TYPE_VAR_NUM))
3176       {
3177 	/* if we're referencing a local var which maps to a string or
3178 	 * number... then copy  */
3179 	if (lmap->type == CS_TYPE_NUM)
3180 	{
3181 	  map->n = lmap->n;
3182 	  map->type = lmap->type;
3183 	}
3184 	else
3185 	{
3186 	  map->s = lmap->s;
3187 	  map->type = lmap->type;
3188 	}
3189       }
3190       else
3191       {
3192 	var = var_lookup_obj (parse, val.s);
3193 	map->h = var;
3194         map->type = CS_TYPE_VAR;
3195         /* Bring across the name we're mapping to, in case h doesn't exist and
3196          * we need to set it. */
3197         map->s = val.s;
3198         map->map_alloc = val.alloc;
3199         val.alloc = 0;
3200       }
3201     }
3202     else
3203     {
3204       ne_warn("Unsupported type %s in call_expr", expand_token_type(val.op_type, 1));
3205     }
3206     if (val.alloc) free(val.s);
3207     map->next = parse->locals;
3208 
3209     darg = darg->next;
3210     carg = carg->next;
3211   }
3212 
3213   if (err == STATUS_OK)
3214   {
3215     map = parse->locals;
3216     if (macro->n_args) parse->locals = call_map;
3217     err = render_node (parse, macro->tree->case_0);
3218     parse->locals = map;
3219   }
3220   for (x = 0; x < macro->n_args; x++)
3221   {
3222     if (call_map[x].map_alloc) free(call_map[x].s);
3223   }
3224   if (call_map) free (call_map);
3225 
3226   *next = node->next;
3227   return nerr_pass(err);
3228 }
3229 
set_parse(CSPARSE * parse,int cmd,char * arg)3230 static NEOERR *set_parse (CSPARSE *parse, int cmd, char *arg)
3231 {
3232   NEOERR *err;
3233   CSTREE *node;
3234   char *s;
3235   char tmp[256];
3236 
3237   err = alloc_node (&node, parse);
3238   if (err) return nerr_pass(err);
3239   node->cmd = cmd;
3240   arg++;
3241   s = arg;
3242   while (*s && *s != '=') s++;
3243   if (*s == '\0')
3244   {
3245     dealloc_node(&node);
3246     return nerr_raise (NERR_PARSE,
3247 	"%s Missing equals in set %s",
3248 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
3249   }
3250   *s = '\0';
3251   s++;
3252   err = parse_expr(parse, arg, 1, &(node->arg1));
3253   if (err)
3254   {
3255     dealloc_node(&node);
3256     return nerr_pass(err);
3257   }
3258 
3259   err = parse_expr(parse, s, 0, &(node->arg2));
3260   if (err)
3261   {
3262     dealloc_node(&node);
3263     return nerr_pass(err);
3264   }
3265 
3266   *(parse->next) = node;
3267   parse->next = &(node->next);
3268   parse->current = node;
3269 
3270   return STATUS_OK;
3271 }
3272 
set_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)3273 static NEOERR *set_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
3274 {
3275   NEOERR *err = STATUS_OK;
3276   CSARG val;
3277   CSARG set;
3278 
3279   err = eval_expr(parse, &(node->arg1), &set);
3280   if (err) return nerr_pass (err);
3281   err = eval_expr(parse, &(node->arg2), &val);
3282   if (err) {
3283     if (set.alloc) free(set.s);
3284     return nerr_pass (err);
3285   }
3286 
3287   if (set.op_type != CS_TYPE_NUM)
3288   {
3289     /* this allow for a weirdness where set:"foo"="bar"
3290      * actually sets the hdf var foo... */
3291     if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM))
3292     {
3293       char buf[256];
3294       long int n_val;
3295 
3296       n_val = arg_eval_num (parse, &val);
3297       snprintf (buf, sizeof(buf), "%ld", n_val);
3298       if (set.s)
3299       {
3300 	err = var_set_value (parse, set.s, buf);
3301       }
3302       else
3303       {
3304 	err = nerr_raise(NERR_ASSERT,
3305 	    "lvalue is NULL/empty in attempt to evaluate set to '%s'", buf);
3306       }
3307     }
3308     else
3309     {
3310       char *s = arg_eval (parse, &val);
3311       /* Do we set it to blank if s == NULL? */
3312       if (set.s)
3313       {
3314 	err = var_set_value (parse, set.s, s);
3315       }
3316       else
3317       {
3318 	err = nerr_raise(NERR_ASSERT,
3319 	    "lvalue is NULL/empty in attempt to evaluate set to '%s'",
3320 	    (s) ? s : "");
3321       }
3322     }
3323   } /* else WARNING */
3324   if (set.alloc) free(set.s);
3325   if (val.alloc) free(val.s);
3326 
3327   *next = node->next;
3328   return nerr_pass (err);
3329 }
3330 
loop_parse(CSPARSE * parse,int cmd,char * arg)3331 static NEOERR *loop_parse (CSPARSE *parse, int cmd, char *arg)
3332 {
3333   NEOERR *err;
3334   CSTREE *node;
3335   CSARG *carg, *larg = NULL;
3336   BOOL last = FALSE;
3337   char *lvar;
3338   char *p, *a;
3339   char tmp[256];
3340   int x;
3341 
3342   err = alloc_node (&node, parse);
3343   if (err) return nerr_pass(err);
3344   node->cmd = cmd;
3345   if (arg[0] == '!')
3346     node->flags |= CSF_REQUIRED;
3347   arg++;
3348 
3349   p = lvar = neos_strip(arg);
3350   while (*p && !isspace(*p) && *p != '=') p++;
3351   if (*p == '\0')
3352   {
3353     dealloc_node(&node);
3354     return nerr_raise (NERR_PARSE,
3355 	"%s Improperly formatted loop directive: %s",
3356 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
3357   }
3358   if (*p != '=')
3359   {
3360     *p++ = '\0';
3361     while (*p && *p != '=') p++;
3362     if (*p == '\0')
3363     {
3364       dealloc_node(&node);
3365       return nerr_raise (NERR_PARSE,
3366 	  "%s Improperly formatted loop directive: %s",
3367 	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
3368     }
3369     p++;
3370   }
3371   else
3372   {
3373     *p++ = '\0';
3374   }
3375   while (*p && isspace(*p)) p++;
3376   if (*p == '\0')
3377   {
3378     dealloc_node(&node);
3379     return nerr_raise (NERR_PARSE,
3380 	"%s Improperly formatted loop directive: %s",
3381 	find_context(parse, -1, tmp, sizeof(tmp)), arg);
3382   }
3383   node->arg1.op_type = CS_TYPE_VAR;
3384   node->arg1.s = lvar;
3385 
3386   x = 0;
3387   while (*p)
3388   {
3389     carg = (CSARG *) calloc (1, sizeof(CSARG));
3390     if (carg == NULL)
3391     {
3392       err = nerr_raise (NERR_NOMEM,
3393 	  "%s Unable to allocate memory for CSARG in loop %s",
3394 	  find_context(parse, -1, tmp, sizeof(tmp)), arg);
3395       break;
3396     }
3397     if (larg == NULL)
3398     {
3399       node->vargs = carg;
3400       larg = carg;
3401     }
3402     else
3403     {
3404       larg->next = carg;
3405       larg = carg;
3406     }
3407     x++;
3408     a = strpbrk(p, ",");
3409     if (a == NULL) last = TRUE;
3410     else *a = '\0';
3411     err = parse_expr (parse, p, 0, carg);
3412     if (err) break;
3413     if (last == TRUE) break;
3414     p = a+1;
3415   }
3416   if (!err && ((x < 1) || (x > 3)))
3417   {
3418     err = nerr_raise (NERR_PARSE,
3419 	"%s Incorrect number of arguments, expected 1, 2, or 3 got %d in loop: %s",
3420 	find_context(parse, -1, tmp, sizeof(tmp)), x, arg);
3421   }
3422 
3423   /* ne_warn ("loop %s %s", lvar, p); */
3424 
3425   *(parse->next) = node;
3426   parse->next = &(node->case_0);
3427   parse->current = node;
3428 
3429   return STATUS_OK;
3430 }
3431 
loop_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)3432 static NEOERR *loop_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
3433 {
3434   NEOERR *err = STATUS_OK;
3435   CS_LOCAL_MAP each_map;
3436   int var;
3437   int start = 0, end = 0, step = 1;
3438   int x, iter = 1;
3439   CSARG *carg;
3440   CSARG val;
3441 
3442   memset(&each_map, 0, sizeof(each_map));
3443 
3444   carg = node->vargs;
3445   if (carg == NULL) return nerr_raise (NERR_ASSERT, "No arguments in loop eval?");
3446   err = eval_expr(parse, carg, &val);
3447   if (err) return nerr_pass(err);
3448   end = arg_eval_num(parse, &val);
3449   if (val.alloc) free(val.s);
3450   if (carg->next)
3451   {
3452     start = end;
3453     carg = carg->next;
3454     err = eval_expr(parse, carg, &val);
3455     if (err) return nerr_pass(err);
3456     end = arg_eval_num(parse, &val);
3457     if (val.alloc) free(val.s);
3458     if (carg->next)
3459     {
3460       carg = carg->next;
3461       err = eval_expr(parse, carg, &val);
3462       if (err) return nerr_pass(err);
3463       step = arg_eval_num(parse, &val);
3464       if (val.alloc) free(val.s);
3465     }
3466   }
3467   if (((step < 0) && (start < end)) ||
3468       ((step > 0) && (end < start)))
3469   {
3470     iter = 0;
3471   }
3472   else if (step == 0)
3473   {
3474     iter = 0;
3475   }
3476   else
3477   {
3478     iter = abs((end - start) / step + 1);
3479   }
3480 
3481   if (iter > 0)
3482   {
3483     /* Init and install local map */
3484     each_map.type = CS_TYPE_NUM;
3485     each_map.name = node->arg1.s;
3486     each_map.next = parse->locals;
3487     each_map.first = 1;
3488     parse->locals = &each_map;
3489 
3490     var = start;
3491     for (x = 0, var = start; x < iter; x++, var += step)
3492     {
3493       if (x == iter - 1) each_map.last = 1;
3494       each_map.n = var;
3495       err = render_node (parse, node->case_0);
3496       if (each_map.map_alloc) {
3497         free(each_map.s);
3498         each_map.s = NULL;
3499       }
3500       if (each_map.first) each_map.first = 0;
3501       if (err != STATUS_OK) break;
3502     }
3503 
3504     /* Remove local map */
3505     parse->locals = each_map.next;
3506   }
3507 
3508   *next = node->next;
3509   return nerr_pass (err);
3510 }
3511 
skip_eval(CSPARSE * parse,CSTREE * node,CSTREE ** next)3512 static NEOERR *skip_eval (CSPARSE *parse, CSTREE *node, CSTREE **next)
3513 {
3514   *next = node->next;
3515   return STATUS_OK;
3516 }
render_node(CSPARSE * parse,CSTREE * node)3517 static NEOERR *render_node (CSPARSE *parse, CSTREE *node)
3518 {
3519   NEOERR *err = STATUS_OK;
3520 
3521   while (node != NULL)
3522   {
3523     /* ne_warn ("%s %08x", Commands[node->cmd].cmd, node); */
3524     err = (*(Commands[node->cmd].eval_handler))(parse, node, &node);
3525     if (err) break;
3526   }
3527   return nerr_pass(err);
3528 }
3529 
cs_render(CSPARSE * parse,void * ctx,CSOUTFUNC cb)3530 NEOERR *cs_render (CSPARSE *parse, void *ctx, CSOUTFUNC cb)
3531 {
3532   CSTREE *node;
3533 
3534   if (parse->tree == NULL)
3535     return nerr_raise (NERR_ASSERT, "No parse tree exists");
3536 
3537   parse->output_ctx = ctx;
3538   parse->output_cb = cb;
3539 
3540   node = parse->tree;
3541   return nerr_pass (render_node(parse, node));
3542 }
3543 
3544 /* **** Functions ******************************************** */
3545 
cs_register_function(CSPARSE * parse,const char * funcname,int n_args,CSFUNCTION function)3546 NEOERR *cs_register_function(CSPARSE *parse, const char *funcname,
3547                                   int n_args, CSFUNCTION function)
3548 {
3549   CS_FUNCTION *csf;
3550 
3551   /* Should we validate the parseability of the name? */
3552 
3553   csf = parse->functions;
3554   while (csf != NULL)
3555   {
3556     if (!strcmp(csf->name, funcname) && csf->function != function)
3557     {
3558       return nerr_raise(NERR_DUPLICATE,
3559 	  "Attempt to register duplicate function %s", funcname);
3560     }
3561     csf = csf->next;
3562   }
3563   csf = (CS_FUNCTION *) calloc (1, sizeof(CS_FUNCTION));
3564   if (csf == NULL)
3565     return nerr_raise(NERR_NOMEM,
3566 	"Unable to allocate memory to register function %s", funcname);
3567   csf->name = strdup(funcname);
3568   if (csf->name == NULL)
3569   {
3570     free(csf);
3571     return nerr_raise(NERR_NOMEM,
3572 	"Unable to allocate memory to register function %s", funcname);
3573   }
3574   csf->function = function;
3575   csf->n_args = n_args;
3576   csf->escape = NEOS_ESCAPE_NONE;
3577   csf->next = parse->functions;
3578   parse->functions = csf;
3579 
3580   return STATUS_OK;
3581 }
3582 
3583 /* This is similar to python's PyArg_ParseTuple, :
3584  *   s - string (allocated)
3585  *   i - int
3586  *   A - arg ptr (maybe later)
3587  */
cs_arg_parsev(CSPARSE * parse,CSARG * args,const char * fmt,va_list ap)3588 NEOERR * cs_arg_parsev(CSPARSE *parse, CSARG *args, const char *fmt,
3589                        va_list ap)
3590 {
3591   NEOERR *err = STATUS_OK;
3592   char **s;
3593   long int *i;
3594   CSARG val;
3595 
3596   while (*fmt)
3597   {
3598     memset(&val, 0, sizeof(val));
3599     err = eval_expr(parse, args, &val);
3600     if (err) return nerr_pass(err);
3601 
3602     switch (*fmt)
3603     {
3604       case 's':
3605 	s = va_arg(ap, char **);
3606 	if (s == NULL)
3607 	{
3608 	  err = nerr_raise(NERR_ASSERT,
3609 	      "Invalid number of arguments in call to cs_arg_parse");
3610 	  break;
3611 	}
3612 	*s = arg_eval_str_alloc(parse, &val);
3613 	break;
3614       case 'i':
3615 	i = va_arg(ap, long int *);
3616 	if (i == NULL)
3617 	{
3618 	  err = nerr_raise(NERR_ASSERT,
3619 	      "Invalid number of arguments in call to cs_arg_parse");
3620 	  break;
3621 	}
3622 	*i = arg_eval_num(parse, &val);
3623 	break;
3624       default:
3625 	break;
3626     }
3627     if (err) return nerr_pass(err);
3628     fmt++;
3629     args = args->next;
3630     if (val.alloc) free(val.s);
3631   }
3632   if (err) return nerr_pass(err);
3633   return STATUS_OK;
3634 }
3635 
cs_arg_parse(CSPARSE * parse,CSARG * args,const char * fmt,...)3636 NEOERR * cs_arg_parse(CSPARSE *parse, CSARG *args, const char *fmt, ...)
3637 {
3638   NEOERR *err;
3639   va_list ap;
3640 
3641   va_start(ap, fmt);
3642   err = cs_arg_parsev(parse, args, fmt, ap);
3643   va_end(ap);
3644   return nerr_pass(err);
3645 }
3646 
_builtin_subcount(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3647 static NEOERR * _builtin_subcount(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
3648 {
3649   NEOERR *err;
3650   HDF *obj;
3651   int count = 0;
3652   CSARG val;
3653 
3654   memset(&val, 0, sizeof(val));
3655   err = eval_expr(parse, args, &val);
3656   if (err) return nerr_pass(err);
3657 
3658   /* default for non-vars is 0 children */
3659   result->op_type = CS_TYPE_NUM;
3660   result->n = 0;
3661 
3662   if (val.op_type & CS_TYPE_VAR)
3663   {
3664     obj = var_lookup_obj (parse, val.s);
3665     if (obj != NULL)
3666     {
3667       obj = hdf_obj_child(obj);
3668       while (obj != NULL)
3669       {
3670 	count++;
3671 	obj = hdf_obj_next(obj);
3672       }
3673     }
3674     result->n = count;
3675   }
3676   if (val.alloc) free(val.s);
3677 
3678   return STATUS_OK;
3679 }
3680 
_builtin_str_length(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3681 static NEOERR * _builtin_str_length(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
3682 {
3683   NEOERR *err;
3684   CSARG val;
3685 
3686   memset(&val, 0, sizeof(val));
3687   err = eval_expr(parse, args, &val);
3688   if (err) return nerr_pass(err);
3689 
3690   /* non var/string objects have 0 length */
3691   result->op_type = CS_TYPE_NUM;
3692   result->n = 0;
3693 
3694   if (val.op_type & (CS_TYPE_VAR | CS_TYPE_STRING))
3695   {
3696     char *s = arg_eval(parse, &val);
3697     if (s) result->n = strlen(s);
3698   }
3699   if (val.alloc) free(val.s);
3700   return STATUS_OK;
3701 }
3702 
_builtin_str_crc(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3703 static NEOERR * _builtin_str_crc(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
3704                                  CSARG *result)
3705 {
3706   NEOERR *err;
3707   CSARG val;
3708 
3709   memset(&val, 0, sizeof(val));
3710   err = eval_expr(parse, args, &val);
3711   if (err) return nerr_pass(err);
3712 
3713   /* non var/string objects have 0 length */
3714   result->op_type = CS_TYPE_NUM;
3715   result->n = 0;
3716 
3717   if (val.op_type & (CS_TYPE_VAR | CS_TYPE_STRING))
3718   {
3719     char *s = arg_eval(parse, &val);
3720     if (s) result->n = ne_crc((unsigned char *)s, strlen(s));
3721   }
3722   if (val.alloc) free(val.s);
3723   return STATUS_OK;
3724 }
3725 
3726 
_builtin_str_find(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3727 static NEOERR * _builtin_str_find(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
3728 {
3729   NEOERR *err;
3730   char *s = NULL;
3731   char *substr = NULL;
3732   char *pstr = NULL;
3733 
3734   result->op_type = CS_TYPE_NUM;
3735   result->n = -1;
3736 
3737   err = cs_arg_parse(parse, args, "ss", &s, &substr);
3738   if (err) return nerr_pass(err);
3739   /* If null arguments, return -1 index */
3740   if (s == NULL || substr == NULL) {
3741     if (s) free(s);
3742     if (substr) free(substr);
3743     return STATUS_OK;
3744   }
3745   pstr = strstr(s, substr);
3746   if (pstr != NULL) {
3747     result->n = (pstr - s) / sizeof(char);
3748   }
3749   free(s);
3750   free(substr);
3751   return STATUS_OK;
3752 }
3753 
3754 
_builtin_name(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3755 static NEOERR * _builtin_name(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
3756 {
3757   NEOERR *err;
3758   HDF *obj;
3759   CSARG val;
3760 
3761   memset(&val, 0, sizeof(val));
3762   err = eval_expr(parse, args, &val);
3763   if (err) return nerr_pass(err);
3764 
3765   result->op_type = CS_TYPE_STRING;
3766   result->s = "";
3767 
3768   if (val.op_type & CS_TYPE_VAR)
3769   {
3770     obj = var_lookup_obj (parse, val.s);
3771     if (obj != NULL)
3772       result->s = hdf_obj_name(obj);
3773   }
3774   else if (val.op_type & CS_TYPE_STRING)
3775   {
3776     result->s = val.s;
3777     result->alloc = val.alloc;
3778     val.alloc = 0;
3779   }
3780   if (val.alloc) free(val.s);
3781   return STATUS_OK;
3782 }
3783 
3784 /* Check to see if a local variable is the first in an each/loop sequence */
_builtin_first(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3785 static NEOERR * _builtin_first(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
3786                                CSARG *result)
3787 {
3788   NEOERR *err;
3789   CS_LOCAL_MAP *map;
3790   char *c;
3791   CSARG val;
3792 
3793   memset(&val, 0, sizeof(val));
3794   err = eval_expr(parse, args, &val);
3795   if (err) return nerr_pass(err);
3796 
3797   /* default is "not first" */
3798   result->op_type = CS_TYPE_NUM;
3799   result->n = 0;
3800 
3801   /* Only applies to possible local vars */
3802   if ((val.op_type & CS_TYPE_VAR) && !strchr(val.s, '.'))
3803   {
3804     map = lookup_map (parse, val.s, &c);
3805     if (map && map->first)
3806       result->n = 1;
3807   }
3808   if (val.alloc) free(val.s);
3809   return STATUS_OK;
3810 }
3811 
3812 /* Check to see if a local variable is the last in an each/loop sequence */
3813 /* TODO: consider making this work on regular HDF vars */
_builtin_last(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3814 static NEOERR * _builtin_last(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
3815                                CSARG *result)
3816 {
3817   NEOERR *err;
3818   CS_LOCAL_MAP *map;
3819   char *c;
3820   CSARG val;
3821 
3822   memset(&val, 0, sizeof(val));
3823   err = eval_expr(parse, args, &val);
3824   if (err) return nerr_pass(err);
3825 
3826   /* default is "not last" */
3827   result->op_type = CS_TYPE_NUM;
3828   result->n = 0;
3829 
3830   /* Only applies to possible local vars */
3831   if ((val.op_type & CS_TYPE_VAR) && !strchr(val.s, '.'))
3832   {
3833     map = lookup_map (parse, val.s, &c);
3834     if (map) {
3835       if (map->last) {
3836         result->n = 1;
3837       } else if (map->type == CS_TYPE_VAR) {
3838         if (hdf_obj_next(map->h) == NULL) {
3839           result->n = 1;
3840         }
3841       }
3842     }
3843   }
3844   if (val.alloc) free(val.s);
3845   return STATUS_OK;
3846 }
3847 
3848 /* returns the absolute value (ie, positive) of a number */
_builtin_abs(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3849 static NEOERR * _builtin_abs (CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
3850                               CSARG *result)
3851 {
3852   NEOERR *err;
3853   int n1 = 0;
3854   CSARG val;
3855 
3856   memset(&val, 0, sizeof(val));
3857   err = eval_expr(parse, args, &val);
3858   if (err) return nerr_pass(err);
3859 
3860   result->op_type = CS_TYPE_NUM;
3861   n1 = arg_eval_num(parse, &val);
3862   result->n = abs(n1);
3863 
3864   if (val.alloc) free(val.s);
3865   return STATUS_OK;
3866 }
3867 
3868 /* returns the larger or two integers */
_builtin_max(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3869 static NEOERR * _builtin_max (CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
3870                               CSARG *result)
3871 {
3872   NEOERR *err;
3873   long int n1 = 0;
3874   long int n2 = 0;
3875 
3876   result->op_type = CS_TYPE_NUM;
3877   result->n = 0;
3878 
3879   err = cs_arg_parse(parse, args, "ii", &n1, &n2);
3880   if (err) return nerr_pass(err);
3881   result->n = (n1 > n2) ? n1 : n2;
3882 
3883   return STATUS_OK;
3884 }
3885 
3886 /* returns the smaller or two integers */
_builtin_min(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3887 static NEOERR * _builtin_min (CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
3888                               CSARG *result)
3889 {
3890   NEOERR *err;
3891   long int n1 = 0;
3892   long int n2 = 0;
3893 
3894   result->op_type = CS_TYPE_NUM;
3895   result->n = 0;
3896 
3897   err = cs_arg_parse(parse, args, "ii", &n1, &n2);
3898   if (err) return nerr_pass(err);
3899   result->n = (n1 < n2) ? n1 : n2;
3900 
3901   return STATUS_OK;
3902 }
3903 
_builtin_str_slice(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3904 static NEOERR * _builtin_str_slice (CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
3905 {
3906   NEOERR *err;
3907   char *s = NULL;
3908   char *slice;
3909   long int b = 0;
3910   long int e = 0;
3911   size_t len;
3912 
3913   result->op_type = CS_TYPE_STRING;
3914   result->s = "";
3915 
3916   err = cs_arg_parse(parse, args, "sii", &s, &b, &e);
3917   if (err) return nerr_pass(err);
3918   /* If null, return empty string */
3919   if (s == NULL) return STATUS_OK;
3920   len = strlen(s);
3921   if (b < 0 && e == 0) e = len;
3922   if (b < 0) b += len;
3923   if (e < 0) e += len;
3924   if (e > len) e = len;
3925   /* Its the whole string */
3926   if (b == 0 && e == len)
3927   {
3928     result->s = s;
3929     result->alloc = 1;
3930     return STATUS_OK;
3931   }
3932   if (e < b) b = e;
3933   if (b == e)
3934   {
3935     /* If null, return empty string */
3936     free(s);
3937     return STATUS_OK;
3938   }
3939   slice = (char *) malloc (sizeof(char) * (e-b+1));
3940   if (slice == NULL)
3941     return nerr_raise(NERR_NOMEM, "Unable to allocate memory for string slice");
3942   strncpy(slice, s + b, e-b);
3943   free(s);
3944   slice[e-b] = '\0';
3945 
3946   result->s = slice;
3947   result->alloc = 1;
3948 
3949   return STATUS_OK;
3950 }
3951 
3952 #ifdef ENABLE_GETTEXT
_builtin_gettext(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3953 static NEOERR * _builtin_gettext(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
3954 {
3955   NEOERR *err;
3956   char *s;
3957   CSARG val;
3958 
3959   memset(&val, 0, sizeof(val));
3960   err = eval_expr(parse, args, &val);
3961   if (err) return nerr_pass(err);
3962 
3963   result->op_type = CS_TYPE_STRING;
3964   result->s = "";
3965 
3966   if (val.op_type & (CS_TYPE_VAR | CS_TYPE_STRING))
3967   {
3968     s = arg_eval(parse, &val);
3969     if (s)
3970     {
3971       result->s = gettext(s);
3972     }
3973   }
3974   if (val.alloc) free(val.s);
3975   return STATUS_OK;
3976 }
3977 #endif
3978 
_str_func_wrapper(CSPARSE * parse,CS_FUNCTION * csf,CSARG * args,CSARG * result)3979 static NEOERR * _str_func_wrapper (CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result)
3980 {
3981   NEOERR *err;
3982   char *s;
3983   CSARG val;
3984 
3985   memset(&val, 0, sizeof(val));
3986   err = eval_expr(parse, args, &val);
3987   if (err) return nerr_pass(err);
3988 
3989   if (val.op_type & (CS_TYPE_VAR | CS_TYPE_STRING))
3990   {
3991     result->op_type = CS_TYPE_STRING;
3992     result->n = 0;
3993 
3994     s = arg_eval(parse, &val);
3995     if (s)
3996     {
3997       err = csf->str_func(s, &(result->s));
3998       if (err) return nerr_pass(err);
3999       result->alloc = 1;
4000     }
4001   }
4002   else
4003   {
4004     result->op_type = val.op_type;
4005     result->n = val.n;
4006     result->s = val.s;
4007     result->alloc = val.alloc;
4008     val.alloc = 0;
4009   }
4010   if (val.alloc) free(val.s);
4011   return STATUS_OK;
4012 }
4013 
cs_register_strfunc(CSPARSE * parse,char * funcname,CSSTRFUNC str_func)4014 NEOERR *cs_register_strfunc(CSPARSE *parse, char *funcname, CSSTRFUNC str_func)
4015 {
4016   NEOERR *err;
4017 
4018   err = cs_register_function(parse, funcname, 1, _str_func_wrapper);
4019   if (err) return nerr_pass(err);
4020   parse->functions->str_func = str_func;
4021 
4022   return STATUS_OK;
4023 }
4024 
cs_register_esc_strfunc(CSPARSE * parse,char * funcname,CSSTRFUNC str_func)4025 NEOERR *cs_register_esc_strfunc(CSPARSE *parse, char *funcname,
4026                                 CSSTRFUNC str_func)
4027 {
4028   NEOERR *err;
4029 
4030   err = cs_register_strfunc(parse, funcname, str_func);
4031   if (err) return nerr_pass(err);
4032   parse->functions->escape = NEOS_ESCAPE_FUNCTION;
4033 
4034   return STATUS_OK;
4035 }
4036 
4037 /* **** CS Initialize/Destroy ************************************ */
cs_init(CSPARSE ** parse,HDF * hdf)4038 NEOERR *cs_init (CSPARSE **parse, HDF *hdf) {
4039   return nerr_pass(cs_init_internal(parse, hdf, NULL));
4040 }
4041 
cs_init_internal(CSPARSE ** parse,HDF * hdf,CSPARSE * parent)4042 static NEOERR *cs_init_internal (CSPARSE **parse, HDF *hdf, CSPARSE *parent)
4043 {
4044   NEOERR *err = STATUS_OK;
4045   CSPARSE *my_parse;
4046   STACK_ENTRY *entry;
4047   char *esc_value;
4048   CS_ESCAPE_MODES *esc_cursor;
4049 
4050   err = nerr_init();
4051   if (err != STATUS_OK) return nerr_pass (err);
4052 
4053   my_parse = (CSPARSE *) calloc (1, sizeof (CSPARSE));
4054   if (my_parse == NULL)
4055     return nerr_raise (NERR_NOMEM, "Unable to allocate memory for CSPARSE");
4056 
4057   err = uListInit (&(my_parse->stack), 10, 0);
4058   if (err != STATUS_OK)
4059   {
4060     free(my_parse);
4061     return nerr_pass(err);
4062   }
4063   err = uListInit (&(my_parse->alloc), 10, 0);
4064   if (err != STATUS_OK)
4065   {
4066     free(my_parse);
4067     return nerr_pass(err);
4068   }
4069   err = alloc_node (&(my_parse->tree), my_parse);
4070   if (err != STATUS_OK)
4071   {
4072     cs_destroy (&my_parse);
4073     return nerr_pass(err);
4074   }
4075   my_parse->current = my_parse->tree;
4076   my_parse->next = &(my_parse->current->next);
4077 
4078   entry = (STACK_ENTRY *) calloc (1, sizeof (STACK_ENTRY));
4079   if (entry == NULL)
4080   {
4081     cs_destroy (&my_parse);
4082     return nerr_raise (NERR_NOMEM,
4083 	"Unable to allocate memory for stack entry");
4084   }
4085   entry->state = ST_GLOBAL;
4086   entry->tree = my_parse->current;
4087   entry->location = 0;
4088   entry->escape = NEOS_ESCAPE_NONE;
4089   err = uListAppend(my_parse->stack, entry);
4090   if (err != STATUS_OK) {
4091     free (entry);
4092     cs_destroy(&my_parse);
4093     return nerr_pass(err);
4094   }
4095   my_parse->tag = hdf_get_value(hdf, "Config.TagStart", "cs");
4096   my_parse->taglen = strlen(my_parse->tag);
4097   my_parse->hdf = hdf;
4098 
4099   /* Let's set the default escape data */
4100   my_parse->escaping.global_ctx = NEOS_ESCAPE_NONE;
4101   my_parse->escaping.next_stack = NEOS_ESCAPE_NONE;
4102   my_parse->escaping.when_undef = NEOS_ESCAPE_NONE;
4103 
4104   /* See CS_ESCAPE_MODES. 0 is "none" */
4105   esc_value = hdf_get_value(hdf, "Config.VarEscapeMode", EscapeModes[0].mode);
4106   /* Let's ensure the specified escape mode is valid and proceed */
4107   for (esc_cursor = &EscapeModes[0];
4108        esc_cursor->mode != NULL;
4109        esc_cursor++)
4110     if (!strcmp(esc_value, esc_cursor->mode))
4111     {
4112       my_parse->escaping.global_ctx = esc_cursor->context;
4113       my_parse->escaping.next_stack = esc_cursor->context;
4114       entry->escape = esc_cursor->context;
4115       break;
4116     }
4117   /* Didn't find an acceptable value we were looking for */
4118   if (esc_cursor->mode == NULL) {
4119     cs_destroy (&my_parse);
4120     return nerr_raise (NERR_OUTOFRANGE,
4121       "Invalid HDF value for Config.VarEscapeMode (none,html,js,url): %s",
4122       esc_value);
4123   }
4124 
4125   /* Read configuration value to determine whether to enable audit mode */
4126   my_parse->audit_mode = hdf_get_int_value(hdf, "Config.EnableAuditMode", 0);
4127 
4128   my_parse->err_list = NULL;
4129 
4130   if (parent == NULL)
4131   {
4132     static struct _builtin_functions {
4133       const char *name;
4134       int nargs;
4135       CSFUNCTION function;
4136     } Builtins[] = {
4137       { "len", 1, _builtin_subcount },
4138       { "subcount", 1, _builtin_subcount },
4139       { "name", 1, _builtin_name },
4140       { "first", 1, _builtin_first },
4141       { "last", 1, _builtin_last },
4142       { "abs", 1, _builtin_abs },
4143       { "max", 2, _builtin_max },
4144       { "min", 2, _builtin_min },
4145       { "string.find", 2, _builtin_str_find },
4146       { "string.slice", 3, _builtin_str_slice },
4147       { "string.length", 1, _builtin_str_length },
4148       { "string.crc", 1, _builtin_str_crc},
4149 #ifdef ENABLE_GETTEXT
4150       { "_", 1, _builtin_gettext },
4151 #endif
4152       { NULL, 0, NULL },
4153     };
4154     int x = 0;
4155     while (Builtins[x].name != NULL) {
4156       err = cs_register_function(my_parse, Builtins[x].name, Builtins[x].nargs,
4157                                Builtins[x].function);
4158       if (err)
4159       {
4160         cs_destroy(&my_parse);
4161         return nerr_pass(err);
4162       }
4163       x++;
4164     }
4165     /* Set global_hdf to be null */
4166     my_parse->global_hdf = NULL;
4167     my_parse->parent = NULL;
4168   }
4169   else
4170   {
4171     /* TODO: macros and functions should actually not be duplicated, they
4172      * should just be modified in lookup to walk the CS struct hierarchy we're
4173      * creating here */
4174     /* BUG: We currently can't copy the macros because they reference the parse
4175      * tree, so if this sub-parse tree adds a macro, the macro reference will
4176      * persist, but the parse tree it points to will be gone when the sub-parse
4177      * is gone. */
4178     my_parse->functions = parent->functions;
4179     my_parse->global_hdf = parent->global_hdf;
4180     my_parse->fileload = parent->fileload;
4181     my_parse->fileload_ctx = parent->fileload_ctx;
4182     // This should be safe since locals handling is done entirely local to the
4183     // eval functions, not globally by the parse handling.  This should
4184     // pass the locals down to the new parse context to make locals work with
4185     // lvar
4186     my_parse->locals = parent->locals;
4187     my_parse->parent = parent;
4188 
4189     /* Copy the audit flag from parent */
4190     my_parse->audit_mode = parent->audit_mode;
4191   }
4192 
4193   *parse = my_parse;
4194   return STATUS_OK;
4195 }
4196 
cs_register_fileload(CSPARSE * parse,void * ctx,CSFILELOAD fileload)4197 void cs_register_fileload(CSPARSE *parse, void *ctx, CSFILELOAD fileload) {
4198   if (parse != NULL) {
4199     parse->fileload_ctx = ctx;
4200     parse->fileload = fileload;
4201   }
4202 }
4203 
cs_destroy(CSPARSE ** parse)4204 void cs_destroy (CSPARSE **parse)
4205 {
4206   CSPARSE *my_parse = *parse;
4207 
4208   if (my_parse == NULL)
4209     return;
4210 
4211   uListDestroy (&(my_parse->stack), ULIST_FREE);
4212   uListDestroy (&(my_parse->alloc), ULIST_FREE);
4213 
4214   dealloc_macro(&my_parse->macros);
4215   dealloc_node(&(my_parse->tree));
4216   if (my_parse->parent == NULL) {
4217     dealloc_function(&(my_parse->functions));
4218   }
4219 
4220   /* Free list of errors */
4221   if (my_parse->err_list != NULL) {
4222     CS_ERROR *ptr;
4223 
4224     while (my_parse->err_list) {
4225       ptr = my_parse->err_list->next;
4226       free(my_parse->err_list->err);
4227       free(my_parse->err_list);
4228       my_parse->err_list = ptr;
4229     }
4230   }
4231 
4232   free(my_parse);
4233   *parse = NULL;
4234 }
4235 
4236 /* **** CS Debug Dumps ******************************************** */
dump_node(CSPARSE * parse,CSTREE * node,int depth,void * ctx,CSOUTFUNC cb,char * buf,int blen)4237 static NEOERR *dump_node (CSPARSE *parse, CSTREE *node, int depth, void *ctx,
4238     CSOUTFUNC cb, char *buf, int blen)
4239 {
4240   NEOERR *err;
4241 
4242   while (node != NULL)
4243   {
4244     snprintf (buf, blen, "%*s %s ", depth, "", Commands[node->cmd].cmd);
4245     err = cb (ctx, buf);
4246     if (err) return nerr_pass (err);
4247     if (node->cmd)
4248     {
4249       if (node->arg1.op_type)
4250       {
4251 	if (node->arg1.op_type == CS_TYPE_NUM)
4252 	{
4253 	  snprintf (buf, blen, "%ld ", node->arg1.n);
4254 	}
4255 	else if (node->arg1.op_type == CS_TYPE_MACRO)
4256 	{
4257 	  snprintf (buf, blen, "%s ", node->arg1.macro->name);
4258 	}
4259 	else
4260 	{
4261 	  snprintf (buf, blen, "%s ", node->arg1.s);
4262 	}
4263 	err = cb (ctx, buf);
4264 	if (err) return nerr_pass (err);
4265       }
4266       if (node->arg2.op_type)
4267       {
4268 	if (node->arg2.op_type == CS_TYPE_NUM)
4269 	{
4270 	  snprintf (buf, blen, "%ld", node->arg2.n);
4271 	}
4272 	else
4273 	{
4274 	  snprintf (buf, blen, "%s", node->arg2.s);
4275 	}
4276 	err = cb (ctx, buf);
4277 	if (err) return nerr_pass (err);
4278       }
4279       if (node->vargs)
4280       {
4281 	CSARG *arg;
4282 	arg = node->vargs;
4283 	while (arg)
4284 	{
4285 	  if (arg->op_type == CS_TYPE_NUM)
4286 	  {
4287 	    snprintf (buf, blen, "%ld ", arg->n);
4288 	  }
4289 	  else
4290 	  {
4291 	    snprintf (buf, blen, "%s ", arg->s);
4292 	  }
4293 	  err = cb (ctx, buf);
4294 	  if (err) return nerr_pass (err);
4295 	  arg = arg->next;
4296 	}
4297       }
4298     }
4299     err = cb (ctx, "\n");
4300     if (err) return nerr_pass (err);
4301     if (node->case_0)
4302     {
4303       snprintf (buf, blen, "%*s %s\n", depth, "", "Case 0");
4304       err = cb (ctx, buf);
4305       if (err) return nerr_pass (err);
4306       err = dump_node (parse, node->case_0, depth+1, ctx, cb, buf, blen);
4307       if (err) return nerr_pass (err);
4308     }
4309     if (node->case_1)
4310     {
4311       snprintf (buf, blen, "%*s %s\n", depth, "", "Case 1");
4312       err = cb (ctx, buf);
4313       if (err) return nerr_pass (err);
4314       err = dump_node (parse, node->case_1, depth+1, ctx, cb, buf, blen);
4315       if (err) return nerr_pass (err);
4316     }
4317     node = node->next;
4318   }
4319   return STATUS_OK;
4320 }
4321 
cs_dump(CSPARSE * parse,void * ctx,CSOUTFUNC cb)4322 NEOERR *cs_dump (CSPARSE *parse, void *ctx, CSOUTFUNC cb)
4323 {
4324   CSTREE *node;
4325   char buf[4096];
4326 
4327   if (parse->tree == NULL)
4328     return nerr_raise (NERR_ASSERT, "No parse tree exists");
4329 
4330   node = parse->tree;
4331   return nerr_pass (dump_node (parse, node, 0, ctx, cb, buf, sizeof(buf)));
4332 }
4333 
4334 #if 0
4335 static char *node_name (CSTREE *node)
4336 {
4337   static char buf[256];
4338 
4339   if (node == NULL)
4340     snprintf (buf, sizeof(buf), "NULL");
4341   else
4342     snprintf (buf, sizeof(buf), "%s_%08x", Commands[node->cmd].cmd,
4343 	node->node_num);
4344 
4345   return buf;
4346 }
4347 
4348 static NEOERR *dump_node_pre_c (CSPARSE *parse, CSTREE *node, FILE *fp)
4349 {
4350   NEOERR *err;
4351 
4352   while (node != NULL)
4353   {
4354     fprintf (fp, "CSTREE %s;\n", node_name(node));
4355     if (node->case_0)
4356     {
4357       err = dump_node_pre_c (parse, node->case_0, fp);
4358       if (err != STATUS_OK) nerr_pass (err);
4359     }
4360     if (node->case_1)
4361     {
4362       err = dump_node_pre_c (parse, node->case_1, fp);
4363       if (err != STATUS_OK) nerr_pass (err);
4364     }
4365     node = node->next;
4366   }
4367   return STATUS_OK;
4368 }
4369 
4370 static NEOERR *dump_node_c (CSPARSE *parse, CSTREE *node, FILE *fp)
4371 {
4372   NEOERR *err;
4373   char *s;
4374 
4375   while (node != NULL)
4376   {
4377     fprintf (fp, "CSTREE %s =\n\t{%d, %d, %d, ", node_name(node), node->node_num,
4378 	node->cmd, node->flags);
4379     s = repr_string_alloc (node->arg1.s);
4380     if (s == NULL)
4381       return nerr_raise(NERR_NOMEM, "Unable to allocate space for repr");
4382     fprintf (fp, "\n\t  { %d, %s, %ld }, ", node->arg1.op_type, s, node->arg1.n);
4383     free(s);
4384     s = repr_string_alloc (node->arg2.s);
4385     if (s == NULL)
4386       return nerr_raise(NERR_NOMEM, "Unable to allocate space for repr");
4387     fprintf (fp, "\n\t  { %d, %s, %ld }, ", node->arg2.op_type, s, node->arg2.n);
4388     free(s);
4389     if (node->case_0)
4390       fprintf (fp, "\n\t%d, &%s, ", node->op, node_name(node->case_0));
4391     else
4392       fprintf (fp, "\n\t%d, NULL, ", node->op);
4393     if (node->case_1)
4394       fprintf (fp, "&%s, ", node_name(node->case_1));
4395     else
4396       fprintf (fp, "NULL, ");
4397     if (node->next)
4398       fprintf (fp, "&%s};\n\n", node_name(node->next));
4399     else
4400       fprintf (fp, "NULL};\n\n");
4401     if (node->case_0)
4402     {
4403       err = dump_node_c (parse, node->case_0, fp);
4404       if (err != STATUS_OK) nerr_pass (err);
4405     }
4406     if (node->case_1)
4407     {
4408       err = dump_node_c (parse, node->case_1, fp);
4409       if (err != STATUS_OK) nerr_pass (err);
4410     }
4411     node = node->next;
4412   }
4413   return STATUS_OK;
4414 }
4415 
4416 NEOERR *cs_dump_c (CSPARSE *parse, char *path)
4417 {
4418   CSTREE *node;
4419   FILE *fp;
4420   NEOERR *err;
4421 
4422   if (parse->tree == NULL)
4423     return nerr_raise (NERR_ASSERT, "No parse tree exists");
4424 
4425   fp = fopen(path, "w");
4426   if (fp == NULL)
4427   {
4428     return nerr_raise (NERR_SYSTEM,
4429 	"Unable to open file %s for writing: [%d] %s", path, errno,
4430 	strerror(errno));
4431   }
4432 
4433   fprintf(fp, "/* Auto-generated file: DO NOT EDIT */\n");
4434   fprintf(fp, "#include <stdlib.h>\n\n");
4435   fprintf(fp, "#include \"cs.h\"\n");
4436   node = parse->tree;
4437   err = dump_node_pre_c (parse, node, fp);
4438   fprintf(fp, "\n");
4439   err = dump_node_c (parse, node, fp);
4440   fclose(fp);
4441   return nerr_pass (err);
4442 }
4443 #endif
4444