diff -Nbru clearsilver-0.3/Makefile clearsilver-0.4/Makefile --- clearsilver-0.3/Makefile Tue Aug 7 14:57:45 2001 +++ clearsilver-0.4/Makefile Fri Jan 11 15:45:44 2002 @@ -3,8 +3,6 @@ # # Copyright (C) 2001 Neotonic and Brandon Long # -# This file is licensed under the terms of the FSF's LGPL, or -# Library General Public License. # @@ -71,14 +69,22 @@ mkdir -p $$mdir; \ done -CS_DISTDIR = clearsilver-0.1 -CS_LABEL = CLEARSILVER-0_1 -CS_FILES = LICENSE CS_LICENSE rules.mk Makefile util cs cgi python scripts -cs_dist: distclean +CS_DISTDIR = clearsilver-0.3 +CS_LABEL = CLEARSILVER-0_3 +CS_FILES = LICENSE CS_LICENSE rules.mk Makefile util cs cgi python scripts mod_ecs +cs_dist: rm -rf $(CS_DISTDIR) cvs -q tag -F $(CS_LABEL) $(CS_FILES) mkdir -p $(CS_DISTDIR) cvs -z3 -q export -r $(CS_LABEL) -d $(CS_DISTDIR) neotonic $(MAKE) -C $(CS_DISTDIR) man - tar chozf clearsilver-0.1.tar.gz $(CS_DISTDIR) + tar chozf $(CS_DISTDIR).tar.gz $(CS_DISTDIR) +TRAKKEN_DISTDIR = trakken-0.55 +TRAKKEN_LABEL = TRAKKEN_0_55 +trakken_dist: + rm -rf $(TRAKKEN_DISTDIR) + cvs -q tag -F $(TRAKKEN_LABEL) + mkdir -p $(TRAKKEN_DISTDIR) + cvs -z3 -q export -r $(TRAKKEN_LABEL) -d $(TRAKKEN_DISTDIR) neotonic + tar chozf $(TRAKKEN_DISTDIR).tar.gz $(TRAKKEN_DISTDIR) diff -Nbru clearsilver-0.3/cgi/Makefile clearsilver-0.4/cgi/Makefile --- clearsilver-0.3/cgi/Makefile Sun Sep 9 16:53:10 2001 +++ clearsilver-0.4/cgi/Makefile Fri Jan 11 15:42:08 2002 @@ -13,12 +13,13 @@ STATIC_EXE = static.cgi STATIC_SRC = static.c STATIC_OBJ = $(STATIC_SRC:%.c=%.o) +STATIC_CSO = $(STATIC_EXE:%.cgi=%.cso) CFLAGS += -I$(NEOTONIC_ROOT) -DHTML_COMPRESSION DLIBS += -lneo_cgi -lneo_cs -lneo_utl # -lefence LIBS += -L$(LIB_DIR) $(DLIBS) -TARGETS = $(CGI_LIB) $(STATIC_EXE) +TARGETS = $(CGI_LIB) $(STATIC_EXE) $(STATIC_CSO) all: $(TARGETS) @@ -27,6 +28,9 @@ $(STATIC_EXE): $(STATIC_OBJ) $(DEP_LIBS) $(LD) $@ $(STATIC_OBJ) $(LIBS) + +$(STATIC_CSO): $(STATIC_OBJ) $(DEP_LIBS) + $(LDSHARED) -o $@ $(STATIC_OBJ) $(LIBS) clean: $(RM) *.o diff -Nbru clearsilver-0.3/cgi/cgiwrap.c clearsilver-0.4/cgi/cgiwrap.c --- clearsilver-0.3/cgi/cgiwrap.c Mon Aug 6 14:28:16 2001 +++ clearsilver-0.4/cgi/cgiwrap.c Fri Jan 11 15:42:08 2002 @@ -30,9 +30,10 @@ ITERENV_FUNC iterenv_cb; void *data; + int emu_init; } CGIWRAPPER; -static CGIWRAPPER GlobalWrapper; +static CGIWRAPPER GlobalWrapper = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0}; static void cgiwrap_init (void) { @@ -51,6 +52,9 @@ void cgiwrap_init_std (int argc, char **argv, char **envp) { + /* so you can compile the same code for embedded without mods */ + if (GlobalWrapper.emu_init) return; + cgiwrap_init(); GlobalWrapper.argc = argc; GlobalWrapper.argv = argv; @@ -70,6 +74,7 @@ GlobalWrapper.getenv_cb = getenv_cb; GlobalWrapper.putenv_cb = putenv_cb; GlobalWrapper.iterenv_cb = iterenv_cb; + GlobalWrapper.emu_init = 1; } NEOERR *cgiwrap_getenv (char *k, char **v) diff -Nbru clearsilver-0.3/cgi/html.c clearsilver-0.4/cgi/html.c --- clearsilver-0.3/cgi/html.c Fri Sep 14 18:23:03 2001 +++ clearsilver-0.4/cgi/html.c Tue Nov 6 16:23:01 2001 @@ -131,11 +131,21 @@ email_match.rm_so = -1; email_match.rm_eo = -1; } + else + { + email_match.rm_so += x; + email_match.rm_eo += x; + } if (regexec (&url_re, src+x, 1, &url_match, 0) != 0) { url_match.rm_so = -1; url_match.rm_eo = -1; } + else + { + url_match.rm_so += x; + url_match.rm_eo += x; + } while ((x < slen) && !((email_match.rm_so == -1) && (url_match.rm_so == -1))) { if (part >= part_count) @@ -145,8 +155,8 @@ } if ((url_match.rm_so != -1) && ((email_match.rm_so == -1) || (url_match.rm_so <= email_match.rm_so))) { - parts[part].begin = x + url_match.rm_so; - parts[part].end = x + url_match.rm_eo; + parts[part].begin = url_match.rm_so; + parts[part].end = url_match.rm_eo; parts[part].type = SC_TYPE_URL; x = parts[part].end + 1; part++; @@ -157,6 +167,11 @@ url_match.rm_so = -1; url_match.rm_eo = -1; } + else + { + url_match.rm_so += x; + url_match.rm_eo += x; + } if ((email_match.rm_so != -1) && (x > email_match.rm_so)) { if (regexec (&email_re, src+x, 1, &email_match, 0) != 0) @@ -164,13 +179,18 @@ email_match.rm_so = -1; email_match.rm_eo = -1; } + else + { + email_match.rm_so += x; + email_match.rm_eo += x; + } } } } else { - parts[part].begin = x + email_match.rm_so; - parts[part].end = x + email_match.rm_eo; + parts[part].begin = email_match.rm_so; + parts[part].end = email_match.rm_eo; parts[part].type = SC_TYPE_EMAIL; x = parts[part].end + 1; part++; @@ -181,6 +201,11 @@ email_match.rm_so = -1; email_match.rm_eo = -1; } + else + { + email_match.rm_so += x; + email_match.rm_eo += x; + } if ((url_match.rm_so != -1) && (x > url_match.rm_so)) { if (regexec (&url_re, src+x, 1, &url_match, 0) != 0) @@ -188,6 +213,11 @@ url_match.rm_so = -1; url_match.rm_eo = -1; } + else + { + url_match.rm_so += x; + url_match.rm_eo += x; + } } } } @@ -276,9 +306,9 @@ err = string_append (out, ">"); else if (src[x] == '\n') if (newlines) - err = string_append (out, "
"); + err = string_append (out, "
"); else if (x && src[x-1] == '\n') - err = string_append (out, "

"); + err = string_append (out, "

