diff -Nru clearsilver-0.10.4/Makefile clearsilver-0.10.5/Makefile --- clearsilver-0.10.4/Makefile 2006-11-14 22:54:13.000000000 -0800 +++ clearsilver-0.10.5/Makefile 2007-07-11 19:43:28.000000000 -0700 @@ -102,14 +102,15 @@ rm -rf $$mdir/*; \ done rm -f config.cache config.log config.status rules.mk cs_config.h + rm -rf autom4te.cache output_dir: @for mdir in $(OUTDIRS); do \ mkdir -p $$mdir; \ done -CS_DISTDIR = clearsilver-0.10.4 -CS_LABEL = CLEARSILVER-0_10_4 +CS_DISTDIR = clearsilver-0.10.5 +CS_LABEL = CLEARSILVER-0_10_5 CS_FILES = README README.python INSTALL LICENSE CS_LICENSE rules.mk.in Makefile acconfig.h autogen.sh config.guess config.sub configure.in cs_config.h.in mkinstalldirs install-sh ClearSilver.h CS_DIRS = util cs cgi python scripts mod_ecs imd java-jni perl ruby dso csharp ports contrib m4 diff -Nru clearsilver-0.10.4/cgi/cgi.c clearsilver-0.10.5/cgi/cgi.c --- clearsilver-0.10.4/cgi/cgi.c 2006-11-06 15:32:16.000000000 -0800 +++ clearsilver-0.10.5/cgi/cgi.c 2007-07-11 19:38:03.000000000 -0700 @@ -280,6 +280,11 @@ return nerr_pass(neos_url_escape(in, esc, other)); } +NEOERR *cgi_url_validate (const char *buf, char **esc) +{ + return nerr_pass(neos_url_validate(buf, esc)); +} + static NEOERR *_parse_query (CGI *cgi, char *query) { NEOERR *err = STATUS_OK; @@ -384,7 +389,7 @@ query = (char *) malloc (sizeof(char) * (len + 1)); if (query == NULL) return nerr_raise (NERR_NOMEM, - "Unable to allocate memory to read POST input of length %d", l); + "Unable to allocate memory to read POST input of length %d", len); o = 0; @@ -885,7 +890,7 @@ stream.next_out = (Bytef*)obuf; stream.avail_out = (uInt)*olen; if ((uLong)stream.avail_out != *olen) - return nerr_raise(NERR_NOMEM, "Destination too big: %ld", *olen); + return nerr_raise(NERR_NOMEM, "Destination too big: %d", *olen); stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; @@ -1285,6 +1290,8 @@ if (err != STATUS_OK) return nerr_pass(err); err = cs_register_strfunc(cs, "html_strip", cgi_html_strip_strfunc); if (err != STATUS_OK) return nerr_pass(err); + err = cs_register_esc_strfunc(cs, "url_validate", cgi_url_validate); + if (err != STATUS_OK) return nerr_pass(err); return STATUS_OK; } @@ -1382,7 +1389,7 @@ void cgi_debug_init (int argc, char **argv) { FILE *fp; - char line[256]; + char line[4096]; char *v, *k; Argv0 = argv[0]; diff -Nru clearsilver-0.10.4/cgi/cgi.h clearsilver-0.10.5/cgi/cgi.h --- clearsilver-0.10.4/cgi/cgi.h 2005-11-30 19:57:32.000000000 -0800 +++ clearsilver-0.10.5/cgi/cgi.h 2007-07-11 19:35:55.000000000 -0700 @@ -284,7 +284,8 @@ * Output: None * Return: None */ -void cgi_error (CGI *cgi, const char *fmt, ...); +void cgi_error (CGI *cgi, const char *fmt, ...) + ATTRIBUTE_PRINTF(2,3); /* * Function: cgi_debug_init - initialize standalone debugging @@ -328,6 +329,20 @@ NEOERR *cgi_url_escape_more (const char *buf, char **esc, const char *other); /* + * Function: cgi_url_validate - validate that url is of an allowed format + * Description: cgi_url_validate will check that a URL starts with + * one of the accepted safe schemes. + * If not, it returns "#" as a safe substitute. + * Currently accepted schemes are http, https, ftp and mailto. + * It then html escapes the entire URL so that it is safe to + * insert in an href attribute. + * Input: buf - a 0 terminated string + * Output: esc - a newly allocated string + * Return: NERR_NOMEM - no memory available to allocate the escaped string + */ +NEOERR *cgi_url_validate (const char *buf, char **esc); + +/* * Function: cgi_url_unescape - unescape an url encoded string * Description: cgi_url_unescape will do URL unescaping on the passed in * string. This function modifies the string in place @@ -351,7 +366,8 @@ * Output: None * Return: None */ -void cgi_redirect (CGI *cgi, const char *fmt, ...); +void cgi_redirect (CGI *cgi, const char *fmt, ...) + ATTRIBUTE_PRINTF(2,3); /* * Function: cgi_redirect_uri - send an HTTP 302 redirect response @@ -367,7 +383,8 @@ * Output: None * Return: None */ -void cgi_redirect_uri (CGI *cgi, const char *fmt, ...); +void cgi_redirect_uri (CGI *cgi, const char *fmt, ...) + ATTRIBUTE_PRINTF(2,3); /* * Function: cgi_vredirect - send an HTTP 302 redirect response diff -Nru clearsilver-0.10.4/cgi/cgiwrap.c clearsilver-0.10.5/cgi/cgiwrap.c --- clearsilver-0.10.4/cgi/cgiwrap.c 2006-03-28 16:12:37.000000000 -0800 +++ clearsilver-0.10.5/cgi/cgiwrap.c 2006-12-18 20:36:20.000000000 -0800 @@ -11,7 +11,9 @@ #include "cs_config.h" +#if HAVE_FEATURES_H #include +#endif #include #include #include diff -Nru clearsilver-0.10.4/cgi/cgiwrap.h clearsilver-0.10.5/cgi/cgiwrap.h --- clearsilver-0.10.4/cgi/cgiwrap.h 2005-06-30 18:22:12.000000000 -0700 +++ clearsilver-0.10.5/cgi/cgiwrap.h 2007-07-11 19:36:04.000000000 -0700 @@ -124,7 +124,8 @@ * Output: None * Returns: NERR_SYSTEM */ -NEOERR *cgiwrap_writef (const char *fmt, ...); +NEOERR *cgiwrap_writef (const char *fmt, ...) + ATTRIBUTE_PRINTF(1,2); /* * Function: cgiwrap_writevf - a wrapper for vprintf diff -Nru clearsilver-0.10.4/cgi/fcgi_hello.c clearsilver-0.10.5/cgi/fcgi_hello.c --- clearsilver-0.10.4/cgi/fcgi_hello.c 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/cgi/fcgi_hello.c 2007-07-05 16:14:46.000000000 -0700 @@ -0,0 +1,59 @@ +/** + * Copyright 2006 Mike Tsao. All rights reserved. + * + * Hello World using FastCGI and ClearSilver. + */ + +#include "ClearSilver.h" +#include +#include +#include +#include +#include + +static bool quit = false; + +static int cs_printf(void *ctx, const char *s, va_list args) { + return printf(s, args); +} + +static int cs_write(void *ctx, const char *s, int n) { + return fwrite(const_cast(s), n, 1, FCGI_stdout); +} + +int main(int argc, char **argv, char **envp) { + openlog(argv[0], 0, LOG_USER); + syslog(LOG_INFO, "%s started.", argv[0]); + + int hits = 0; + while (FCGI_Accept() >= 0) { + HDF *hdf = NULL; + CGI *cgi = NULL; + + /* Note that we aren't doing any error handling here, we really should. */ + hdf_init(&hdf); + + // Takes ownership of HDF. + cgi_init(&cgi, hdf); + + hits++; + + /* Initialize the standard cgiwrap environment. FastCGI already wraps some + * of the standard calls that cgiwrap wraps. */ + cgiwrap_init_std(argc, argv, environ); + + /* Then, we install our own wrappers for some cgiwrap calls that aren't + * already wrapped in the standard wrappers. */ + cgiwrap_init_emu(NULL, NULL, cs_printf, cs_write, NULL, NULL, NULL); + + hdf_read_file(cgi->hdf, "common.hdf"); + hdf_read_file(cgi->hdf, "hello_world.hdf"); + + cgi_display(cgi, "hello_world.cs"); + + // This destroys HDF. + cgi_destroy(&cgi); + } + syslog(LOG_INFO, "%s ending.", argv[0]); + return 0; +} diff -Nru clearsilver-0.10.4/configure.in clearsilver-0.10.5/configure.in --- clearsilver-0.10.4/configure.in 2006-03-12 16:05:26.000000000 -0800 +++ clearsilver-0.10.5/configure.in 2007-07-12 12:35:37.000000000 -0700 @@ -26,7 +26,7 @@ AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS(fcntl.h stdarg.h varargs.h limits.h strings.h sys/ioctl.h sys/time.h unistd.h) +AC_CHECK_HEADERS(fcntl.h stdarg.h varargs.h limits.h strings.h sys/ioctl.h sys/time.h unistd.h features.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -400,7 +400,7 @@ if test $cs_cv_java_path != "no" -a -d $cs_cv_java_path; then java_path=$cs_cv_java_path else - java_search_path="/neo/opt /usr/local /usr" + java_search_path="/neo/opt /usr/local /usr /usr/lib" for path in $java_search_path; do if test -d $path/java/j2sdk; then java_path=$path/java/j2sdk diff -Nru clearsilver-0.10.4/cs/Makefile clearsilver-0.10.5/cs/Makefile --- clearsilver-0.10.4/cs/Makefile 2006-11-09 14:33:41.000000000 -0800 +++ clearsilver-0.10.5/cs/Makefile 2007-05-02 17:21:03.000000000 -0700 @@ -33,7 +33,7 @@ test_each_array.cs test_name.cs test_with.cs test_numbers.cs \ test_splice.cs test_joo.cs test_first_last.cs test_abs_max_min.cs \ test_comma.cs test_macro_set.cs test_func.cs test_escape.cs \ - test_uvar.cs + test_uvar.cs test_crc.cs all: $(TARGETS) diff -Nru clearsilver-0.10.4/cs/cs.h clearsilver-0.10.5/cs/cs.h --- clearsilver-0.10.4/cs/cs.h 2006-08-07 13:01:51.000000000 -0700 +++ clearsilver-0.10.5/cs/cs.h 2007-06-26 17:21:21.000000000 -0700 @@ -103,10 +103,13 @@ typedef struct _parse CSPARSE; typedef struct _funct CS_FUNCTION; typedef struct _escape_context CS_ECONTEXT; +typedef struct _position CS_POSITION; +typedef struct _error CS_ERROR; typedef struct _arg { CSTOKEN_TYPE op_type; + char *argexpr; char *s; long int n; int alloc; @@ -129,6 +132,10 @@ CSARG arg2; CSARG *vargs; + char *fname; + int linenum; + int colnum; + struct _tree *case_0; struct _tree *case_1; struct _tree *next; @@ -212,8 +219,8 @@ */ struct _escape_context { - NEOS_ESCAPE global; /* Contains global default escaping mode: - none,html,js,url */ + NEOS_ESCAPE global_ctx; /* Contains global default escaping mode: + none,html,js,url */ NEOS_ESCAPE current; /* Used to pass around parse and evaluation specific data from subfunctions upward. */ NEOS_ESCAPE next_stack; /* This is a big fat workaround. Since STACK_ENTRYs @@ -229,11 +236,31 @@ to get call's parsing context at eval time. */ }; +/* This structure is used to track current location within the CS file being + * parsed. This information is used to find the filename and line number for + * each node. + */ +struct _position { + int line; /* Line number for current position */ + int col; /* Column number for current position */ + int cur_offset; /* The current position - commence reading from here */ +}; + +struct _error { + NEOERR *err; + struct _error *next; +}; + struct _parse { const char *context; /* A string identifying where the parser is parsing */ int in_file; /* Indicates if current context is a file */ int offset; + + int audit_mode; /* If in audit_mode, gather some extra information */ + CS_POSITION pos; /* Container for current position in CS file */ + CS_ERROR *err_list; /* List of non-fatal errors encountered */ + char *context_string; CS_ECONTEXT escaping; /* Context container for escape data */ diff -Nru clearsilver-0.10.4/cs/csparse.c clearsilver-0.10.5/cs/csparse.c --- clearsilver-0.10.4/cs/csparse.c 2006-10-19 16:26:11.000000000 -0700 +++ clearsilver-0.10.5/cs/csparse.c 2007-07-11 19:37:34.000000000 -0700 @@ -201,7 +201,61 @@ static int NodeNumber = 0; -static NEOERR *alloc_node (CSTREE **node) +static void init_node_pos(CSTREE *node, CSPARSE *parse) +{ + CS_POSITION *pos = &parse->pos; + char *data; + + if (parse->offset < pos->cur_offset) { + /* Oops, we went backwards in file, is this an error? */ + node->linenum = -1; + node->colnum = parse->offset; + return; + } + + /* Start counting from 1 not 0 */ + if (pos->line == 0) pos->line = 1; + if (pos->col == 0) pos->col = 1; + + if (parse->context == NULL) { + /* Not in a file */ + node->fname = NULL; + } + else { + node->fname = strdup(parse->context); + if (node->fname == NULL) { + /* malloc error, cannot proceed */ + node->linenum = -1; + return; + } + } + + data = parse->context_string; + if (data == NULL) { + node->linenum = -1; + return; + } + + while (pos->cur_offset < parse->offset) { + if (data[pos->cur_offset] == '\n') { + pos->line++; + pos->col = 1; + } + else { + pos->col++; + } + + pos->cur_offset++; + } + + node->linenum = pos->line; + node->colnum = pos->col; + + return; + +} + +static NEOERR *alloc_node (CSTREE **node, CSPARSE *parse) { CSTREE *my_node; @@ -214,6 +268,10 @@ my_node->node_num = NodeNumber++; *node = my_node; + + if (parse->audit_mode) { + init_node_pos(my_node, parse); + } return STATUS_OK; } @@ -227,6 +285,9 @@ if (p->expr1) dealloc_arg (&(p->expr1)); if (p->expr2) dealloc_arg (&(p->expr2)); if (p->next) dealloc_arg (&(p->next)); + + if (p->argexpr) free(p->argexpr); + free(p); *arg = NULL; } @@ -248,6 +309,10 @@ if (my_node->arg2.expr2) dealloc_arg (&(my_node->arg2.expr2)); if (my_node->arg2.next) dealloc_arg (&(my_node->arg2.next)); + if (my_node->arg1.argexpr) free(my_node->arg1.argexpr); + if (my_node->arg2.argexpr) free(my_node->arg2.argexpr); + if (my_node->fname) free(my_node->fname); + free(my_node); *node = NULL; } @@ -302,6 +367,35 @@ return -1; } +static NEOERR *_store_error (CSPARSE *parse, NEOERR *err) +{ + CS_ERROR *ptr; + CS_ERROR *node; + + node = (CS_ERROR *) calloc(1, sizeof(CS_ERROR)); + if (node == NULL) + { + return nerr_raise (NERR_NOMEM, + "Unable to allocate memory for error entry"); + } + + node->err = err; + + if (parse->err_list == NULL) + { + parse->err_list = node; + return STATUS_OK; + } + + ptr = parse->err_list; + while (ptr->next != NULL) + ptr = ptr->next; + + ptr->next = node; + return STATUS_OK; + +} + NEOERR *cs_parse_file (CSPARSE *parse, const char *path) { NEOERR *err; @@ -309,6 +403,7 @@ const char *save_context; int save_infile; char fpath[_POSIX_PATH_MAX]; + CS_POSITION pos; if (path == NULL) return nerr_raise (NERR_ASSERT, "path is NULL"); @@ -336,7 +431,22 @@ parse->context = path; save_infile = parse->in_file; parse->in_file = 1; + + if (parse->audit_mode) { + /* Save previous position before parsing the new file */ + memcpy(&pos, &parse->pos, sizeof(CS_POSITION)); + + parse->pos.line = 0; + parse->pos.col = 0; + parse->pos.cur_offset = 0; + } + err = cs_parse_string(parse, ibuf, strlen(ibuf)); + + if (parse->audit_mode) { + memcpy(&parse->pos, &pos, sizeof(CS_POSITION)); + } + parse->in_file = save_infile; parse->context = save_context; @@ -556,7 +666,7 @@ * we parse "escape", the new stack has not yet been established. */ entry->escape = parse->escaping.next_stack; - parse->escaping.next_stack = parse->escaping.global; + parse->escaping.next_stack = parse->escaping.global_ctx; err = uListAppend(parse->stack, entry); if (err != STATUS_OK) { free (entry); @@ -1339,6 +1449,12 @@ memset(tokens, 0, sizeof(CSTOKEN) * MAX_TOKENS); err = parse_tokens (parse, arg, tokens, &ntokens); if (err) return nerr_pass(err); + + if (parse->audit_mode) { + /* Save the complete expression string for future reference */ + expr->argexpr = strdup(arg); + } + err = parse_expr2 (parse, tokens, ntokens, lvalue, expr); if (err) return nerr_pass(err); return STATUS_OK; @@ -1350,7 +1466,7 @@ CSTREE *node; /* ne_warn ("literal: %s", arg); */ - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; node->arg1.op_type = CS_TYPE_STRING; @@ -1380,7 +1496,7 @@ char tmp[256]; /* ne_warn ("name: %s", arg); */ - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; if (arg[0] == '!') @@ -1415,7 +1531,7 @@ CSTREE *node; /* ne_warn ("escape: %s", arg); */ - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; /* Since this throws an error always if there's a problem @@ -1494,7 +1610,7 @@ if (err != STATUS_OK) return nerr_pass(err); /* ne_warn ("var: %s", arg); */ - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; @@ -1532,7 +1648,7 @@ CSTREE *node; /* ne_warn ("lvar: %s", arg); */ - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; if (arg[0] == '!') @@ -1559,7 +1675,7 @@ CSTREE *node; /* ne_warn ("linclude: %s", arg); */ - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; if (arg[0] == '!') @@ -1586,7 +1702,7 @@ CSTREE *node; /* ne_warn ("var: %s", arg); */ - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; if (arg[0] == '!') @@ -1617,7 +1733,7 @@ char tmp[256]; /* ne_warn ("evar: %s", arg); */ - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; if (arg[0] == '!') @@ -1670,7 +1786,7 @@ CSTREE *node; /* ne_warn ("if: %s", arg); */ - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err != STATUS_OK) return nerr_pass(err); node->cmd = cmd; arg++; @@ -2131,9 +2247,9 @@ if (arg2.op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM)) { long int n2 = arg_eval_num (parse, &arg2); - result->s = sprintf_alloc("%s.%d", arg1.s, n2); + result->s = sprintf_alloc("%s.%ld", 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); + return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %ld", arg1.s, n2); } else { @@ -2169,9 +2285,9 @@ if (arg2.op_type & CS_TYPE_NUM) { long int n2 = arg_eval_num (parse, &arg2); - result->s = sprintf_alloc("%s.%d", arg1.s, n2); + result->s = sprintf_alloc("%s.%ld", 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); + return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %ld", arg1.s, n2); } else { @@ -2504,7 +2620,7 @@ char *p; char tmp[256]; - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; if (arg[0] == '!') @@ -2722,7 +2838,7 @@ */ parse->escaping.next_stack = NEOS_ESCAPE_UNDEF; - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; arg++; @@ -2896,7 +3012,7 @@ err = uListGet (parse->stack, -1, (void *)&entry); if (err != STATUS_OK) return nerr_pass(err); - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; node->escape = entry->escape; @@ -2927,9 +3043,15 @@ if (macro == NULL) { dealloc_node(&node); - return nerr_raise (NERR_PARSE, - "%s Undefined macro called: %s", - find_context(parse, -1, tmp, sizeof(tmp)), arg); + err = nerr_raise (NERR_PARSE, "%s Undefined macro called: %s", + find_context(parse, -1, tmp, sizeof(tmp)), arg); + if (parse->audit_mode) { + /* Ignore macros that cannot be found */ + return _store_error(parse, err); + } + else { + return err; + } } node->arg1.op_type = CS_TYPE_MACRO; node->arg1.macro = macro; @@ -3112,7 +3234,7 @@ char *s; char tmp[256]; - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; arg++; @@ -3217,7 +3339,7 @@ char tmp[256]; int x; - err = alloc_node (&node); + err = alloc_node (&node, parse); if (err) return nerr_pass(err); node->cmd = cmd; if (arg[0] == '!') @@ -3578,6 +3700,29 @@ return STATUS_OK; } +static NEOERR * _builtin_str_crc(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, + CSARG *result) +{ + NEOERR *err; + CSARG val; + + memset(&val, 0, sizeof(val)); + err = eval_expr(parse, args, &val); + if (err) return nerr_pass(err); + + /* non var/string objects have 0 length */ + result->op_type = CS_TYPE_NUM; + result->n = 0; + + if (val.op_type & (CS_TYPE_VAR | CS_TYPE_STRING)) + { + char *s = arg_eval(parse, &val); + if (s) result->n = ne_crc((unsigned char *)s, strlen(s)); + } + if (val.alloc) free(val.s); + return STATUS_OK; +} + static NEOERR * _builtin_str_find(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args, CSARG *result) { @@ -3921,7 +4066,7 @@ free(my_parse); return nerr_pass(err); } - err = alloc_node (&(my_parse->tree)); + err = alloc_node (&(my_parse->tree), my_parse); if (err != STATUS_OK) { cs_destroy (&my_parse); @@ -3952,7 +4097,7 @@ my_parse->hdf = hdf; /* Let's set the default escape data */ - my_parse->escaping.global = NEOS_ESCAPE_NONE; + my_parse->escaping.global_ctx = NEOS_ESCAPE_NONE; my_parse->escaping.next_stack = NEOS_ESCAPE_NONE; my_parse->escaping.when_undef = NEOS_ESCAPE_NONE; @@ -3964,7 +4109,7 @@ esc_cursor++) if (!strcmp(esc_value, esc_cursor->mode)) { - my_parse->escaping.global = esc_cursor->context; + my_parse->escaping.global_ctx = esc_cursor->context; my_parse->escaping.next_stack = esc_cursor->context; entry->escape = esc_cursor->context; break; @@ -3977,6 +4122,11 @@ esc_value); } + /* Read configuration value to determine whether to enable audit mode */ + my_parse->audit_mode = hdf_get_int_value(hdf, "Config.EnableAuditMode", 0); + + my_parse->err_list = NULL; + if (parent == NULL) { static struct _builtin_functions { @@ -3995,6 +4145,7 @@ { "string.find", 2, _builtin_str_find }, { "string.slice", 3, _builtin_str_slice }, { "string.length", 1, _builtin_str_length }, + { "string.crc", 1, _builtin_str_crc}, #ifdef ENABLE_GETTEXT { "_", 1, _builtin_gettext }, #endif @@ -4028,7 +4179,15 @@ my_parse->global_hdf = parent->global_hdf; my_parse->fileload = parent->fileload; my_parse->fileload_ctx = parent->fileload_ctx; + // This should be safe since locals handling is done entirely local to the + // eval functions, not globally by the parse handling. This should + // pass the locals down to the new parse context to make locals work with + // lvar + my_parse->locals = parent->locals; my_parse->parent = parent; + + /* Copy the audit flag from parent */ + my_parse->audit_mode = parent->audit_mode; } *parse = my_parse; @@ -4058,12 +4217,23 @@ dealloc_function(&(my_parse->functions)); } + /* Free list of errors */ + if (my_parse->err_list != NULL) { + CS_ERROR *ptr; + + while (my_parse->err_list) { + ptr = my_parse->err_list->next; + free(my_parse->err_list->err); + free(my_parse->err_list); + my_parse->err_list = ptr; + } + } + 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 -Nru clearsilver-0.10.4/cs/test16.cs clearsilver-0.10.5/cs/test16.cs --- clearsilver-0.10.4/cs/test16.cs 2005-06-30 11:51:51.000000000 -0700 +++ clearsilver-0.10.5/cs/test16.cs 2006-12-19 17:12:40.000000000 -0800 @@ -1,3 +1,7 @@ + + + + diff -Nru clearsilver-0.10.4/cs/test16.cs.gold clearsilver-0.10.5/cs/test16.cs.gold --- clearsilver-0.10.4/cs/test16.cs.gold 2006-10-09 17:53:19.000000000 -0700 +++ clearsilver-0.10.5/cs/test16.cs.gold 2007-05-02 17:21:17.000000000 -0700 @@ -2,3 +2,19 @@ HELLO/WORLD HELLO/WORLD HELLO/WORLD + + + 0/WORLD + + 1/WORLD + + 2/WORLD + + 3/WORLD + + 4/WORLD + + 5/WORLD + + 6/WORLD + diff -Nru clearsilver-0.10.4/cs/test_crc.cs clearsilver-0.10.5/cs/test_crc.cs --- clearsilver-0.10.4/cs/test_crc.cs 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/cs/test_crc.cs 2007-05-02 17:18:24.000000000 -0700 @@ -0,0 +1,3 @@ + + + diff -Nru clearsilver-0.10.4/cs/test_crc.cs.gold clearsilver-0.10.5/cs/test_crc.cs.gold --- clearsilver-0.10.4/cs/test_crc.cs.gold 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/cs/test_crc.cs.gold 2007-05-02 17:21:17.000000000 -0700 @@ -0,0 +1,4 @@ +Parsing test_crc.cs +419156592 +1357503972 +-2128917020 diff -Nru clearsilver-0.10.4/cs/test_url_validate.cs clearsilver-0.10.5/cs/test_url_validate.cs --- clearsilver-0.10.4/cs/test_url_validate.cs 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/cs/test_url_validate.cs 2007-07-11 18:23:59.000000000 -0700 @@ -0,0 +1,23 @@ +The following urls should be allowed unmodified: + = + = + = + = + + = + = + = + + = + = + +This URL should be html escaped: + = + + +These URLs should be changed to # + = + = + = + = + = diff -Nru clearsilver-0.10.4/cs/test_url_validate.hdf clearsilver-0.10.5/cs/test_url_validate.hdf --- clearsilver-0.10.4/cs/test_url_validate.hdf 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/cs/test_url_validate.hdf 2007-07-11 18:23:59.000000000 -0700 @@ -0,0 +1,18 @@ +BlahUrl = http://www.google.com +SslUrl = https://www.google.com +FtpUrl = ftp://www.google.com/a +MailUrl = mailto:tester@google.com + +JsUrl = javascript:www.google.com +DataUrl = data:text/html;base64,PHNjcmlwdD5hbGVydCgncmZjMjM5NyBpcyBzY2FyeScpPC9zY3JpcHQ+ + +AbsUrl = /mail/ +AbsUrl2 = / +RelUrl = mail/google.x +HtmlUrl = http://www.google.com//good.x + +ColonUrl = relative/path:name +ColonUrlTwo = /mail/path:name +InvalidUrl = mail:80 +InvalidUrl2 = www.google.com:80 +ShortUrl = m:x diff -Nru clearsilver-0.10.4/cs_config.h.in clearsilver-0.10.5/cs_config.h.in --- clearsilver-0.10.4/cs_config.h.in 2005-06-30 18:49:22.000000000 -0700 +++ clearsilver-0.10.5/cs_config.h.in 2006-12-14 19:11:09.000000000 -0800 @@ -74,6 +74,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H +/* Define to 1 if you have the header file. */ +#undef HAVE_FEATURES_H + /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY diff -Nru clearsilver-0.10.4/csharp/CS.cs clearsilver-0.10.5/csharp/CS.cs --- clearsilver-0.10.4/csharp/CS.cs 2005-06-30 11:51:53.000000000 -0700 +++ clearsilver-0.10.5/csharp/CS.cs 2007-07-12 12:57:57.000000000 -0700 @@ -53,12 +53,14 @@ public HDF *hdf_root; public Hdf() { - NEOERR* err = hdf_init(&hdf_root); + fixed (HDF **hdf_ptr = &hdf_root) { + hdf_init(hdf_ptr); + } // Console.WriteLine((int)hdf_root); } public void setValue(string name,string value) { - NEOERR* err = hdf_set_value(hdf_root,name,value); + hdf_set_value(hdf_root,name,value); } public string getValue(string name,string defvalue) { @@ -81,16 +83,18 @@ unsafe struct CSPARSE {}; public class CSTContext { - CSPARSE *csp; + unsafe CSPARSE *csp; unsafe public CSTContext(Hdf hdf) { - NEOERR *err = cs_init(&csp, hdf.hdf_root); + fixed (CSPARSE **csp_ptr = &csp) { + cs_init(csp_ptr, hdf.hdf_root); + } } [DllImport("libneo")] extern static unsafe NEOERR *cs_init (CSPARSE **parse, HDF *hdf); public unsafe void parseFile(string filename) { - NEOERR* err = cs_parse_file(csp,filename); + cs_parse_file(csp,filename); } [DllImport("libneo")] @@ -131,7 +135,7 @@ public unsafe string render() { OutputBuilder ob = new OutputBuilder(); - NEOERR* err = cs_render(csp,null,new CSOUTFUNC(ob.handleOutput)); + cs_render(csp,null,new CSOUTFUNC(ob.handleOutput)); return ob.result(); } @@ -142,4 +146,4 @@ }; -} // namespace Clearsilver \ No newline at end of file +} // namespace Clearsilver diff -Nru clearsilver-0.10.4/csharp/Makefile clearsilver-0.10.5/csharp/Makefile --- clearsilver-0.10.4/csharp/Makefile 2005-12-02 02:34:30.000000000 -0800 +++ clearsilver-0.10.5/csharp/Makefile 2007-07-12 12:39:33.000000000 -0700 @@ -19,13 +19,13 @@ all: $(TARGETS) clearsilver.dll: CS.cs - $(CSHARP_CC) -target:library --unsafe CS.cs -out:clearsilver.dll + $(CSHARP_CC) -target:library -unsafe CS.cs -out:clearsilver.dll cstest.exe: clearsilver.dll ../dso/libneo.so cstest.cs - $(CSHARP_CC) -r:clearsilver.dll --unsafe cstest.cs + $(CSHARP_CC) -r:clearsilver.dll -unsafe cstest.cs csperftest.exe: clearsilver.dll ../dso/libneo.so csperftest.cs - $(CSHARP_CC) -r:clearsilver.dll --unsafe csperftest.cs + $(CSHARP_CC) -r:clearsilver.dll -unsafe csperftest.cs perf: csperftest.exe export LD_LIBRARY_PATH=../dso; \ diff -Nru clearsilver-0.10.4/java-jni/CGI.java clearsilver-0.10.5/java-jni/CGI.java --- clearsilver-0.10.4/java-jni/CGI.java 2005-06-30 11:51:54.000000000 -0700 +++ clearsilver-0.10.5/java-jni/CGI.java 2007-02-01 17:06:17.000000000 -0800 @@ -6,12 +6,7 @@ public int _cgiptr; static { - try { - System.loadLibrary("clearsilver-jni"); - } catch ( UnsatisfiedLinkError e ) { - System.out.println("Could not load neo_cgi.so"); - System.exit(1); - } + JNI.loadLibrary(); } public CGI() { diff -Nru clearsilver-0.10.4/java-jni/CS.java clearsilver-0.10.5/java-jni/CS.java --- clearsilver-0.10.4/java-jni/CS.java 2005-10-11 11:41:32.000000000 -0700 +++ clearsilver-0.10.5/java-jni/CS.java 2007-02-01 17:06:17.000000000 -0800 @@ -5,20 +5,17 @@ public class CS { public int csptr; - + protected HDF globalHDF; + protected HDF localHDF; - static { - try { - System.loadLibrary("clearsilver-jni"); - } catch ( UnsatisfiedLinkError e ) { - System.out.println("Could not load library 'clearsilver-jni'"); - System.exit(1); - } + static { + JNI.loadLibrary(); } - + public CS(HDF ho) { this.globalHDF = null; + this.localHDF = ho; csptr = _init(ho.hdfptr); } @@ -48,7 +45,7 @@ _dealloc(csptr); csptr = 0; } - } + } public void finalize() { close(); @@ -58,7 +55,7 @@ if (csptr == 0) { throw new NullPointerException("CS is closed."); } - _parseFile(csptr,filename); + _parseFile(csptr, filename, fileLoader != null); } public void parseStr(String content) { @@ -74,10 +71,49 @@ } return _render(csptr); } - + + + protected String fileLoad(String filename) throws IOException, + FileNotFoundException { + if (csptr == 0) { + throw new NullPointerException("CS is closed."); + } + CSFileLoader aFileLoader = fileLoader; + if (aFileLoader == null) { + throw new NullPointerException("No fileLoader specified."); + } else { + String result = aFileLoader.load(localHDF, filename); + if (result == null) { + throw new NullPointerException("CSFileLoader.load() returned null"); + } + return result; + } + } + + // The optional CS file loader to use to read in files + private CSFileLoader fileLoader = null; + + /** + * Get the file loader in use, if any. + * @return the file loader in use. + */ + public CSFileLoader getFileLoader() { + return fileLoader; + } + + /** + * Set the CS file loader to use + * @param fileLoader the file loader that should be used. + */ + public void setFileLoader(CSFileLoader fileLoader) { + this.fileLoader = fileLoader; + } + + private native int _init(int ptr); private native void _dealloc(int ptr); - private native void _parseFile(int ptr,String filename); + private native void _parseFile(int ptr, String filename, + boolean use_cb); private native void _parseStr(int ptr, String content); private native String _render(int ptr); private native void _setGlobalHdf(int csptr, int hdfptr); diff -Nru clearsilver-0.10.4/java-jni/CSFileLoader.java clearsilver-0.10.5/java-jni/CSFileLoader.java --- clearsilver-0.10.4/java-jni/CSFileLoader.java 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/java-jni/CSFileLoader.java 2007-01-05 14:22:52.000000000 -0800 @@ -0,0 +1,22 @@ +package org.clearsilver; + +import java.io.IOException; + +/** + * Interface for CS file hook + * + * @author smarti@google.com (Sergio Marti) + */ +public interface CSFileLoader { + + /** + * Callback method that is expected to return the contents of the specified + * file as a string. + * @param hdf the HDF structure associated with HDF or CS object making the + * callback. + * @param filename the name of the file that should be loaded. + * @return a string containing the contents of the file. + */ + public String load(HDF hdf, String filename) throws IOException; + +} diff -Nru clearsilver-0.10.4/java-jni/CSTest.java clearsilver-0.10.5/java-jni/CSTest.java --- clearsilver-0.10.4/java-jni/CSTest.java 2006-11-09 16:54:04.000000000 -0800 +++ clearsilver-0.10.5/java-jni/CSTest.java 2007-01-05 14:22:52.000000000 -0800 @@ -3,9 +3,16 @@ import java.util.*; import org.clearsilver.CS; +import org.clearsilver.CSFileLoader; import org.clearsilver.HDF; -class CSTest { +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + + +public class CSTest { public static void main( String [] args ) throws IOException { org.clearsilver.HDF hdf = new HDF(); @@ -226,5 +233,39 @@ System.out.println("----"); cs.parseStr(tmplstr); System.out.println(cs.render()); + + System.out.println("Testing HDF.readFile() with callback\n"); + file_hdf = new HDF(); + file_hdf.setFileLoader(new CSTestLoader()); + file_hdf.readFile("testdata/test1.hdf"); + System.out.println(file_hdf.dump()); + + System.out.println("Testing CS.parseFile() with callback\n"); + cs = new CS(file_hdf); + cs.setFileLoader(new CSTestLoader()); + cs.parseFile("testdata/test.cs"); + System.out.println(cs.render()); + } +}; + +class CSTestLoader implements CSFileLoader { + public String load(HDF hdf, String filename) throws IOException { + System.out.println("CSTestLoader::Load " + filename + "\n"); + String data = readFile(new File(filename)); + System.out.println("---- file begin ----\n" + data + + "\n---- file end ----\n"); + return data; + } + + private String readFile(File file) throws IOException { + InputStreamReader fin = new InputStreamReader(new FileInputStream(file), + "UTF-8"); + StringBuilder sb = new StringBuilder(1024); + char[] charbuf = new char[1024]; + int len = 0; + while ((len = fin.read(charbuf)) != -1) { + sb.append(charbuf, 0, len); } + return sb.toString(); + } }; diff -Nru clearsilver-0.10.4/java-jni/CSUtil.java clearsilver-0.10.5/java-jni/CSUtil.java --- clearsilver-0.10.4/java-jni/CSUtil.java 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/java-jni/CSUtil.java 2006-12-18 20:26:12.000000000 -0800 @@ -0,0 +1,62 @@ +package org.clearsilver; + +import java.util.LinkedList; +import java.util.List; +import java.io.File; + +/** + * Utility class containing helper methods + * + * @author smarti@google.com (Sergio Marti) + */ +public class CSUtil { + + private CSUtil() { } + + public static final String HDF_LOADPATHS = "hdf.loadpaths"; + + /** + * Helper function that returns a concatenation of the loadpaths in the + * provided HDF. + * @param hdf an HDF structure containing load paths. + * @return A list of loadpaths in order in which to search. + * @throws NullPointerException if no loadpaths are found. + */ + public static List getLoadPaths(HDF hdf) { + List list = new LinkedList(); + HDF loadpathsHdf = hdf.getObj(HDF_LOADPATHS); + if (loadpathsHdf == null) { + throw new NullPointerException("No HDF loadpaths located in the specified" + + " HDF structure"); + } + for (HDF lpHdf = loadpathsHdf.objChild(); lpHdf != null; + lpHdf = lpHdf.objNext()) { + list.add(lpHdf.objValue()); + } + return list; + } + + /** + * Given an ordered list of directories to look in, locate the specified file. + * Returns null if file not found. + * @param loadpaths the ordered list of paths to search. + * @param filename the name of the file. + * @return a File object corresponding to the file. null if + * file not found. + */ + public static File locateFile(List loadpaths, String filename) { + if (filename == null) { + throw new NullPointerException("No filename provided"); + } + if (loadpaths == null) { + throw new NullPointerException("No loadpaths provided."); + } + for (String path : loadpaths) { + File file = new File(path, filename); + if (file.exists()) { + return file; + } + } + return null; + } +} diff -Nru clearsilver-0.10.4/java-jni/HDF.java clearsilver-0.10.5/java-jni/HDF.java --- clearsilver-0.10.4/java-jni/HDF.java 2006-10-09 17:47:43.000000000 -0700 +++ clearsilver-0.10.5/java-jni/HDF.java 2007-02-01 17:06:17.000000000 -0800 @@ -17,12 +17,7 @@ // to hold a reference on the root to prevent the root from // being GC-ed. static { - try { - System.loadLibrary("clearsilver-jni"); - } catch ( UnsatisfiedLinkError e ) { - System.out.println("Could not load 'clearsilver-jni'"); - System.exit(1); - } + JNI.loadLibrary(); } /** Constructs an empty HDF dataset */ @@ -69,7 +64,43 @@ if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } - return _readFile(hdfptr, filename); + return _readFile(hdfptr, filename, fileLoader != null); + } + + protected String fileLoad(String filename) throws IOException, + FileNotFoundException { + if (hdfptr == 0) { + throw new NullPointerException("HDF is closed."); + } + CSFileLoader aFileLoader = fileLoader; + if (aFileLoader == null) { + throw new NullPointerException("No fileLoader specified."); + } else { + String result = aFileLoader.load(this, filename); + if (result == null) { + throw new NullPointerException("CSFileLoader.load() returned null"); + } + return result; + } + } + + // The optional CS file loader to use to read in files + private CSFileLoader fileLoader = null; + + /** + * Get the file loader in use, if any. + * @return the file loader in use. + */ + public CSFileLoader getFileLoader() { + return fileLoader; + } + + /** + * Set the CS file loader to use + * @param fileLoader the file loader that should be used. + */ + public void setFileLoader(CSFileLoader fileLoader) { + this.fileLoader = fileLoader; } /** Serializes HDF contents to a file (readable by readFile) @@ -332,7 +363,7 @@ private static native int _init(); private static native void _dealloc(int ptr); - private static native boolean _readFile(int ptr, String filename); + private native boolean _readFile(int ptr, String filename, boolean use_cb); private static native boolean _writeFile(int ptr, String filename); private static native boolean _writeFileAtomic(int ptr, String filename); private static native boolean _readString(int ptr, String data); diff -Nru clearsilver-0.10.4/java-jni/JNI.java clearsilver-0.10.5/java-jni/JNI.java --- clearsilver-0.10.4/java-jni/JNI.java 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/java-jni/JNI.java 2007-02-01 17:06:17.000000000 -0800 @@ -0,0 +1,80 @@ +package org.clearsilver; + +/** + * Loads the ClearSilver JNI library. + * + *

