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 *)¤t_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(¯o);
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(¯o);
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