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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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... */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 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 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 } 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 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 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 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 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 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 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 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 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 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 3512 static NEOERR *skip_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) 3513 { 3514 *next = node->next; 3515 return STATUS_OK; 3516 } 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 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 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 */ 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 ************************************ */ 4038 NEOERR *cs_init (CSPARSE **parse, HDF *hdf) { 4039 return nerr_pass(cs_init_internal(parse, hdf, NULL)); 4040 } 4041 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 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 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 ******************************************** */ 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 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