By default, it attempts to load the library 'clearsilver-jni' from the + * path specified in the 'java.library.path' system property.

+ * + *

If this fails, the JVM exits with a code of 1. However, this strategy + * can be changed using {@link #setFailureCallback(Runnable)}.

+ */ +public class JNI { + + /** + * Failure callback strategy that writes a message to sysout, then calls + * System.exit(1). + */ + public static Runnable EXIT_JVM = new Runnable() { + public void run() { + System.out.println("Could not load '" + libraryName + "'"); + System.out.println("java.library.path = " + + System.getProperty("java.library.path")); + System.exit(1); + } + }; + + /** + * Failure callback strategy that throws an UnsatisfiedLinkError, which + * should be caught be client code. + */ + public static Runnable THROW_ERROR = new Runnable() { + public void run() { + throw new UnsatisfiedLinkError("Could not load '" + libraryName + "'"); + } + }; + + private static Runnable failureCallback = EXIT_JVM; + + private static Object callbackLock = new Object(); + + private static String libraryName = "clearsilver-jni"; + + /** + * Attempts to load the ClearSilver JNI library. + * + * @see #setFailureCallback(Runnable) + */ + public static void loadLibrary() { + try { + System.loadLibrary(libraryName); + } catch (UnsatisfiedLinkError e) { + synchronized (callbackLock) { + if (failureCallback != null) { + failureCallback.run(); + } + } + } + } + + /** + * Sets a callback for what should happen if the JNI library cannot + * be loaded. The default is {@link #EXIT_JVM}. + * + * @see #EXIT_JVM + * @see #THROW_ERROR + */ + public static void setFailureCallback(Runnable failureCallback) { + synchronized(callbackLock) { + JNI.failureCallback = failureCallback; + } + } + + /** + * Set name of JNI library to load. Default is 'clearsilver-jni'. + */ + public static void setLibraryName(String libraryName) { + JNI.libraryName = libraryName; + } + +} \ No newline at end of file diff -Nru clearsilver-0.10.4/java-jni/Makefile clearsilver-0.10.5/java-jni/Makefile --- clearsilver-0.10.4/java-jni/Makefile 2006-08-07 13:05:13.000000000 -0700 +++ clearsilver-0.10.5/java-jni/Makefile 2007-02-01 17:06:17.000000000 -0800 @@ -8,27 +8,29 @@ include $(NEOTONIC_ROOT)/rules.mk NEO_UTIL_SO = libclearsilver-jni.so -NEO_UTIL_JAVA_SRC = HDF.java CS.java # CGI.java -NEO_UTIL_JAVA_CLASS = $(NEO_UTIL_JAVA_SRC:%.java=%) -NEO_UTIL_JAVA_CLASSFILES = $(NEO_UTIL_JAVA_SRC:%.java=%.class) +ifeq ($(OSTYPE),Darwin) +NEO_UTIL_SO = libclearsilver-jni.jnilib +endif +NEO_UTIL_JAVA_SRC = HDF.java CS.java CSUtil.java CSFileLoader.java JNI.java # CGI.java + NEO_UTIL_JAVA_JAR = clearsilver.jar NEO_UTIL_SRC = j_neo_util.c j_neo_cs.c NEO_UTIL_OBJ = $(NEO_UTIL_SRC:%.c=%.o) - CFLAGS += $(JAVA_INCLUDE_PATH) DLIBS += -lneo_cgi -lneo_cs -lneo_utl LIBS += $(DLIBS) +ifneq ($(OSTYPE),Darwin) LDFLAGS += -Wl,-soname=$(NEO_UTIL_SO) +endif TARGETS = org_clearsilver_HDF.h org_clearsilver_CS.h $(NEO_UTIL_SO) all: $(TARGETS) test $(NEO_UTIL_JAVA_JAR): $(NEO_UTIL_JAVA_SRC) - $(JAVAC) $(NEO_UTIL_JAVA_SRC) $(MKDIR) org/clearsilver - cp $(NEO_UTIL_JAVA_CLASSFILES) org/clearsilver + $(JAVAC) -d . $(NEO_UTIL_JAVA_SRC) $(JAR) cf $(NEO_UTIL_JAVA_JAR) org $(RM) -r org Binary files clearsilver-0.10.4/java-jni/clearsilver.jar and clearsilver-0.10.5/java-jni/clearsilver.jar differ diff -Nru clearsilver-0.10.4/java-jni/j_neo_cs.c clearsilver-0.10.5/java-jni/j_neo_cs.c --- clearsilver-0.10.4/java-jni/j_neo_cs.c 2005-10-11 11:41:32.000000000 -0700 +++ clearsilver-0.10.5/java-jni/j_neo_cs.c 2006-12-19 15:44:54.000000000 -0800 @@ -14,6 +14,7 @@ #include "cgi/html.h" #include "cs/cs.h" +#include "j_neo_util.h" jfieldID _csobjFldID = NULL; @@ -55,19 +56,32 @@ } -JNIEXPORT void JNICALL Java_org_clearsilver_CS__1parseFile - (JNIEnv *env, jclass objClass, jint cs_obj_ptr, - jstring j_filename) { - +JNIEXPORT void JNICALL Java_org_clearsilver_CS__1parseFile(JNIEnv *env, + jobject objCS, jint cs_obj_ptr, jstring j_filename, jboolean use_cb) { CSPARSE *cs = (CSPARSE *)cs_obj_ptr; NEOERR *err; const char *filename; + FILELOAD_INFO fl_info; if (!j_filename) { return; } // throw + + if (use_cb == JNI_TRUE) { + jclass csClass; + csClass = (*env)->GetObjectClass(env, objCS); + if (csClass == NULL) return; + fl_info.env = env; + fl_info.fl_obj = objCS; + fl_info.hdf = cs->hdf; + fl_info.fl_method = (*env)->GetMethodID(env, csClass, + "fileLoad", "(Ljava/lang/String;)Ljava/lang/String;"); + if (fl_info.fl_method == NULL) return; + cs_register_fileload(cs, &fl_info, jni_fileload_cb); + } filename = (*env)->GetStringUTFChars(env,j_filename,0); err = cs_parse_file(cs,(char *)filename); + if (use_cb == JNI_TRUE) cs_register_fileload(cs, NULL, NULL); if (err != STATUS_OK) { jNeoErr(env,err); return; } diff -Nru clearsilver-0.10.4/java-jni/j_neo_util.c clearsilver-0.10.5/java-jni/j_neo_util.c --- clearsilver-0.10.4/java-jni/j_neo_util.c 2006-04-20 12:56:25.000000000 -0700 +++ clearsilver-0.10.5/java-jni/j_neo_util.c 2006-12-19 15:44:42.000000000 -0800 @@ -1,3 +1,4 @@ +#include #include #include "org_clearsilver_HDF.h" @@ -11,6 +12,8 @@ #include "cgi/date.h" #include "cgi/html.h" +#include "j_neo_util.h" + void throwException(JNIEnv *env, const char* class_name, const char *message) { jclass ex_class = (*env)->FindClass(env, class_name); if (ex_class == NULL) { @@ -241,16 +244,71 @@ return retval; } +NEOERR *jni_fileload_cb(void *ctx, HDF *hdf, const char *filename, + char **contents) { + FILELOAD_INFO *info = (FILELOAD_INFO *)ctx; + jstring filename_str; + jstring loaded_string; + const char *c_loaded_string; + + // We assume that the hdf passed back is actually the hdf we already + // have... + if (hdf != info->hdf) + return nerr_raise(NERR_ASSERT, + "jni_fileload_cb: passed HDF pointer doesn't match hdf_obj_ptr"); + + filename_str = (*info->env)->NewStringUTF(info->env, filename); + (*info->env)->NewLocalRef(info->env, filename_str); + + loaded_string = (*info->env)->CallObjectMethod(info->env, info->fl_obj, + info->fl_method, filename_str); + if ((*info->env)->ExceptionCheck(info->env)) { + (*info->env)->ExceptionDescribe(info->env); + (*info->env)->ExceptionClear(info->env); + return nerr_raise(NERR_ASSERT, + "jni_fileload_cb: HDF.fileLoad returned exception, see STDERR"); + } + c_loaded_string = (*info->env)->GetStringUTFChars(info->env, loaded_string, + 0); + if (c_loaded_string) { + *contents = strdup(c_loaded_string); + } + (*info->env)->ReleaseStringUTFChars(info->env, loaded_string, + c_loaded_string); + + return STATUS_OK; +} + JNIEXPORT jboolean JNICALL Java_org_clearsilver_HDF__1readFile( - JNIEnv *env, jobject objClass, jint hdf_obj_ptr, jstring j_filename) { + JNIEnv *env, jobject objClass, jint hdf_obj_ptr, jstring j_filename, + jboolean use_cb) { HDF *hdf = (HDF *)hdf_obj_ptr; NEOERR *err; const char *filename; jboolean retval; + FILELOAD_INFO fl_info; + + if (use_cb == JNI_TRUE) { + jclass hdfClass; + + fl_info.env = env; + fl_info.fl_obj = objClass; + fl_info.hdf = hdf; + + hdfClass = (*env)->GetObjectClass(env, objClass); + if (hdfClass == NULL) return JNI_FALSE; + + fl_info.fl_method = (*env)->GetMethodID(env, hdfClass, + "fileLoad", "(Ljava/lang/String;)Ljava/lang/String;"); + if (fl_info.fl_method == NULL) return JNI_FALSE; + + hdf_register_fileload(hdf, &fl_info, jni_fileload_cb); + } filename = (*env)->GetStringUTFChars(env, j_filename, 0); err = hdf_read_file(hdf, filename); (*env)->ReleaseStringUTFChars(env, j_filename, filename); + if (use_cb == JNI_TRUE) hdf_register_fileload(hdf, NULL, NULL); if (err != STATUS_OK) { // Throw an exception. jNeoErr handles all types of errors other than // NOT_FOUND, since that can mean different things in different contexts. diff -Nru clearsilver-0.10.4/java-jni/j_neo_util.h clearsilver-0.10.5/java-jni/j_neo_util.h --- clearsilver-0.10.4/java-jni/j_neo_util.h 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/java-jni/j_neo_util.h 2006-12-18 19:36:09.000000000 -0800 @@ -0,0 +1,20 @@ +// Copyright 2006 Brandon Long +// All Rights Reserved. +// +// This code is made available under the terms of the ClearSilver License. +// http://www.clearsilver.net/license.hdf + +#ifndef __J_NEO_UTIL_H_ +#define __J_NEO_UTIL_H_ 1 + +typedef struct _fileload_info { + JNIEnv *env; + jobject fl_obj; + HDF *hdf; + jmethodID fl_method; +} FILELOAD_INFO; + +NEOERR *jni_fileload_cb(void *ctx, HDF *hdf, const char *filename, + char **contents); + +#endif // __J_NEO_UTIL_H_ diff -Nru clearsilver-0.10.4/java-jni/javatest.gold clearsilver-0.10.5/java-jni/javatest.gold --- clearsilver-0.10.4/java-jni/javatest.gold 2006-11-09 16:54:04.000000000 -0800 +++ clearsilver-0.10.5/java-jni/javatest.gold 2006-12-18 20:20:05.000000000 -0800 @@ -163,3 +163,44 @@ html escape block: <script src="some.js">alert('123');</script> +Testing HDF.readFile() with callback + +CSTestLoader::Load testdata/test1.hdf + +---- file begin ---- +# Simple HDF file to test that HDF.readFile() works +Foo.Bar = 10 +Foo.Baz = 20 + +---- file end ---- + +Foo.Bar = 10 +Foo.Baz = 20 + +Testing CS.parseFile() with callback + +CSTestLoader::Load testdata/test.cs + +---- file begin ---- +Testing CS parse file... + + + + + + + +---- file end ---- + +Testing CS parse file... + + + + + 10 + + 20 + + Beans + + Binary files clearsilver-0.10.4/java-jni/libclearsilver-jni.so and clearsilver-0.10.5/java-jni/libclearsilver-jni.so differ diff -Nru clearsilver-0.10.4/java-jni/testdata/test.cs clearsilver-0.10.5/java-jni/testdata/test.cs --- clearsilver-0.10.4/java-jni/testdata/test.cs 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/java-jni/testdata/test.cs 2006-12-18 20:17:07.000000000 -0800 @@ -0,0 +1,7 @@ +Testing CS parse file... + + + + + + diff -Nru clearsilver-0.10.4/perl/ClearSilver.xs clearsilver-0.10.5/perl/ClearSilver.xs --- clearsilver-0.10.4/perl/ClearSilver.xs 2005-12-02 03:08:39.000000000 -0800 +++ clearsilver-0.10.5/perl/ClearSilver.xs 2007-07-11 18:31:34.000000000 -0700 @@ -34,10 +34,9 @@ static NEOERR *output (void *ctx, char *s) { - NEOERR* err; - STRING* str_p = (STRING*)ctx; - err = string_append(str_p, s); - return err; + sv_catpv((SV*)ctx, s); + + return STATUS_OK; } static int sortFunction(const void* in_a, const void* in_b) @@ -400,27 +399,18 @@ char * perlcs_render(cs) ClearSilver::CS cs - PREINIT: - STRING str; CODE: - string_init(&str); - - cs->err = cs_render(cs->cs, &str, output); - do { - if (cs->err != STATUS_OK) { - RETVAL = NULL; - break; - } - RETVAL = (char*)malloc(str.len + 1); - if (! RETVAL) { - break; - } - strncpy(RETVAL, str.buf, str.len); - *(RETVAL + str.len) = '\0'; - string_clear (&str); - } while (0); - OUTPUT: - RETVAL + { + SV *str = newSV(0); + cs->err = cs_render(cs->cs, str, output); + if (cs->err == STATUS_OK) { + ST(0) = sv_2mortal(str); + } else { + SvREFCNT_dec(str); + ST(0) = &PL_sv_undef; + } + XSRETURN(1); + } int perlcs_parseFile(cs, cs_file) diff -Nru clearsilver-0.10.4/perl/test.out clearsilver-0.10.5/perl/test.out --- clearsilver-0.10.4/perl/test.out 2005-06-30 11:51:55.000000000 -0700 +++ clearsilver-0.10.5/perl/test.out 1969-12-31 16:00:00.000000000 -0800 @@ -1,11 +0,0 @@ -value3 -value1 - - -value1 - -value2 - -value3 - - diff -Nru clearsilver-0.10.4/ports/rpm/clearsilver.spec clearsilver-0.10.5/ports/rpm/clearsilver.spec --- clearsilver-0.10.4/ports/rpm/clearsilver.spec 2006-11-14 22:54:20.000000000 -0800 +++ clearsilver-0.10.5/ports/rpm/clearsilver.spec 2007-07-11 19:43:43.000000000 -0700 @@ -53,11 +53,11 @@ Summary: Neotonic ClearSilver Name: clearsilver -Version: 0.10.4 +Version: 0.10.5 Release: 1 Copyright: Open Source - Neotonic ClearSilver License (Apache 1.1 based) Group: Development/Libraries -Source: http://www.clearsilver.net/downloads/clearsilver-0.10.4.tar.gz +Source: http://www.clearsilver.net/downloads/clearsilver-0.10.5.tar.gz URL: http://www.clearsilver.net/ Vendor: Neotonic Software Corporation, Inc. Packager: Brandon Long diff -Nru clearsilver-0.10.4/python/neo_cgi.c clearsilver-0.10.5/python/neo_cgi.c --- clearsilver-0.10.4/python/neo_cgi.c 2006-11-09 14:34:08.000000000 -0800 +++ clearsilver-0.10.5/python/neo_cgi.c 2007-07-11 20:07:43.000000000 -0700 @@ -728,7 +728,7 @@ v = PyTuple_GetItem (result, 1); if (k == NULL || v == NULL) { - ne_warn ("p_iterenv: Unable to get k,v %s,%s", k, v); + ne_warn ("p_iterenv: Unable to get k,v %p,%p", k, v); Py_DECREF(env_list); PyErr_Clear(); return -1; diff -Nru clearsilver-0.10.4/python/setup.py clearsilver-0.10.5/python/setup.py --- clearsilver-0.10.4/python/setup.py 2006-11-14 22:54:32.000000000 -0800 +++ clearsilver-0.10.5/python/setup.py 2007-07-11 19:43:33.000000000 -0700 @@ -13,7 +13,7 @@ from distutils.core import Extension from distutils import sysconfig -VERSION = "0.10.4" +VERSION = "0.10.5" INC_DIRS = ["../"] LIBRARIES = ["neo_cgi", "neo_cs", "neo_utl"] LIB_DIRS = ["../libs"] @@ -31,7 +31,7 @@ if not os.path.exists("../rules.mk"): raise "You need to run configure first to generate the rules.mk file!" -make_vars = {} +make_vars = { 'NEOTONIC_ROOT' : '..' } rules = open("../rules.mk").read() for line in string.split(rules, "\n"): parts = string.split(line, '=', 1) @@ -78,7 +78,11 @@ if var[:2] == "$(" and var[-1] == ")": var = variables.get(var[2:-1], "") return var - return re.sub('(\$\([^\)]*\))', replace_var, var) + while 1: + new_var = re.sub('(\$\([^\)]*\))', replace_var, var) + if new_var == var: break + var = new_var + return var.strip() def expand_vars(vlist, vars): nlist = [] diff -Nru clearsilver-0.10.4/ruby/ext/hdf/neo_cs.c clearsilver-0.10.5/ruby/ext/hdf/neo_cs.c --- clearsilver-0.10.4/ruby/ext/hdf/neo_cs.c 2005-06-30 11:51:57.000000000 -0700 +++ clearsilver-0.10.5/ruby/ext/hdf/neo_cs.c 2007-02-15 16:31:39.000000000 -0800 @@ -11,6 +11,7 @@ #include #include "ClearSilver.h" +#include "neo_ruby.h" static VALUE cCs; extern VALUE mNeotonic; @@ -33,14 +34,14 @@ VALUE c_new (VALUE class, VALUE oHdf) { CSPARSE *cs = NULL; NEOERR *err; - HDF *hdf; + t_hdfh *hdfh; VALUE r_cs; - Data_Get_Struct(oHdf, HDF, hdf); + Data_Get_Struct(oHdf, t_hdfh, hdfh); - if (hdf == NULL) rb_raise(eHdfError, "must include an Hdf object"); + if (hdfh == NULL) rb_raise(eHdfError, "must include an Hdf object"); - err = cs_init (&cs, hdf); + err = cs_init (&cs, hdfh->hdf); if (err) Srb_raise(r_neo_error(err)); err = cgi_register_strfuncs(cs); if (err) Srb_raise(r_neo_error(err)); @@ -69,7 +70,7 @@ CSPARSE *cs = NULL; NEOERR *err; char *s, *ms; - int l; + long l; Data_Get_Struct(self, CSPARSE, cs); s = rb_str2cstr(oString, &l); @@ -78,7 +79,7 @@ ms = strdup(s); if (ms == NULL) rb_raise(rb_eNoMemError, "out of memory"); - err = cs_parse_string (cs, ms, l); + err = cs_parse_string (cs, ms, (size_t)l); if (err) Srb_raise(r_neo_error(err)); diff -Nru clearsilver-0.10.4/ruby/ext/hdf/neo_ruby.h clearsilver-0.10.5/ruby/ext/hdf/neo_ruby.h --- clearsilver-0.10.4/ruby/ext/hdf/neo_ruby.h 1969-12-31 16:00:00.000000000 -0800 +++ clearsilver-0.10.5/ruby/ext/hdf/neo_ruby.h 2007-02-15 16:31:39.000000000 -0800 @@ -0,0 +1,11 @@ + +#ifndef __NEO_RUBY_H_ +#define __NEO_RUBY_H_ + +typedef struct s_hdfh { + HDF *hdf; + struct s_hdfh *parent; + VALUE top; +} t_hdfh; + +#endif diff -Nru clearsilver-0.10.4/ruby/ext/hdf/neo_util.c clearsilver-0.10.5/ruby/ext/hdf/neo_util.c --- clearsilver-0.10.4/ruby/ext/hdf/neo_util.c 2005-06-30 11:51:57.000000000 -0700 +++ clearsilver-0.10.5/ruby/ext/hdf/neo_util.c 2007-02-15 16:32:03.000000000 -0800 @@ -12,10 +12,12 @@ #include #include #include "ClearSilver.h" +#include "neo_ruby.h" VALUE mNeotonic; static VALUE cHdf; VALUE eHdfError; +static ID id_to_s; #define Srb_raise(val) rb_raise(eHdfError, "%s/%d %s",__FILE__,__LINE__,RSTRING(val)->ptr) @@ -37,10 +39,31 @@ return errstr; } -static void h_free(void *p) { - hdf_destroy(p); +static void h_free2(t_hdfh *hdfh) { +#ifdef DEBUG + fprintf(stderr,"freeing hdf 0x%x\n",hdfh); +#endif + hdf_destroy(&(hdfh->hdf)); + free(hdfh); +} +static void h_free(t_hdfh *hdfh) { +#ifdef DEBUG + fprintf(stderr,"freeing hdf holder 0x%x of 0x%x\n",hdfh,hdfh->parent); +#endif + free(hdfh); +} +static void h_mark(t_hdfh *hdfh) { + /* Only mark the array if this is the top node, only the original node should + set up the marker. + */ +#ifdef DEBUG + fprintf(stderr,"marking 0x%x\n",hdfh); +#endif + if ( ! NIL_P(hdfh->top) ) + rb_gc_mark(hdfh->top); + else + fprintf(stderr,"mark top 0x%x\n",hdfh); } - static VALUE h_init (VALUE self) { @@ -49,32 +72,35 @@ VALUE h_new(VALUE class) { - HDF *hdf = NULL; + t_hdfh *hdfh; NEOERR *err; - VALUE r_hdf; + VALUE obj; - err = hdf_init (&hdf); + obj=Data_Make_Struct(class,t_hdfh,0,h_free2,hdfh); + err = hdf_init (&(hdfh->hdf)); if (err) Srb_raise(r_neo_error(err)); - - r_hdf = Data_Wrap_Struct(class, 0, h_free, hdf); - rb_obj_call_init(r_hdf, 0, NULL); - return r_hdf; +#ifdef DEBUG + fprintf(stderr,"allocated 0x%x\n",(void *)hdfh); +#endif + hdfh->top=Qnil; + rb_obj_call_init(obj, 0, NULL); + return obj; } static VALUE h_get_attr (VALUE self, VALUE oName) { - HDF *hdf = NULL; + t_hdfh *hdfh; char *name; HDF_ATTR *attr; VALUE k,v; VALUE rv; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); name = STR2CSTR(oName); rv = rb_hash_new(); - attr = hdf_get_attr(hdf, name); + attr = hdf_get_attr(hdfh->hdf, name); while ( attr != NULL ) { k=rb_str_new2(attr->key); v=rb_str_new2(attr->value); @@ -86,11 +112,11 @@ static VALUE h_set_attr(VALUE self, VALUE oName, VALUE oKey, VALUE oValue) { - HDF *hdf= NULL; + t_hdfh *hdfh; char *name, *key, *value; NEOERR *err; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); name = STR2CSTR(oName); key = STR2CSTR(oKey); @@ -99,7 +125,7 @@ else value = STR2CSTR(oValue); - err = hdf_set_attr(hdf, name, key, value); + err = hdf_set_attr(hdfh->hdf, name, key, value); if (err) Srb_raise(r_neo_error(err)); return self; @@ -107,16 +133,23 @@ static VALUE h_set_value (VALUE self, VALUE oName, VALUE oValue) { - HDF *hdf = NULL; + t_hdfh *hdfh; char *name, *value; NEOERR *err; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); - name=STR2CSTR(oName); - value=STR2CSTR(oValue); + if ( TYPE(oName) == T_STRING ) + name=STR2CSTR(oName); + else + name=STR2CSTR(rb_funcall(oName,id_to_s,0)); + + if ( TYPE(oValue) == T_STRING ) + value=STR2CSTR(oValue); + else + value=STR2CSTR(rb_funcall(oValue,id_to_s,0)); - err = hdf_set_value (hdf, name, value); + err = hdf_set_value (hdfh->hdf, name, value); if (err) Srb_raise(r_neo_error(err)); @@ -125,116 +158,178 @@ static VALUE h_get_int_value (VALUE self, VALUE oName, VALUE oDefault) { - HDF *hdf = NULL; + t_hdfh *hdfh; char *name; int r, d = 0; VALUE rv; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); + name=STR2CSTR(oName); d=NUM2INT(oDefault); - r = hdf_get_int_value (hdf, name, d); + r = hdf_get_int_value (hdfh->hdf, name, d); rv = INT2NUM(r); return rv; } static VALUE h_get_value (VALUE self, VALUE oName, VALUE oDefault) { - HDF *hdf = NULL; + t_hdfh *hdfh; char *name; char *r, *d = NULL; VALUE rv; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); name=STR2CSTR(oName); d=STR2CSTR(oDefault); - r = hdf_get_value (hdf, name, d); + r = hdf_get_value (hdfh->hdf, name, d); rv = rb_str_new2(r); return rv; } static VALUE h_get_child (VALUE self, VALUE oName) { - HDF *hdf = NULL; + t_hdfh *hdfh,*hdfh_new; + HDF *r; + VALUE rv; + char *name; + + Data_Get_Struct(self, t_hdfh, hdfh); + name=STR2CSTR(oName); + + r = hdf_get_child (hdfh->hdf, name); + if (r == NULL) { + return Qnil; + } + rv=Data_Make_Struct(cHdf,t_hdfh,h_mark,h_free,hdfh_new); + hdfh_new->top=self; + hdfh_new->hdf=r; + hdfh_new->parent=hdfh; + + return rv; +} + +static VALUE h_get_obj (VALUE self, VALUE oName) +{ + t_hdfh *hdfh,*hdfh_new; HDF *r; VALUE rv; char *name; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); name=STR2CSTR(oName); - r = hdf_get_child (hdf, name); + r = hdf_get_obj (hdfh->hdf, name); if (r == NULL) { return Qnil; } - rv = Data_Wrap_Struct(cHdf, 0, h_free, r); + rv=Data_Make_Struct(cHdf,t_hdfh,h_mark,h_free,hdfh_new); + hdfh_new->top=self; + hdfh_new->hdf=r; + hdfh_new->parent=hdfh; + + return rv; +} + +static VALUE h_get_node (VALUE self, VALUE oName) +{ + t_hdfh *hdfh,*hdfh_new; + HDF *r; + VALUE rv; + char *name; + NEOERR *err; + + Data_Get_Struct(self, t_hdfh, hdfh); + name=STR2CSTR(oName); + + err = hdf_get_node (hdfh->hdf, name, &r); + if (err) + Srb_raise(r_neo_error(err)); + + rv=Data_Make_Struct(cHdf,t_hdfh,h_mark,h_free,hdfh_new); + hdfh_new->top=self; + hdfh_new->hdf=r; + hdfh_new->parent=hdfh; + return rv; } static VALUE h_obj_child (VALUE self) { - HDF *hdf = NULL; + t_hdfh *hdfh,*hdfh_new; HDF *r = NULL; VALUE rv; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); - r = hdf_obj_child (hdf); + r = hdf_obj_child (hdfh->hdf); if (r == NULL) { return Qnil; } - rv = Data_Wrap_Struct(cHdf, 0, h_free, r); + rv=Data_Make_Struct(cHdf,t_hdfh,h_mark,h_free,hdfh_new); + hdfh_new->top=self; + hdfh_new->hdf=r; + hdfh_new->parent=hdfh; + return rv; } static VALUE h_obj_next (VALUE self) { - HDF *hdf = NULL; + t_hdfh *hdfh,*hdfh_new; HDF *r = NULL; VALUE rv; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); - r = hdf_obj_next (hdf); + r = hdf_obj_next (hdfh->hdf); if (r == NULL) { return Qnil; } - rv = Data_Wrap_Struct(cHdf, 0, h_free, r); + rv=Data_Make_Struct(cHdf,t_hdfh,h_mark,h_free,hdfh_new); + hdfh_new->top=self; + hdfh_new->hdf=r; + hdfh_new->parent=hdfh; + return rv; } static VALUE h_obj_top (VALUE self) { - HDF *hdf = NULL; + t_hdfh *hdfh,*hdfh_new; HDF *r = NULL; VALUE rv; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); - r = hdf_obj_top (hdf); + r = hdf_obj_top (hdfh->hdf); if (r == NULL) { return Qnil; } - rv = Data_Wrap_Struct(cHdf, 0, h_free, r); + rv=Data_Make_Struct(cHdf,t_hdfh,h_mark,h_free,hdfh_new); + hdfh_new->top=self; + hdfh_new->hdf=r; + hdfh_new->parent=hdfh; + return rv; } static VALUE h_obj_name (VALUE self) { - HDF *hdf = NULL; + t_hdfh *hdfh; VALUE rv; char *r; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); - r = hdf_obj_name (hdf); + r = hdf_obj_name (hdfh->hdf); if (r == NULL) { return Qnil; } @@ -245,15 +340,15 @@ static VALUE h_obj_attr (VALUE self) { - HDF *hdf = NULL; + t_hdfh *hdfh; HDF_ATTR *attr; VALUE k,v; VALUE rv; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); rv = rb_hash_new(); - attr = hdf_obj_attr(hdf); + attr = hdf_obj_attr(hdfh->hdf); while ( attr != NULL ) { k=rb_str_new2(attr->key); v=rb_str_new2(attr->value); @@ -266,13 +361,13 @@ static VALUE h_obj_value (VALUE self) { - HDF *hdf = NULL; + t_hdfh *hdfh; VALUE rv; char *r; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); - r = hdf_obj_value (hdf); + r = hdf_obj_value (hdfh->hdf); if (r == NULL) { return Qnil; } @@ -283,15 +378,15 @@ static VALUE h_read_file (VALUE self, VALUE oPath) { - HDF *hdf = NULL; + t_hdfh *hdfh; char *path; NEOERR *err; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); path=STR2CSTR(oPath); - err = hdf_read_file (hdf, path); + err = hdf_read_file (hdfh->hdf, path); if (err) Srb_raise(r_neo_error(err)); return self; @@ -299,15 +394,15 @@ static VALUE h_write_file (VALUE self, VALUE oPath) { - HDF *hdf = NULL; + t_hdfh *hdfh; char *path; NEOERR *err; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); path=STR2CSTR(oPath); - err = hdf_write_file (hdf, path); + err = hdf_write_file (hdfh->hdf, path); if (err) Srb_raise(r_neo_error(err)); @@ -316,15 +411,15 @@ static VALUE h_write_file_atomic (VALUE self, VALUE oPath) { - HDF *hdf = NULL; + t_hdfh *hdfh; char *path; NEOERR *err; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); path=STR2CSTR(oPath); - err = hdf_write_file_atomic (hdf, path); + err = hdf_write_file_atomic (hdfh->hdf, path); if (err) Srb_raise(r_neo_error(err)); return self; @@ -332,14 +427,14 @@ static VALUE h_remove_tree (VALUE self, VALUE oName) { - HDF *hdf = NULL; + t_hdfh *hdfh; char *name; NEOERR *err; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); name = STR2CSTR(oName); - err = hdf_remove_tree (hdf, name); + err = hdf_remove_tree (hdfh->hdf, name); if (err) Srb_raise(r_neo_error(err)); return self; @@ -347,18 +442,21 @@ static VALUE h_dump (VALUE self) { - HDF *hdf = NULL; + t_hdfh *hdfh; VALUE rv; NEOERR *err; STRING str; string_init (&str); - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); - err = hdf_dump_str (hdf, NULL, 0, &str); + err = hdf_dump_str (hdfh->hdf, NULL, 0, &str); if (err) Srb_raise(r_neo_error(err)); + if (str.len==0) + return Qnil; + rv = rb_str_new2(str.buf); string_clear (&str); return rv; @@ -366,14 +464,14 @@ static VALUE h_write_string (VALUE self) { - HDF *hdf = NULL; + t_hdfh *hdfh; VALUE rv; NEOERR *err; char *s = NULL; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); - err = hdf_write_string (hdf, &s); + err = hdf_write_string (hdfh->hdf, &s); if (err) Srb_raise(r_neo_error(err)); @@ -384,17 +482,17 @@ static VALUE h_read_string (VALUE self, VALUE oString, VALUE oIgnore) { - HDF *hdf = NULL; + t_hdfh *hdfh; NEOERR *err; char *s = NULL; int ignore = 0; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); s = STR2CSTR(oString); ignore = NUM2INT(oIgnore); - err = hdf_read_string_ignore (hdf, s, ignore); + err = hdf_read_string_ignore (hdfh->hdf, s, ignore); if (err) Srb_raise(r_neo_error(err)); @@ -403,19 +501,18 @@ static VALUE h_copy (VALUE self, VALUE oName, VALUE oHdfSrc) { - HDF *hdf = NULL; - HDF *src = NULL; + t_hdfh *hdfh, *hdfh_src; char *name; NEOERR *err; - Data_Get_Struct(self, HDF, hdf); - Data_Get_Struct(oHdfSrc, HDF, src); + Data_Get_Struct(self, t_hdfh, hdfh); + Data_Get_Struct(oHdfSrc, t_hdfh, hdfh_src); name = STR2CSTR(oName); - if (src == NULL) rb_raise(eHdfError, "second argument must be an Hdf object"); + if (hdfh_src == NULL) rb_raise(eHdfError, "second argument must be an Hdf object"); - err = hdf_copy (hdf, name, src); + err = hdf_copy (hdfh->hdf, name, hdfh_src->hdf); if (err) Srb_raise(r_neo_error(err)); return self; @@ -423,16 +520,16 @@ static VALUE h_set_symlink (VALUE self, VALUE oSrc, VALUE oDest) { - HDF *hdf = NULL; + t_hdfh *hdfh; char *src; char *dest; NEOERR *err; - Data_Get_Struct(self, HDF, hdf); + Data_Get_Struct(self, t_hdfh, hdfh); src = STR2CSTR(oSrc); dest = STR2CSTR(oDest); - err = hdf_set_symlink (hdf, src, dest); + err = hdf_set_symlink (hdfh->hdf, src, dest); if (err) Srb_raise(r_neo_error(err)); return self; @@ -452,7 +549,7 @@ esc_char = STR2CSTR(oEsc_char); escape = STR2CSTR(oEsc); - err = neos_escape(s, buflen, esc_char[0], escape, &ret); + err = neos_escape((UINT8*)s, buflen, esc_char[0], escape, &ret); if (err) Srb_raise(r_neo_error(err)); @@ -476,7 +573,7 @@ copy = strdup(s); if (copy == NULL) rb_raise(rb_eNoMemError, "out of memory"); - neos_unescape(copy, buflen, esc_char[0]); + neos_unescape((UINT8*)copy, buflen, esc_char[0]); rv = rb_str_new2(copy); free(copy); @@ -486,6 +583,9 @@ void Init_cs(); void Init_hdf() { + + id_to_s=rb_intern("to_s"); + mNeotonic = rb_define_module("Neo"); cHdf = rb_define_class_under(mNeotonic, "Hdf", rb_cObject); @@ -494,9 +594,12 @@ rb_define_method(cHdf, "get_attr", h_get_attr, 1); rb_define_method(cHdf, "set_attr", h_set_attr, 3); rb_define_method(cHdf, "set_value", h_set_value, 2); + rb_define_method(cHdf, "put", h_set_value, 2); rb_define_method(cHdf, "get_int_value", h_get_int_value, 2); rb_define_method(cHdf, "get_value", h_get_value, 2); rb_define_method(cHdf, "get_child", h_get_child, 1); + rb_define_method(cHdf, "get_obj", h_get_obj, 1); + rb_define_method(cHdf, "get_node", h_get_node, 1); rb_define_method(cHdf, "obj_child", h_obj_child, 0); rb_define_method(cHdf, "obj_next", h_obj_next, 0); rb_define_method(cHdf, "obj_top", h_obj_top, 0); diff -Nru clearsilver-0.10.4/rules.mk.in clearsilver-0.10.5/rules.mk.in --- clearsilver-0.10.4/rules.mk.in 2005-12-02 03:25:19.000000000 -0800 +++ clearsilver-0.10.5/rules.mk.in 2006-12-18 20:39:58.000000000 -0800 @@ -105,6 +105,10 @@ ifeq ($(OSNAME),SunOS) LDSHARED = ld -G -fPIC endif +ifeq ($(OSTYPE),Darwin) +LDSHARED = $(CC) -bundle -flat_namespace -undefined suppress $(PICFLG) +CPPLDSHARED = $(CPP) -bundle -flat_namespace -undefined suppress $(PICFLG) +endif ## --------------win32 options diff -Nru clearsilver-0.10.4/scripts/document.py clearsilver-0.10.5/scripts/document.py --- clearsilver-0.10.4/scripts/document.py 2005-07-27 17:53:10.000000000 -0700 +++ clearsilver-0.10.5/scripts/document.py 2007-07-12 13:07:05.000000000 -0700 @@ -1,4 +1,4 @@ -#!/bin/env python +#!/usr/bin/env python """ document.py -- Simple script to generate manpages from C header files. Looks for the following formatted C comments in the C header files: diff -Nru clearsilver-0.10.4/util/neo_err.h clearsilver-0.10.5/util/neo_err.h --- clearsilver-0.10.4/util/neo_err.h 2005-12-15 14:17:36.000000000 -0800 +++ clearsilver-0.10.5/util/neo_err.h 2007-07-11 20:09:09.000000000 -0700 @@ -12,6 +12,8 @@ #ifndef __NEO_ERR_H_ #define __NEO_ERR_H_ 1 +#include "util/neo_misc.h" + /* For compilers (well, cpp actually) which don't define __PRETTY_FUNCTION__ */ #ifndef __GNUC__ #define __PRETTY_FUNCTION__ "unknown_function" @@ -58,6 +60,16 @@ struct _neo_err *next; } NEOERR; +/* Technically, we could do this in configure and detect what their compiler + * can handle, but for now... */ +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define USE_C99_VARARG_MACROS 1 +#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 4) || defined (S_SPLINT_S) +#define USE_GNUC_VARARG_MACROS 1 +#else +#error The compiler is missing support for variable-argument macros. +#endif + /* * function: nerr_raise @@ -65,34 +77,38 @@ * return up the call chain * arguments: using the macro, the function name, file, and lineno are * automagically recorded for you. You just provide the - * error (from those listed above) and the printf-style + * error (from those listed above) and the printf-style * reason. THIS IS A PRINTF STYLE FUNCTION, DO NOT PASS * UNKNOWN STRING DATA AS THE FORMAT STRING. * returns: a pointer to a NEOERR, or INTERNAL_ERR if allocation of * NEOERR fails */ -#ifdef __GNUC__ -#define nerr_raise(e,f,a...) \ - nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a) -#else +#if defined(USE_C99_VARARG_MACROS) #define nerr_raise(e,f,...) \ nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__) +#elif defined(USE_GNUC_VARARG_MACROS) +#define nerr_raise(e,f,a...) \ + nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a) #endif -NEOERR *nerr_raisef (const char *func, const char *file, int lineno, - NERR_TYPE error, const char *fmt, ...); +NEOERR *nerr_raisef (const char *func, const char *file, int lineno, + NERR_TYPE error, const char *fmt, ...) + ATTRIBUTE_PRINTF(5,6); + -#ifdef __GNUC__ -#define nerr_raise_errno(e,f,a...) \ - nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a) -#else +#if defined(USE_C99_VARARG_MACROS) #define nerr_raise_errno(e,f,...) \ nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__) +#elif defined(USE_GNUC_VARARG_MACROS) +#define nerr_raise_errno(e,f,a...) \ + nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a) #endif -NEOERR *nerr_raise_errnof (const char *func, const char *file, int lineno, - int error, const char *fmt, ...); +NEOERR *nerr_raise_errnof (const char *func, const char *file, int lineno, + int error, const char *fmt, ...) + ATTRIBUTE_PRINTF(5,6); + /* function: nerr_pass * description: this function is used to pass an error up a level in the * call chain (ie, if the error isn't handled at the @@ -104,7 +120,8 @@ */ #define nerr_pass(e) \ nerr_passf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e) -NEOERR *nerr_passf (const char *func, const char *file, int lineno, + +NEOERR *nerr_passf (const char *func, const char *file, int lineno, NEOERR *err); /* function: nerr_pass_ctx @@ -115,20 +132,22 @@ * This version includes context information about lower * errors * arguments: with the macro, the function name, file and lineno are - * automagically recorded. Just pass the error and + * automagically recorded. Just pass the error and * a printf format string giving more information about where * the error is occuring. * returns: a pointer to an error */ -#ifdef __GNUC__ -#define nerr_pass_ctx(e,f,a...) \ - nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a) -#else +#if defined(USE_C99_VARARG_MACROS) #define nerr_pass_ctx(e,f,...) \ nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__) +#elif defined(USE_GNUC_VARARG_MACROS) +#define nerr_pass_ctx(e,f,a...) \ + nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a) #endif -NEOERR *nerr_pass_ctxf (const char *func, const char *file, int lineno, NEOERR *err, - const char *fmt, ...); + +NEOERR *nerr_pass_ctxf (const char *func, const char *file, int lineno, + NEOERR *err, const char *fmt, ...) + ATTRIBUTE_PRINTF(5,6); /* function: nerr_log_error * description: currently, this prints out the error to stderr, and @@ -164,7 +183,7 @@ * description: register an error type. This will assign a numeric value * to the type, and keep track of the "pretty name" for it. * arguments: err - pointer to a NERR_TYPE - * name - pretty name for the error type + * name - pretty name for the error type * returns: NERR_NOMEM on no memory */ NEOERR *nerr_register (NERR_TYPE *err, const char *name); @@ -186,7 +205,7 @@ * parlance, this would be the equivalent of "catch". * Typically, you can just compare a NEOERR against STATUS_OK * or just test for true if you are checking for any error. - * arguments: err - the NEOERR that has an error. + * arguments: err - the NEOERR that has an error. * type - the NEOERR type, as registered with nerr_register * returns: true on match */ @@ -196,7 +215,7 @@ * description: nerr_handle is a convenience function. It is the equivalent * of nerr_match, but it will also deallocate the error chain * on a match. - * arguments: err - pointer to a pointer NEOERR + * arguments: err - pointer to a pointer NEOERR * type - the NEOERR type, as registered with nerr_register * returns: true on match */ diff -Nru clearsilver-0.10.4/util/neo_files.c clearsilver-0.10.5/util/neo_files.c --- clearsilver-0.10.4/util/neo_files.c 2005-06-30 17:41:29.000000000 -0700 +++ clearsilver-0.10.5/util/neo_files.c 2007-07-11 19:14:23.000000000 -0700 @@ -92,7 +92,7 @@ { close(fd); return nerr_raise (NERR_NOMEM, - "Unable to allocate memory (%d) to load file %s", s.st_size, path); + "Unable to allocate memory (%d) to load file %s", len + 1, path); } if ((bytes_read = read (fd, *str, len)) == -1) { diff -Nru clearsilver-0.10.4/util/neo_hdf.c clearsilver-0.10.5/util/neo_hdf.c --- clearsilver-0.10.4/util/neo_hdf.c 2006-08-11 16:47:01.000000000 -0700 +++ clearsilver-0.10.5/util/neo_hdf.c 2007-07-11 18:52:37.000000000 -0700 @@ -640,7 +640,24 @@ return nerr_raise(NERR_ASSERT, "Unable to set Empty component %s", name); } - hn = hdf; + if (hdf->link) + { + char *new_name = (char *) malloc(strlen(hdf->value) + 1 + strlen(name) + 1); + if (new_name == NULL) + { + return nerr_raise(NERR_NOMEM, "Unable to allocate memory"); + } + strcpy(new_name, hdf->value); + strcat(new_name, "."); + strcat(new_name, name); + err = _set_value (hdf->top, new_name, value, dup, wf, link, attr, set_node); + free(new_name); + return nerr_pass(err); + } + else + { + hn = hdf; + } while (1) { @@ -779,7 +796,7 @@ } strcpy(new_name, hp->value); strcat(new_name, s); - err = _set_value (hdf, new_name, value, dup, wf, link, attr, set_node); + err = _set_value (hdf->top, new_name, value, dup, wf, link, attr, set_node); free(new_name); return nerr_pass(err); } diff -Nru clearsilver-0.10.4/util/neo_hdf.h clearsilver-0.10.5/util/neo_hdf.h --- clearsilver-0.10.4/util/neo_hdf.h 2006-04-06 15:05:43.000000000 -0700 +++ clearsilver-0.10.5/util/neo_hdf.h 2007-07-11 19:32:52.000000000 -0700 @@ -155,13 +155,14 @@ * default value possible. * Input: hdf -> the dataset node to start from * namefmt -> the printf-style format string - * ... -> arguments to fill out namefmt + * ... -> arguments to fill out namefmt * Output: None * Returns: A pointer to the string stored in the data set, or NULL. * The data set maintains ownership of the string, if you want * a copy you either have to call strdup yourself. */ -char* hdf_get_valuef (HDF *hdf, const char *namefmt, ...); +char* hdf_get_valuef (HDF *hdf, const char *namefmt, ...) + ATTRIBUTE_PRINTF(2,3); /* * Function: hdf_get_copy - Returns a copy of a string in the HDF data set @@ -173,9 +174,9 @@ * exist * Output: value -> the allocated string (if defval = NULL, then value * will be NULL if defval is used) - * Returns: NERR_NOMEM if unable to allocate the new copy + * Returns: NERR_NOMEM if unable to allocate the new copy */ -NEOERR* hdf_get_copy (HDF *hdf, const char *name, char **value, +NEOERR* hdf_get_copy (HDF *hdf, const char *name, char **value, const char *defval); /* @@ -231,7 +232,7 @@ * Output: * Returns: */ -NEOERR* hdf_set_attr (HDF *hdf, const char *name, const char *key, +NEOERR* hdf_set_attr (HDF *hdf, const char *name, const char *key, const char *value); /* @@ -344,8 +345,9 @@ * Output: None * Returns: NERR_NOMEM */ -NEOERR* hdf_set_valuef (HDF *hdf, const char *fmt, ...); -NEOERR* hdf_set_valuevf (HDF *hdf, const char *fmt, va_list ap); +NEOERR* hdf_set_valuef (HDF *hdf, const char *fmt, ...) + ATTRIBUTE_PRINTF(2,3); +NEOERR* hdf_set_valuevf (HDF *hdf, const char *fmt, va_list ap); /* * Function: hdf_set_int_value - Set the value of a named node to a number @@ -405,7 +407,7 @@ * structure directly will bypass the symlink. Use this * feature sparingly as its likely to surprise you. * Input: hdf -> the dataset node - * src -> the source node name + * src -> the source node name * dest -> the destination node name (from the top of the * dataset, not relative names) * Output: None @@ -414,7 +416,7 @@ NEOERR *hdf_set_symlink (HDF *hdf, const char *src, const char *dest); /* - * Function: hdf_sort_obj - sort the children of an HDF node + * Function: hdf_sort_obj - sort the children of an HDF node * Description: hdf_sort_obj will sort the children of an HDF node, * based on the given comparison function. * This function works by creating an array of the pointers @@ -425,7 +427,7 @@ * a pointer to an HDF struct, so your comparison function * should work on HDF ** pointers. * Input: h - HDF node - * compareFunc - function which returns 1,0,-1 depending on some + * compareFunc - function which returns 1,0,-1 depending on some * criteria. The arguments to this sort function * are pointers to pointers to HDF elements. For * example: @@ -437,7 +439,7 @@ * } * * Output: None (h children will be sorted) - * Return: NERR_NOMEM + * Return: NERR_NOMEM */ NEOERR *hdf_sort_obj(HDF *h, int (*compareFunc)(const void *, const void *)); @@ -563,10 +565,10 @@ /* * Function: hdf_register_fileload - register a fileload function - * Description: hdf_register_fileload registers a fileload function that + * Description: hdf_register_fileload registers a fileload function that * overrides the built-in function. The built-in function * uses hdf_search_path and ne_file_load (based on stat/open/read) - * to find and load the file on every hdf_read_file (including + * to find and load the file on every hdf_read_file (including * #include). You can override this function if you wish to provide * other file search functions, or load the hdf file * from an in-memory cache, etc. diff -Nru clearsilver-0.10.4/util/neo_misc.h clearsilver-0.10.5/util/neo_misc.h --- clearsilver-0.10.4/util/neo_misc.h 2005-12-05 20:19:36.000000000 -0800 +++ clearsilver-0.10.5/util/neo_misc.h 2007-07-11 19:36:32.000000000 -0700 @@ -16,12 +16,12 @@ #include #include -/* In case they didn't start from ClearSilver.h... */ +/* In case they didn't start from ClearSilver.h. */ #ifndef __CS_CONFIG_H_ #include "cs_config.h" #endif -/* Fix Up for systems that don't define these standard things... */ +/* Fix Up for systems that don't define these standard things */ #ifndef __BEGIN_DECLS #ifdef __cplusplus #define __BEGIN_DECLS extern "C" { @@ -55,6 +55,15 @@ #define S_IROTH S_IRUSR #endif +/* Format string checking for compilers that support it (GCC style) */ + +#if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ > 6 +#define ATTRIBUTE_PRINTF(a1,a2) __attribute__((__format__ (__printf__, a1, a2))) +#else +#define ATTRIBUTE_PRINTF(a1,a2) +#endif + + __BEGIN_DECLS #ifndef HAVE_STRTOK_R @@ -74,7 +83,8 @@ #endif #ifndef HAVE_SNPRINTF -int snprintf (char *str, size_t count, const char *fmt, ...); +int snprintf (char *str, size_t count, const char *fmt, ...) + ATTRIBUTE_PRINTF(3,4); #endif #ifndef HAVE_VSNPRINTF @@ -104,9 +114,11 @@ #endif void ne_vwarn (const char *fmt, va_list ap); -void ne_warn (const char *fmt, ...); +void ne_warn (const char *fmt, ...) + ATTRIBUTE_PRINTF(1,2); void ne_set_log (int level); -void ne_log (int level, const char *fmt, ...); +void ne_log (int level, const char *fmt, ...) + ATTRIBUTE_PRINTF(2,3); UINT32 python_string_hash (const char *s); UINT8 *ne_stream4 (UINT8 *dest, UINT32 num); UINT8 *ne_unstream4 (UINT32 *pnum, UINT8 *src); diff -Nru clearsilver-0.10.4/util/neo_str.c clearsilver-0.10.5/util/neo_str.c --- clearsilver-0.10.4/util/neo_str.c 2006-08-07 13:01:53.000000000 -0700 +++ clearsilver-0.10.5/util/neo_str.c 2007-07-11 18:24:00.000000000 -0700 @@ -801,6 +801,69 @@ return STATUS_OK; } +char *URL_PROTOCOLS[] = {"http://", "https://", "ftp://", "mailto:"}; + +NEOERR *neos_url_validate (const char *in, char **esc) +{ + NEOERR *err = STATUS_OK; + STRING out_s; + int valid = 0; + size_t i; + size_t inlen; + int num_protocols = sizeof(URL_PROTOCOLS) / sizeof(char*); + void* slashpos; + void* colonpos; + + inlen = strlen(in); + + /* + * or are allowed by browsers + * and ":" is treated as part of the path, while + * is an invalid url + * and ":" is treated as a scheme separator. + * + * Hence allow for ":" in the path part of a url (after /) + */ + slashpos = memchr(in, '/', inlen); + if (slashpos == NULL) { + i = inlen; + } + else { + i = (size_t)((char*)slashpos - in); + } + + colonpos = memchr(in, ':', i); + + if (colonpos == NULL) { + // no scheme in 'in': so this is a relative url + valid = 1; + } + else { + for (i = 0; i < num_protocols; i++) + { + if ((inlen >= strlen(URL_PROTOCOLS[i])) && + strncmp(in, URL_PROTOCOLS[i], strlen(URL_PROTOCOLS[i])) == 0) { + // 'in' starts with one of the allowed protocols + valid = 1; + break; + } + + } + } + + if (valid) + return neos_html_escape(in, inlen, esc); + + // 'in' contains an unsupported scheme, replace with '#' + string_init(&out_s); + err = string_append (&out_s, "#"); + if (err) return nerr_pass (err); + + *esc = out_s.buf; + return STATUS_OK; + +} + NEOERR *neos_var_escape (NEOS_ESCAPE context, const char *in, char **esc) diff -Nru clearsilver-0.10.4/util/neo_str.h clearsilver-0.10.5/util/neo_str.h --- clearsilver-0.10.4/util/neo_str.h 2006-08-07 13:01:53.000000000 -0700 +++ clearsilver-0.10.5/util/neo_str.h 2007-07-11 19:34:19.000000000 -0700 @@ -20,22 +20,22 @@ /* This modifies the string its called with by replacing all the white * space on the end with \0, and returns a pointer to the first - * non-white space character in the string + * non-white space character in the string */ char *neos_strip (char *s); void neos_lower (char *s); -char *sprintf_alloc (const char *fmt, ...); -char *nsprintf_alloc (int start_size, const char *fmt, ...); +char *sprintf_alloc (const char *fmt, ...) ATTRIBUTE_PRINTF(1,2); +char *nsprintf_alloc (int start_size, const char *fmt, ...) ATTRIBUTE_PRINTF(2,3); char *vsprintf_alloc (const char *fmt, va_list ap); char *vnsprintf_alloc (int start_size, const char *fmt, va_list ap); -/* Versions of the above which actually return a length, necessary if +/* Versions of the above which actually return a length, necessary if * you expect embedded NULLs */ int vnisprintf_alloc (char **buf, int start_size, const char *fmt, va_list ap); int visprintf_alloc (char **buf, const char *fmt, va_list ap); -int isprintf_alloc (char **buf, const char *fmt, ...); +int isprintf_alloc (char **buf, const char *fmt, ...) ATTRIBUTE_PRINTF(2,3); typedef struct _string { @@ -59,7 +59,7 @@ NEOERR *string_append (STRING *str, const char *buf); NEOERR *string_appendn (STRING *str, const char *buf, int l); NEOERR *string_append_char (STRING *str, char c); -NEOERR *string_appendf (STRING *str, const char *fmt, ...); +NEOERR *string_appendf (STRING *str, const char *fmt, ...) ATTRIBUTE_PRINTF(2,3); NEOERR *string_appendvf (STRING *str, const char *fmt, va_list ap); NEOERR *string_readline (STRING *str, FILE *fp); void string_clear (STRING *str); @@ -68,7 +68,7 @@ #include "util/ulist.h" /* s is not const because we actually temporarily modify the string * during split */ -NEOERR *string_array_split (ULIST **list, char *s, const char *sep, +NEOERR *string_array_split (ULIST **list, char *s, const char *sep, int max); BOOL reg_search (const char *re, const char *str); @@ -85,7 +85,7 @@ NEOS_ESCAPE_FUNCTION = 1<<4 /* Special case used to override the others */ } NEOS_ESCAPE; -NEOERR* neos_escape(UINT8 *buf, int buflen, char esc_char, const char *escape, +NEOERR* neos_escape(UINT8 *buf, int buflen, char esc_char, const char *escape, char **esc); UINT8 *neos_unescape (UINT8 *s, int buflen, char esc_char); @@ -107,6 +107,8 @@ NEOERR *neos_html_escape (const char *src, int slen, char **out); +NEOERR *neos_url_validate (const char *in, char **esc); + __END_DECLS #endif /* __NEO_STR_H_ */