"); else err = string_append_char (out, '\n'); else if (src[x] != '\r') @@ -312,7 +342,7 @@ char last_char = src[parts[i].end-1]; int suffix=0; if (last_char == '.' || last_char == ',') { suffix=1; } - err = string_append (out, " "); + err = string_append (out, ""); if (suffix) { err = string_appendn(out,src + parts[i].end - 1,1); if (err != STATUS_OK) break; @@ -333,7 +363,7 @@ } else /* type == SC_TYPE_EMAIL */ { - err = string_append (out, ""); + err = string_append (out, ""); } x = parts[i].end; i++; diff -Nbru clearsilver-0.3/cgi/rfc2388.c clearsilver-0.4/cgi/rfc2388.c --- clearsilver-0.3/cgi/rfc2388.c Sun Sep 9 16:53:10 2001 +++ clearsilver-0.4/cgi/rfc2388.c Tue Oct 16 15:39:59 2001 @@ -392,12 +392,12 @@ if (filename) { if (last) fwrite (last, sizeof(char), strlen(last), fp); - if (l > 2 && s[l-1] == '\n' && s[l-2] == '\r') + if (l > 1 && s[l-1] == '\n' && s[l-2] == '\r') { last = "\r\n"; l-=2; } - else if (l > 1 && s[l-1] == '\n') + else if (l > 0 && s[l-1] == '\n') { last = "\n"; l--; diff -Nbru clearsilver-0.3/cgi/static.c clearsilver-0.4/cgi/static.c --- clearsilver-0.3/cgi/static.c Mon Aug 6 14:28:16 2001 +++ clearsilver-0.4/cgi/static.c Wed Oct 10 17:26:13 2001 @@ -47,6 +47,7 @@ { *p = '\0'; err = hdf_set_value (cgi->hdf, "hdf.loadpaths.0", cs_file); + chdir(cs_file); *p = '/'; if (err) { diff -Nbru clearsilver-0.3/cs/Makefile clearsilver-0.4/cs/Makefile --- clearsilver-0.3/cs/Makefile Sat Sep 15 17:08:55 2001 +++ clearsilver-0.4/cs/Makefile Tue Nov 13 13:58:15 2001 @@ -23,7 +23,7 @@ TARGETS = $(CS_LIB) $(CSTEST_EXE) test -CS_TESTS = test.cs test2.cs test3.cs test4.cs test5.cs test6.cs +CS_TESTS = test.cs test2.cs test3.cs test4.cs test5.cs test6.cs test7.cs all: $(TARGETS) @@ -43,7 +43,7 @@ ./cstest test.hdf $$test > $$test.gold; \ done -test: $(CSTEST_EXE) +test: $(CSTEST_EXE) $(CS_TESTS) @echo "Running cs regression tests" @for test in $(CS_TESTS); do \ rm -f $$test.out; \ diff -Nbru clearsilver-0.3/cs/cs.h clearsilver-0.4/cs/cs.h --- clearsilver-0.3/cs/cs.h Sat Sep 15 16:38:40 2001 +++ clearsilver-0.4/cs/cs.h Tue Nov 13 13:58:15 2001 @@ -15,13 +15,15 @@ * CS_OPEN := * COMMAND := (CMD_IF | CMD_VAR | CMD_EVAR | CMD_INCLUDE | CMD_EACH - * | CMD_DEF | CMD_CALL | CMD_SET ) + * | CMD_DEF | CMD_CALL | CMD_SET | CMD_LOOP ) * CMD_IF := CS_OPEN IF CS_CLOSE CS CMD_ENDIF * CMD_ENDIF := CS_OPEN ENDIF CS_CLOSE * CMD_INCLUDE := CS_OPEN INCLUDE CS_CLOSE * CMD_DEF := CS_OPEN DEF CS_CLOSE * CMD_CALL := CS_OPEN CALL CS_CLOSE * CMD_SET := CS_OPEN SET CS_CLOSE + * CMD_LOOP := CS_OPEN LOOP CS_CLOSE + * LOOP := loop:VAR = EXPR, EXPR, EXPR * SET := set:VAR = EXPR * EXPR := (ARG | ARG OP EXPR) * CALL := call:VAR LPAREN ARG (,ARG)* RPAREN diff -Nbru clearsilver-0.3/cs/csparse.c clearsilver-0.4/cs/csparse.c --- clearsilver-0.3/cs/csparse.c Sat Sep 15 17:22:56 2001 +++ clearsilver-0.4/cs/csparse.c Thu Jan 10 15:11:39 2002 @@ -34,9 +34,10 @@ ST_EACH = 1<<3, ST_POP = 1<<4, ST_DEF = 1<<5, + ST_LOOP = 1<<6, } CS_STATE; -#define ST_ANYWHERE (ST_EACH | ST_ELSE | ST_IF | ST_GLOBAL | ST_DEF) +#define ST_ANYWHERE (ST_EACH | ST_ELSE | ST_IF | ST_GLOBAL | ST_DEF | ST_LOOP) typedef struct _stack_entry { @@ -70,6 +71,9 @@ static NEOERR *call_eval (CSPARSE *parse, CSTREE *node, CSTREE **next); static NEOERR *set_parse (CSPARSE *parse, int cmd, char *arg); static NEOERR *set_eval (CSPARSE *parse, CSTREE *node, CSTREE **next); +static NEOERR *loop_parse (CSPARSE *parse, int cmd, char *arg); +static NEOERR *loop_eval (CSPARSE *parse, CSTREE *node, CSTREE **next); +static NEOERR *endloop_parse (CSPARSE *parse, int cmd, char *arg); static NEOERR *render_node (CSPARSE *parse, CSTREE *node); @@ -109,7 +113,7 @@ endeach_parse, skip_eval, 0}, {"include", sizeof("include")-1, ST_ANYWHERE, ST_SAME, include_parse, skip_eval, 1}, - {"def", sizeof("def")-1, ST_GLOBAL, ST_DEF, + {"def", sizeof("def")-1, ST_ANYWHERE, ST_DEF, def_parse, skip_eval, 1}, {"/def", sizeof("/def")-1, ST_DEF, ST_POP, enddef_parse, skip_eval, 0}, @@ -117,6 +121,10 @@ call_parse, call_eval, 1}, {"set", sizeof("set")-1, ST_ANYWHERE, ST_SAME, set_parse, set_eval, 1}, + {"loop", sizeof("loop")-1, ST_ANYWHERE, ST_LOOP, + loop_parse, loop_eval, 1}, + {"/loop", sizeof("/loop")-1, ST_LOOP, ST_POP, + endloop_parse, skip_eval, 1}, {NULL}, }; @@ -435,7 +443,7 @@ if (!strncasecmp(token, Commands[i].cmd, n)) { if ((Commands[i].has_arg && ((token[n] == ':') || (token[n] == '!'))) - || (token[n] == ' ' || token[n] == '\0')) + || (token[n] == ' ' || token[n] == '\0' || token[n] == '\r' || token[n] == '\n')) { err = uListGet (parse->stack, -1, (void **)&entry); if (err != STATUS_OK) goto cs_parse_done; @@ -639,193 +647,6 @@ return atoi(vs); } -static NEOERR *literal_parse (CSPARSE *parse, int cmd, char *arg) -{ - NEOERR *err; - CSTREE *node; - - /* ne_warn ("literal: %s", arg); */ - err = alloc_node (&node); - if (err) return nerr_pass(err); - node->cmd = cmd; - node->arg1.op_type = CS_TYPE_STRING; - node->arg1.s = arg; - *(parse->next) = node; - parse->next = &(node->next); - parse->current = node; - - return STATUS_OK; -} - -static NEOERR *literal_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) -{ - NEOERR *err = STATUS_OK; - - if (node->arg1.s != NULL) - err = parse->output_cb (parse->output_ctx, node->arg1.s); - *next = node->next; - return nerr_pass(err); -} - -static NEOERR *name_parse (CSPARSE *parse, int cmd, char *arg) -{ - NEOERR *err; - CSTREE *node; - char *a, *s; - char tmp[256]; - - /* ne_warn ("name: %s", arg); */ - err = alloc_node (&node); - if (err) return nerr_pass(err); - node->cmd = cmd; - if (arg[0] == '!') - node->flags |= CSF_REQUIRED; - arg++; - /* Validate arg is a var (regex /^[#" ]$/) */ - a = neos_strip(arg); - s = strpbrk(a, "#\" <>"); - if (s != NULL) - { - dealloc_node(&node); - return nerr_raise (NERR_PARSE, "%s Invalid character in var name %s: %c", - find_context(parse, -1, tmp, sizeof(tmp)), - a, s[0]); - } - - node->arg1.op_type = CS_TYPE_VAR; - node->arg1.s = a; - *(parse->next) = node; - parse->next = &(node->next); - parse->current = node; - - return STATUS_OK; -} - -static NEOERR *name_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) -{ - NEOERR *err = STATUS_OK; - HDF *obj; - char *v; - - if (node->arg1.op_type == CS_TYPE_VAR && node->arg1.s != NULL) - { - obj = var_lookup_obj (parse, node->arg1.s); - if (obj != NULL) - { - v = hdf_obj_name(obj); - err = parse->output_cb (parse->output_ctx, v); - } - } - *next = node->next; - return nerr_pass(err); -} - -static NEOERR *var_parse (CSPARSE *parse, int cmd, char *arg) -{ - NEOERR *err; - CSTREE *node; - char *a, *s; - char tmp[256]; - - /* ne_warn ("var: %s", arg); */ - err = alloc_node (&node); - if (err) return nerr_pass(err); - node->cmd = cmd; - if (arg[0] == '!') - node->flags |= CSF_REQUIRED; - arg++; - /* Validate arg is a var (regex /^[#" ]$/) */ - a = neos_strip(arg); - s = strpbrk(a, "#\" <>"); - if (s != NULL) - { - dealloc_node(&node); - return nerr_raise (NERR_PARSE, "%s Invalid character in var name %s: %c", - find_context(parse, -1, tmp, sizeof(tmp)), - a, s[0]); - } - - node->arg1.op_type = CS_TYPE_VAR; - node->arg1.s = a; - *(parse->next) = node; - parse->next = &(node->next); - parse->current = node; - - return STATUS_OK; -} - -static NEOERR *var_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) -{ - NEOERR *err = STATUS_OK; - char *v; - - if (node->arg1.op_type == CS_TYPE_VAR && node->arg1.s != NULL) - { - v = var_lookup (parse, node->arg1.s); - if (v != NULL) - err = parse->output_cb (parse->output_ctx, v); - } - *next = node->next; - return nerr_pass(err); -} - -static NEOERR *evar_parse (CSPARSE *parse, int cmd, char *arg) -{ - NEOERR *err; - CSTREE *node; - char *a, *s; - char *save_context; - int save_infile; - char tmp[256]; - - /* ne_warn ("evar: %s", arg); */ - err = alloc_node (&node); - if (err) return nerr_pass(err); - node->cmd = cmd; - if (arg[0] == '!') - node->flags |= CSF_REQUIRED; - arg++; - /* Validate arg is a var (regex /^[#" ]$/) */ - a = neos_strip(arg); - s = strpbrk(a, "#\" <>"); - if (s != NULL) - { - dealloc_node(&node); - return nerr_raise (NERR_PARSE, "%s Invalid character in var name %s: %c", - find_context(parse, -1, tmp, sizeof(tmp)), - a, s[0]); - } - - err = hdf_get_copy (parse->hdf, a, &s, NULL); - if (err) - { - dealloc_node(&node); - return nerr_pass (err); - } - if (node->flags & CSF_REQUIRED && s == NULL) - { - dealloc_node(&node); - return nerr_raise (NERR_NOT_FOUND, "%s Unable to evar empty variable %s", - find_context(parse, -1, tmp, sizeof(tmp)), a); - } - - node->arg1.op_type = CS_TYPE_VAR; - node->arg1.s = a; - *(parse->next) = node; - parse->next = &(node->next); - parse->current = node; - - save_context = parse->context; - save_infile = parse->in_file; - parse->context = a; - parse->in_file = 0; - if (s) err = cs_parse_string (parse, s, strlen(s)); - parse->context = save_context; - parse->in_file = save_infile; - - return nerr_pass (err); -} - typedef struct _token { CSTOKEN_TYPE type; @@ -987,52 +808,217 @@ } else { - return nerr_raise (NERR_PARSE, - "%s Terminal token is not an argument, type is %d", - find_context(parse, -1, tmp, sizeof(tmp)), tokens[0].type); - } + return nerr_raise (NERR_PARSE, + "%s Terminal token is not an argument, type is %d", + find_context(parse, -1, tmp, sizeof(tmp)), tokens[0].type); + } + } + + while (BinaryOpOrder[op]) + { + x = ntokens-1; + while (x >= 0) + { + if (tokens[x].type & BinaryOpOrder[op]) + { + arg->op_type = tokens[x].type; + arg->expr2 = (CSARG *) calloc (1, sizeof (CSARG)); + arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG)); + if (arg->expr1 == NULL || arg->expr2 == 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 + x + 1, ntokens-x-1, arg->expr2); + if (err) return nerr_pass (err); + err = parse_expr2(parse, tokens, x, arg->expr1); + if (err) return nerr_pass (err); + return STATUS_OK; + } + x--; + } + op++; + } + return nerr_raise (NERR_PARSE, "%s Bad Expression", + find_context(parse, -1, tmp, sizeof(tmp))); +} + +static NEOERR *parse_expr (CSPARSE *parse, char *arg, CSARG *expr) +{ + NEOERR *err; + CSTOKEN tokens[MAX_TOKENS]; + int ntokens = 0; + + memset(tokens, 0, sizeof(CSTOKEN) * MAX_TOKENS); + err = parse_tokens (parse, arg, tokens, &ntokens); + if (err) return nerr_pass(err); + err = parse_expr2 (parse, tokens, ntokens, expr); + if (err) return nerr_pass(err); + return STATUS_OK; +} + +static NEOERR *literal_parse (CSPARSE *parse, int cmd, char *arg) +{ + NEOERR *err; + CSTREE *node; + + /* ne_warn ("literal: %s", arg); */ + err = alloc_node (&node); + if (err) return nerr_pass(err); + node->cmd = cmd; + node->arg1.op_type = CS_TYPE_STRING; + node->arg1.s = arg; + *(parse->next) = node; + parse->next = &(node->next); + parse->current = node; + + return STATUS_OK; +} + +static NEOERR *literal_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) +{ + NEOERR *err = STATUS_OK; + + if (node->arg1.s != NULL) + err = parse->output_cb (parse->output_ctx, node->arg1.s); + *next = node->next; + return nerr_pass(err); +} + +static NEOERR *name_parse (CSPARSE *parse, int cmd, char *arg) +{ + NEOERR *err; + CSTREE *node; + char *a, *s; + char tmp[256]; + + /* ne_warn ("name: %s", arg); */ + err = alloc_node (&node); + if (err) return nerr_pass(err); + node->cmd = cmd; + if (arg[0] == '!') + node->flags |= CSF_REQUIRED; + arg++; + /* Validate arg is a var (regex /^[#" ]$/) */ + a = neos_strip(arg); + s = strpbrk(a, "#\" <>"); + if (s != NULL) + { + dealloc_node(&node); + return nerr_raise (NERR_PARSE, "%s Invalid character in var name %s: %c", + find_context(parse, -1, tmp, sizeof(tmp)), + a, s[0]); + } + + node->arg1.op_type = CS_TYPE_VAR; + node->arg1.s = a; + *(parse->next) = node; + parse->next = &(node->next); + parse->current = node; + + return STATUS_OK; +} + +static NEOERR *name_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) +{ + NEOERR *err = STATUS_OK; + HDF *obj; + char *v; + + if (node->arg1.op_type == CS_TYPE_VAR && node->arg1.s != NULL) + { + obj = var_lookup_obj (parse, node->arg1.s); + if (obj != NULL) + { + v = hdf_obj_name(obj); + err = parse->output_cb (parse->output_ctx, v); + } + } + *next = node->next; + return nerr_pass(err); +} + +static NEOERR *var_parse (CSPARSE *parse, int cmd, char *arg) +{ + NEOERR *err; + CSTREE *node; + + /* ne_warn ("var: %s", arg); */ + err = alloc_node (&node); + if (err) return nerr_pass(err); + node->cmd = cmd; + if (arg[0] == '!') + node->flags |= CSF_REQUIRED; + arg++; + /* Validate arg is a var (regex /^[#" ]$/) */ + err = parse_expr (parse, arg, &(node->arg1)); + if (err) + { + dealloc_node(&node); + return nerr_pass(err); + } + + *(parse->next) = node; + parse->next = &(node->next); + parse->current = node; + + return STATUS_OK; +} + +static NEOERR *evar_parse (CSPARSE *parse, int cmd, char *arg) +{ + NEOERR *err; + CSTREE *node; + char *a, *s; + char *save_context; + int save_infile; + char tmp[256]; + + /* ne_warn ("evar: %s", arg); */ + err = alloc_node (&node); + if (err) return nerr_pass(err); + node->cmd = cmd; + if (arg[0] == '!') + node->flags |= CSF_REQUIRED; + arg++; + /* Validate arg is a var (regex /^[#" ]$/) */ + a = neos_strip(arg); + s = strpbrk(a, "#\" <>"); + if (s != NULL) + { + dealloc_node(&node); + return nerr_raise (NERR_PARSE, "%s Invalid character in var name %s: %c", + find_context(parse, -1, tmp, sizeof(tmp)), + a, s[0]); } - while (BinaryOpOrder[op]) - { - x = ntokens-1; - while (x >= 0) - { - if (tokens[x].type & BinaryOpOrder[op]) + err = hdf_get_copy (parse->hdf, a, &s, NULL); + if (err) { - arg->op_type = tokens[x].type; - arg->expr2 = (CSARG *) calloc (1, sizeof (CSARG)); - arg->expr1 = (CSARG *) calloc (1, sizeof (CSARG)); - if (arg->expr1 == NULL || arg->expr2 == 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 + x + 1, ntokens-x-1, arg->expr2); - if (err) return nerr_pass (err); - err = parse_expr2(parse, tokens, x, arg->expr1); - if (err) return nerr_pass (err); - return STATUS_OK; - } - x--; + dealloc_node(&node); + return nerr_pass (err); } - op++; + if (node->flags & CSF_REQUIRED && s == NULL) + { + dealloc_node(&node); + return nerr_raise (NERR_NOT_FOUND, "%s Unable to evar empty variable %s", + find_context(parse, -1, tmp, sizeof(tmp)), a); } - return nerr_raise (NERR_PARSE, "%s Bad Expression", - find_context(parse, -1, tmp, sizeof(tmp))); -} -static NEOERR *parse_expr (CSPARSE *parse, char *arg, CSARG *expr) -{ - NEOERR *err; - CSTOKEN tokens[MAX_TOKENS]; - int ntokens = 0; + node->arg1.op_type = CS_TYPE_VAR; + node->arg1.s = a; + *(parse->next) = node; + parse->next = &(node->next); + parse->current = node; - memset(tokens, 0, sizeof(CSTOKEN) * MAX_TOKENS); - err = parse_tokens (parse, arg, tokens, &ntokens); - if (err) return nerr_pass(err); - err = parse_expr2 (parse, tokens, ntokens, expr); - if (err) return nerr_pass(err); - return STATUS_OK; + save_context = parse->context; + save_infile = parse->in_file; + parse->context = a; + parse->in_file = 0; + if (s) err = cs_parse_string (parse, s, strlen(s)); + parse->context = save_context; + parse->in_file = save_infile; + + return nerr_pass (err); } static NEOERR *if_parse (CSPARSE *parse, int cmd, char *arg) @@ -1117,9 +1103,13 @@ static NEOERR *eval_expr (CSPARSE *parse, CSARG *expr, CSARG *result) { + memset(result, 0, sizeof(CSARG)); if (expr->op_type & CS_TYPES) { *result = *expr; + /* we transfer ownership of the string here.. ugh */ + if (expr->op_type == CS_TYPE_STRING_ALLOC) + expr->op_type = CS_TYPE_STRING; return STATUS_OK; } else @@ -1223,11 +1213,18 @@ result->n = (s2 == NULL) ? 1 : 0; break; case CS_OP_ADD: - result->op_type = CS_TYPE_STRING; if (s1 == NULL) + { result->s = s2; + result->op_type = arg2.op_type; + arg2.op_type = CS_TYPE_STRING; + } else + { result->s = s1; + result->op_type = arg1.op_type; + arg1.op_type = CS_TYPE_STRING; + } break; default: ne_warn ("Unsupported op %d in eval_expr", expr->op_type); @@ -1262,7 +1259,7 @@ 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); - strcat(result->s, s1); + strcpy(result->s, s1); strcat(result->s, s2); break; default: @@ -1271,6 +1268,7 @@ } } } + if (arg1.op_type == CS_TYPE_STRING_ALLOC) free(arg1.s); if (arg2.op_type == CS_TYPE_STRING_ALLOC) @@ -1279,6 +1277,39 @@ return STATUS_OK; } +static NEOERR *var_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) +{ + NEOERR *err = STATUS_OK; + CSARG val; + + err = eval_expr(parse, &(node->arg1), &val); + if (err) return nerr_pass(err); + if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) + { + char buf[256]; + long int n_val; + + n_val = arg_eval_num (parse, &val); + snprintf (buf, sizeof(buf), "%ld", n_val); + err = parse->output_cb (parse->output_ctx, buf); + } + else + { + char *s = arg_eval (parse, &val); + /* Do we set it to blank if s == NULL? */ + if (s) + { + err = parse->output_cb (parse->output_ctx, s); + } + } + if (val.op_type == CS_TYPE_STRING_ALLOC) + free(val.s); + + *next = node->next; + return nerr_pass(err); +} + + static NEOERR *if_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) { NEOERR *err = STATUS_OK; @@ -1926,6 +1957,194 @@ *next = node->next; return nerr_pass (err); +} + +static NEOERR *loop_parse (CSPARSE *parse, int cmd, char *arg) +{ + NEOERR *err; + CSTREE *node; + CSARG *carg, *larg = NULL; + BOOL last = FALSE; + char *lvar; + char *p, *a; + char tmp[256]; + int x; + + err = alloc_node (&node); + if (err) return nerr_pass(err); + node->cmd = cmd; + if (arg[0] == '!') + node->flags |= CSF_REQUIRED; + arg++; + + p = lvar = neos_strip(arg); + while (*p && !isspace(*p) && *p != '=') p++; + if (*p == '\0') + { + dealloc_node(&node); + return nerr_raise (NERR_PARSE, + "%s Improperly formatted loop directive: %s", + find_context(parse, -1, tmp, sizeof(tmp)), arg); + } + if (*p != '=') + { + *p++ = '\0'; + while (*p && *p != '=') p++; + if (*p == '\0') + { + dealloc_node(&node); + return nerr_raise (NERR_PARSE, + "%s Improperly formatted loop directive: %s", + find_context(parse, -1, tmp, sizeof(tmp)), arg); + } + p++; + } + else + { + *p++ = '\0'; + } + while (*p && isspace(*p)) p++; + if (*p == '\0') + { + dealloc_node(&node); + return nerr_raise (NERR_PARSE, + "%s Improperly formatted loop directive: %s", + find_context(parse, -1, tmp, sizeof(tmp)), arg); + } + node->arg1.op_type = CS_TYPE_VAR; + node->arg1.s = lvar; + + x = 0; + while (*p) + { + carg = (CSARG *) calloc (1, sizeof(CSARG)); + if (carg == NULL) + { + err = nerr_raise (NERR_NOMEM, + "%s Unable to allocate memory for CSARG in loop %s", + find_context(parse, -1, tmp, sizeof(tmp)), arg); + break; + } + if (larg == NULL) + { + node->vargs = carg; + larg = carg; + } + else + { + larg->next = carg; + larg = carg; + } + x++; + a = strpbrk(p, ","); + if (a == NULL) last = TRUE; + else *a = '\0'; + err = parse_expr (parse, p, carg); + if (err) break; + if (last == TRUE) break; + p = a+1; + } + if (!err && ((x < 1) || (x > 3))) + { + err = nerr_raise (NERR_PARSE, + "%s Incorrect number of arguments, expected 1, 2, or 3 got %d in loop: %s", + find_context(parse, -1, tmp, sizeof(tmp)), x, arg); + } + + /* ne_warn ("loop %s %s", lvar, p); */ + + *(parse->next) = node; + parse->next = &(node->case_0); + parse->current = node; + + return STATUS_OK; +} + +static NEOERR *loop_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) +{ + NEOERR *err = STATUS_OK; + CS_LOCAL_MAP each_map; + int var; + int start = 0, end = 0, step = 1; + int x, iter = 1; + CSARG *carg; + CSARG val; + + carg = node->vargs; + if (carg == NULL) return nerr_raise (NERR_ASSERT, "No arguments in loop eval?"); + err = eval_expr(parse, carg, &val); + if (err) return nerr_pass(err); + end = arg_eval_num(parse, &val); + if (val.op_type == CS_TYPE_STRING_ALLOC) free(val.s); + if (carg->next) + { + start = end; + carg = carg->next; + err = eval_expr(parse, carg, &val); + if (err) return nerr_pass(err); + end = arg_eval_num(parse, &val); + if (val.op_type == CS_TYPE_STRING_ALLOC) free(val.s); + if (carg->next) + { + carg = carg->next; + err = eval_expr(parse, carg, &val); + if (err) return nerr_pass(err); + step = arg_eval_num(parse, &val); + if (val.op_type == CS_TYPE_STRING_ALLOC) free(val.s); + } + } + /* automatically handle cases where the step is backwards */ + if (((step < 0) && (start < end)) || + ((step > 0) && (end < start))) + { + x = start; + start = end; + end = x; + } + if (step == 0) + { + if (start == end) iter = 1; + else iter = 0; + } + else + { + iter = abs((end - start) / step + 1); + } + + if (iter > 0) + { + /* Init and install local map */ + each_map.type = CS_TYPE_NUM; + each_map.name = node->arg1.s; + each_map.next = parse->locals; + parse->locals = &each_map; + + var = start; + for (x = 0, var = start; x < iter; x++, var += step) + { + each_map.value.n = var; + err = render_node (parse, node->case_0); + if (err != STATUS_OK) break; + } + + /* Remove local map */ + parse->locals = each_map.next; + } + + *next = node->next; + return nerr_pass (err); +} +static NEOERR *endloop_parse (CSPARSE *parse, int cmd, char *arg) +{ + NEOERR *err; + STACK_ENTRY *entry; + + err = uListGet (parse->stack, -1, (void **)&entry); + if (err != STATUS_OK) return nerr_pass(err); + + parse->next = &(entry->tree->next); + parse->current = entry->tree; + return STATUS_OK; } static NEOERR *skip_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) diff -Nbru clearsilver-0.3/cs/test7.cs clearsilver-0.4/cs/test7.cs --- clearsilver-0.3/cs/test7.cs Wed Dec 31 16:00:00 1969 +++ clearsilver-0.4/cs/test7.cs Tue Nov 13 13:58:15 2001 @@ -0,0 +1,14 @@ + +LOOP Test + +1, 3, 5 +, + +1, 3, 5... 205 +, + +backwards +, + +broken +, diff -Nbru clearsilver-0.3/cs/test7.cs.gold clearsilver-0.4/cs/test7.cs.gold --- clearsilver-0.3/cs/test7.cs.gold Wed Dec 31 16:00:00 1969 +++ clearsilver-0.4/cs/test7.cs.gold Tue Nov 13 13:58:15 2001 @@ -0,0 +1,15 @@ +Parsing test7.cs + +LOOP Test + +1, 3, 5 +1, 3, 5, + +1, 3, 5... 205 +1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, + +backwards +205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185, 183, 181, 179, 177, 175, 173, 171, 169, 167, 165, 163, 161, 159, 157, 155, 153, 151, 149, 147, 145, 143, 141, 139, 137, 135, 133, 131, 129, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, 105, 103, 101, 99, 97, 95, 93, 91, 89, 87, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, + +broken +205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185, 183, 181, 179, 177, 175, 173, 171, 169, 167, 165, 163, 161, 159, 157, 155, 153, 151, 149, 147, 145, 143, 141, 139, 137, 135, 133, 131, 129, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, 105, 103, 101, 99, 97, 95, 93, 91, 89, 87, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, diff -Nbru clearsilver-0.3/mod_ecs/Makefile.tmpl clearsilver-0.4/mod_ecs/Makefile.tmpl --- clearsilver-0.3/mod_ecs/Makefile.tmpl Wed Dec 31 16:00:00 1969 +++ clearsilver-0.4/mod_ecs/Makefile.tmpl Fri Jan 11 15:32:32 2002 @@ -0,0 +1 @@ +# Makefile for mod_ecs diff -Nbru clearsilver-0.3/mod_ecs/README clearsilver-0.4/mod_ecs/README --- clearsilver-0.3/mod_ecs/README Wed Dec 31 16:00:00 1969 +++ clearsilver-0.4/mod_ecs/README Fri Jan 11 15:42:27 2002 @@ -0,0 +1,83 @@ +mod_ecs - Apache Embedded ClearSilver CGI Module +------------------------------------------------------- +mod_ecs is based on a heavily modified version of mod_ecgi from: +http://www.webthing.com/software/mod_ecgi.html + +This directory contains an Apache module which is designed to work with +the ClearSilver CGI Kit. The point of this Apache module is +performance, if your server is under sufficient load that the overhead +of forking and execing the CGI for every request is too much, this +module is for you. This module is also useful if you want some of the +benefits of having a long-lived program: ie, the CGI can maintain +connections to data sources such as databases or cache data in memory. +The chief disadvantage is the same thing: your CGI becomes a long lived +process, and you have to watch that you don't hold connections or memory +that you don't want to. You might want to look into the Apache +configuration directives for limiting the number of connections that +each child process handles: MaxRequestsPerChild. + +If you are already using the full ClearSilver CGI Kit, all you need to +do to compile for the embedded ClearSilver is compile to a shared +library instead of to an executable. For instance, under Linux: + + Executable: ld -o static.cgi -lneo_cgi -lneo_cs -lneo_util + Shared Library: ld -shared -fPic -o static.cso -lneo_cgi -lneo_cs -lneo_util + +Also, remember not to call exit(), as this will cause the entire Apache +child to exit. + +There are two extra functions you can have in your CGI that the embedded +ClearSilver module will try to find and call if they exist. They are: +void ECSInit(void); +and +void ECSCleanup(void); + +The first is called when the embedded CGI is loaded, the second before +the embedded CGI is unloaded. + +This module supports the following three Apache configuration +directives: +ECSReload + When yes, mod_ecs will stat the .cso every time its run, to see if the + file on disk has been updated. If it has been updated, it will reload + the shared file from disk. This incurs some performance overhead, and + when a change does occur, it removes most of the gains of ECSPreload. + Notice also that on many operating systems, changing a shared library + on disk that has been demand loaded can cause problems such as unexpected + core dumps. This setting is most useful for development environments where + speed/throughput requirements aren't as high, but constant change is a + factor. +ECSDepLib + Brings the benefits of ECSPreload to dependent shared libraries. Will + cause mod_ecs to dlopen() the library at apache initialization time. + This can be avoided by using ECSPreload and having an ECSInit() + function in your library which does the shared library initialization. +ECSPreload + This function can be used to preload any shared libraries that you might + be calling later. This allows you to hide the latency of load/init time + from your users by doing it once at apache initialization. + +Requirements: + A later version of Apache 1.3.x, probably 1.3.12+. + +To Compile: +To dynamically load this module (assuming your copy of Apache is +compiled to use mod_so), do: + + /path/to/apxs -c mod_ecs.c + +Optionally, to (semi-)automatically install the module, do: + /path/to/apxs -i -a -n ecs mod_ecs.so + +Or, you can just edit your httpd.conf file yourself, adding the +following lines: + LoadModule ecs_module /path/to/installed/mod_ecs.so + # This line needs to be after and ClearModuleList command + AddModule mod_ecs.c + +There are two ways to tell Apache that a file is an embedded ClearSilver +CGI shared library, both are by extension. Typically, we use the .cso +extension. You can either use AddHandler or AddType: + AddHandler ecs-cgi .cso + AddType application/x-ecs-cgi + diff -Nbru clearsilver-0.3/mod_ecs/mod_ecs.c clearsilver-0.4/mod_ecs/mod_ecs.c --- clearsilver-0.3/mod_ecs/mod_ecs.c Wed Dec 31 16:00:00 1969 +++ clearsilver-0.4/mod_ecs/mod_ecs.c Fri Jan 11 17:05:31 2002 @@ -0,0 +1,832 @@ +/* +mod_ecs - Embedded ClearSilver CGI Apache Module + +mod_ecs is a heavily modified version of mod_ecgi from: +http://www.webthing.com/software/mod_ecgi.html + +This version is designed to run with the ClearSilver CGIKit, specifically +with the cgi_wrap calls from that kit. Those calls wrap the standard CGI +access methods, namely environment variables and stdin/stdout, allowing +those calls to be replaced easily. mod_ecs provides replacement calls which +interface directly with the Apache internals. + +Additionally, mod_ecs is designed to dlopen() the shared library CGI once, +and keep it in memory, making the CGI almost identical in performance to a +regular Apache module. The fact that your CGI will be called multiple times +is the biggest difference you can expect from a standard ClearSilver based CGI. +This means your code must be clean! + +ECS - Embedded ClearSilver + +Platform: UNIX only. Anyone who wants to is welcome to port it elsewhere. + +======================================================= +To COMPILE Apache with embedded CGI support, use + -ldl in EXTRA_LIBS + possibly -rdynamic in EXTRA_LFLAGS + I took this out of the config because its not there on freebsd4 + = ConfigStart + LIBS="$LIBS -ldl" + = ConfigEnd +(or as required by your platform) + +OK, here's for APACI: + * MODULE-DEFINITION-START + * Name: ecs_module + * MODULE-DEFINITION-END + +======================================================= + +======================================================= +BUGS +Lots - here are some obvious ones + - won't work with NPH + - No mechanism is provided for running from an SSI + - Can't take part in content-negotiation + - No graceful cleanup if a CGI program crashes (though it's OK + if the CGI fails but returns). + - Suspected memory leak inherited from Apache (which ignores it + because it happens just before exit there). + +*/ + +#include +#include "mod_ecs.h" + +#include "httpd.h" +#include "http_config.h" +#include "http_request.h" +#include "http_core.h" +#include "http_protocol.h" +#include "http_main.h" +#include "http_log.h" +#include "util_script.h" +#include "http_conf_globals.h" + +module ecs_module; + +/* Configuration stuff */ + +#define log_reason(reason,name,r) ap_log_error(APLOG_MARK,APLOG_ERR,(r)->server,(reason),(name)) +#define log_scripterror(r,conf,ret,error) (log_reason((error),(r)->filename,(r)),ret) + +char** ecs_create_argv(pool*,char*,char*,char*,char*,const char*); + +/**************************************************************** + * + * Actual CGI handling... + */ +const int ERROR = 500; +const int INTERNAL_REDIRECT = 3020; + +#undef ECS_DEBUG + +/****************************************************************** + * cgiwrap routines + * We've replaced all the normal CGI api calls with calls to the + * appropriate cgiwrap routines instead. Then, we provide versions of + * the cgiwrap callback here that interface directly with apache. We + * need to mimic a bunch of the stuff that apache does in mod_cgi in + * order to implement the output portion of the CGI spec. + */ +typedef struct header_buf { + char *buf; + int len; + int max; + int loc; + int nonl; +} HEADER_BUF; + +typedef struct wrap_data { + HEADER_BUF hbuf; + int end_of_header; + int returns; + request_rec *r; +} WRAPPER_DATA; + +static int buf_getline (char *idata, int ilen, char *odata, int olen, int *nonl) +{ + char *eol; + int len; + + *nonl = 1; + eol = strchr (idata, '\n'); + if (eol == NULL) + { + len = ilen; + } + else + { + *nonl = 0; + len = eol - idata + 1; + } + if (len > olen) len = olen; + memcpy (odata, idata, len); + odata[len] = '\0'; + return len; +} + +static int h_getline (char *buf, int len, void *h) +{ + HEADER_BUF *hbuf = (HEADER_BUF *)h; + int ret; + + buf[0] = '\0'; + if (hbuf->loc > hbuf->len) + return 0; + + ret = buf_getline (hbuf->buf + hbuf->loc, hbuf->len - hbuf->loc, buf, len, &(hbuf->nonl)); + hbuf->loc += ret; +#if ECS_DEBUG>1 + fprintf (stderr, "h_getline: [%d] %s\n", ret, buf); +#endif + return ret; +} + +static int header_write (HEADER_BUF *hbuf, char *data, int dlen) +{ + char buf[1024]; + int done, len; + int nonl = hbuf->nonl; + + done = 0; + while (done < dlen) + { + nonl = hbuf->nonl; + len = buf_getline (data + done, dlen - done, buf, sizeof(buf), &(hbuf->nonl)); + if (len == 0) + break; + done += len; + if (hbuf->len + len > hbuf->max) + { + hbuf->max *= 2; + if (hbuf->len + len > hbuf->max) + { + hbuf->max += len + 1; + } + hbuf->buf = (char *) realloc ((void *)(hbuf->buf), hbuf->max); + } + memcpy (hbuf->buf + hbuf->len, buf, len); + hbuf->len += len; + if (!nonl && (buf[0] == '\n' || buf[0] == '\r')) + { + /* end of headers */ + return done; + } + } + + return 0; +} + +/* The normal CGI module passes the returned data through + * ap_scan_script_header(). We can't do that directly, since we don't + * have a constant stream of data, so we buffer the header into our own + * structure, and call ap_scan_script_header_err_core() with our own + * getline() function to walk the header buffer we have. We could + * probably get some speed improvement by keeping the header buffer + * between runs, instead of growing it every time... for later. Also, + * we currently don't use the pool allocation routines here, so we have + * to be very careful not to leak. We could probably at least use the + * ap_register_cleanup() function to make sure we clean up our mess... + */ +static int wrap_write (void *data, char *buf, size_t len) +{ + WRAPPER_DATA *wrap = (WRAPPER_DATA *)data; + int wl; + int ret; + +#if ECS_DEBUG>1 + fprintf (stderr, "wrap_write (%s, %d)\n", buf, len); +#endif + if (!wrap->end_of_header) + { + wl = header_write (&(wrap->hbuf), buf, len); + if (wl == 0) + { + return len; + } + wrap->end_of_header = 1; + wrap->hbuf.loc = 0; +#if ECS_DEBUG>1 + fprintf (stderr, "ap_scan_script_header_err_core\n%s\n", wrap->hbuf.buf); +#endif + wrap->returns = ap_scan_script_header_err_core(wrap->r, NULL, h_getline, + (void *)&(wrap->hbuf)); +#if ECS_DEBUG>1 + fprintf (stderr, "ap_scan_script_header_err_core.. done\n"); +#endif + if (len >= wl) + { + len = len - wl; + buf = buf + wl; + } + + if (wrap->returns == OK) + { + const char* location = ap_table_get (wrap->r->headers_out, "Location"); + + if (location && location[0] == '/' && wrap->r->status == 200) + { + wrap->returns = INTERNAL_REDIRECT; + } + else if (location && wrap->r->status == 200) + { + /* XX Note that if a script wants to produce its own Redirect + * body, it now has to explicitly *say* "Status: 302" + */ + wrap->returns = REDIRECT; + } + else + { +#ifdef ECS_DEBUG + fprintf (stderr, "ap_send_http_header\n"); +#endif + ap_send_http_header(wrap->r); +#ifdef ECS_DEBUG + fprintf (stderr, "ap_send_http_header.. done\n"); +#endif + } + } + } + /* if header didn't return OK, ignore the rest */ + if ((wrap->returns != OK) || wrap->r->header_only) + { + return len; + } +#if ECS_DEBUG>1 + fprintf (stderr, "ap_rwrite(%s,%d)\n", buf, len); +#endif + ret = ap_rwrite (buf, len, wrap->r); +#if ECS_DEBUG>1 + fprintf (stderr, "ap_rwrite.. done\n"); +#endif + return ret; +} + +int wrap_vprintf (void *data, char *fmt, va_list ap) +{ + char buf[4096]; + int len; + + len = ap_vsnprintf (buf, sizeof(buf), fmt, ap); + return wrap_write (data, buf, len); +} + +static int wrap_read (void *data, void *buf, size_t len) +{ + WRAPPER_DATA *wrap = (WRAPPER_DATA *)data; + int ret; + int x = 0; + +#if ECS_DEBUG>1 + fprintf (stderr, "wrap_read (%s, %d)\n", buf, len); +#endif + do + { + ret = ap_get_client_block(wrap->r, buf + x, len - x); + if (ret <= 0) break; + x += ret; + } while (x < len); +#if ECS_DEBUG>1 + fprintf (stderr, "done ap_get_client_block\n"); +#endif + if (ret < 0) return ret; + return x; +} + +static char *wrap_getenv (void *data, char *s) +{ + WRAPPER_DATA *wrap = (WRAPPER_DATA *)data; + char *v; + + v = (char *) ap_table_get (wrap->r->subprocess_env, s); + if (v) return strdup(v); + return NULL; +} + +static int wrap_putenv (void *data, char *k, char *v) +{ + WRAPPER_DATA *wrap = (WRAPPER_DATA *)data; + + ap_table_set (wrap->r->subprocess_env, k, v); + + return 0; +} + +static char *wrap_iterenv (void *data, int x, char **k, char **v) +{ + WRAPPER_DATA *wrap = (WRAPPER_DATA *)data; + array_header *env = ap_table_elts(wrap->r->subprocess_env); + table_entry *entry = (table_entry*)env->elts; + + if (x >= env->nelts) return 0; + + if (entry[x].key == NULL || entry[x].val == NULL) + return 0; + + *k = strdup(entry[x].key); + *v = strdup(entry[x].val); + + return 0; +} + +/************************************************************************* + * Actual mod_ecs data structures for configuration + */ + +typedef void (*InitFunc)(); +typedef void (*CleanupFunc)(); +typedef int (*CGIMainFunc)(int,char**,char**); +typedef int (*WrapInitFunc)(void *,void *,void*,void*,void*,void*,void*); + +typedef struct { + const char *libpath; + ap_os_dso_handle_t dlib; +} ecs_deplibs; + +typedef struct { + const char *libpath; + ap_os_dso_handle_t dlib; + WrapInitFunc wrap_init; + CGIMainFunc start; + time_t mtime; + int loaded; +} ecs_manager; + +typedef struct { + array_header *deplibs; + array_header *handlers; + int fork_enabled; + int reload_enabled; +} ecs_server_conf; + +const char *ECSInit = "ECSInit"; +const char *ECSCleanUp = "ECSCleanup"; +const char *WrapInit = "cgiwrap_init_emu"; +const char *CGIMain = "main"; + +static void dummy (ap_os_dso_handle_t dlhandle) +{ +} + +static void slib_cleanup (ap_os_dso_handle_t dlhandle) +{ + CleanupFunc cleanupFunc; + if ((cleanupFunc = (CleanupFunc)ap_os_dso_sym(dlhandle, ECSCleanUp))) { + (*cleanupFunc)(); + } + ap_os_dso_unload(dlhandle); +#ifdef ECS_DEBUG + fprintf(stderr, "Unloading handle %d", dlhandle); +#endif +} + +void *create_ecs_config (pool *p, server_rec *dummy) +{ + ecs_server_conf *new = ap_palloc (p, sizeof(ecs_server_conf)); + new->deplibs = ap_make_array(p,1,sizeof(ecs_deplibs)); + new->handlers = ap_make_array(p,1,sizeof(ecs_manager)); + new->fork_enabled = 0; + new->reload_enabled = 0; + return (void *) new; +} + +char** e_setup_cgi_env (request_rec* r) +{ + char** env; + + ap_add_common_vars(r); + ap_add_cgi_vars(r); + env = ap_create_environment(r->pool,r->subprocess_env); + + return env; +} + +const char *set_dep_lib (cmd_parms *parms, void *dummy, char *arg) +{ + ecs_server_conf *cls = ap_get_module_config (parms->server->module_config, + &ecs_module); + ecs_deplibs *entry; + ap_os_dso_handle_t dlhandle; + InitFunc init_func; + + if ((dlhandle = ap_os_dso_load(arg)) == NULL) { + return ap_os_dso_error(); + } + + if ((init_func = (InitFunc)ap_os_dso_sym(dlhandle, ECSInit))) { + (*init_func)(); + } + + ap_register_cleanup (cls->deplibs->pool, dlhandle, slib_cleanup, slib_cleanup); + + entry = (ecs_deplibs*)ap_push_array(cls->deplibs); + entry->libpath = ap_pstrdup(cls->deplibs->pool, arg); + entry->dlib = dlhandle; + + return NULL; +} + +/* Load an ecs shared library */ +static const char *load_library (ap_pool *p, ecs_manager *entry, int do_stat, char *prefix) +{ + ap_os_dso_handle_t dlhandle; + InitFunc init_func; + CGIMainFunc cgi_main; + WrapInitFunc wrap_init; + char *err; + struct stat s; + + if (do_stat) + { + if (stat(entry->libpath, &s) == -1) + { + err = ap_psprintf (p, "Failed to stat library file %s: %d", entry->libpath, errno); + return err; + } + entry->mtime = s.st_mtime; + } + + if (entry->loaded == 1) + { + fprintf (stderr, "Warning: attempting to reload %s but it's already loaded\n", entry->libpath); + } + + /* This does a RTLD_NOW, if we want lazy, we're going to have to do it + * ourselves */ + if ((dlhandle = ap_os_dso_load(entry->libpath)) == NULL) { + return ap_os_dso_error(); + } + + if (entry->dlib == dlhandle) + { + fprintf (stderr, "Warning: Reload of %s returned same handle\n", entry->libpath); + } + + if ((init_func = (InitFunc)ap_os_dso_sym(dlhandle, ECSInit))) { + (*init_func)(); + } + if (!(wrap_init = (WrapInitFunc)ap_os_dso_sym(dlhandle, WrapInit))) { + err = ap_psprintf (p, "Failed to find wrap init function %s in shared object: %s", WrapInit, dlerror()); + ap_os_dso_unload(dlhandle); + return err; + } + if (!(cgi_main = (CGIMainFunc)ap_os_dso_sym(dlhandle, CGIMain))) { + err = ap_psprintf (p, "Failed to find entry function %s in shared object: %s", CGIMain, dlerror()); + ap_os_dso_unload(dlhandle); + return err; + } + + /* Um, this may be a problem... */ + ap_register_cleanup (p, dlhandle, slib_cleanup, dummy); + + entry->dlib = dlhandle; + entry->wrap_init = wrap_init; + entry->start = cgi_main; + entry->loaded = 1; + + fprintf (stderr, "%sLoaded library %s [%d]\n", prefix, entry->libpath, dlhandle); + + return NULL; +} + +const char *set_pre_lib (cmd_parms *parms, void *dummy, char *arg) +{ + ecs_server_conf *cls = ap_get_module_config (parms->server->module_config, + &ecs_module); + ecs_manager *entry; + + entry = (ecs_manager*)ap_push_array(cls->handlers); + entry->libpath = ap_pstrdup(cls->handlers->pool, arg); + + return load_library (cls->handlers->pool, entry, 1, "Pre"); +} + +const char *set_fork (cmd_parms *parms, void *dummy, int flag) +{ + ecs_server_conf *cls = ap_get_module_config (parms->server->module_config, + &ecs_module); + + cls->fork_enabled = (flag ? 1 : 0); + + return NULL; +} + +const char *set_reload (cmd_parms *parms, void *dummy, int flag) +{ + ecs_server_conf *cls = ap_get_module_config (parms->server->module_config, + &ecs_module); + + cls->reload_enabled = (flag ? 1 : 0); + + return NULL; +} + +static ecs_manager *findHandler(array_header *a, char *file) +{ + ecs_manager *list = (ecs_manager*)(a->elts); + int i; + + for (i = 0; i < a->nelts; i++) + { + if (!strcmp(list[i].libpath, file)) + return &(list[i]); + } + return NULL; +} + +static int run_dl_cgi (ecs_server_conf *sconf, request_rec* r, char* argv0) +{ + int ret = 0; + void* handle; + int cgi_status; + int argc; + char** argv; + WRAPPER_DATA *wdata; + ecs_manager *handler; + const char *err; + + char** envp = e_setup_cgi_env(r); + + /* Find/open library */ + handler = findHandler (sconf->handlers, r->filename); + if (handler == NULL) + { + ecs_manager my_handler; + my_handler.libpath = ap_pstrdup(sconf->handlers->pool, r->filename); + err = load_library(sconf->handlers->pool, &my_handler, 1, ""); + if (err != NULL) + { + log_reason("Error opening library:", err, r); + ret = ERROR; + } + else + { + handler = (ecs_manager*)ap_push_array(sconf->handlers); + handler->dlib = my_handler.dlib; + handler->wrap_init = my_handler.wrap_init; + handler->start = my_handler.start; + handler->mtime = my_handler.mtime; + handler->loaded = my_handler.loaded; + handler->libpath = my_handler.libpath; + } + } + else if (sconf->reload_enabled) + { + struct stat s; + if (stat(handler->libpath, &s) == -1) + { + log_reason("Unable to stat file: ", handler->libpath, r); + ret = ERROR; + } + else if (!handler->loaded || (s.st_mtime > handler->mtime)) + { + if (handler->loaded) + { + int x; + fprintf (stderr, "Unloading %s\n", handler->libpath); + slib_cleanup(handler->dlib); + /* Really unload this thing */ + while ((x < 100) && (dlclose(handler->dlib) != -1)) x++; + if (x == 100) + fprintf (stderr, "dlclose() never returned -1"); + handler->loaded = 0; + } + err = load_library(sconf->handlers->pool, handler, 0, "Re"); + if (err != NULL) + { + log_reason("Error opening library:", err, r); + ret = ERROR; + } + handler->mtime = s.st_mtime; + } + } + + if (!ret) { + if ((!r->args) || (!r->args[0]) || (ap_ind(r->args,'=') >= 0) ) + { + argc = 1; + argv = &argv0; + } else { + argv = ecs_create_argv(r->pool, NULL,NULL,NULL,argv0,r->args); + for (argc = 0 ; argv[argc] ; ++argc); + } + } + + /* Yow ... at last we can go ... + + Now, what to do if CGI crashes (aaargh) + Methinks an atexit ... cleanup perhaps; have to figgerout + what the atexit needs to invoke ... yuk! + + Or maybe better to catch SIGSEGV and SIGBUS ? + - we don't want coredumps from someone else's bugs, do we? + still doesn't guarantee anything very good :-( + + Ugh .. nothing better??? + */ + if (!ret) + { + wdata = (WRAPPER_DATA *) ap_pcalloc (r->pool, sizeof (WRAPPER_DATA)); + /* We use malloc here because there is no pool alloc command for + * realloc... */ + wdata->hbuf.buf = (char *) malloc (sizeof(char) * 1024); + wdata->hbuf.max = 1024; + wdata->r = r; + +#ifdef ECS_DEBUG + fprintf (stderr, "wrap_init()\n"); +#endif + handler->wrap_init(wdata, wrap_read, wrap_vprintf, wrap_write, wrap_getenv, wrap_putenv, wrap_iterenv); + +#ifdef ECS_DEBUG + fprintf (stderr, "cgi_main()\n"); +#endif + cgi_status = handler->start(argc,argv,envp); + if (cgi_status != 0) + { + /*log_reason("CGI returned error status", cgi_status, r) ;*/ + ret = ERROR; + } + + if (wdata->returns != OK) + ret = wdata->returns; + + free (wdata->hbuf.buf); + } + + return ret; +} + +int run_xcgi (ecs_server_conf *conf, request_rec* r, char* argv0) +{ + int len_read; + char argsbuffer[HUGE_STRING_LEN]; + int ret = 0; + + ret = run_dl_cgi (conf, r, argv0); + + if (ret == INTERNAL_REDIRECT) + { + const char* location = ap_table_get (r->headers_out, "Location"); + + /* This redirect needs to be a GET no matter what the original + * method was. + */ + r->method = ap_pstrdup(r->pool, "GET"); + r->method_number = M_GET; + + /* We already read the message body (if any), so don't allow + * the redirected request to think it has one. We can ignore + * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. + */ + ap_table_unset(r->headers_in, "Content-Length"); + + ap_internal_redirect_handler (location, r); + return OK; + } + + return ret; +} + +int ecs_handler (request_rec* r) +{ + int retval; + char *argv0; + int is_included = !strcmp (r->protocol, "INCLUDED"); + void *sconf = r->server->module_config; + ecs_server_conf *conf = + (ecs_server_conf *)ap_get_module_config(sconf, &ecs_module); + + ap_error_log2stderr(r->server); +#ifdef ECS_DEBUG + fprintf(stderr, "running ecs_handler %s\n", r->filename); +#endif + + if((argv0 = strrchr(r->filename,'/')) != NULL) + argv0++; + else argv0 = r->filename; + + if (!(ap_allow_options (r) & OPT_EXECCGI) ) + return log_scripterror(r, conf, FORBIDDEN, + "Options ExecCGI is off in this directory"); + + if (S_ISDIR(r->finfo.st_mode)) + return log_scripterror(r, conf, FORBIDDEN, + "attempt to invoke directory as script"); + if (r->finfo.st_mode == 0) + return log_scripterror(r, conf, NOT_FOUND, + "file not found or unable to stat"); + +#ifdef ECS_DEBUG + fprintf (stderr, "ap_setup_client_block\n"); +#endif + if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) + return retval; + +#ifdef ECS_DEBUG + fprintf (stderr, "before run\n"); +#endif + return run_xcgi(conf, r, argv0); +} + +handler_rec ecs_handlers[] = { + { ECS_MAGIC_TYPE, ecs_handler }, + { "ecs-cgi", ecs_handler}, + { NULL } +}; + +command_rec ecs_cmds[] = { + { "ECSFork", set_fork, NULL, OR_FILEINFO, FLAG, + "On or off to enable or disable (default) forking before calling cgi_main" }, + { "ECSReload", set_reload, NULL, OR_FILEINFO, FLAG, + "On or off to enable or disable (default) checking if the shared library\n" \ + " has changed and reloading it if it has"}, + { "ECSDepLib", set_dep_lib, NULL, RSRC_CONF, TAKE1, + "The location of a dependent lib to dlopen during init"}, + { "ECSPreload", set_pre_lib, NULL, RSRC_CONF, TAKE1, + "The location of a shared lib handler to preload during init"}, + { NULL } +}; + +module ecs_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_ecs_config, /* server config */ + NULL, /*merge_ecs_config,*/ /* merge server config */ + ecs_cmds, /* command table */ + ecs_handlers, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ +#if MODULE_MAGIC_NUMBER >= 19970103 + NULL, /* [3] header parser */ +#endif +#if MODULE_MAGIC_NUMBER >= 19970719 + NULL, /* process initializer */ +#endif +#if MODULE_MAGIC_NUMBER >= 19970728 + NULL, /* process exit/cleanup */ +#endif +#if MODULE_MAGIC_NUMBER >= 19970902 + NULL, /* [1] post read_request handling */ +#endif +}; + + +/* Here's some stuff that essentially duplicates util_script.c + This really should be merged, but if _I_ do that it'll break + modularity and leave users with a nasty versioning problem. + + If I get a round tuit sometime, I might ask the Apache folks + about integrating some changes in the main source tree. +*/ +/* If a request includes query info in the URL (stuff after "?"), and + * the query info does not contain "=" (indicative of a FORM submission), + * then this routine is called to create the argument list to be passed + * to the CGI script. When suexec is enabled, the suexec path, user, and + * group are the first three arguments to be passed; if not, all three + * must be NULL. The query info is split into separate arguments, where + * "+" is the separator between keyword arguments. + */ +char **ecs_create_argv(pool *p, char *path, char *user, char *group, + char *av0, const char *args) +{ + int x, numwords; + char **av; + char *w; + int idx = 0; + + /* count the number of keywords */ + + for (x = 0, numwords = 1; args[x]; x++) + if (args[x] == '+') ++numwords; + + if (numwords > APACHE_ARG_MAX - 5) { + numwords = APACHE_ARG_MAX - 5; /* Truncate args to prevent overrun */ + } + av = (char **)ap_palloc(p, (numwords + 5) * sizeof(char *)); + + if (path) + av[idx++] = path; + if (user) + av[idx++] = user; + if (group) + av[idx++] = group; + + av[idx++] = av0; + + for (x = 1; x <= numwords; x++) { + w = ap_getword_nulls(p, &args, '+'); + ap_unescape_url(w); + av[idx++] = ap_escape_shell_cmd(p, w); + } + av[idx] = NULL; + return av; +} diff -Nbru clearsilver-0.3/mod_ecs/mod_ecs.h clearsilver-0.4/mod_ecs/mod_ecs.h --- clearsilver-0.3/mod_ecs/mod_ecs.h Wed Dec 31 16:00:00 1969 +++ clearsilver-0.4/mod_ecs/mod_ecs.h Fri Jan 11 15:32:32 2002 @@ -0,0 +1,24 @@ +#ifndef _MOD_ECS_H_ +#define _MOD_ECS_H_ 1 + +/* not a real .h file - just for the cgiplusplus interface */ + +/* not an enum - want a bitfield */ +#define APACHE_CGI 0x1000 +/* need nonzero even for a default :-) */ +#define CGIPLUSPLUS 1 +#define EXTENDED_CGI 2 +#define USE_STRICT 4 +#define OPTIMISED_DESCRIPTORS 8 +#define ENV_AS_TABLE 0x10 +#define USE_CGI_STDERR 0x20 +#define STDERR_TO_HTML 0x40 +#define NPH 0x100 +#define STDIN_BUF 0x200 +#define OWN_STDOUT 0x400 +#define OWN_STDERR 0x800 +/* one day we'll get round to implementing all the above */ + +#define ECS_MAGIC_TYPE "application/x-ecs-cgi" + +#endif /* _MOD_ECS_H_ */ diff -Nbru clearsilver-0.3/python/neo_util.c clearsilver-0.4/python/neo_util.c --- clearsilver-0.3/python/neo_util.c Tue Aug 7 14:58:46 2001 +++ clearsilver-0.4/python/neo_util.c Tue Oct 23 00:01:35 2001 @@ -366,6 +366,32 @@ return Py_None; } +static PyObject * p_hdf_copy (PyObject *self, PyObject *args) +{ + HDFObject *ho = (HDFObject *)self; + HDF *src = NULL; + PyObject *rv, *o = NULL; + char *name; + NEOERR *err; + + if (!PyArg_ParseTuple(args, "sO:copy(name, src_hdf)", &name, &o)) + return NULL; + + src = p_object_to_hdf (o); + if (src == NULL) + { + PyErr_Format(PyExc_TypeError, "second argument must be an HDFObject"); + return NULL; + } + + err = hdf_copy (ho->data, name, src); + if (err) return p_neo_error(err); + + rv = Py_None; + Py_INCREF(rv); + return rv; +} + static PyMethodDef HDFMethods[] = { {"getIntValue", p_hdf_get_int_value, METH_VARARGS, NULL}, @@ -383,6 +409,7 @@ {"writeString", p_hdf_write_string, METH_VARARGS, NULL}, {"removeTree", p_hdf_remove_tree, METH_VARARGS, NULL}, {"dump", p_hdf_dump, METH_VARARGS, NULL}, + {"copy", p_hdf_copy, METH_VARARGS, NULL}, {NULL, NULL} }; diff -Nbru clearsilver-0.3/util/neo_hdf.c clearsilver-0.4/util/neo_hdf.c --- clearsilver-0.3/util/neo_hdf.c Fri Sep 14 17:21:30 2001 +++ clearsilver-0.4/util/neo_hdf.c Wed Oct 10 17:26:13 2001 @@ -288,7 +288,15 @@ char* hdf_obj_value (HDF *hdf) { + int count = 0; + if (hdf == NULL) return NULL; + while (hdf->link && count < 100) + { + if (_walk_hdf (hdf->top, hdf->value, &hdf)) + return NULL; + count++; + } return hdf->value; } @@ -326,6 +334,7 @@ hdf->alloc_value = wf; hdf->value = value; } + return STATUS_OK; } n = name; diff -Nbru clearsilver-0.3/util/neo_misc.c clearsilver-0.4/util/neo_misc.c --- clearsilver-0.3/util/neo_misc.c Mon Aug 6 14:28:17 2001 +++ clearsilver-0.4/util/neo_misc.c Wed Jan 2 16:36:42 2002 @@ -338,7 +338,7 @@ { if (errno == ENOENT) continue; closedir(dp); - return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", + return nerr_raise_errno (NERR_SYSTEM, "Unable to unlink file %s", npath); } } diff -Nbru clearsilver-0.3/util/neo_misc.h clearsilver-0.4/util/neo_misc.h --- clearsilver-0.3/util/neo_misc.h Mon Aug 6 14:28:17 2001 +++ clearsilver-0.4/util/neo_misc.h Mon Dec 17 23:17:05 2001 @@ -24,6 +24,8 @@ typedef char INT8; typedef char BOOL; +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) + #ifndef TRUE #define TRUE 1 #endif diff -Nbru clearsilver-0.3/util/neo_str.c clearsilver-0.4/util/neo_str.c --- clearsilver-0.3/util/neo_str.c Mon Aug 6 14:28:17 2001 +++ clearsilver-0.4/util/neo_str.c Mon Dec 17 23:17:05 2001 @@ -45,6 +45,15 @@ return s; } +void neos_lower(char *s) +{ + while(*s != 0) { + *s = tolower(*s); + s++; + } +} + + void string_init (STRING *str) { str->buf = NULL; diff -Nbru clearsilver-0.3/util/neo_str.h clearsilver-0.4/util/neo_str.h --- clearsilver-0.3/util/neo_str.h Mon Aug 6 14:28:17 2001 +++ clearsilver-0.4/util/neo_str.h Mon Dec 17 23:17:05 2001 @@ -23,6 +23,8 @@ */ char *neos_strip (char *s); +void neos_lower (char *s); + char *sprintf_alloc (char *fmt, ...); char *vsprintf_alloc (char *fmt, va_list ap); diff -Nbru clearsilver-0.3/util/ulocks.c clearsilver-0.4/util/ulocks.c --- clearsilver-0.3/util/ulocks.c Thu Sep 6 13:10:56 2001 +++ clearsilver-0.4/util/ulocks.c Wed Jan 2 16:36:31 2002 @@ -27,7 +27,11 @@ *plock = -1; - if((lock = open(file, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) < 0) + /* note the default mode of 666 is possible a security hole in that + * someone else can grab your lock and DoS you. For internal use, who + * cares? + */ + if((lock = open(file, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0666)) < 0) { if (errno == ENOENT) { @@ -38,7 +42,7 @@ err = ne_mkdirs(file, 0777); *p = '/'; if (err != STATUS_OK) return nerr_pass(err); - lock = open(file, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); + lock = open(file, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0666); } } if (lock < 0) @@ -67,9 +71,9 @@ *plock = -1; - if((lock = open(file, O_WRONLY|O_NDELAY|O_APPEND, 0600)) < 0) { + if((lock = open(file, O_WRONLY|O_NDELAY|O_APPEND, 0666)) < 0) { if (errno == ENOENT) - nerr_raise (NERR_NOT_FOUND, "Unable to find lock file %s", file); + return nerr_raise (NERR_NOT_FOUND, "Unable to find lock file %s", file); return nerr_raise_errno (NERR_IO, "Unable to open lock file %s", file); }