diff -ur clearsilver-0.6.2/Makefile clearsilver-0.7.0/Makefile --- clearsilver-0.6.2/Makefile Mon May 13 17:43:00 2002 +++ clearsilver-0.7.0/Makefile Mon May 20 00:39:04 2002 @@ -13,6 +13,10 @@ OUTDIRS = bin libs +# These are blank here... but populated under automated build +VERSION = +RELEASE = + all: cs cs: output_dir @@ -95,4 +99,4 @@ trakken: cs $(MAKE) -C retrieve - $(MAKE) -C trakken + $(MAKE) VERSION=$(VERSION) RELEASE=$(RELEASE) -C trakken diff -ur clearsilver-0.6.2/cgi/cgi.c clearsilver-0.7.0/cgi/cgi.c --- clearsilver-0.6.2/cgi/cgi.c Tue Apr 30 20:05:15 2002 +++ clearsilver-0.7.0/cgi/cgi.c Wed Jul 3 15:33:57 2002 @@ -25,6 +25,7 @@ #include "util/neo_misc.h" #include "util/neo_str.h" #include "cgi.h" +#include "html.h" #include "cs/cs.h" /* HACK for now, until we actually support autoconf/configure */ @@ -140,6 +141,53 @@ return s; } +NEOERR *cgi_js_escape (char *buf, char **esc) +{ + int nl = 0; + int l = 0; + char *s; + + while (buf[l]) + { + if (buf[l] == '/' || buf[l] == '&' || buf[l] == '"' || buf[l] == '\'' || + buf[l] == '\\' || buf[l] == '>' || buf[l] == '<' || + buf[l] < 32 || buf[l] > 122) + { + nl += 3; + } + nl++; + l++; + } + + s = (char *) malloc (sizeof(char) * (nl + 1)); + if (s == NULL) + return nerr_raise (NERR_NOMEM, "Unable to allocate memory to escape %s", + buf); + + nl = 0; l = 0; + while (buf[l]) + { + if (buf[l] == '/' || buf[l] == '&' || buf[l] == '"' || buf[l] == '\'' || + buf[l] == '\\' || buf[l] == '>' || buf[l] == '<' || + buf[l] < 32 || buf[l] > 122) + { + s[nl++] = '\\'; + s[nl++] = 'x'; + s[nl++] = "0123456789ABCDEF"[buf[l] / 16]; + s[nl++] = "0123456789ABCDEF"[buf[l] % 16]; + l++; + } + else + { + s[nl++] = buf[l++]; + } + } + s[nl] = '\0'; + + *esc = s; + return STATUS_OK; +} + NEOERR *cgi_url_escape_more (char *buf, char **esc, char *other) { int nl = 0; @@ -764,11 +812,13 @@ int use_deflate = 0; int use_gzip = 0; int do_debug = 0; + int do_timefooter = 0; char *s, *e; s = hdf_get_value (cgi->hdf, "Query.debug", NULL); e = hdf_get_value (cgi->hdf, "Config.DebugPassword", NULL); if (s && e && !strcmp(s, e)) do_debug = 1; + do_timefooter = hdf_get_int_value (cgi->hdf, "Config.TimeFooter", 1); dis = ne_timef(); if (err != STATUS_OK) return nerr_pass (err); @@ -802,7 +852,7 @@ s = hdf_get_value (cgi->hdf, "HTTP.UserAgent", NULL); if (s) { - if (strstr(s, "MSIE 4") || strstr(s, "MSIE 5")) + if (strstr(s, "MSIE 4") || strstr(s, "MSIE 5") || strstr(s, "MSIE 6")) { e = hdf_get_value (cgi->hdf, "HTTP.Accept", NULL); if (e && !strcmp(e, "*/*")) @@ -847,10 +897,13 @@ char buf[50]; int x; - snprintf (buf, sizeof(buf), "\n\n", - dis - cgi->time_start, use_deflate || use_gzip); - err = string_append (str, buf); - if (err != STATUS_OK) return nerr_pass(err); + if (do_timefooter) + { + snprintf (buf, sizeof(buf), "\n\n", + dis - cgi->time_start, use_deflate || use_gzip); + err = string_append (str, buf); + if (err != STATUS_OK) return nerr_pass(err); + } if (do_debug) { @@ -936,6 +989,21 @@ return nerr_pass(err); } +static NEOERR *_html_escape_strfunc(char *str, char **ret) +{ + return nerr_pass(html_escape_alloc(str, strlen(str), ret)); +} + +static NEOERR *_html_strip_strfunc(char *str, char **ret) +{ + return nerr_pass(html_strip_alloc(str, strlen(str), ret)); +} + +static NEOERR *_text_html_strfunc(char *str, char **ret) +{ + return nerr_pass(convert_text_html_alloc(str, strlen(str), ret)); +} + NEOERR *cgi_display (CGI *cgi, char *cs_file) { NEOERR *err = STATUS_OK; @@ -955,6 +1023,16 @@ { err = cs_init (&cs, cgi->hdf); if (err != STATUS_OK) break; + err = cs_register_strfunc(cs, "url_escape", cgi_url_escape); + if (err != STATUS_OK) break; + err = cs_register_strfunc(cs, "html_escape", _html_escape_strfunc); + if (err != STATUS_OK) break; + err = cs_register_strfunc(cs, "text_html", _text_html_strfunc); + if (err != STATUS_OK) break; + err = cs_register_strfunc(cs, "js_escape", cgi_js_escape); + if (err != STATUS_OK) break; + err = cs_register_strfunc(cs, "html_strip", _html_strip_strfunc); + if (err != STATUS_OK) break; err = cs_parse_file (cs, cs_file); if (err != STATUS_OK) break; if (do_dump) @@ -1125,12 +1203,12 @@ } NEOERR *cgi_cookie_set (CGI *cgi, char *name, char *value, char *path, - char *domain, char *time_str, int persistant) + char *domain, char *time_str, int persistent) { char my_time[256]; if (path == NULL) path = "/"; - if (persistant) + if (persistent) { if (time_str == NULL) { diff -ur clearsilver-0.6.2/cgi/cgi.h clearsilver-0.7.0/cgi/cgi.h --- clearsilver-0.6.2/cgi/cgi.h Mon May 13 13:40:33 2002 +++ clearsilver-0.7.0/cgi/cgi.h Wed May 15 11:22:29 2002 @@ -305,13 +305,13 @@ * the browser as the sending domain only. * time_str - expiration time string in the following format * Wdy, DD-Mon-YYYY HH:MM:SS GMT. Only used if - * persistant. Default is one year from time of call. - * persistant - cookie will be stored by the browser between sessions + * persistent. Default is one year from time of call. + * persistent - cookie will be stored by the browser between sessions * Output: None * Return: NERR_IO */ NEOERR *cgi_cookie_set (CGI *cgi, char *name, char *value, char *path, - char *domain, char *time_str, int persistant); + char *domain, char *time_str, int persistent); /* * Function: cgi_cookie_clear - clear browser cookie diff -ur clearsilver-0.6.2/cgi/date.c clearsilver-0.7.0/cgi/date.c --- clearsilver-0.6.2/cgi/date.c Mon Aug 6 14:28:16 2001 +++ clearsilver-0.7.0/cgi/date.c Tue May 14 12:18:31 2002 @@ -28,6 +28,7 @@ * prefix.mday * prefix.mon - numeric month * prefix.year - full year (ie, 4 digits) + * prefix.2yr - year (2 digits) * prefix.wday - day of the week * */ @@ -39,9 +40,13 @@ int hour, am = 1; char buf[256]; - err = hdf_set_value (data, prefix, ""); - if (err) return nerr_pass(err); obj = hdf_get_obj (data, prefix); + if (obj == NULL) + { + err = hdf_set_value (data, prefix, ""); + if (err) return nerr_pass(err); + obj = hdf_get_obj (data, prefix); + } snprintf (buf, sizeof(buf), "%02d", ttm->tm_sec); err = hdf_set_value (obj, "sec", buf); @@ -74,6 +79,9 @@ err = hdf_set_int_value (obj, "mon", ttm->tm_mon + 1); if (err) return nerr_pass(err); err = hdf_set_int_value (obj, "year", ttm->tm_year + 1900); + if (err) return nerr_pass(err); + snprintf(buf, sizeof(buf), "%02d", ttm->tm_year % 100); + err = hdf_set_value (obj, "2yr", buf); if (err) return nerr_pass(err); err = hdf_set_int_value (obj, "wday", ttm->tm_wday); if (err) return nerr_pass(err); diff -ur clearsilver-0.6.2/cgi/html.c clearsilver-0.7.0/cgi/html.c --- clearsilver-0.6.2/cgi/html.c Tue Apr 30 20:05:15 2002 +++ clearsilver-0.7.0/cgi/html.c Tue Jun 25 16:14:47 2002 @@ -536,3 +536,189 @@ *out = out_s.buf; return STATUS_OK; } + +static char *StripTags[] = {"script", "style", "head"}; + +/* Replace ampersand with iso-8859-1 character code */ +static char _expand_amp_8859_1_char (char *s) +{ + if (s[0] == '\0') + return 0; + + switch (s[0]) { + case '#': + if (s[1] == 'x') return strtol (&s[2], NULL, 16); + return strtol (&s[1], NULL, 10); + case 'a': + if (!strcmp(s, "agrave")) return 0xe0; /* à */ + if (!strcmp(s, "aacute")) return 0xe1; /* á */ + if (!strcmp(s, "acirc")) return 0xe2; /* â */ + if (!strcmp(s, "atilde")) return 0xe3; /* ã */ + if (!strcmp(s, "auml")) return 0xe4; /* ä */ + if (!strcmp(s, "aring")) return 0xe5; /* å */ + if (!strcmp(s, "aelig")) return 0xe6; /* æ */ + if (!strcmp(s, "amp")) return '&'; + return 0; + case 'c': + if (!strcmp(s, "ccedil")) return 0xe7; /* ç */ + return 0; + case 'e': + if (!strcmp(s, "egrave")) return 0xe8; /* è */ + if (!strcmp(s, "eacute")) return 0xe9; /* é */ + if (!strcmp(s, "ecirc")) return 0xea; /* ê */ + if (!strcmp(s, "euml")) return 0xeb; /* ë */ + if (!strcmp(s, "eth")) return 0xf0; /* ð */ + return 0; + case 'i': + if (!strcmp(s, "igrave")) return 0xec; /* ì */ + if (!strcmp(s, "iacute")) return 0xed; /* í */ + if (!strcmp(s, "icirc")) return 0xee; /* î */ + if (!strcmp(s, "iuml")) return 0xef; /* ï */ + return 0; + case 'g': + if (!strcmp(s, "gt")) return '>'; + return 0; + case 'l': + if (!strcmp(s, "lt")) return '<'; + return 0; + case 'n': + if (!strcmp(s, "ntilde")) return 0xf1; /* ñ */ + if (!strcmp(s, "nbsp")) return ' '; + return 0; + case 'o': + if (!strcmp(s, "ograve")) return 0xf2; /* ò */ + if (!strcmp(s, "oacute")) return 0xf3; /* ó */ + if (!strcmp(s, "ocirc")) return 0xf4; /* ô */ + if (!strcmp(s, "otilde")) return 0xf5; /* õ */ + if (!strcmp(s, "ouml")) return 0xf6; /* ö */ + if (!strcmp(s, "oslash")) return 0xf8; /* ø */ + return 0; + case 'q': /* quot */ + if (!strcmp(s, "quot")) return '"'; + return 0; + case 's': + if (!strcmp(s, "szlig")) return 0xdf; /* ß */ + return 0; + case 't': + if (!strcmp(s, "thorn")) return 0xfe; /* þ */ + return 0; + case 'u': + if (!strcmp(s, "ugrave")) return 0xf9; /* ù */ + if (!strcmp(s, "uacute")) return 0xfa; /* ú */ + if (!strcmp(s, "ucirc")) return 0xfb; /* û */ + if (!strcmp(s, "uuml")) return 0xfc; /* ü */ + return 0; + case 'y': + if (!strcmp(s, "yacute")) return 0xfd; /* ý */ + + } + return 0; +} + +char *html_expand_amp_8859_1(char *amp, char *buf) +{ + char ch; + + ch = _expand_amp_8859_1_char(amp); + if (ch == '\0') + { + if (!strcmp(amp, "copy")) return "(C)"; + return ""; + } + else { + buf[0] = ch; + buf[1] = '\0'; + return buf; + } +} + +NEOERR *html_strip_alloc(char *src, int slen, char **out) +{ + NEOERR *err = STATUS_OK; + STRING out_s; + int x = 0; + int strip_match = -1; + int state = 0; + char amp[10]; + char buf[10]; + int ampl = 0; + + string_init(&out_s); + err = string_append (&out_s, ""); + if (err) return nerr_pass (err); + + while (x < slen) + { + switch (state) { + case 0: + /* Default */ + if (src[x] == '&') + { + state = 3; + ampl = 0; + } + else if (src[x] == '<') + { + state = 1; + } + else + { + if (strip_match == -1) + { + err = string_append_char(&out_s, src[x]); + if (err) break; + } + } + x++; + break; + case 1: + /* Starting TAG */ + if (src[x] == '>') + { + state = 0; + } + else if (src[x] == '/') + { + } + else + { + } + x++; + break; + case 2: + /* In TAG */ + if (src[x] == '>') + { + state = 0; + } + x++; + break; + case 3: + /* In AMP */ + if (src[x] == ';') + { + amp[ampl] = '\0'; + state = 0; + err = string_append(&out_s, html_expand_amp_8859_1(amp, buf)); + if (err) break; + } + else + { + if (ampl < sizeof(amp)-1) + amp[ampl++] = tolower(src[x]); + } + x++; + break; + } + if (err) break; + } + + + if (err) + { + string_clear (&out_s); + return nerr_pass (err); + } + *out = out_s.buf; + return STATUS_OK; +} diff -ur clearsilver-0.6.2/cgi/html.h clearsilver-0.7.0/cgi/html.h --- clearsilver-0.6.2/cgi/html.h Mon May 13 13:40:33 2002 +++ clearsilver-0.7.0/cgi/html.h Tue Jun 25 16:14:47 2002 @@ -19,6 +19,7 @@ NEOERR *convert_text_html_alloc (char *src, int slen, char **out); NEOERR *html_escape_alloc (char *src, int slen, char **out); +NEOERR *html_strip_alloc(char *src, int slen, char **out); __END_DECLS diff -ur clearsilver-0.6.2/cs/Makefile clearsilver-0.7.0/cs/Makefile --- clearsilver-0.6.2/cs/Makefile Tue Apr 30 19:57:02 2002 +++ clearsilver-0.7.0/cs/Makefile Mon Jun 10 18:46:23 2002 @@ -23,7 +23,7 @@ TARGETS = $(CS_LIB) $(CSTEST_EXE) test -CS_TESTS = test.cs test2.cs test3.cs test4.cs test5.cs test6.cs test7.cs test8.cs test9.cs test10.cs test11.cs test12.cs test13.cs +CS_TESTS = test.cs test2.cs test3.cs test4.cs test5.cs test6.cs test7.cs test8.cs test9.cs test10.cs test11.cs test12.cs test13.cs test14.cs test15.cs all: $(TARGETS) diff -ur clearsilver-0.6.2/cs/cs.h clearsilver-0.7.0/cs/cs.h --- clearsilver-0.6.2/cs/cs.h Mon May 13 13:40:35 2002 +++ clearsilver-0.7.0/cs/cs.h Mon Jun 10 18:46:23 2002 @@ -50,51 +50,59 @@ typedef enum { /* Unary operators */ - CS_OP_EXISTS = (1<<0), - CS_OP_NOT = (1<<1), + CS_OP_NONE = (1<<0), + CS_OP_EXISTS = (1<<1), + CS_OP_NOT = (1<<2), + CS_OP_NUM = (1<<3), /* Binary Operators */ - CS_OP_EQUAL = (1<<2), - CS_OP_NEQUAL = (1<<3), - CS_OP_LT = (1<<4), - CS_OP_LTE = (1<<5), - CS_OP_GT = (1<<6), - CS_OP_GTE = (1<<7), - CS_OP_AND = (1<<8), - CS_OP_OR = (1<<9), - CS_OP_ADD = (1<<10), - CS_OP_SUB = (1<<11), - CS_OP_MULT = (1<<12), - CS_OP_DIV = (1<<13), - CS_OP_MOD = (1<<14), + CS_OP_EQUAL = (1<<4), + CS_OP_NEQUAL = (1<<5), + CS_OP_LT = (1<<6), + CS_OP_LTE = (1<<7), + CS_OP_GT = (1<<8), + CS_OP_GTE = (1<<9), + CS_OP_AND = (1<<10), + CS_OP_OR = (1<<11), + CS_OP_ADD = (1<<12), + CS_OP_SUB = (1<<13), + CS_OP_MULT = (1<<14), + CS_OP_DIV = (1<<15), + CS_OP_MOD = (1<<16), /* Associative Operators */ - CS_OP_LPAREN = (1<<15), - CS_OP_RPAREN = (1<<16), - CS_OP_LBRACKET = (1<<17), - CS_OP_RBRACKET = (1<<18), - + CS_OP_LPAREN = (1<<17), + CS_OP_RPAREN = (1<<18), + CS_OP_LBRACKET = (1<<19), + CS_OP_RBRACKET = (1<<20), /* Types */ - CS_TYPE_STRING = (1<<19), - CS_TYPE_NUM = (1<<20), - CS_TYPE_VAR = (1<<21), - CS_TYPE_VAR_NUM = (1<<22), - CS_TYPE_MACRO = (1<<23), - CS_TYPE_EXPR = (1<<24) + CS_TYPE_STRING = (1<<21), + CS_TYPE_NUM = (1<<22), + CS_TYPE_VAR = (1<<23), + CS_TYPE_VAR_NUM = (1<<24), + + /* Not real types... */ + CS_TYPE_MACRO = (1<<25), + CS_TYPE_FUNCTION = (1<<26) } CSTOKEN_TYPE; +#define CS_OPS_UNARY (CS_OP_EXISTS | CS_OP_NOT | CS_OP_NUM) #define CS_TYPES (CS_TYPE_STRING | CS_TYPE_NUM | CS_TYPE_VAR | CS_TYPE_VAR_NUM) #define CS_TYPES_VAR (CS_TYPE_VAR | CS_TYPE_VAR_NUM) #define CS_TYPES_CONST (CS_TYPE_STRING | CS_TYPE_NUM) #define CS_ASSOC (CS_OP_RPAREN | CS_OP_RBRACKET) +typedef struct _parse CSPARSE; +typedef struct _funct CS_FUNCTION; + typedef struct _arg { CSTOKEN_TYPE op_type; char *s; long int n; int alloc; + struct _funct *function; struct _macro *macro; struct _arg *expr1; struct _arg *expr2; @@ -144,7 +152,22 @@ struct _macro *next; } CS_MACRO; -typedef struct _parse +typedef NEOERR* (*CSFUNCTION)(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result); +typedef NEOERR* (*CSSTRFUNC)(char *str, char **ret); + +struct _funct +{ + char *name; + int name_len; + int n_args; + + CSFUNCTION function; + CSSTRFUNC str_func; + + struct _funct *next; +}; + +struct _parse { char *context; /* A string identifying where the parser is parsing */ int in_file; /* Indicates if current context is a file */ @@ -160,12 +183,13 @@ CS_LOCAL_MAP *locals; CS_MACRO *macros; + CS_FUNCTION *functions; /* Output */ void *output_ctx; CSOUTFUNC output_cb; -} CSPARSE; +}; /* * Function: cs_init - create and initialize a CS context @@ -279,6 +303,33 @@ * Return: None */ void cs_destroy (CSPARSE **parse); + +/* + * Function: cs_register_strfunc - register a string handling function + * Description: cs_register_strfunc will register a string function that + * can be called during CS render. This not-callback is + * designed to allow for string formating/escaping + * functions that are not built-in to CS (since CS is not + * HTML specific, for instance, but it is very useful to + * have CS have functions for javascript/html/url + * escaping). Note that we explicitly don't provide any + * associated data or anything to attempt to keep you from + * using this as a generic callback... + * The format of a CSSTRFUNC is: + * NEOERR * str_func(char *in, char **out); + * This function should not modify the input string, and + * should allocate the output string with a libc function. + * (as we will call free on it) + * Input: parse - a pointer to a CSPARSE structure initialized with cs_init() + * funcname - the name for the CS function call + * Note that registering a duplicate funcname will + * raise a NERR_DUPLICATE error + * str_func - a CSSTRFUNC not-callback + * Return: NERR_NOMEM - failure to allocate any memory for data structures + * NERR_DUPLICATE - funcname already registered + * + */ +NEOERR *cs_register_strfunc(CSPARSE *parse, char *funcname, CSSTRFUNC str_func); __END_DECLS diff -ur clearsilver-0.6.2/cs/csparse.c clearsilver-0.7.0/cs/csparse.c --- clearsilver-0.6.2/cs/csparse.c Mon May 13 17:42:18 2002 +++ clearsilver-0.7.0/cs/csparse.c Mon Jun 10 18:52:59 2002 @@ -146,6 +146,9 @@ {NULL}, }; + +/* **** CS alloc/dealloc ******************************************** */ + static int NodeNumber = 0; static NEOERR *alloc_node (CSTREE **node) @@ -211,78 +214,16 @@ *macro = NULL; } -NEOERR *cs_init (CSPARSE **parse, HDF *hdf) -{ - NEOERR *err = STATUS_OK; - CSPARSE *my_parse; - STACK_ENTRY *entry; - - err = nerr_init(); - if (err != STATUS_OK) return nerr_pass (err); - - my_parse = (CSPARSE *) calloc (1, sizeof (CSPARSE)); - if (my_parse == NULL) - return nerr_raise (NERR_NOMEM, "Unable to allocate memory for CSPARSE"); - - - err = uListInit (&(my_parse->stack), 10, 0); - if (err != STATUS_OK) - { - free(my_parse); - return nerr_pass(err); - } - err = uListInit (&(my_parse->alloc), 10, 0); - if (err != STATUS_OK) - { - free(my_parse); - return nerr_pass(err); - } - err = alloc_node (&(my_parse->tree)); - if (err != STATUS_OK) - { - cs_destroy (&my_parse); - return nerr_pass(err); - } - my_parse->current = my_parse->tree; - my_parse->next = &(my_parse->current->next); - - entry = (STACK_ENTRY *) calloc (1, sizeof (STACK_ENTRY)); - if (entry == NULL) - { - cs_destroy (&my_parse); - return nerr_raise (NERR_NOMEM, - "Unable to allocate memory for stack entry"); - } - entry->state = ST_GLOBAL; - entry->tree = my_parse->current; - entry->location = 0; - err = uListAppend(my_parse->stack, entry); - if (err != STATUS_OK) { - free (entry); - cs_destroy(&my_parse); - return nerr_pass(err); - } - my_parse->hdf = hdf; - - *parse = my_parse; - return STATUS_OK; -} - -void cs_destroy (CSPARSE **parse) +static void dealloc_function (CS_FUNCTION **csf) { - CSPARSE *my_parse = *parse; + CS_FUNCTION *my_csf; - if (my_parse == NULL) - return; - - uListDestroy (&(my_parse->stack), ULIST_FREE); - uListDestroy (&(my_parse->alloc), ULIST_FREE); - - dealloc_macro(&my_parse->macros); - dealloc_node(&(my_parse->tree)); - - free(my_parse); - *parse = NULL; + if (*csf == NULL) return; + my_csf = *csf; + if (my_csf->name) free (my_csf->name); + if (my_csf->next) dealloc_function (&(my_csf->next)); + free (my_csf); + *csf = NULL; } static int find_open_delim (char *buf, int x, int len) @@ -726,9 +667,14 @@ { TRUE, "!=", CS_OP_NEQUAL }, { TRUE, "||", CS_OP_OR }, { TRUE, "&&", CS_OP_AND }, + { FALSE, "!", CS_OP_NOT }, +/* For now, we are still treating this special instead of as an op + * If we make this an op, then we'd have to determine how to handle + * NUM types without doing something like #"5" */ +/* { FALSE, "#", CS_OP_NUM }, */ + { FALSE, "?", CS_OP_EXISTS }, { FALSE, "<", CS_OP_LT }, { FALSE, ">", CS_OP_GT }, - { FALSE, "!", CS_OP_NOT }, { FALSE, "+", CS_OP_ADD }, { FALSE, "-", CS_OP_SUB }, { FALSE, "*", CS_OP_MULT }, @@ -848,12 +794,13 @@ 0 }; -static char *expand_token_type(CSTOKEN_TYPE t_type) +static char *expand_token_type(CSTOKEN_TYPE t_type, int more) { switch (t_type) { case CS_OP_EXISTS: return "?"; case CS_OP_NOT: return "!"; + case CS_OP_NUM: return "#"; case CS_OP_EQUAL: return "=="; case CS_OP_NEQUAL: return "!="; case CS_OP_LT: return "<"; @@ -871,10 +818,10 @@ case CS_OP_RPAREN: return ")"; case CS_OP_LBRACKET: return "["; case CS_OP_RBRACKET: return "]"; - case CS_TYPE_STRING: return "s"; - case CS_TYPE_NUM: return "n"; - case CS_TYPE_VAR: return "v"; - case CS_TYPE_VAR_NUM: return "vn"; + case CS_TYPE_STRING: return more ? "STRING" : "s"; + case CS_TYPE_NUM: return more ? "NUM" : "n"; + case CS_TYPE_VAR: return more ? "VAR" : "v"; + case CS_TYPE_VAR_NUM: return more ? "VARNUM" : "vn"; default: return "u"; } return "u"; @@ -891,35 +838,45 @@ #if DEBUG_EXPR_PARSE for (x = 0; x < ntokens; x++) { - fprintf (stderr, "%s ", expand_token_type(tokens[x].type)); + fprintf (stderr, "%s ", expand_token_type(tokens[x].type, 0)); } fprintf(stderr, "\n"); #endif - if (ntokens == 1 || (ntokens == 2 && tokens[0].type == CS_OP_NOT)) + if (ntokens == 1) { x = 0; - if (tokens[0].type == CS_OP_NOT) x = 1; - if (tokens[x].type & CS_TYPES) + if (tokens[0].type & CS_TYPES) { - arg->s = tokens[x].value; - if (tokens[x].len >= 0) - arg->s[tokens[x].len] = '\0'; - arg->op_type = tokens[x].type; + arg->s = tokens[0].value; + if (tokens[0].len >= 0) + arg->s[tokens[0].len] = '\0'; + arg->op_type = tokens[0].type; if (tokens[x].type == CS_TYPE_NUM) arg->n = strtol(arg->s, NULL, 0); - if (tokens[0].type == CS_OP_NOT) arg->op_type |= CS_OP_NOT; return STATUS_OK; } else { return nerr_raise (NERR_PARSE, "%s Terminal token is not an argument, type is %s", - find_context(parse, -1, tmp, sizeof(tmp)), expand_token_type(tokens[0].type)); + find_context(parse, -1, tmp, sizeof(tmp)), expand_token_type(tokens[0].type, 0)); } } + if (ntokens == 2 && (tokens[0].type & CS_OPS_UNARY)) + { + arg->op_type = tokens[0].type; + arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG)); + if (arg->expr1 == NULL) + return nerr_raise (NERR_NOMEM, + "%s Unable to allocate memory for expression", + find_context(parse, -1, tmp, sizeof(tmp))); + err = parse_expr2(parse, tokens + 1, 1, arg->expr1); + return nerr_pass(err); + } + while (BinaryOpOrder[op]) { x = ntokens-1; @@ -1006,6 +963,65 @@ return nerr_pass(parse_expr2(parse, tokens + 1, ntokens-2, arg)); } + /* Unary op against an entire expression */ + if ((tokens[0].type & CS_OPS_UNARY) && tokens[1].type == CS_OP_LPAREN && + tokens[x].type == CS_OP_RPAREN) + { + arg->op_type = tokens[0].type; + arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG)); + if (arg->expr1 == NULL) + return nerr_raise (NERR_NOMEM, + "%s Unable to allocate memory for expression", + find_context(parse, -1, tmp, sizeof(tmp))); + err = parse_expr2(parse, tokens + 2, ntokens-3, arg->expr1); + return nerr_pass(err); + } + if (tokens[0].type & CS_OPS_UNARY) + { + arg->op_type = tokens[0].type; + arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG)); + if (arg->expr1 == NULL) + return nerr_raise (NERR_NOMEM, + "%s Unable to allocate memory for expression", + find_context(parse, -1, tmp, sizeof(tmp))); + err = parse_expr2(parse, tokens + 1, ntokens-1, arg->expr1); + return nerr_pass(err); + } + + /* function call (we only handle a single arg for now) */ + if ((tokens[0].type & CS_TYPE_VAR) && tokens[1].type == CS_OP_LPAREN && + tokens[x].type == CS_OP_RPAREN) + { + CS_FUNCTION *csf; + + if (tokens[0].len >= 0) + tokens[0].value[tokens[0].len] = '\0'; + + arg->op_type = CS_TYPE_FUNCTION; + csf = parse->functions; + while (csf != NULL) + { + if (!strcmp(tokens[0].value, csf->name)) + { + arg->function = csf; + break; + } + csf = csf->next; + } + if (csf == NULL) + { + return nerr_raise (NERR_PARSE, "%s Unknown function %s called", + find_context(parse, -1, tmp, sizeof(tmp)), tokens[0].value); + } + arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG)); + if (arg->expr1 == NULL) + return nerr_raise (NERR_NOMEM, + "%s Unable to allocate memory for expression", + find_context(parse, -1, tmp, sizeof(tmp))); + err = parse_expr2(parse, tokens + 2, ntokens-3, arg->expr1); + return nerr_pass(err); + } + return nerr_raise (NERR_PARSE, "%s Bad Expression", find_context(parse, -1, tmp, sizeof(tmp))); } @@ -1297,25 +1313,17 @@ char *arg_eval (CSPARSE *parse, CSARG *arg) { - if (arg->op_type & CS_OP_NOT) - { - ne_warn ("String eval shouldn't have a NOT op"); - return NULL; - } - else + switch ((arg->op_type & CS_TYPES)) { - switch ((arg->op_type & CS_TYPES)) - { - case CS_TYPE_STRING: - return arg->s; - case CS_TYPE_VAR: - return var_lookup (parse, arg->s); - case CS_TYPE_NUM: - case CS_TYPE_VAR_NUM: - default: - ne_warn ("Unsupported type %d in arg_eval", arg->op_type); - return NULL; - } + case CS_TYPE_STRING: + return arg->s; + case CS_TYPE_VAR: + return var_lookup (parse, arg->s); + case CS_TYPE_NUM: + case CS_TYPE_VAR_NUM: + default: + ne_warn ("Unsupported type %s in arg_eval", expand_token_type(arg->op_type, 1)); + return NULL; } } @@ -1337,21 +1345,23 @@ v = var_int_lookup (parse, arg->s); break; default: - ne_warn ("Unsupported type %s in arg_eval_num", arg->op_type); + ne_warn ("Unsupported type %s in arg_eval_num", expand_token_type(arg->op_type, 1)); v = 0; break; } - if (arg->op_type & CS_OP_NOT) - v = !v; return v; } #if DEBUG_EXPR_EVAL static char *expand_arg (CSARG *arg) { - fprintf(stderr, "op: %s alloc: %d value: ", expand_token_type(arg->op_type), arg->alloc); + fprintf(stderr, "op: %s alloc: %d value: ", expand_token_type(arg->op_type, 0), arg->alloc); if (arg->op_type & CS_OP_NOT) fprintf(stderr, "!"); + if (arg->op_type & CS_OP_NUM) + fprintf(stderr, "#"); + if (arg->op_type & CS_OP_EXISTS) + fprintf(stderr, "?"); if (arg->op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM)) fprintf(stderr, "#"); if (arg->op_type & CS_TYPE_NUM) @@ -1396,191 +1406,248 @@ fprintf(stderr, "arg1 "); expand_arg(&arg1); #endif - err = eval_expr (parse, expr->expr2, &arg2); -#if DEBUG_EXPR_EVAL - fprintf(stderr, "arg2 "); - expand_arg(&arg2); -#endif - if (err) return nerr_pass(err); - - if (expr->op_type == CS_OP_LBRACKET) + if (expr->op_type & CS_TYPE_FUNCTION) { - /* the bracket op is essentially hdf array lookups, which just - * means appending .0 */ - result->op_type = CS_TYPE_VAR; - result->alloc = 1; - if (arg2.op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM)) - { - n2 = arg_eval_num (parse, &arg2); - result->s = sprintf_alloc("%s.%d", arg1.s, n2); - if (result->s == NULL) - return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %d", arg1.s, n2); - } - else - { - s2 = arg_eval (parse, &arg2); - if (s2 && s2[0]) - { - result->s = sprintf_alloc("%s.%s", arg1.s, s2); - if (result->s == NULL) - return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %s", arg1.s, s2); - } - else - { - /* if s2 doesn't match anything, then the whole thing is empty */ - result->s = ""; - result->alloc = 0; - } - } + if (expr->function == NULL || expr->function->function == NULL) + return nerr_raise(NERR_ASSERT, + "Function is NULL in attempt to evaluate function call %s", + (expr->function) ? expr->function->name : ""); + + err = expr->function->function(parse, expr->function, &arg1, result); + if (err) return nerr_pass(err); } - else if ((arg1.op_type & (CS_OP_NOT | CS_TYPE_NUM | CS_TYPE_VAR_NUM)) || - (arg2.op_type & (CS_OP_NOT | CS_TYPE_NUM | CS_TYPE_VAR_NUM)) || - (expr->op_type & (CS_OP_AND | CS_OP_OR | CS_OP_SUB | CS_OP_MULT | CS_OP_DIV | CS_OP_MOD))) + else if (expr->op_type & CS_OPS_UNARY) { - /* eval as num */ - result->op_type = CS_TYPE_NUM; - n1 = arg_eval_num (parse, &arg1); - n2 = arg_eval_num (parse, &arg2); - - switch (expr->op_type) - { - case CS_OP_EQUAL: - result->n = (n1 == n2) ? 1 : 0; - break; - case CS_OP_NEQUAL: - result->n = (n1 != n2) ? 1 : 0; - break; - case CS_OP_LT: - result->n = (n1 < n2) ? 1 : 0; - break; - case CS_OP_LTE: - result->n = (n1 <= n2) ? 1 : 0; - break; - case CS_OP_GT: - result->n = (n1 > n2) ? 1 : 0; - break; - case CS_OP_GTE: - result->n = (n1 >= n2) ? 1 : 0; - break; - case CS_OP_AND: - result->n = (n1 && n2) ? 1 : 0; - break; - case CS_OP_OR: - result->n = (n1 || n2) ? 1 : 0; - break; - case CS_OP_ADD: - result->n = (n1 + n2); - break; - case CS_OP_SUB: - result->n = (n1 - n2); - break; - case CS_OP_MULT: - result->n = (n1 * n2); + switch (expr->op_type) { + case CS_OP_NOT: + if (arg1.op_type & CS_TYPE_VAR) + { + /* This case is a "not exist" test */ + s1 = arg_eval (parse, &arg1); + if (s1 == NULL || *s1 == '\0') + result->n = 1; + else + result->n = 0; + } + else + { + result->n = arg_eval_num (parse, &arg1); + result->n = result->n ? 0 : 1; + } break; - case CS_OP_DIV: - if (n2 == 0) result->n = UINT_MAX; - else result->n = (n1 / n2); + case CS_OP_EXISTS: + if (arg1.op_type & (CS_TYPE_VAR | CS_TYPE_VAR_NUM)) + { + s1 = arg_eval (parse, &arg1); + if (s1 == NULL || *s1 == '\0') + result->n = 0; + else + result->n = 1; + } + else + { + /* All numbers/strings exist */ + result->n = 1; + } break; - case CS_OP_MOD: - if (n2 == 0) result->n = 0; - else result->n = (n1 % n2); + case CS_OP_NUM: + result->n = arg_eval_num (parse, &arg1); break; default: - ne_warn ("Unsupported op %d in eval_expr", expr->op_type); + result->n = 0; + ne_warn ("Unsupported op %s in eval_expr", expand_token_type(expr->op_type, 1)); break; } } - else /* eval as string */ + else { - result->op_type = CS_TYPE_NUM; - s1 = arg_eval (parse, &arg1); - s2 = arg_eval (parse, &arg2); + err = eval_expr (parse, expr->expr2, &arg2); +#if DEBUG_EXPR_EVAL + fprintf(stderr, "arg2 "); + expand_arg(&arg2); +#endif + if (err) return nerr_pass(err); - if ((s1 == NULL) || (s2 == NULL)) + if (expr->op_type == CS_OP_LBRACKET) + { + /* the bracket op is essentially hdf array lookups, which just + * means appending .0 */ + result->op_type = CS_TYPE_VAR; + result->alloc = 1; + if (arg2.op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM)) + { + n2 = arg_eval_num (parse, &arg2); + result->s = sprintf_alloc("%s.%d", arg1.s, n2); + if (result->s == NULL) + return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %d", arg1.s, n2); + } + else + { + s2 = arg_eval (parse, &arg2); + if (s2 && s2[0]) + { + result->s = sprintf_alloc("%s.%s", arg1.s, s2); + if (result->s == NULL) + return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %s", arg1.s, s2); + } + else + { + /* if s2 doesn't match anything, then the whole thing is empty */ + result->s = ""; + result->alloc = 0; + } + } + } + else if ((arg1.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) || + (arg2.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) || + (expr->op_type & (CS_OP_AND | CS_OP_OR | CS_OP_SUB | CS_OP_MULT | CS_OP_DIV | CS_OP_MOD))) { + /* eval as num */ + + result->op_type = CS_TYPE_NUM; + n1 = arg_eval_num (parse, &arg1); + n2 = arg_eval_num (parse, &arg2); + switch (expr->op_type) { case CS_OP_EQUAL: - result->n = (s1 == s2) ? 1 : 0; + result->n = (n1 == n2) ? 1 : 0; break; case CS_OP_NEQUAL: - result->n = (s1 != s2) ? 1 : 0; + result->n = (n1 != n2) ? 1 : 0; break; case CS_OP_LT: - result->n = ((s1 == NULL) && (s2 != NULL)) ? 1 : 0; + result->n = (n1 < n2) ? 1 : 0; break; case CS_OP_LTE: - result->n = (s1 == NULL) ? 1 : 0; + result->n = (n1 <= n2) ? 1 : 0; break; case CS_OP_GT: - result->n = ((s1 != NULL) && (s2 == NULL)) ? 1 : 0; + result->n = (n1 > n2) ? 1 : 0; break; case CS_OP_GTE: - result->n = (s2 == NULL) ? 1 : 0; - break; - case CS_OP_ADD: - /* be sure to transfer ownership of the string here */ - result->op_type = CS_TYPE_STRING; - if (s1 == NULL) - { - result->s = s2; - result->alloc = arg2.alloc; - arg2.alloc = 0; - } - else - { - result->s = s1; - result->alloc = arg1.alloc; - arg1.alloc = 0; - } - break; - default: - ne_warn ("Unsupported op %d in eval_expr", expr->op_type); + result->n = (n1 >= n2) ? 1 : 0; break; - } - } - else - { - out = strcmp (s1, s2); - switch (expr->op_type) - { - case CS_OP_EQUAL: - result->n = (!out) ? 1 : 0; + case CS_OP_AND: + result->n = (n1 && n2) ? 1 : 0; break; - case CS_OP_NEQUAL: - result->n = (out) ? 1 : 0; + case CS_OP_OR: + result->n = (n1 || n2) ? 1 : 0; break; - case CS_OP_LT: - result->n = (out < 0) ? 1 : 0; + case CS_OP_ADD: + result->n = (n1 + n2); break; - case CS_OP_LTE: - result->n = (out <= 0) ? 1 : 0; + case CS_OP_SUB: + result->n = (n1 - n2); break; - case CS_OP_GT: - result->n = (out > 0) ? 1 : 0; + case CS_OP_MULT: + result->n = (n1 * n2); break; - case CS_OP_GTE: - result->n = (out >= 0) ? 1 : 0; + case CS_OP_DIV: + if (n2 == 0) result->n = UINT_MAX; + else result->n = (n1 / n2); break; - case CS_OP_ADD: - result->op_type = CS_TYPE_STRING; - result->alloc = 1; - result->s = (char *) calloc ((strlen(s1) + strlen(s2) + 1), sizeof(char)); - if (result->s == NULL) - return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate strings in expression: %s + %s", s1, s2); - strcpy(result->s, s1); - strcat(result->s, s2); + case CS_OP_MOD: + if (n2 == 0) result->n = 0; + else result->n = (n1 % n2); break; default: - ne_warn ("Unsupported op %d in eval_expr", expr->op_type); + ne_warn ("Unsupported op %s in eval_expr", expand_token_type(expr->op_type, 1)); break; } } + else /* eval as string */ + { + result->op_type = CS_TYPE_NUM; + s1 = arg_eval (parse, &arg1); + s2 = arg_eval (parse, &arg2); + + if ((s1 == NULL) || (s2 == NULL)) + { + switch (expr->op_type) + { + case CS_OP_EQUAL: + result->n = (s1 == s2) ? 1 : 0; + break; + case CS_OP_NEQUAL: + result->n = (s1 != s2) ? 1 : 0; + break; + case CS_OP_LT: + result->n = ((s1 == NULL) && (s2 != NULL)) ? 1 : 0; + break; + case CS_OP_LTE: + result->n = (s1 == NULL) ? 1 : 0; + break; + case CS_OP_GT: + result->n = ((s1 != NULL) && (s2 == NULL)) ? 1 : 0; + break; + case CS_OP_GTE: + result->n = (s2 == NULL) ? 1 : 0; + break; + case CS_OP_ADD: + /* be sure to transfer ownership of the string here */ + result->op_type = CS_TYPE_STRING; + if (s1 == NULL) + { + result->s = s2; + result->alloc = arg2.alloc; + arg2.alloc = 0; + } + else + { + result->s = s1; + result->alloc = arg1.alloc; + arg1.alloc = 0; + } + break; + default: + ne_warn ("Unsupported op %s in eval_expr", expand_token_type(expr->op_type, 1)); + break; + } + } + else + { + out = strcmp (s1, s2); + switch (expr->op_type) + { + case CS_OP_EQUAL: + result->n = (!out) ? 1 : 0; + break; + case CS_OP_NEQUAL: + result->n = (out) ? 1 : 0; + break; + case CS_OP_LT: + result->n = (out < 0) ? 1 : 0; + break; + case CS_OP_LTE: + result->n = (out <= 0) ? 1 : 0; + break; + case CS_OP_GT: + result->n = (out > 0) ? 1 : 0; + break; + case CS_OP_GTE: + result->n = (out >= 0) ? 1 : 0; + break; + case CS_OP_ADD: + result->op_type = CS_TYPE_STRING; + result->alloc = 1; + result->s = (char *) calloc ((strlen(s1) + strlen(s2) + 1), sizeof(char)); + if (result->s == NULL) + return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate strings in expression: %s + %s", s1, s2); + strcpy(result->s, s1); + strcat(result->s, s2); + break; + default: + ne_warn ("Unsupported op %s in eval_expr", expand_token_type(expr->op_type, 1)); + break; + } + } + } + + if (arg1.alloc) free(arg1.s); + if (arg2.alloc) free(arg2.s); } - - if (arg1.alloc) free(arg1.s); - if (arg2.alloc) free(arg2.s); } #if DEBUG_EXPR_EVAL fprintf(stderr, "result "); @@ -1646,11 +1713,13 @@ do { err = cs_init(&cs, parse->hdf); if (err) break; + cs->functions = parse->functions; err = cs_parse_string(cs, s, strlen(s)); if (err) break; err = cs_render(cs, parse->output_ctx, parse->output_cb); if (err) break; } while (0); + cs->functions = NULL; cs_destroy(&cs); } } @@ -1686,6 +1755,7 @@ do { err = cs_init(&cs, parse->hdf); if (err) break; + cs->functions = parse->functions; err = cs_parse_file(cs, s); if (!(node->flags & CSF_REQUIRED)) { @@ -1695,6 +1765,7 @@ err = cs_render(cs, parse->output_ctx, parse->output_cb); if (err) break; } while (0); + cs->functions = NULL; cs_destroy(&cs); } } @@ -2220,6 +2291,16 @@ node->arg1.op_type = CS_TYPE_MACRO; node->arg1.macro = macro; + a = strrchr(s, ')'); + if (a == NULL) + { + dealloc_node(&node); + return nerr_raise (NERR_PARSE, + "%s Missing right paren in def %s", + find_context(parse, -1, tmp, sizeof(tmp)), arg); + } + *a = '\0'; + x = 0; while (*s) { @@ -2242,16 +2323,15 @@ larg = carg; } x++; - a = strpbrk(s, ",)"); + a = strpbrk(s, ","); if (a == NULL) { - err = nerr_raise (NERR_PARSE, - "%s Missing right paren in def %s", - find_context(parse, -1, tmp, sizeof(tmp)), arg); - break; + last = TRUE; + } + else + { + *a = '\0'; } - if (*a == ')') last = TRUE; - *a = '\0'; err = parse_expr (parse, s, carg); if (err) break; if (last == TRUE) break; @@ -2346,7 +2426,7 @@ } else { - ne_warn("Unsupported type %d in call_expr", val.op_type); + ne_warn("Unsupported type %s in call_expr", expand_token_type(val.op_type, 1)); } if (val.alloc) free(val.s); map->next = parse->locals; @@ -2636,7 +2716,6 @@ *next = node->next; return STATUS_OK; } - static NEOERR *render_node (CSPARSE *parse, CSTREE *node) { NEOERR *err = STATUS_OK; @@ -2663,6 +2742,199 @@ node = parse->tree; return nerr_pass (render_node(parse, node)); } + +/* **** Functions ******************************************** */ + +static NEOERR *_register_function(CSPARSE *parse, char *funcname, int n_args, CSFUNCTION function) +{ + CS_FUNCTION *csf; + + if (n_args != 1) + return nerr_raise(NERR_ASSERT, "Currently, only 1 argument functions are supported"); + + /* Should we validate the parseability of the name? */ + + csf = parse->functions; + while (csf != NULL) + { + if (!strcmp(csf->name, funcname) && csf->function != function) + { + return nerr_raise(NERR_DUPLICATE, + "Attempt to register duplicate function %s", funcname); + } + csf = csf->next; + } + csf = (CS_FUNCTION *) calloc (1, sizeof(CS_FUNCTION)); + if (csf == NULL) + return nerr_raise(NERR_NOMEM, "Unable to allocate memory to register function %s", funcname); + csf->name = strdup(funcname); + if (csf->name == NULL) + { + free(csf); + return nerr_raise(NERR_NOMEM, "Unable to allocate memory to register function %s", funcname); + } + csf->function = function; + csf->n_args = n_args; + csf->next = parse->functions; + parse->functions = csf; + + return STATUS_OK; +} + +static NEOERR * _builtin_len(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result) +{ + HDF *obj; + int count = 0; + + result->op_type = CS_TYPE_NUM; + result->n = 0; + + if (args->op_type & CS_TYPE_VAR) + { + obj = var_lookup_obj (parse, args->s); + if (obj != NULL) + { + obj = hdf_obj_child(obj); + while (obj != NULL) + { + count++; + obj = hdf_obj_next(obj); + } + } + result->n = count; + } + else if (args->op_type & CS_TYPE_STRING) + { + result->n = strlen(args->s); + } + return STATUS_OK; +} + +static NEOERR * _str_func_wrapper (CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result) +{ + NEOERR *err; + char *s; + + if (args->op_type & (CS_TYPE_VAR | CS_TYPE_STRING)) + { + result->op_type = CS_TYPE_STRING; + result->n = 0; + + s = arg_eval(parse, args); + if (s) + { + err = csf->str_func(s, &(result->s)); + if (err) return nerr_pass(err); + result->alloc = 1; + } + } + else + { + result->op_type = args->op_type; + result->n = args->n; + result->s = args->s; + result->alloc = args->alloc; + args->alloc = 0; + } + return STATUS_OK; +} + +NEOERR *cs_register_strfunc(CSPARSE *parse, char *funcname, CSSTRFUNC str_func) +{ + NEOERR *err; + + err = _register_function(parse, funcname, 1, _str_func_wrapper); + if (err) return nerr_pass(err); + parse->functions->str_func = str_func; + + return STATUS_OK; +} + + +/* **** CS Initialize/Destroy ************************************ */ + +NEOERR *cs_init (CSPARSE **parse, HDF *hdf) +{ + NEOERR *err = STATUS_OK; + CSPARSE *my_parse; + STACK_ENTRY *entry; + + err = nerr_init(); + if (err != STATUS_OK) return nerr_pass (err); + + my_parse = (CSPARSE *) calloc (1, sizeof (CSPARSE)); + if (my_parse == NULL) + return nerr_raise (NERR_NOMEM, "Unable to allocate memory for CSPARSE"); + + + err = uListInit (&(my_parse->stack), 10, 0); + if (err != STATUS_OK) + { + free(my_parse); + return nerr_pass(err); + } + err = uListInit (&(my_parse->alloc), 10, 0); + if (err != STATUS_OK) + { + free(my_parse); + return nerr_pass(err); + } + err = alloc_node (&(my_parse->tree)); + if (err != STATUS_OK) + { + cs_destroy (&my_parse); + return nerr_pass(err); + } + my_parse->current = my_parse->tree; + my_parse->next = &(my_parse->current->next); + + entry = (STACK_ENTRY *) calloc (1, sizeof (STACK_ENTRY)); + if (entry == NULL) + { + cs_destroy (&my_parse); + return nerr_raise (NERR_NOMEM, + "Unable to allocate memory for stack entry"); + } + entry->state = ST_GLOBAL; + entry->tree = my_parse->current; + entry->location = 0; + err = uListAppend(my_parse->stack, entry); + if (err != STATUS_OK) { + free (entry); + cs_destroy(&my_parse); + return nerr_pass(err); + } + err = _register_function(my_parse, "len", 1, _builtin_len); + if (err) + { + cs_destroy(&my_parse); + return nerr_pass(err); + } + my_parse->hdf = hdf; + + *parse = my_parse; + return STATUS_OK; +} + +void cs_destroy (CSPARSE **parse) +{ + CSPARSE *my_parse = *parse; + + if (my_parse == NULL) + return; + + uListDestroy (&(my_parse->stack), ULIST_FREE); + uListDestroy (&(my_parse->alloc), ULIST_FREE); + + dealloc_macro(&my_parse->macros); + dealloc_node(&(my_parse->tree)); + dealloc_function(&(my_parse->functions)); + + free(my_parse); + *parse = NULL; +} + +/* **** CS Debug Dumps ******************************************** */ static NEOERR *dump_node (CSPARSE *parse, CSTREE *node, int depth, void *ctx, CSOUTFUNC cb, char *buf, int blen) diff -ur clearsilver-0.6.2/rules.mk clearsilver-0.7.0/rules.mk --- clearsilver-0.6.2/rules.mk Tue Apr 30 20:05:14 2002 +++ clearsilver-0.7.0/rules.mk Fri Jun 14 17:29:59 2002 @@ -18,7 +18,7 @@ DB2_INC = -I$(HOME)/src/db-2.7.7/dist DB2_LIB = -L$(HOME)/src/db-2.7.7/dist -ldb endif -PYTHON_INC = -I/neo/opt/include/python2.1 -I/neo/opt/include/python2.2 +PYTHON_INC = -I/neo/opt/include/python2.2 ## Programs MKDIR = mkdir -p diff -ur clearsilver-0.6.2/util/neo_hdf.c clearsilver-0.7.0/util/neo_hdf.c --- clearsilver-0.6.2/util/neo_hdf.c Fri May 10 12:39:59 2002 +++ clearsilver-0.7.0/util/neo_hdf.c Mon May 20 12:39:52 2002 @@ -478,7 +478,12 @@ free(hdf->value); hdf->value = NULL; } - if (dup) + if (value == NULL) + { + hdf->alloc_value = 0; + hdf->value = NULL; + } + else if (dup) { hdf->alloc_value = 1; hdf->value = strdup(value); @@ -528,6 +533,7 @@ { err = _alloc_hdf (&hp, n, x, value, dup, wf, hdf->top); if (link) hp->link = 1; + else hp->link = 0; hp->attr = attr; } if (err != STATUS_OK) @@ -554,7 +560,12 @@ free(hp->value); hp->value = NULL; } - if (dup) + if (value == NULL) + { + hp->alloc_value = 0; + hp->value = NULL; + } + else if (dup) { hp->alloc_value = 1; hp->value = strdup(value); @@ -568,6 +579,7 @@ hp->value = value; } if (link) hp->link = 1; + else hp->link = 0; } if (s == NULL) break; @@ -1274,6 +1286,17 @@ if (err != STATUS_OK) return nerr_pass_ctx(err, "In String %d", *line); } + else if (s[0] == ':' && s[1] == '=') /* copy */ + { + *s = '\0'; + name = neos_strip(name); + s+=2; + value = neos_strip(s); + value = hdf_get_value(hdf->top, value, ""); + err = _set_value (hdf, name, value, 1, 1, 0, attr); + if (err != STATUS_OK) + return nerr_pass_ctx(err, "In string %d", *line); + } else if (s[0] == ':') /* link */ { *s = '\0'; @@ -1393,14 +1416,17 @@ STRING str; HDF *lower; HDF_ATTR *attr = NULL; - char buf[4096]; char *s; char *name, *value; int l; string_init(&str); err = string_readline(&str, fp); - if (err) return nerr_pass(err); + if (err) + { + string_clear(&str); + return nerr_pass(err); + } while (str.len != 0) { attr = NULL; @@ -1419,7 +1445,10 @@ } err = hdf_read_file(hdf, name); if (err != STATUS_OK) + { + string_clear(&str); return nerr_pass_ctx(err, "In file %s:%d", path, *line); + } } else if (s[0] == '#') { @@ -1430,10 +1459,13 @@ s = neos_strip(s); if (strcmp(s, "}")) { - return nerr_raise(NERR_PARSE, + err = nerr_raise(NERR_PARSE, "[%s:%d] Trailing garbage on line following }: %s", path, *line, - buf); + str.buf); + string_clear(&str); + return err; } + string_clear(&str); return STATUS_OK; } else if (s[0]) @@ -1449,7 +1481,11 @@ name = neos_strip(name); s++; err = parse_attr(&s, &attr); - if (err) return nerr_pass_ctx(err, "In file %s:%d", path, *line); + if (err) + { + string_clear(&str); + return nerr_pass_ctx(err, "In file %s:%d", path, *line); + } SKIPWS(s); } if (s[0] == '=') /* assignment */ @@ -1460,7 +1496,24 @@ value = neos_strip(s); err = _set_value (hdf, name, value, 1, 1, 0, attr); if (err != STATUS_OK) + { + string_clear(&str); + return nerr_pass_ctx(err, "In file %s:%d", path, *line); + } + } + else if (s[0] == ':' && s[1] == '=') /* copy */ + { + *s = '\0'; + name = neos_strip(name); + s+=2; + value = neos_strip(s); + value = hdf_get_value(hdf->top, value, ""); + err = _set_value (hdf, name, value, 1, 1, 0, attr); + if (err != STATUS_OK) + { + string_clear(&str); return nerr_pass_ctx(err, "In file %s:%d", path, *line); + } } else if (s[0] == ':') /* link */ { @@ -1470,7 +1523,10 @@ value = neos_strip(s); err = _set_value (hdf, name, value, 1, 1, 1, attr); if (err != STATUS_OK) + { + string_clear(&str); return nerr_pass_ctx(err, "In file %s:%d", path, *line); + } } else if (s[0] == '{') /* deeper */ { @@ -1481,7 +1537,10 @@ { err = _set_value (hdf, name, NULL, 1, 1, 0, attr); if (err != STATUS_OK) + { + string_clear(&str); return nerr_pass_ctx(err, "In file %s:%d", path, *line); + } lower = hdf_get_obj (hdf, name); } else @@ -1490,7 +1549,10 @@ } err = hdf_read_file_fp(lower, fp, path, line); if (err != STATUS_OK) + { + string_clear(&str); return nerr_pass_ctx(err, "In file %s:%d", path, *line); + } if (feof(fp)) break; } else if (s[0] == '<' && s[1] == '<') /* multi-line assignment */ @@ -1506,14 +1568,21 @@ value = neos_strip(s); l = strlen(value); if (l == 0) - return nerr_raise(NERR_PARSE, + { + err = nerr_raise(NERR_PARSE, "[%s:%d] No multi-assignment terminator given: %s", path, *line, - buf); + str.buf); + string_clear(&str); + return err; + } m = (char *) malloc (mmax * sizeof(char)); if (m == NULL) + { + string_clear(&str); return nerr_raise(NERR_NOMEM, "[%s:%d] Unable to allocate memory for multi-line assignment to %s", path, *line, name); + } while (fgets(m+msize, mmax-msize, fp) != NULL) { if (!strncmp(value, m+msize, l) && (m[msize+l] == '\r' || m[msize+l] == '\n')) @@ -1527,15 +1596,19 @@ mmax += 128; m = (char *) realloc (m, mmax * sizeof(char)); if (m == NULL) + { + string_clear(&str); return nerr_raise(NERR_NOMEM, "[%s:%d] Unable to allocate memory for multi-line assignment to %s: size=%d", path, *line, name, mmax); + } } } err = _set_value (hdf, name, m, 0, 1, 0, attr); if (err != STATUS_OK) { free (m); + string_clear(&str); return nerr_pass_ctx(err, "In file %s:%d", path, *line); } /* count the newlines so we know what line we're on... +1 for EOM */ @@ -1543,14 +1616,22 @@ } else { - return nerr_raise(NERR_PARSE, "[%s:%d] Unable to parse line %s", - path, *line, buf); + err = nerr_raise(NERR_PARSE, "[%s:%d] Unable to parse line %s", + path, *line, str.buf); + string_clear(&str); + return err; } } str.len = 0; err = string_readline(&str, fp); - if (err) return nerr_pass(err); + /* ne_warn("string buf len is %d", str.len); */ + if (err) + { + string_clear(&str); + return nerr_pass(err); + } } + string_clear(&str); return STATUS_OK; } diff -ur clearsilver-0.6.2/util/test/Makefile clearsilver-0.7.0/util/test/Makefile --- clearsilver-0.6.2/util/test/Makefile Thu Apr 18 12:24:55 2002 +++ clearsilver-0.7.0/util/test/Makefile Mon May 20 12:40:43 2002 @@ -10,6 +10,10 @@ HDFTEST_SRC = hdftest.c HDFTEST_OBJ = $(HDFTEST_SRC:%.c=%.o) +HDFLOADTEST_EXE = hdfloadtest +HDFLOADTEST_SRC = hdfloadtest.c +HDFLOADTEST_OBJ = $(HDFLOADTEST_SRC:%.c=%.o) + LISTDIRTEST_EXE = listdir_test LISTDIRTEST_SRC = listdir_test.c LISTDIRTEST_OBJ = $(LISTDIRTEST_SRC:%.c=%.o) @@ -22,12 +26,16 @@ CFLAGS += -I$(NEOTONIC_ROOT)/util LIBS += -L$(LIB_DIR) -lneo_utl -TARGETS = $(HDFTEST_EXE) $(LISTDIRTEST_EXE) $(HDFCOPYTEST_EXE) +TARGETS = $(HDFTEST_EXE) $(LISTDIRTEST_EXE) $(HDFCOPYTEST_EXE) \ + $(HDFLOADTEST_EXE) all: $(TARGETS) $(HDFTEST_EXE): $(HDFTEST_OBJ) $(NTR_LIB) $(LD) $@ $(HDFTEST_OBJ) $(LIBS) + +$(HDFLOADTEST_EXE): $(HDFLOADTEST_OBJ) $(NTR_LIB) + $(LD) $@ $(HDFLOADTEST_OBJ) $(LIBS) $(LISTDIRTEST_EXE): $(LISTDIRTEST_OBJ) $(NTR_LIB) $(LD) $@ $(LISTDIRTEST_OBJ) $(LIBS)