diff -Nbru clearsilver-0.4/Makefile clearsilver-0.5/Makefile --- clearsilver-0.4/Makefile Fri Jan 11 15:45:44 2002 +++ clearsilver-0.5/Makefile Fri Mar 15 13:50:52 2002 @@ -5,6 +5,7 @@ # # +NEOTONIC_ROOT = ./ include rules.mk @@ -69,8 +70,8 @@ mkdir -p $$mdir; \ done -CS_DISTDIR = clearsilver-0.3 -CS_LABEL = CLEARSILVER-0_3 +CS_DISTDIR = clearsilver-0.5 +CS_LABEL = CLEARSILVER-0_5_0 CS_FILES = LICENSE CS_LICENSE rules.mk Makefile util cs cgi python scripts mod_ecs cs_dist: rm -rf $(CS_DISTDIR) diff -Nbru clearsilver-0.4/cgi/cgi.c clearsilver-0.5/cgi/cgi.c --- clearsilver-0.4/cgi/cgi.c Sat Sep 15 16:37:24 2001 +++ clearsilver-0.5/cgi/cgi.c Thu Apr 11 18:11:39 2002 @@ -105,7 +105,7 @@ return STATUS_OK; } -static char *url_decode (char *s) +char *cgi_url_unescape (char *s) { int i = 0, o = 0; @@ -134,20 +134,35 @@ return s; } -NEOERR *cgi_url_escape (char *buf, char **esc) +NEOERR *cgi_url_escape_more (char *buf, char **esc, char *other) { int nl = 0; int l = 0; + int x = 0; char *s; + int match = 0; while (buf[l]) { if (buf[l] == '/' || buf[l] == '+' || buf[l] == '=' || buf[l] == '&' || - buf[l] == '"' || buf[l] == '%' || + buf[l] == '"' || buf[l] == '%' || buf[l] == '?' || buf[l] < 32 || buf[l] > 122) { nl += 2; } + else if (other) + { + x = 0; + while (other[x]) + { + if (other[x] == buf[l]) + { + nl +=2; + break; + } + x++; + } + } nl++; l++; } @@ -160,16 +175,35 @@ nl = 0; l = 0; while (buf[l]) { + match = 0; if (buf[l] == ' ') { s[nl++] = '+'; l++; } else + { if (buf[l] == '/' || buf[l] == '+' || buf[l] == '=' || buf[l] == '&' || - buf[l] == '"' || buf[l] == '%' || + buf[l] == '"' || buf[l] == '%' || buf[l] == '?' || buf[l] < 32 || buf[l] > 122) { + match = 1; + } + else if (other) + { + x = 0; + while (other[x]) + { + if (other[x] == buf[l]) + { + match = 1; + break; + } + x++; + } + } + if (match) + { s[nl++] = '%'; s[nl++] = "0123456789ABCDEF"[buf[l] / 16]; s[nl++] = "0123456789ABCDEF"[buf[l] % 16]; @@ -180,12 +214,18 @@ s[nl++] = buf[l++]; } } + } s[nl] = '\0'; *esc = s; return STATUS_OK; } +NEOERR *cgi_url_escape (char *buf, char **esc) +{ + return nerr_pass(cgi_url_escape_more(buf, esc, NULL)); +} + static NEOERR *_parse_query (CGI *cgi, char *query) { NEOERR *err = STATUS_OK; @@ -208,10 +248,10 @@ v = strtok_r(NULL, "&", &l); } if (v == NULL) v = ""; - snprintf(buf, sizeof(buf), "Query.%s", url_decode(k)); + snprintf(buf, sizeof(buf), "Query.%s", cgi_url_unescape(k)); if (!(cgi->ignore_empty_form_vars && (v == NULL || *v == '\0'))) { - url_decode(v); + cgi_url_unescape(v); obj = hdf_get_obj (cgi->hdf, buf); if (obj != NULL) { @@ -258,6 +298,7 @@ l = hdf_get_value (cgi->hdf, "CGI.ContentLength", NULL); if (l == NULL) return STATUS_OK; len = atoi (l); + if (len == 0) return STATUS_OK; cgi->data_expected = len; @@ -271,9 +312,15 @@ while (o < len) { cgiwrap_read (query + o, len - o, &r); - if (r == 0) break; + if (r <= 0) break; o = o + r; } + if (r < 0) + { + free(query); + return nerr_raise_errno (NERR_IO, "Short read on CGI POST input (%d < %d)", + o, len); + } if (o != len) { free(query); @@ -472,6 +519,55 @@ } #endif } + else if (!strcmp(method, "PUT")) + { + FILE *fp; + int len, x, r, w; + char *l; + char buf[4096]; + int unlink_files = hdf_get_int_value(cgi->hdf, "Config.Upload.Unlink", 1); + + err = open_upload(cgi, unlink_files, &fp); + if (err) return nerr_pass(err); + + l = hdf_get_value (cgi->hdf, "CGI.ContentLength", NULL); + if (l == NULL) return STATUS_OK; + len = atoi (l); + + x = 0; + while (x < len) + { + if (len-x > sizeof(buf)) + cgiwrap_read (buf, sizeof(buf), &r); + else + cgiwrap_read (buf, len - x, &r); + w = fwrite (buf, sizeof(char), r, fp); + if (w != r) + { + err = nerr_raise_errno(NERR_IO, "Short write on PUT: %d < %d", w, r); + break; + } + x += r; + } + if (err) return nerr_pass(err); + fseek(fp, 0, SEEK_SET); + l = hdf_get_value(cgi->hdf, "CGI.PathInfo", NULL); + if (l) err = hdf_set_value (cgi->hdf, "PUT", l); + if (err) return nerr_pass(err); + if (type) err = hdf_set_value (cgi->hdf, "PUT.Type", type); + if (err) return nerr_pass(err); + err = hdf_set_int_value (cgi->hdf, "PUT.FileHandle", uListLength(cgi->files)); + if (err) return nerr_pass(err); + if (!unlink_files) + { + char *name; + err = uListGet(cgi->filenames, uListLength(cgi->filenames)-1, + (void **)&name); + if (err) return nerr_pass(err); + err = hdf_set_value (cgi->hdf, "PUT.FileName", name); + if (err) return nerr_pass(err); + } + } return STATUS_OK; } @@ -791,6 +887,7 @@ dest = (char *) malloc (sizeof(char) * len2); if (dest != NULL) { + do { err = cgi_compress (str, dest, &len2); if (err == STATUS_OK) { @@ -799,12 +896,16 @@ err = cgiwrap_writef("%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); } + if (err != STATUS_OK) break; err = cgiwrap_write(dest, len2); + if (err != STATUS_OK) break; if (use_gzip) { err = cgiwrap_writef("%c%c%c%c", (0xff & (crc >> 0)), (0xff & (crc >> 8)), (0xff & (crc >> 16)), (0xff & (crc >> 24))); + if (err != STATUS_OK) break; err = cgiwrap_writef("%c%c%c%c", (0xff & (str->len >> 0)), (0xff & (str->len >> 8)), (0xff & (str->len >> 16)), (0xff & (str->len >> 24))); + if (err != STATUS_OK) break; } } else @@ -812,6 +913,7 @@ nerr_log_error (err); err = cgiwrap_write(str->buf, str->len); } + } while (0); free (dest); } else @@ -825,7 +927,7 @@ err = cgiwrap_write(str->buf, str->len); } - return err; + return nerr_pass(err); } NEOERR *cgi_display (CGI *cgi, char *cs_file) @@ -880,7 +982,7 @@ cgiwrap_writef("Content-Type: text/html\n\n"); cgiwrap_writef("\nAn error occured:
");
-  nerr_error_string (err, &str);
+  nerr_error_traceback(err, &str);
   cgiwrap_write(str.buf, str.len);
   cgiwrap_writef("
\n"); } diff -Nbru clearsilver-0.4/cgi/cgi.h clearsilver-0.5/cgi/cgi.h --- clearsilver-0.4/cgi/cgi.h Sun Sep 9 16:53:10 2001 +++ clearsilver-0.5/cgi/cgi.h Thu Apr 11 18:11:39 2002 @@ -134,7 +134,8 @@ * the start of the file when first available. * Input: cgi - a pointer to a CGI struct allocated with cgi_init * form_name - the form name that the file was uploaded as - * (not the filename) + * (not the filename) (if NULL, we're asking for the + * file handle for the PUT upload) * Output: None * Return: A stdio FILE pointer, or NULL if an error occurs (usually * indicates that the form_name wasn't found, but might indicate @@ -196,6 +197,31 @@ NEOERR *cgi_url_escape (char *buf, char **esc); /* + * Function: cgi_url_escape_more - url escape a string + * Description: cgi_url_escape_more will do URL escaping on the passed in + * string, and return a newly allocated string that is escaped. + * Characters which are escaped include control characters, + * %, ?, +, space, =, &, /, and " and any characters in + * other + * Input: buf - a 0 terminated string + * other - a 0 terminated string of characters to escape + * Output: esc - a newly allocated string + * Return: NERR_NOMEM - no memory available to allocate the escaped string + */ +NEOERR *cgi_url_escape_more (char *buf, char **esc, char *other); + +/* + * 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 + * This function will decode any %XX character, and will + * decode + as space + * Input: buf - a 0 terminated string + * Return: pointer to same buf + */ +char *cgi_url_unescape (char *buf); + +/* * Function: cgi_redirect - send an HTTP 302 redirect response * Description: cgi_redirect will redirect the user to another page on * your site. This version takes only the path portion of @@ -306,5 +332,6 @@ /* internal use only */ NEOERR * parse_rfc2388 (CGI *cgi); +NEOERR * open_upload(CGI *cgi, int unlink_files, FILE **fpw); #endif /* __CGI_H_ */ diff -Nbru clearsilver-0.4/cgi/cgiwrap.c clearsilver-0.5/cgi/cgiwrap.c --- clearsilver-0.4/cgi/cgiwrap.c Fri Jan 11 15:42:08 2002 +++ clearsilver-0.5/cgi/cgiwrap.c Thu Feb 21 16:49:23 2002 @@ -178,7 +178,7 @@ { r = GlobalWrapper.writef_cb (GlobalWrapper.data, fmt, ap); if (r) - return nerr_raise (NERR_SYSTEM, "writef_cb returned %d", r); + return nerr_raise_errno (NERR_IO, "writef_cb returned %d", r); } else { @@ -196,14 +196,14 @@ { r = GlobalWrapper.write_cb (GlobalWrapper.data, buf, buf_len); if (r != buf_len) - return nerr_raise (NERR_IO, "write_cb returned %d<%d", r, buf_len); + return nerr_raise_errno (NERR_IO, "write_cb returned %d<%d", r, buf_len); } else { /* r = fwrite(buf, sizeof(char), buf_len, stderr); */ r = fwrite(buf, sizeof(char), buf_len, stdout); if (r != buf_len) - return nerr_raise (NERR_IO, "fwrite returned %d<%d", r, buf_len); + return nerr_raise_errno (NERR_IO, "fwrite returned %d<%d", r, buf_len); } return STATUS_OK; } diff -Nbru clearsilver-0.4/cgi/html.c clearsilver-0.5/cgi/html.c --- clearsilver-0.4/cgi/html.c Tue Nov 6 16:23:01 2001 +++ clearsilver-0.5/cgi/html.c Wed Mar 27 10:20:34 2002 @@ -55,6 +55,7 @@ return 0; } +/* static int has_long_lines (char *s, int l) { char *ptr; @@ -73,6 +74,7 @@ } return 0; } +*/ /* The first step is to actually find all of the URLs and email * addresses using our handy regular expressions. We then mark these, @@ -89,8 +91,8 @@ #define SC_TYPE_URL 2 #define SC_TYPE_EMAIL 3 -static char *EmailRe = "[^][@:;<>\\\"()[:space:][:cntrl:]]+@[-+a-zA-Z0-9].[-+a-zA-Z0-9.]+"; -static char *URLRe = "((((ht|f)tp)|mailto):(//)?[^[:space:]>\"\t]*|www\\.[-a-z0-9\\.]+)[^[:space:];\t\">]"; +static char *EmailRe = "[^][@:;<>\\\"()[:space:][:cntrl:]]+@[-+a-zA-Z0-9]+\\.[-+a-zA-Z0-9\\.]+[-+a-zA-Z0-9]"; +static char *URLRe = "((((ht|f)tp)|mailto):(//)?[^[:space:]>\"\t]*|www\\.[-a-z0-9\\.]+)[^[:space:];\t\">]*"; static NEOERR *split_and_convert (char *src, int slen, STRING *out, int newlines, int space_convert) { @@ -99,7 +101,7 @@ static regex_t email_re, url_re; regmatch_t email_match, url_match; int errcode; - char buf[256], *ptr; + char buf[256], *ptr, *esc; struct _parts *parts; int part_count; int part; @@ -337,12 +339,24 @@ } else { + if (spaces) + { + int sp; + for (sp = 0; sp < spaces - 1; sp++) + { + err = string_append (out, " "); + if (err != STATUS_OK) break; + } + if (err != STATUS_OK) break; + err = string_append_char (out, ' '); + } + spaces = 0; if (parts[i].type == SC_TYPE_URL) { char last_char = src[parts[i].end-1]; int suffix=0; if (last_char == '.' || last_char == ',') { suffix=1; } - err = string_append (out, " "); if (err != STATUS_OK) break; - err = string_appendn (out, src + x, parts[i].end - x - suffix); + err = html_escape_alloc(src + x, parts[i].end - x - suffix, &esc); if (err != STATUS_OK) break; - err = string_append (out, ""); + err = string_append (out, esc); + free(esc); + if (err != STATUS_OK) break; + err = string_append (out, ""); if (suffix) { err = string_appendn(out,src + parts[i].end - 1,1); if (err != STATUS_OK) break; @@ -363,15 +380,18 @@ } else /* type == SC_TYPE_EMAIL */ { - err = string_append (out, ""); if (err != STATUS_OK) break; - err = string_appendn (out, src + x, parts[i].end - x); + err = html_escape_alloc(src + x, parts[i].end - x, &esc); if (err != STATUS_OK) break; - err = string_append (out, ""); + err = string_append (out, esc); + free(esc); + if (err != STATUS_OK) break; + err = string_append (out, ""); } x = parts[i].end; i++; @@ -406,7 +426,7 @@ } else { - x = i = ptr - str->buf; + x = i = ptr - (char *) str->buf; if (x) { x--; @@ -447,7 +467,7 @@ } else { - int nl = has_long_lines (src, slen); + /* int nl = has_long_lines (src, slen); */ err = split_and_convert(src, slen, &out_s, 1, formatting); } } while (0); @@ -483,9 +503,9 @@ while (x < slen) { ptr = strpbrk(src + x, "&<>\"\r"); - if (ptr == NULL) + if (ptr == NULL || (ptr-src >= slen)) { - err = string_append (&out_s, src + x); + err = string_appendn (&out_s, src + x, slen-x); x = slen; } else diff -Nbru clearsilver-0.4/cgi/rfc2388.c clearsilver-0.5/cgi/rfc2388.c --- clearsilver-0.4/cgi/rfc2388.c Tue Oct 16 15:39:59 2001 +++ clearsilver-0.5/cgi/rfc2388.c Thu Apr 11 18:11:39 2002 @@ -260,6 +260,68 @@ return STATUS_OK; } +NEOERR *open_upload(CGI *cgi, int unlink_files, FILE **fpw) +{ + NEOERR *err = STATUS_OK; + FILE *fp; + char path[_POSIX_PATH_MAX]; + int fd; + + *fpw = NULL; + + snprintf (path, sizeof(path), "%s/cgi_upload.XXXXXX", + hdf_get_value(cgi->hdf, "Config.Upload.TmpDir", "/var/tmp")); + + fd = mkstemp(path); + if (fd == -1) + { + return nerr_raise_errno (NERR_SYSTEM, "Unable to open temp file %s", + path); + } + + fp = fdopen (fd, "w+"); + if (fp == NULL) + { + close(fd); + return nerr_raise_errno (NERR_SYSTEM, "Unable to fdopen file %s", path); + } + if (unlink_files) unlink(path); + if (cgi->files == NULL) + { + err = uListInit (&(cgi->files), 10, 0); + if (err) + { + fclose(fp); + return nerr_pass(err); + } + } + err = uListAppend (cgi->files, fp); + if (err) + { + fclose (fp); + return nerr_pass(err); + } + if (!unlink_files) { + if (cgi->filenames == NULL) + { + err = uListInit (&(cgi->filenames), 10, 0); + if (err) + { + fclose(fp); + return nerr_pass(err); + } + } + err = uListAppend (cgi->filenames, strdup(path)); + if (err) + { + fclose (fp); + return nerr_pass(err); + } + } + *fpw = fp; + return STATUS_OK; +} + static NEOERR * _read_part (CGI *cgi, char *boundary, int *done) { NEOERR *err = STATUS_OK; @@ -324,61 +386,10 @@ { if (filename) { - char path[_POSIX_PATH_MAX]; - int fd; - - snprintf (path, sizeof(path), "%s/cgi_upload.XXXXXX", - hdf_get_value(cgi->hdf, "Config.Upload.TmpDir", "/var/tmp")); - - fd = mkstemp(path); - if (fd == -1) - { - err = nerr_raise_errno (NERR_SYSTEM, "Unable to open temp file %s", - path); - break; + err = open_upload(cgi, unlink_files, &fp); + if (err) break; } - fp = fdopen (fd, "w+"); - if (fp == NULL) - { - close(fd); - err = nerr_raise_errno (NERR_SYSTEM, "Unable to fdopen file %s", path); - break; - } - if (unlink_files) unlink(path); - if (cgi->files == NULL) - { - err = uListInit (&(cgi->files), 10, 0); - if (err) - { - fclose(fp); - break; - } - } - err = uListAppend (cgi->files, fp); - if (err) - { - fclose (fp); - break; - } - if (!unlink_files) { - if (cgi->filenames == NULL) - { - err = uListInit (&(cgi->filenames), 10, 0); - if (err) - { - fclose(fp); - break; - } - } - err = uListAppend (cgi->filenames, strdup(path)); - if (err) - { - fclose (fp); - break; - } - } - } string_set(&str, ""); while (1) { @@ -509,8 +520,16 @@ char buf[256]; int n; + if ((form_name == NULL) || (form_name[0] == '\0')) + { + /* if NULL, then its the PUT data we're looking for... */ + n = hdf_get_int_value (cgi->hdf, "PUT.FileHandle", -1); + } + else + { snprintf (buf, sizeof(buf), "Query.%s.FileHandle", form_name); n = hdf_get_int_value (cgi->hdf, buf, -1); + } if (n == -1) return NULL; err = uListGet(cgi->files, n-1, (void **)&fp); if (err) diff -Nbru clearsilver-0.4/cs/Makefile clearsilver-0.5/cs/Makefile --- clearsilver-0.4/cs/Makefile Tue Nov 13 13:58:15 2001 +++ clearsilver-0.5/cs/Makefile Thu Mar 28 01:18:51 2002 @@ -23,7 +23,7 @@ TARGETS = $(CS_LIB) $(CSTEST_EXE) test -CS_TESTS = test.cs test2.cs test3.cs test4.cs test5.cs test6.cs test7.cs +CS_TESTS = test.cs test2.cs test3.cs test4.cs test5.cs test6.cs test7.cs test8.cs test9.cs test10.cs test11.cs all: $(TARGETS) diff -Nbru clearsilver-0.4/cs/cs.h clearsilver-0.5/cs/cs.h --- clearsilver-0.4/cs/cs.h Tue Nov 13 13:58:15 2001 +++ clearsilver-0.5/cs/cs.h Thu Mar 28 01:18:51 2002 @@ -66,23 +66,33 @@ CS_OP_DIV = (1<<13), CS_OP_MOD = (1<<14), + /* Associative Operators */ + CS_OP_LPAREN = (1<<15), + CS_OP_RPAREN = (1<<16), + CS_OP_LBRACKET = (1<<17), + CS_OP_RBRACKET = (1<<18), + + /* Types */ - CS_TYPE_STRING = (1<<15), - CS_TYPE_NUM = (1<<16), - CS_TYPE_VAR = (1<<17), - CS_TYPE_VAR_NUM = (1<<18), - CS_TYPE_MACRO = (1<<19), - CS_TYPE_EXPR = (1<<20), - CS_TYPE_STRING_ALLOC = (1<<21) + CS_TYPE_STRING = (1<<19), + CS_TYPE_NUM = (1<<20), + CS_TYPE_VAR = (1<<21), + CS_TYPE_VAR_NUM = (1<<22), + CS_TYPE_MACRO = (1<<23), + CS_TYPE_EXPR = (1<<24) } CSTOKEN_TYPE; -#define CS_TYPES (CS_TYPE_STRING | CS_TYPE_NUM | CS_TYPE_VAR | CS_TYPE_VAR_NUM | CS_TYPE_STRING_ALLOC) +#define CS_TYPES (CS_TYPE_STRING | CS_TYPE_NUM | CS_TYPE_VAR | CS_TYPE_VAR_NUM) +#define CS_TYPES_VAR (CS_TYPE_VAR | CS_TYPE_VAR_NUM) +#define CS_TYPES_CONST (CS_TYPE_STRING | CS_TYPE_NUM) +#define CS_ASSOC (CS_OP_RPAREN | CS_OP_RBRACKET) typedef struct _arg { CSTOKEN_TYPE op_type; char *s; long int n; + int alloc; struct _macro *macro; struct _arg *expr1; struct _arg *expr2; @@ -111,6 +121,7 @@ { CSTOKEN_TYPE type; char *name; + int alloc; union { char *s; diff -Nbru clearsilver-0.4/cs/csgrammer.y clearsilver-0.5/cs/csgrammer.y --- clearsilver-0.4/cs/csgrammer.y Sat Sep 15 00:05:21 2001 +++ clearsilver-0.5/cs/csgrammer.y Wed Dec 31 16:00:00 1969 @@ -1,51 +0,0 @@ - -file ::= contents. - -contents ::= LITERAL contents. -contents ::= command contents. -contents ::= LITERAL. -contents ::= command. - -command ::= CS_OPEN cmd CS_CLOSE. -command ::= if_cmd. -command ::= each_cmd. -command ::= def_cmd. - -cmd ::= VAR opt_req expr. -cmd ::= EVAR opt_req expr. -cmd ::= INCLUDE opt_req expr. -cmd ::= SET opt_req expr EQUALS expr. -cmd ::= CALL opt_req expr LPAREN comma_exprs RPAREN. - -if_cmd ::= CS_OPEN IF opt_req expr CS_CLOSE else_contents CS_OPEN ENDIF CS_CLOSE. -each_cmd ::= CS_OPEN EACH opt_req expr EQUALS expr CS_CLOSE contents CS_OPEN ENDEACH CS_CLOSE. -def_cmd ::= CS_OPEN DEF opt_req expr LPAREN comma_exprs RPAREN CS_CLOSE contents CS_OPEN ENDDEF CS_CLOSE. - -else_contents ::= contents else_contents. -else_contents ::= CS_OPEN ELIF opt_req expr CS_CLOSE else_contents. -else_contents ::= CS_OPEN ELSE CS_CLOSE contents. - -comma_exprs ::= expr COMMA comma_exprs. -comma_exprs ::= expr. - -expr ::= expr PLUS expr. -expr ::= expr MINUS expr. -expr ::= expr MULT expr. -expr ::= expr DIV expr. -expr ::= expr MOD expr. -expr ::= expr AND expr. -expr ::= expr OR expr. -expr ::= expr EQ expr. -expr ::= expr NE expr. -expr ::= expr GT expr. -expr ::= expr GE expr. -expr ::= expr LT expr. -expr ::= expr LE expr. -expr ::= NOT expr. -expr ::= NUM. -expr ::= STRING. -expr ::= VAR. -expr ::= VARNUM. - -opt_req ::= COLON. -opt_req ::= BANG. diff -Nbru clearsilver-0.4/cs/csparse.c clearsilver-0.5/cs/csparse.c --- clearsilver-0.4/cs/csparse.c Thu Jan 10 15:11:39 2002 +++ clearsilver-0.5/cs/csparse.c Thu Mar 28 17:40:56 2002 @@ -21,10 +21,15 @@ #include "util/neo_err.h" #include "util/neo_misc.h" +#include "util/neo_files.h" #include "util/neo_str.h" #include "util/ulist.h" #include "cs.h" +/* turn on some debug output for expressions */ +#define DEBUG_EXPR_PARSE 0 +#define DEBUG_EXPR_EVAL 0 + typedef enum { ST_SAME = 0, @@ -35,9 +40,10 @@ ST_POP = 1<<4, ST_DEF = 1<<5, ST_LOOP = 1<<6, + ST_ALT = 1<<7, } CS_STATE; -#define ST_ANYWHERE (ST_EACH | ST_ELSE | ST_IF | ST_GLOBAL | ST_DEF | ST_LOOP) +#define ST_ANYWHERE (ST_EACH | ST_ELSE | ST_IF | ST_GLOBAL | ST_DEF | ST_LOOP | ST_ALT) typedef struct _stack_entry { @@ -62,18 +68,18 @@ static NEOERR *endif_parse (CSPARSE *parse, int cmd, char *arg); static NEOERR *each_parse (CSPARSE *parse, int cmd, char *arg); static NEOERR *each_eval (CSPARSE *parse, CSTREE *node, CSTREE **next); -static NEOERR *endeach_parse (CSPARSE *parse, int cmd, char *arg); +static NEOERR *end_parse (CSPARSE *parse, int cmd, char *arg); static NEOERR *include_parse (CSPARSE *parse, int cmd, char *arg); static NEOERR *def_parse (CSPARSE *parse, int cmd, char *arg); static NEOERR *skip_eval (CSPARSE *parse, CSTREE *node, CSTREE **next); -static NEOERR *enddef_parse (CSPARSE *parse, int cmd, char *arg); static NEOERR *call_parse (CSPARSE *parse, int cmd, char *arg); 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 *alt_parse (CSPARSE *parse, int cmd, char *arg); +static NEOERR *alt_eval (CSPARSE *parse, CSTREE *node, CSTREE **next); static NEOERR *render_node (CSPARSE *parse, CSTREE *node); @@ -110,13 +116,13 @@ {"each", sizeof("each")-1, ST_ANYWHERE, ST_EACH, each_parse, each_eval, 1}, {"/each", sizeof("/each")-1, ST_EACH, ST_POP, - endeach_parse, skip_eval, 0}, + end_parse, skip_eval, 0}, {"include", sizeof("include")-1, ST_ANYWHERE, ST_SAME, include_parse, skip_eval, 1}, {"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}, + end_parse, skip_eval, 0}, {"call", sizeof("call")-1, ST_ANYWHERE, ST_SAME, call_parse, call_eval, 1}, {"set", sizeof("set")-1, ST_ANYWHERE, ST_SAME, @@ -124,7 +130,11 @@ {"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}, + end_parse, skip_eval, 1}, + {"alt", sizeof("alt")-1, ST_ANYWHERE, ST_ALT, + alt_parse, alt_eval, 1}, + {"/alt", sizeof("/alt")-1, ST_ALT, ST_POP, + end_parse, skip_eval, 1}, {NULL}, }; @@ -323,17 +333,15 @@ { FILE *fp; int err = 1; - char *context; char line[256]; int count = 0; int lineno = 0; - context = parse->context ? parse->context : ""; if (offset == -1) offset = parse->offset; do { - if (parse->in_file) + if (parse->in_file && parse->context) { /* Open the file and find which line we're on */ @@ -354,12 +362,20 @@ } else { + if (parse->context) snprintf (buf, blen, "[%s:%d]", parse->context, offset); + else + snprintf (buf, blen, "[offset:%d]", offset); } err = 0; } while (0); if (err) + { + if (parse->context) snprintf (buf, blen, "[-E- %s:%d]", parse->context, offset); + else + snprintf (buf, blen, "[-E- offset:%d]", offset); + } return buf; } @@ -378,6 +394,10 @@ return "EACH"; else if (state & ST_DEF) return "DEF"; + else if (state & ST_LOOP) + return "LOOP"; + else if (state & ST_ALT) + return "ALT"; snprintf(buf, sizeof(buf), "Unknown state %d", state); return buf; @@ -532,6 +552,8 @@ CS_LOCAL_MAP *map; char *c; + /* This shouldn't happen, but it did once... */ + if (name == NULL) return NULL; map = parse->locals; c = strchr (name, '.'); if (c != NULL) *c = '\0'; @@ -621,6 +643,8 @@ /* Hmm, if c != NULL, they are asking for a sub member of something * which isn't a var... right now we ignore them, I don't know what * the right thing is */ + /* hmm, its possible now that they are getting a reference to a + * string that will be deleted... where is it used? */ else if (map->type == CS_TYPE_STRING) { return map->value.s; @@ -674,6 +698,10 @@ { FALSE, "*", CS_OP_MULT }, { FALSE, "/", CS_OP_DIV }, { FALSE, "%", CS_OP_MOD }, + { FALSE, "(", CS_OP_LPAREN }, + { FALSE, ")", CS_OP_RPAREN }, + { FALSE, "[", CS_OP_LBRACKET }, + { FALSE, "]", CS_OP_RBRACKET }, { FALSE, NULL, 0 } }; @@ -780,15 +808,57 @@ CS_OP_GT | CS_OP_GTE | CS_OP_LT | CS_OP_LTE, CS_OP_ADD | CS_OP_SUB, CS_OP_MULT | CS_OP_DIV | CS_OP_MOD, + CS_OP_LBRACKET, 0 }; +static char *expand_token_type(CSTOKEN_TYPE t_type) +{ + switch (t_type) + { + case CS_OP_EXISTS: return "?"; + case CS_OP_NOT: return "!"; + case CS_OP_EQUAL: return "=="; + case CS_OP_NEQUAL: return "!="; + case CS_OP_LT: return "<"; + case CS_OP_LTE: return "<="; + case CS_OP_GT: return ">"; + case CS_OP_GTE: return ">="; + case CS_OP_AND: return "&&"; + case CS_OP_OR: return "||"; + case CS_OP_ADD: return "+"; + case CS_OP_SUB: return "-"; + case CS_OP_MULT: return "*"; + case CS_OP_DIV: return "/"; + case CS_OP_MOD: return "%"; + case CS_OP_LPAREN: return "("; + case CS_OP_RPAREN: return ")"; + case CS_OP_LBRACKET: return "["; + case CS_OP_RBRACKET: return "]"; + case CS_TYPE_STRING: return "s"; + case CS_TYPE_NUM: return "n"; + case CS_TYPE_VAR: return "v"; + case CS_TYPE_VAR_NUM: return "vn"; + default: return "u"; + } + return "u"; +} + static NEOERR *parse_expr2 (CSPARSE *parse, CSTOKEN *tokens, int ntokens, CSARG *arg) { NEOERR *err; char tmp[256]; int x, op = 0; + int m; + +#if DEBUG_EXPR_PARSE + for (x = 0; x < ntokens; x++) + { + fprintf (stderr, "%s ", expand_token_type(tokens[x].type)); + } + fprintf(stderr, "\n"); +#endif if (ntokens == 1 || (ntokens == 2 && tokens[0].type == CS_OP_NOT)) { @@ -809,8 +879,8 @@ 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); + "%s Terminal token is not an argument, type is %s", + find_context(parse, -1, tmp, sizeof(tmp)), expand_token_type(tokens[0].type)); } } @@ -819,6 +889,52 @@ x = ntokens-1; while (x >= 0) { + /* handle associative ops by skipping through the entire set here, + * ie the whole thing is an expression that can't match a binary op */ + if (tokens[x].type & CS_OP_RPAREN) + { + m = 1; + x--; + while (x >= 0) + { + if (tokens[x].type & CS_OP_RPAREN) m++; + if (tokens[x].type & CS_OP_LPAREN) m--; + if (m == 0) break; + x--; + } + if (m) + return nerr_raise (NERR_PARSE, + "%s Missing left parenthesis in expression", + find_context(parse, -1, tmp, sizeof(tmp))); + if (x == 0) break; + x--; + } + if (tokens[x].type & CS_OP_RBRACKET) + { + m = 1; + x--; + while (x >= 0) + { + if (tokens[x].type & CS_OP_RBRACKET) m++; + if (tokens[x].type & CS_OP_LBRACKET) m--; + if (m == 0) break; + x--; + } + if (m) + return nerr_raise (NERR_PARSE, + "%s Missing left bracket in expression", + find_context(parse, -1, tmp, sizeof(tmp))); + if (x == 0) break; + /* we don't do an x-- here, because we are special casing the + * left bracket to be both an operator and an associative */ + } + else if (tokens[x].type & (CS_OP_LBRACKET | CS_OP_LPAREN)) + { + return nerr_raise (NERR_PARSE, + "%s Missing right %s in expression", + find_context(parse, -1, tmp, sizeof(tmp)), + (tokens[x].type == CS_OP_LBRACKET) ? "bracket" : "parenthesis"); + } if (tokens[x].type & BinaryOpOrder[op]) { arg->op_type = tokens[x].type; @@ -828,7 +944,14 @@ return nerr_raise (NERR_NOMEM, "%s Unable to allocate memory for expression", find_context(parse, -1, tmp, sizeof(tmp))); + if (tokens[x].type == CS_OP_LBRACKET) + { + err = parse_expr2(parse, tokens + x, ntokens-x, arg->expr2); + } + else + { 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); @@ -838,6 +961,15 @@ } op++; } + /* ah, this expression just contains enclosing associatives, strip them */ + x = ntokens-1; + if ((tokens[0].type == CS_OP_LPAREN && tokens[x].type == CS_OP_RPAREN) || + (tokens[0].type == CS_OP_LBRACKET && tokens[x].type == CS_OP_RBRACKET)) + { + /* parens don't do anything, just strip them and pass */ + return nerr_pass(parse_expr2(parse, tokens + 1, ntokens-2, arg)); + } + return nerr_raise (NERR_PARSE, "%s Bad Expression", find_context(parse, -1, tmp, sizeof(tmp))); } @@ -964,6 +1096,33 @@ return STATUS_OK; } +static NEOERR *alt_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->case_0); + parse->current = node; + + return STATUS_OK; +} + static NEOERR *evar_parse (CSPARSE *parse, int cmd, char *arg) { NEOERR *err; @@ -1058,16 +1217,13 @@ switch ((arg->op_type & CS_TYPES)) { case CS_TYPE_STRING: - case CS_TYPE_STRING_ALLOC: return arg->s; case CS_TYPE_VAR: return var_lookup (parse, arg->s); case CS_TYPE_NUM: case CS_TYPE_VAR_NUM: - /* These types should force numeric evaluation... so nothing - * should get here */ default: - ne_warn ("Unsupported type %s in arg_eval", arg->op_type); + ne_warn ("Unsupported type %d in arg_eval", arg->op_type); return NULL; } } @@ -1080,7 +1236,6 @@ switch ((arg->op_type & CS_TYPES)) { case CS_TYPE_STRING: - case CS_TYPE_STRING_ALLOC: v = strtol(arg->s, NULL, 0); break; case CS_TYPE_NUM: @@ -1101,33 +1256,98 @@ return v; } +#if DEBUG_EXPR_EVAL +static char *expand_arg (CSARG *arg) +{ + fprintf(stderr, "op: %s alloc: %d value: ", expand_token_type(arg->op_type), arg->alloc); + if (arg->op_type & CS_OP_NOT) + fprintf(stderr, "!"); + if (arg->op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM)) + fprintf(stderr, "#"); + if (arg->op_type & CS_TYPE_NUM) + fprintf(stderr, "%ld\n", arg->n); + else if (arg->op_type & (CS_TYPE_VAR_NUM | CS_TYPE_VAR | CS_TYPE_STRING)) + fprintf(stderr, "%s\n", arg->s); + else + fprintf(stderr, "\n"); +} +#endif + static NEOERR *eval_expr (CSPARSE *parse, CSARG *expr, CSARG *result) { + CSARG arg1, arg2; + NEOERR *err; + long int n1, n2; + char *s1, *s2; + int out; + +#if DEBUG_EXPR_EVAL + fprintf(stderr, "expr "); + expand_arg(expr); +#endif + 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; + if (expr->alloc) expr->alloc = 0; +#if DEBUG_EXPR_EVAL + fprintf(stderr, "result "); + expand_arg(result); +#endif return STATUS_OK; } else { - CSARG arg1, arg2; - NEOERR *err; - err = eval_expr (parse, expr->expr1, &arg1); if (err) return nerr_pass(err); +#if DEBUG_EXPR_EVAL + fprintf(stderr, "arg1 "); + expand_arg(&arg1); +#endif err = eval_expr (parse, expr->expr2, &arg2); +#if DEBUG_EXPR_EVAL + fprintf(stderr, "arg2 "); + expand_arg(&arg2); +#endif if (err) return nerr_pass(err); - /* Check for type conversion */ - if ((arg1.op_type & (CS_OP_NOT | CS_TYPE_NUM | CS_TYPE_VAR_NUM)) || + + if (expr->op_type == CS_OP_LBRACKET) + { + /* the bracket op is essentially hdf array lookups, which just + * means appending .0 */ + result->op_type = CS_TYPE_VAR; + result->alloc = 1; + if (arg2.op_type & (CS_TYPE_VAR_NUM | CS_TYPE_NUM)) + { + n2 = arg_eval_num (parse, &arg2); + result->s = sprintf_alloc("%s.%d", arg1.s, n2); + if (result->s == NULL) + return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %d", arg1.s, n2); + } + else + { + s2 = arg_eval (parse, &arg2); + if (s2 && s2[0]) + { + result->s = sprintf_alloc("%s.%s", arg1.s, s2); + if (result->s == NULL) + return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate varnames in expression: %s + %s", arg1.s, s2); + } + else + { + /* if s2 doesn't match anything, then the whole thing is empty */ + result->s = ""; + result->alloc = 0; + } + } + } + else if ((arg1.op_type & (CS_OP_NOT | CS_TYPE_NUM | CS_TYPE_VAR_NUM)) || (arg2.op_type & (CS_OP_NOT | CS_TYPE_NUM | CS_TYPE_VAR_NUM)) || (expr->op_type & (CS_OP_AND | CS_OP_OR | CS_OP_SUB | CS_OP_MULT | CS_OP_DIV | CS_OP_MOD))) { /* eval as num */ - long int n1, n2; result->op_type = CS_TYPE_NUM; n1 = arg_eval_num (parse, &arg1); @@ -1183,9 +1403,6 @@ } else /* eval as string */ { - char *s1, *s2; - int out; - result->op_type = CS_TYPE_NUM; s1 = arg_eval (parse, &arg1); s2 = arg_eval (parse, &arg2); @@ -1213,17 +1430,19 @@ result->n = (s2 == NULL) ? 1 : 0; break; case CS_OP_ADD: + /* be sure to transfer ownership of the string here */ + result->op_type = CS_TYPE_STRING; if (s1 == NULL) { result->s = s2; - result->op_type = arg2.op_type; - arg2.op_type = CS_TYPE_STRING; + result->alloc = arg2.alloc; + arg2.alloc = 0; } else { result->s = s1; - result->op_type = arg1.op_type; - arg1.op_type = CS_TYPE_STRING; + result->alloc = arg1.alloc; + arg1.alloc = 0; } break; default: @@ -1255,7 +1474,8 @@ result->n = (out >= 0) ? 1 : 0; break; case CS_OP_ADD: - result->op_type = CS_TYPE_STRING_ALLOC; + result->op_type = CS_TYPE_STRING; + result->alloc = 1; result->s = (char *) calloc ((strlen(s1) + strlen(s2) + 1), sizeof(char)); if (result->s == NULL) return nerr_raise (NERR_NOMEM, "Unable to allocate memory to concatenate strings in expression: %s + %s", s1, s2); @@ -1263,17 +1483,19 @@ strcat(result->s, s2); break; default: - ne_warn ("Unsupported op %d in expr_eval", expr->op_type); + ne_warn ("Unsupported op %d in eval_expr", expr->op_type); break; } } } - if (arg1.op_type == CS_TYPE_STRING_ALLOC) - free(arg1.s); - if (arg2.op_type == CS_TYPE_STRING_ALLOC) - free(arg2.s); + if (arg1.alloc) free(arg1.s); + if (arg2.alloc) free(arg2.s); } +#if DEBUG_EXPR_EVAL + fprintf(stderr, "result "); + expand_arg(result); +#endif return STATUS_OK; } @@ -1302,8 +1524,64 @@ err = parse->output_cb (parse->output_ctx, s); } } - if (val.op_type == CS_TYPE_STRING_ALLOC) - free(val.s); + if (val.alloc) free(val.s); + + *next = node->next; + return nerr_pass(err); +} + +/* if the expr evaluates to true, display it, else render the alternate */ +static NEOERR *alt_eval (CSPARSE *parse, CSTREE *node, CSTREE **next) +{ + NEOERR *err = STATUS_OK; + CSARG val; + int eval_true = 1; + + 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); + if (n_val) + { + snprintf (buf, sizeof(buf), "%ld", n_val); + err = parse->output_cb (parse->output_ctx, buf); + } + else + { + eval_true = 0; + } + } + else + { + char *s; + BOOL not = FALSE; + if (val.op_type & CS_OP_NOT) + { + not = TRUE; + val.op_type &= ~CS_OP_NOT; + } + s = arg_eval (parse, &val); + if (s == NULL || *s == '\0') + eval_true = 0; + + if (not == TRUE) + eval_true = !eval_true; + + if (eval_true && s) + { + err = parse->output_cb (parse->output_ctx, s); + } + } + if (val.alloc) free(val.s); + + if (eval_true == 0) + { + err = render_node (parse, node->case_0); + } *next = node->next; return nerr_pass(err); @@ -1338,8 +1616,7 @@ if (not == TRUE) eval_true = !eval_true; } - if (val.op_type == CS_TYPE_STRING_ALLOC) - free(val.s); + if (val.alloc) free(val.s); if (eval_true) { @@ -1455,9 +1732,12 @@ node->arg1.op_type = CS_TYPE_VAR; node->arg1.s = lvar; - node->arg2.op_type = CS_TYPE_VAR; - node->arg2.s = p; - + err = parse_expr(parse, p, &(node->arg2)); + if (err) + { + dealloc_node(&node); + return nerr_pass(err); + } /* ne_warn ("each %s %s", lvar, p); */ *(parse->next) = node; @@ -1471,9 +1751,15 @@ { NEOERR *err = STATUS_OK; CS_LOCAL_MAP each_map; + CSARG val; HDF *var, *child; - var = var_lookup_obj (parse, node->arg2.s); + err = eval_expr(parse, &(node->arg2), &val); + if (err) return nerr_pass(err); + + if (val.op_type == CS_TYPE_VAR) + { + var = var_lookup_obj (parse, val.s); if (var != NULL) { @@ -1499,12 +1785,14 @@ /* Remove local map */ parse->locals = each_map.next; } + } /* else WARNING */ + if (val.alloc) free(val.s); *next = node->next; return nerr_pass (err); } -static NEOERR *endeach_parse (CSPARSE *parse, int cmd, char *arg) +static NEOERR *end_parse (CSPARSE *parse, int cmd, char *arg) { NEOERR *err; STACK_ENTRY *entry; @@ -1703,19 +1991,6 @@ return STATUS_OK; } -static NEOERR *enddef_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 *call_parse (CSPARSE *parse, int cmd, char *arg) { NEOERR *err; @@ -1843,36 +2118,74 @@ for (x = 0; x < macro->n_args; x++) { + CSARG val; map = &call_map[x]; if (x) call_map[x-1].next = map; map->name = darg->s; - if (carg->op_type == CS_TYPE_STRING) + err = eval_expr(parse, carg, &val); + if (err) break; + if (val.op_type & CS_TYPE_STRING) { - map->value.s = carg->s; - map->type = CS_TYPE_STRING; + map->value.s = val.s; + map->type = val.op_type; + map->alloc = val.alloc; + val.alloc = 0; } - else if (carg->op_type == CS_TYPE_NUM) + else if (val.op_type & CS_TYPE_NUM) { - map->value.n = carg->n; + map->value.n = val.n; map->type = CS_TYPE_NUM; } + else if (val.op_type & (CS_TYPE_VAR | CS_TYPE_VAR_NUM)) + { + CS_LOCAL_MAP *lmap; + char *c; + lmap = lookup_map (parse, val.s, &c); + if (lmap != NULL && (lmap->type != CS_TYPE_VAR && lmap->type != CS_TYPE_VAR_NUM)) + { + /* if we're referencing a local var which maps to a string or + * number... then copy */ + if (lmap->type == CS_TYPE_NUM) + { + map->value.n = lmap->value.n; + map->type = lmap->type; + } else { - var = var_lookup_obj (parse, carg->s); + map->value.s = lmap->value.s; + map->type = lmap->type; + } + } + else + { + var = var_lookup_obj (parse, val.s); map->value.h = var; map->type = CS_TYPE_VAR; } + } + else + { + ne_warn("Unsupported type %d in call_expr", val.op_type); + } + if (val.alloc) free(val.s); map->next = parse->locals; darg = darg->next; carg = carg->next; } + if (err == STATUS_OK) + { map = parse->locals; if (macro->n_args) parse->locals = call_map; err = render_node (parse, macro->tree->case_0); parse->locals = map; + } + for (x = 0; x < macro->n_args; x++) + { + if (call_map[x].alloc) free(call_map[x].value.s); + } free (call_map); *next = node->next; @@ -1885,32 +2198,28 @@ CSTREE *node; char *s; char tmp[256]; - char name[256]; - int x = 0; err = alloc_node (&node); if (err) return nerr_pass(err); node->cmd = cmd; arg++; s = arg; - while (*s && isspace(*s)) s++; - while (x < 256 && *s && *s != ' ' && *s != '#' && *s != '=') - { - name[x++] = *s; - s++; - } - name[x] = '\0'; - while (*s && isspace(*s)) s++; - if (*s == '\0' || *s != '=') + while (*s && *s != '=') s++; + if (*s == '\0') { dealloc_node(&node); return nerr_raise (NERR_PARSE, "%s Missing equals in set %s", find_context(parse, -1, tmp, sizeof(tmp)), arg); } + *s = '\0'; s++; - node->arg1.op_type = CS_TYPE_VAR; - node->arg1.s = strdup(name); + err = parse_expr(parse, arg, &(node->arg1)); + if (err) + { + dealloc_node(&node); + return nerr_pass(err); + } err = parse_expr(parse, s, &(node->arg2)); if (err) @@ -1930,10 +2239,20 @@ { NEOERR *err = STATUS_OK; CSARG val; + CSARG set; - err = eval_expr(parse, &(node->arg2), &val); + err = eval_expr(parse, &(node->arg1), &set); if (err) return nerr_pass (err); + err = eval_expr(parse, &(node->arg2), &val); + if (err) { + if (set.alloc) free(set.s); + return nerr_pass (err); + } + if (set.op_type != CS_TYPE_NUM) + { + /* this allow for a weirdness where set:"foo"="bar" + * actually sets the hdf var foo... */ if (val.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) { char buf[256]; @@ -1941,7 +2260,7 @@ n_val = arg_eval_num (parse, &val); snprintf (buf, sizeof(buf), "%ld", n_val); - err = var_set_value (parse, node->arg1.s, buf); + err = var_set_value (parse, set.s, buf); } else { @@ -1949,11 +2268,12 @@ /* Do we set it to blank if s == NULL? */ if (s) { - err = var_set_value (parse, node->arg1.s, s); + err = var_set_value (parse, set.s, s); } } - if (val.op_type == CS_TYPE_STRING_ALLOC) - free(val.s); + } /* else WARNING */ + if (set.alloc) free(set.s); + if (val.alloc) free(val.s); *next = node->next; return nerr_pass (err); @@ -2075,7 +2395,7 @@ 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 (val.alloc) free(val.s); if (carg->next) { start = end; @@ -2083,14 +2403,14 @@ 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 (val.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); + if (val.alloc) free(val.s); } } /* automatically handle cases where the step is backwards */ @@ -2133,18 +2453,6 @@ *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.4/cs/test.hdf clearsilver-0.5/cs/test.hdf --- clearsilver-0.4/cs/test.hdf Sat Sep 15 17:08:55 2001 +++ clearsilver-0.5/cs/test.hdf Thu Mar 28 17:40:56 2002 @@ -60,3 +60,22 @@ My.Test2 : Days.0 Color = #fffff + +CGI.box.msgs { + 0 { + ticket_id = 1 + } + 1 { + ticket_id = 2 + } + 2 { + ticket_id = 3 + } +} + +Query.boxid = 2 +Query.split = 1 +Query.filter = 0 +Query.sort = t +Query.sort_dir = u +CGI.box.cur.min_box_idx = 1 diff -Nbru clearsilver-0.4/cs/test10.cs clearsilver-0.5/cs/test10.cs --- clearsilver-0.4/cs/test10.cs Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/cs/test10.cs Wed Mar 13 00:31:27 2002 @@ -0,0 +1,22 @@ +test new alt tag + + +this should always display [1] + + + +ERROR: this shouldn't display (static string) + + + +ERROR: this should never display (#1) + + + + +ERROR: this should never display (Foo.Bar.Baz.0 exists) + + + +This should display [3] + diff -Nbru clearsilver-0.4/cs/test10.cs.gold clearsilver-0.5/cs/test10.cs.gold --- clearsilver-0.4/cs/test10.cs.gold Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/cs/test10.cs.gold Wed Mar 13 00:31:27 2002 @@ -0,0 +1,17 @@ +Parsing test10.cs +test new alt tag + + +this should always display [1] + + +this should display [2] + +1 + +zero +zero + + +This should display [3] + diff -Nbru clearsilver-0.4/cs/test11.cs clearsilver-0.5/cs/test11.cs --- clearsilver-0.4/cs/test11.cs Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/cs/test11.cs Thu Mar 28 01:18:52 2002 @@ -0,0 +1,34 @@ + +testing parenthesis for order of operations + + == 40 + == 7 + == 19 + == 35 + == 40 + == 40 + == 81 + == 46 + == 49 + +testing brackets for hdf var arrays + + + + + == 0 + == 1 + == 2 + + == Mon + == Tues + == Wed + + + == 2 3 + + + == + + + diff -Nbru clearsilver-0.4/cs/test11.cs.gold clearsilver-0.5/cs/test11.cs.gold --- clearsilver-0.4/cs/test11.cs.gold Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/cs/test11.cs.gold Thu Mar 28 01:18:52 2002 @@ -0,0 +1,73 @@ +Parsing test11.cs + +testing parenthesis for order of operations + +40 == 40 +7 == 7 +19 == 19 +35 == 35 +40 == 40 +40 == 40 +81 == 81 +46 == 46 +49 == 49 + +testing brackets for hdf var arrays + + +9 + +0 == 0 +1 == 1 +2 == 2 + +Mon == Mon +Tues == Tues +Wed == Wed + + + 2 3 == 2 3 + + +1 == 1 +2 == 2 +3 == 3 +4 == 4 +5 == 5 +6 == 6 +7 == 7 +8 == 8 +9 == 9 +10 == 10 +11 == 11 +12 == 12 +13 == 13 +14 == 14 +15 == 15 +16 == 16 +17 == 17 +18 == 18 +19 == 19 +20 == 20 + +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 + diff -Nbru clearsilver-0.4/cs/test11.cs.out clearsilver-0.5/cs/test11.cs.out --- clearsilver-0.4/cs/test11.cs.out Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/cs/test11.cs.out Thu Mar 28 01:18:52 2002 @@ -0,0 +1,73 @@ +Parsing test11.cs + +testing parenthesis for order of operations + +40 == 40 +7 == 7 +19 == 19 +35 == 35 +40 == 40 +40 == 40 +81 == 81 +46 == 46 +49 == 49 + +testing brackets for hdf var arrays + + +9 + +0 == 0 +1 == 1 +2 == 2 + +Mon == Mon +Tues == Tues +Wed == Wed + + + 2 3 == 2 3 + + +1 == 1 +2 == 2 +3 == 3 +4 == 4 +5 == 5 +6 == 6 +7 == 7 +8 == 8 +9 == 9 +10 == 10 +11 == 11 +12 == 12 +13 == 13 +14 == 14 +15 == 15 +16 == 16 +17 == 17 +18 == 18 +19 == 19 +20 == 20 + +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 + diff -Nbru clearsilver-0.4/cs/test3.cs clearsilver-0.5/cs/test3.cs --- clearsilver-0.4/cs/test3.cs Thu Jul 5 01:23:13 2001 +++ clearsilver-0.5/cs/test3.cs Wed Mar 27 16:47:28 2002 @@ -34,10 +34,47 @@ before echo echo a variable: 3 - + echo a string: hellow world echo a number: 5 + + + + +echo a variable: 3 + +echo a string: hellow world + +echo a number: 5 + + + + + + + + + + +these tests show that local variables are live in sub calls +echo a variable: 3 + +echo a string: hellow world + +echo a number: 5 + + after echo + + + == + + +testing macro calls in local vars in an each + + + + diff -Nbru clearsilver-0.4/cs/test3.cs.gold clearsilver-0.5/cs/test3.cs.gold --- clearsilver-0.4/cs/test3.cs.gold Fri Jul 6 00:29:42 2001 +++ clearsilver-0.5/cs/test3.cs.gold Wed Mar 27 16:47:28 2002 @@ -34,15 +34,114 @@ echo a variable: 3 + 3 + +echo a string: hellow world + + hello world + +echo a number: 5 + + 5 + + + + +echo a variable: 3 + + + 3 echo a string: hellow world + hello world + echo a number: 5 + 5 + + + + + +these tests show that local variables are live in sub calls +echo a variable: 3 + + + 3 + + +echo a string: hellow world + + + hello world + + +echo a number: 5 + + + 5 + + + after echo + + + +testing macro calls in local vars in an each + + + 0 == Mon + + + Mon + + + + 1 == Tues + + + Tues + + + + 2 == Wed + + + Wed + + + + 3 == Thur + + + Thur + + + + 4 == Fri + + + Fri + + + + 5 == Sat + + + Sat + + + + 6 == Sun + + + Sun + + diff -Nbru clearsilver-0.4/cs/test4.cs clearsilver-0.5/cs/test4.cs --- clearsilver-0.4/cs/test4.cs Tue Jul 3 17:43:05 2001 +++ clearsilver-0.5/cs/test4.cs Thu Mar 28 17:40:56 2002 @@ -48,3 +48,54 @@ right, 4 > 0 + + +right, 0 <= 5 + +ERROR! 0 <= 5 + + += #5 ?> +ERROR! 0 >= 5 + +right, 0 >= 5 + + + +right "0" <= #5 + +ERROR! "0" <= #5 + + + + + + + + + + + + + + + + + + + + diff -Nbru clearsilver-0.4/cs/test4.cs.gold clearsilver-0.5/cs/test4.cs.gold --- clearsilver-0.4/cs/test4.cs.gold Sat Sep 15 16:38:40 2001 +++ clearsilver-0.5/cs/test4.cs.gold Thu Mar 28 17:40:56 2002 @@ -43,3 +43,58 @@ right, 4 > 0 + + +right, 0 <= 5 + + + +right, 0 >= 5 + + + +right "0" <= #5 + + + + + + + +/box_bm_body_frm.cs?boxid=2&cur=1&idx_cur=1&split=1&filter=0&sort=t&sort_dir=u&from_search= + + + + + +/box_bm_body_frm.cs?boxid=2&cur=2&idx_cur=1&split=1&filter=0&sort=t&sort_dir=u&from_search= + + + + + +/box_bm_body_frm.cs?boxid=2&cur=3&idx_cur=1&split=1&filter=0&sort=t&sort_dir=u&from_search= + + + + + + + +/box_bm_body_frm.cs?boxid=&cur=1&idx_cur=1&split=&filter=&sort=&sort_dir=&from_search= + + + + + +/box_bm_body_frm.cs?boxid=&cur=2&idx_cur=1&split=&filter=&sort=&sort_dir=&from_search= + + + + + +/box_bm_body_frm.cs?boxid=&cur=3&idx_cur=1&split=&filter=&sort=&sort_dir=&from_search= + + + + diff -Nbru clearsilver-0.4/cs/test8.cs clearsilver-0.5/cs/test8.cs --- clearsilver-0.4/cs/test8.cs Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/cs/test8.cs Wed Mar 13 00:27:11 2002 @@ -0,0 +1,10 @@ + +some tests for new var is an expression + + + + + + + + diff -Nbru clearsilver-0.4/cs/test8.cs.gold clearsilver-0.5/cs/test8.cs.gold --- clearsilver-0.4/cs/test8.cs.gold Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/cs/test8.cs.gold Wed Mar 13 00:27:11 2002 @@ -0,0 +1,11 @@ +Parsing test8.cs + +some tests for new var is an expression + +5 + +6 + +big is better + +wow potato zero diff -Nbru clearsilver-0.4/cs/test9.cs clearsilver-0.5/cs/test9.cs --- clearsilver-0.4/cs/test9.cs Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/cs/test9.cs Wed Mar 13 00:27:11 2002 @@ -0,0 +1,6 @@ +Test for bug where in certain cases we didn't find the ending cs tag if +there was a newline + + + diff -Nbru clearsilver-0.4/cs/test9.cs.gold clearsilver-0.5/cs/test9.cs.gold --- clearsilver-0.4/cs/test9.cs.gold Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/cs/test9.cs.gold Wed Mar 13 00:27:11 2002 @@ -0,0 +1,5 @@ +Parsing test9.cs +Test for bug where in certain cases we didn't find the ending cs tag if +there was a newline + + Binary files clearsilver-0.4/imd/0.gif and clearsilver-0.5/imd/0.gif differ Binary files clearsilver-0.4/imd/1.gif and clearsilver-0.5/imd/1.gif differ Binary files clearsilver-0.4/imd/2.gif and clearsilver-0.5/imd/2.gif differ Binary files clearsilver-0.4/imd/3.gif and clearsilver-0.5/imd/3.gif differ Binary files clearsilver-0.4/imd/4.gif and clearsilver-0.5/imd/4.gif differ Binary files clearsilver-0.4/imd/5.gif and clearsilver-0.5/imd/5.gif differ Binary files clearsilver-0.4/imd/6.gif and clearsilver-0.5/imd/6.gif differ Binary files clearsilver-0.4/imd/7.gif and clearsilver-0.5/imd/7.gif differ diff -Nbru clearsilver-0.4/imd/Makefile clearsilver-0.5/imd/Makefile --- clearsilver-0.4/imd/Makefile Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/imd/Makefile Sat Dec 30 01:57:16 2000 @@ -0,0 +1,28 @@ + + +ifeq ($(NEOTONIC_ROOT),) +NEOTONIC_ROOT = ../ +endif + +include $(NEOTONIC_ROOT)rules.mk + +IMD_EXE = imd.cgi +IMD_SRC = imd.c +IMD_OBJ = $(IMD_SRC:%.c=%.o) + +CFLAGS += -I$(NEOTONIC_ROOT) -I/usr/local/include +DLIBS += -lneo_cgi -lneo_cs -lneo_utl # -lefence +LIBS += -L$(LIB_DIR) $(DLIBS) -L/usr/local/lib -lgd -ljpeg -lz + +TARGETS = $(IMD_EXE) + +all: $(TARGETS) + +$(IMD_EXE): $(IMD_OBJ) $(DEP_LIBS) + $(LD) $@ $(IMD_OBJ) $(LIBS) + +clean: + $(RM) *.o + +distclean: + $(RM) $(TARGETS) *.o diff -Nbru clearsilver-0.4/imd/README clearsilver-0.5/imd/README --- clearsilver-0.4/imd/README Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/imd/README Sat Dec 30 01:57:16 2000 @@ -0,0 +1,14 @@ + +To set up imd, you need to add the following directives to an apache +conf file. If you have sufficient permissions, you can add these to the +.htaccess files for an image directory: + +AddHandler cgi-script .cgi +AddHandler imd-handler .imd +Action imd-handler /url/path/to/imd.cgi + +Then, copy example.imd to somewhere in your URL space, and modify the +settings in there. You will probably need to modify Template to point +to the installed location of the imd.cs file. You can personalize the +imd.cs file to personalize your image server. + diff -Nbru clearsilver-0.4/imd/example.imd clearsilver-0.5/imd/example.imd --- clearsilver-0.4/imd/example.imd Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/imd/example.imd Sat Feb 2 20:08:47 2002 @@ -0,0 +1,22 @@ +# Location of the image albums (an album is a directory of images +# so this is a directory of directories of imaages) +BASEDIR = /home/blong/images + +# Full Path to the CS template file used for display +Template=/home/blong/public_html/Images/imd.cs + +# Scaling sizes. imd will scale the image to be at or below this size +# Thumb is for the thumbnails, and Picture is for individual pictures +ThumbWidth = 120 +ThumbHeight = 90 +PictureWidth = 600 +PictureHeight = 450 + +# Number of thumbnails to show per page +PerPage = 50 + +# Assumed browser width for album show +PageWidth = 640 + +# Image Server Title +Title = My Pictures diff -Nbru clearsilver-0.4/imd/imd.c clearsilver-0.5/imd/imd.c --- clearsilver-0.4/imd/imd.c Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/imd/imd.c Mon Feb 11 12:16:23 2002 @@ -0,0 +1,1110 @@ +/* + * IMD image server + * + * Neotonic ClearSilver Templating System + * + * This code is made available under the terms of the FSF's + * Library Gnu Public License (LGPL). + * + * Copyright (C) 2001 by Brandon Long + */ + +/* Bring in gd library functions */ +#include "gd.h" + +/* Bring in standard I/O so we can output the PNG to a file */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cgi/cgi.h" +#include "cgi/cgiwrap.h" +#include "util/neo_misc.h" + +/* from httpd util.c : made infamous with Roy owes Rob beer. */ +static char *months[] = { + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +int find_month(char *mon) { + register int x; + + for(x=0;x<12;x++) + if(!strcmp(months[x],mon)) + return x; + return -1; +} + +int later_than(struct tm *lms, char *ims) { + char *ip; + char mname[256]; + int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, x; + + /* Whatever format we're looking at, it will start + * with weekday. */ + /* Skip to first space. */ + if(!(ip = strchr(ims,' '))) + return 0; + else + while(isspace(*ip)) + ++ip; + + if(isalpha(*ip)) { + /* ctime */ + sscanf(ip,"%s %d %d:%d:%d %d",mname,&day,&hour,&min,&sec,&year); + } + else if(ip[2] == '-') { + /* RFC 850 (normal HTTP) */ + char t[256]; + sscanf(ip,"%s %d:%d:%d",t,&hour,&min,&sec); + t[2] = '\0'; + day = atoi(t); + t[6] = '\0'; + strcpy(mname,&t[3]); + x = atoi(&t[7]); + /* Prevent + * wraparound + * from + * ambiguity + * */ + if(x < 70) + x += 100; + year = 1900 + x; + } + else { + /* RFC 822 */ + sscanf(ip,"%d %s %d %d:%d:%d",&day,mname,&year,&hour,&min,&sec); + } + month = find_month(mname); + + if((x = (1900+lms->tm_year) - year)) + return x < 0; + if((x = lms->tm_mon - month)) + return x < 0; + if((x = lms->tm_mday - day)) + return x < 0; + if((x = lms->tm_hour - hour)) + return x < 0; + if((x = lms->tm_min - min)) + return x < 0; + if((x = lms->tm_sec - sec)) + return x < 0; + + return 1; +} + + + +int gif_size (char *file, int *width, int *height) +{ + UINT8 data[256]; + int fd; + int blen; + + *width = 0; *height = 0; + fd = open (file, O_RDONLY); + if (fd == -1) + return -1; + + blen = read(fd, data, sizeof(data)); + close(fd); + + if (blen < 10) return -1; + if (strncmp(data, "GIF87a", 6) && strncmp(data, "GIF89a", 6)) + return -1; + + *width = data[6] + data[7]*256; + *height = data[8] + data[9]*256; + + return 0; +} + +int jpeg_size (char *file, int *width, int *height) +{ + UINT8 data[64*1024]; + int blen; + int fd; + int pos; + int length; + UINT8 tag, marker; + + + *width = 0; *height = 0; + fd = open (file, O_RDONLY); + if (fd == -1) + return -1; + + blen = read(fd, data, sizeof(data)); + close(fd); + pos = 2; + while (pos+8 < blen) + { + tag = data[pos+0]; + if (tag != 0xff) return -1; + marker = data[pos+1]; + length = data[pos+2] * 256 + data[pos+3] + 2; + if (marker >= 0xc0 && marker <= 0xcf && marker != 0xc4 && + marker != 0xc8 && marker != 0xcc) + { + *height = data[pos+5] * 256 + data[pos+6]; + *width = data[pos+7] * 256 + data[pos+8]; + return 0; + } + pos += length; + } + return -1; +} + +int isdir(char *dir) { + struct stat statinfo; + if ( stat(dir, &statinfo) != 0) { + return 0; + } + + return S_ISDIR(statinfo.st_mode); +} + +int create_directories(char *fullpath) { + char s[4000]; + char *last_slash; + int last_slash_pos; + + if ((fullpath == NULL) || (strlen(fullpath) > 4000)) { + return 1; + } + + last_slash = strrchr(fullpath,'/'); + last_slash_pos = (last_slash - fullpath); + /* fprintf(stderr,"dira(%d): %s\n", last_slash_pos,fullpath); */ + + if (last_slash_pos > 2) { + strncpy(s,fullpath,last_slash_pos); + s[last_slash_pos] = 0; + /* fprintf(stderr,"dir: %s\n", s); */ + + if (!isdir(s)) { + char s2[4000]; + sprintf(s2,"mkdir -p %s", s); + return system(s2); + } + + } else { + return 1; + } + + return 0; +} + +NEOERR *rotate_image(char *path, char *file, int degree, char *rpath) +{ + char cmd[256]; + char nfile[_POSIX_PATH_MAX]; + char ofile[_POSIX_PATH_MAX]; + char *ch, *opt; + int is_jpeg = 0; + struct stat s; + int r; + + snprintf (ofile, sizeof(ofile), "%s/%s", path, file); + snprintf (rpath, _POSIX_PATH_MAX, "%s/%s", path, file); + ch = strrchr(rpath, '.'); + if ((!strcasecmp(ch, ".jpg")) || + (!strcasecmp(ch, ".jpeg"))) + { + is_jpeg = 1; + } + else if (strcasecmp(ch, ".gif")) + { + return nerr_raise(NERR_ASSERT, "Only support gif/jpeg for rotation, ext %s", + ch); + } + *ch = '\0'; + if (degree == 90) + { + strcat(rpath, "_r"); + opt = "-cw"; + } + else if (degree == -90) + { + strcat(rpath, "_l"); + opt = "-ccw"; + } + else if (degree == 180) + { + strcat(rpath, "_u"); + opt = "-rotate180"; + } + else + { + return nerr_raise(NERR_ASSERT, "currently only support 90/-90/180 rotations"); + } + if (is_jpeg) + { + strcat(rpath, ".jpg"); + snprintf(cmd, sizeof(cmd), "djpeg -pnm %s | pnmflip %s | cjpeg -quality 85 > %s", ofile, opt, rpath); + } + else + { + strcat(rpath, ".gif"); + snprintf(cmd, sizeof(cmd), "giftopnm %s | pnmflip %s | ppmtogif > %s", ofile, opt, rpath); + } + /* already exists? */ + if (!stat(rpath, &s)) + { + return STATUS_OK; + } + r = system(cmd); + if (r) return nerr_raise_errno (NERR_SYSTEM, "%s returned %d", cmd, r); + /* always save off the old file */ + snprintf (nfile, sizeof(nfile), "%s/%s.orig", path, file); + if (stat(nfile, &s)) + { + if (link(ofile, nfile)) + return nerr_raise_errno (NERR_SYSTEM, "Unable to link %s -> %s", ofile, nfile); + unlink(ofile); + } + return STATUS_OK; +} + +NEOERR *scale_and_display_image(char *fname,int maxW,int maxH,char *cachepath, + int quality) +{ + NEOERR *err = STATUS_OK; + /* Declare the image */ + gdImagePtr src_im = 0; + /* Declare input file */ + FILE *infile=0, *cachefile=0; + int srcX,srcY,srcW,srcH; + FILE *dispfile=0; + struct stat s; + + /* if we can open the cachepath, then just print it */ + if (!stat(cachepath, &s) && s.st_size) + cachefile = fopen(cachepath,"rb"); + if (cachefile) { + /* we should probably stat the files and make sure the thumbnail + is current */ + /* fprintf(stderr,"using cachefile: %s\n",cachepath); */ + dispfile = cachefile; + } else { + char cmd[1024]; + int factor=1; + int l; + int is_jpeg = 0, is_gif = 0; + + l = strlen(fname); + if ((l>4 && !strcasecmp(fname+l-4, ".jpg")) || + (l>5 && !strcasecmp(fname+l-5, ".jpeg"))) + is_jpeg = 1; + else if (l>4 && !strcasecmp(fname+l-4, ".gif")) + is_gif = 1; + + if (is_jpeg) + { + if (!quality) + { + if (!jpeg_size (fname, &srcW, &srcH)) + { + if ((srcW > maxW) || (srcH > maxH)) + { + factor = 2; + if (srcW / factor > maxW) + { + factor = 4; + if (srcW / factor > maxW) + factor = 8; + } + } + } + + /* ne_warn("factor %d\n", factor); */ + snprintf (cmd, sizeof(cmd), "/usr/bin/djpeg -fast -scale 1/%d '%s' | /usr/bin/cjpeg -quality 60 -progressive -dct fast -outfile '%s'", factor, fname, cachepath); + + create_directories(cachepath); + system(cmd); + if (!stat(cachepath, &s) && s.st_size) + cachefile = fopen(cachepath,"rb"); + else + ne_warn("external command failed to create file\n"); + } + if (cachefile) { + dispfile = cachefile; + + } else /* no cachefile */ { + + + /* fprintf(stderr,"reading image\n"); */ + /* Read the image in */ + infile = fopen(fname,"rb"); + src_im = gdImageCreateFromJpeg(infile); + srcX=0; srcY=0; srcW=src_im->sx; srcH=src_im->sy; + + + /* figure out if we need to scale it */ + + if ((srcW > maxW) || (srcH > maxH)) { + /* scale paramaters */ + int dstX,dstY,dstW,dstH; + /* Declare output file */ + FILE *jpegout; + gdImagePtr dest_im; + float srcAspect,dstAspect; + + /* create the destination image */ + + dstX=0; dstY=0; + + + srcAspect = ((float)srcW/(float)srcH); + dstAspect = ((float)maxW/(float)maxH); + + if (srcAspect == dstAspect) { + /* they are the same aspect ratio */ + dstW = maxW; + dstH = maxH; + } else if ( srcAspect > dstAspect ) { + /* if the src image has wider aspect ratio than the max */ + dstW = maxW; + dstH = (int) ( ((float)dstW/(float)srcW) * srcH ); + } else { + /* if the src image has taller aspect ratio than the max */ + dstH = maxW; + dstW = (int) ( ((float)dstH/(float)srcH) * srcW ); + } + + dest_im = gdImageCreate(dstW,dstH); + + /* fprintf(stderr,"scaling to (%d,%d)\n",dstW,dstH); */ + + /* Scale it to the destination image */ + + gdImageCopyResized(dest_im,src_im,dstX,dstY,srcX,srcY,dstW,dstH,srcW,srcH); + + /* fprintf(stderr,"scaling finished\n"); */ + + /* write the output image */ + create_directories(cachepath); + jpegout = fopen(cachepath,"wb+"); + if (!jpegout) { + jpegout = fopen("/tmp/foobar.jpg","wb+"); + } + if (jpegout) { + gdImageJpeg(dest_im,jpegout,-1); + fflush(jpegout); + + /* now print that data out the stream */ + dispfile = jpegout; + } else { + return nerr_raise_errno(NERR_IO, "Unable to create output file: %s", cachepath); + } + + + gdImageDestroy(dest_im); + + } else { + /* just print the input file because it's small enough */ + dispfile = infile; + } + + } + } + else if (is_gif) + { + float scale = 1.0; + if (!gif_size (fname, &srcW, &srcH)) + { + if ((srcW > maxW) || (srcH > maxH)) + { + scale = 0.5; + if (srcW * scale > maxW) + { + scale = 0.25; + if (srcW * scale > maxW) + factor = 0.125; + } + } + } + + if (scale < 1.0) + { + snprintf (cmd, sizeof(cmd), "/usr/bin/giftopnm '%s' | /usr/bin/pnmscale %5.3f | ppmquant 256 | ppmtogif > '%s'", fname, scale, cachepath); + + create_directories(cachepath); + system(cmd); + dispfile = fopen(cachepath,"rb"); + if (dispfile == NULL) + return nerr_raise_errno(NERR_IO, "Unable to open file: %s", cachepath); + + } + else + { + dispfile = fopen(fname, "rb"); + if (dispfile == NULL) + return nerr_raise_errno(NERR_IO, "Unable to open file: %s", fname); + } + } + else { + ne_warn("How'd I get here?"); + return nerr_raise(NERR_ASSERT, "I shouldn't get here..."); + } + } + + /* the data in "dispfile" is going to be printed now */ + { + + char buf[8192]; + int count; + + fseek(dispfile,0,SEEK_SET); + + do { + count = fread(buf,1,sizeof(buf),dispfile); + if (count > 0) { + err = cgiwrap_write(buf,count); + } + } while (count > 0); + + } + + if (dispfile) fclose(dispfile); + if (src_im) gdImageDestroy(src_im); + + return nerr_pass(err); +} + +char *url_escape (char *buf) +{ + int nl = 0; + int l = 0; + char *s; + + while (buf[l]) + { + if (buf[l] == '/' || buf[l] == '+' || buf[l] == '=' || buf[l] == '&' || + buf[l] == '"' || + buf[l] < 32 || buf[l] > 122) + { + nl += 2; + } + nl++; + l++; + } + + s = (char *) malloc (sizeof(char) * (nl + 1)); + if (s == NULL) return NULL; + + nl = 0; l = 0; + while (buf[l]) + { + if (buf[l] == ' ') + { + s[nl++] = '+'; + l++; + } + else + if (buf[l] == '/' || buf[l] == '+' || buf[l] == '=' || buf[l] == '&' || + buf[l] == '"' || + buf[l] < 32 || buf[l] > 122) + { + s[nl++] = '%'; + s[nl++] = "0123456789ABCDEF"[buf[l] / 16]; + s[nl++] = "0123456789ABCDEF"[buf[l] % 16]; + l++; + } + else + { + s[nl++] = buf[l++]; + } + } + s[nl] = '\0'; + + return s; +} + +NEOERR *load_images (char *path, ULIST **rfiles, char *partial, int descend) +{ + NEOERR *err = STATUS_OK; + DIR *dp; + struct dirent *de; + int is_jpeg, is_gif, l; + char fpath[_POSIX_PATH_MAX]; + char ppath[_POSIX_PATH_MAX]; + ULIST *files = NULL; + + if ((dp = opendir (path)) == NULL) + { + return nerr_raise(NERR_IO, "Unable to opendir %s: [%d] %s", path, errno, + strerror(errno)); + } + + if (rfiles == NULL || *rfiles == NULL) + { + err = uListInit(&files, 50, 0); + if (err) return nerr_pass(err); + *rfiles = files; + } + else + { + files = *rfiles; + } + + while ((de = readdir (dp)) != NULL) + { + if (de->d_name[0] != '.') + { + snprintf(fpath, sizeof(fpath), "%s/%s", path, de->d_name); + if (partial) + { + snprintf(ppath, sizeof(ppath), "%s/%s", partial, de->d_name); + } + else + { + strncpy(ppath, de->d_name, sizeof(ppath)); + } + if (descend && isdir(fpath)) + { + err = load_images(fpath, rfiles, ppath, descend); + if (err) break; + } + else + { + l = strlen(de->d_name); + is_jpeg = 0; is_gif = 0; + + if ((l>4 && !strcasecmp(de->d_name+l-4, ".jpg")) || + (l>5 && !strcasecmp(de->d_name+l-5, ".jpeg"))) + is_jpeg = 1; + else if (l>4 && !strcasecmp(de->d_name+l-4, ".gif")) + is_gif = 1; + + if (is_gif || is_jpeg) + { + err = uListAppend(files, strdup(ppath)); + if (err) break; + } + } + } + } + closedir(dp); + if (err) + { + uListDestroy(&files, ULIST_FREE); + } + else + { + *rfiles = files; + } + return nerr_pass(err); +} + +NEOERR *export_image(CGI *cgi, char *prefix, char *path, char *file) +{ + NEOERR *err; + char buf[256]; + char num[20]; + int i = 0; + int r, l; + int width, height; + char ipath[_POSIX_PATH_MAX]; + int is_jpeg = 0, is_gif = 0; + + l = strlen(file); + if ((l>4 && !strcasecmp(file+l-4, ".jpg")) || + (l>5 && !strcasecmp(file+l-5, ".jpeg"))) + is_jpeg = 1; + else if (l>4 && !strcasecmp(file+l-4, ".gif")) + is_gif = 1; + + snprintf (buf, sizeof(buf), "%s.%d", prefix, i); + err = hdf_set_buf (cgi->hdf, prefix, url_escape(file)); + if (err != STATUS_OK) return nerr_pass(err); + snprintf (ipath, sizeof(ipath), "%s/%s", path, file); + if (is_jpeg) + r = jpeg_size(ipath, &width, &height); + else + r = gif_size(ipath, &width, &height); + if (!r) + { + snprintf (buf, sizeof(buf), "%s.width", prefix); + snprintf (num, sizeof(num), "%d", width); + err = hdf_set_value (cgi->hdf, buf, num); + if (err != STATUS_OK) return nerr_pass(err); + snprintf (buf, sizeof(buf), "%s.height", prefix); + snprintf (num, sizeof(num), "%d", height); + err = hdf_set_value (cgi->hdf, buf, num); + if (err != STATUS_OK) return nerr_pass(err); + } + return STATUS_OK; +} + +NEOERR *scale_images (CGI *cgi, char *prefix, int width, int height, int force) +{ + NEOERR *err; + char num[20]; + HDF *obj; + int i, x; + int factor; + + obj = hdf_get_obj (cgi->hdf, prefix); + if (obj) obj = hdf_obj_child (obj); + while (obj) + { + factor = 1; + i = hdf_get_int_value(obj, "height", -1); + if (i != -1) + { + x = i; + while (x > height) + { + /* factor = factor * 2;*/ + factor++; + x = i / factor; + } + snprintf (num, sizeof(num), "%d", x); + err = hdf_set_value (obj, "height", num); + if (err != STATUS_OK) return nerr_pass (err); + + i = hdf_get_int_value(obj, "width", -1); + if (i != -1) + { + i = i / factor; + snprintf (num, sizeof(num), "%d", i); + err = hdf_set_value (obj, "width", num); + if (err != STATUS_OK) return nerr_pass (err); + } + } + else + { + snprintf (num, sizeof(num), "%d", height); + err = hdf_set_value (obj, "height", num); + if (err != STATUS_OK) return nerr_pass (err); + snprintf (num, sizeof(num), "%d", width); + err = hdf_set_value (obj, "width", num); + if (err != STATUS_OK) return nerr_pass (err); + } + obj = hdf_obj_next(obj); + } + return STATUS_OK; +} + +int alpha_sort(const void *a, const void *b) +{ + char **sa = (char **)a; + char **sb = (char **)b; + + /* ne_warn("%s %s: %d", *sa, *sb, strcmp(*sa, *sb)); */ + + return strcmp(*sa, *sb); +} + +NEOERR *dowork_picture (CGI *cgi, char *album, char *picture) +{ + NEOERR *err = STATUS_OK; + char *base, *name; + char path[_POSIX_PATH_MAX]; + char buf[256]; + char *enc_picture; + int i, x, factor, y; + int thumb_width, thumb_height; + int pic_width, pic_height; + ULIST *files = NULL; + char t_album[_POSIX_PATH_MAX]; + char t_pic[_POSIX_PATH_MAX]; + char nfile[_POSIX_PATH_MAX]; + char *ch; + int rotate; + + ch = strrchr(picture, '/'); + if (ch != NULL) + { + *ch = '\0'; + snprintf(t_album, sizeof(t_album), "%s/%s", album, picture); + *ch = '/'; + strncpy(t_pic, ch+1, sizeof(t_pic)); + picture = t_pic; + album = t_album; + } + + base = hdf_get_value (cgi->hdf, "BASEDIR", NULL); + if (base == NULL) + { + cgi_error (cgi, "No BASEDIR in imd file"); + return nerr_raise(CGIFinished, "Finished"); + } + + thumb_width = hdf_get_int_value (cgi->hdf, "ThumbWidth", 120); + thumb_height = hdf_get_int_value (cgi->hdf, "ThumbWidth", 90); + pic_width = hdf_get_int_value (cgi->hdf, "PictureWidth", 120); + pic_height = hdf_get_int_value (cgi->hdf, "PictureWidth", 90); + + err = hdf_set_value (cgi->hdf, "Context", "picture"); + if (err != STATUS_OK) return nerr_pass(err); + + snprintf (path, sizeof(path), "%s/%s", base, album); + rotate = hdf_get_int_value(cgi->hdf, "Query.rotate", 0); + if (rotate) + { + err = rotate_image(path, picture, rotate, nfile); + if (err) return nerr_pass(err); + picture = strrchr(nfile, '/') + 1; + } + + err = hdf_set_buf (cgi->hdf, "Album", url_escape(album)); + if (err != STATUS_OK) return nerr_pass(err); + err = hdf_set_value (cgi->hdf, "Album.Raw", album); + if (err != STATUS_OK) return nerr_pass(err); + enc_picture = url_escape(picture); + err = hdf_set_buf (cgi->hdf, "Picture", enc_picture); + if (err != STATUS_OK) return nerr_pass(err); + + err = load_images(path, &files, NULL, 0); + if (err != STATUS_OK) return nerr_pass(err); + err = uListSort(files, alpha_sort); + if (err != STATUS_OK) return nerr_pass(err); + + i = -1; + for (x = 0; x < uListLength(files); x++) + { + err = uListGet(files, x, (void *)&name); + if (err) break; + if (!strcmp(name, picture)) + { + i = x; + break; + } + } + if (i != -1) + { + for (x = 2; x > 0; x--) + { + if (i - x < 0) continue; + err = uListGet(files, i-x, (void *)&name); + if (err) break; + snprintf(buf, sizeof(buf), "Show.%d", i-x); + err = export_image(cgi, buf, path, name); + if (err) break; + } + for (x = 0; x < 3; x++) + { + if (i + x > uListLength(files)) break; + err = uListGet(files, i+x, (void *)&name); + if (err) break; + snprintf(buf, sizeof(buf), "Show.%d", i+x); + err = export_image(cgi, buf, path, name); + if (err) break; + } + snprintf (buf, sizeof(buf), "Show.%d.width", i); + x = hdf_get_int_value (cgi->hdf, buf, -1); + if (x != -1) + { + factor = 1; + y = x; + while (y > pic_width) + { + /* factor = factor * 2; */ + factor++; + y = x / factor; + } + snprintf (buf, sizeof(buf), "%d", y); + hdf_set_value (cgi->hdf, "Picture.width", buf); + snprintf (buf, sizeof(buf), "Show.%d.height", i); + x = hdf_get_int_value (cgi->hdf, buf, -1); + y = x / factor; + snprintf (buf, sizeof(buf), "%d", y); + hdf_set_value (cgi->hdf, "Picture.height", buf); + } + else + { + snprintf (buf, sizeof(buf), "%d", pic_width); + hdf_set_value (cgi->hdf, "Picture.width", buf); + snprintf (buf, sizeof(buf), "%d", pic_height); + hdf_set_value (cgi->hdf, "Picture.height", buf); + } + + err = scale_images (cgi, "Show", thumb_width, thumb_height, 0); + } + uListDestroy(&files, ULIST_FREE); + + return nerr_pass(err); +} + +NEOERR *dowork_album_overview (CGI *cgi, char *album) +{ + NEOERR *err = STATUS_OK; + DIR *dp; + struct dirent *de; + char path[_POSIX_PATH_MAX]; + char buf[256]; + int i = 0, x; + int thumb_width, thumb_height; + ULIST *files = NULL; + char *name; + + thumb_width = hdf_get_int_value (cgi->hdf, "ThumbWidth", 120); + thumb_height = hdf_get_int_value (cgi->hdf, "ThumbWidth", 90); + + if ((dp = opendir (album)) == NULL) + { + return nerr_raise(NERR_IO, "Unable to opendir %s: [%d] %s", album, errno, + strerror(errno)); + } + + while ((de = readdir (dp)) != NULL) + { + if (de->d_name[0] != '.') + { + snprintf(path, sizeof(path), "%s/%s", album, de->d_name); + if (isdir(path)) + { + snprintf(buf, sizeof(buf), "Albums.%d", i); + err = hdf_set_buf (cgi->hdf, buf, url_escape(de->d_name)); + if (err != STATUS_OK) break; + err = load_images(path, &files, NULL, 1); + if (err != STATUS_OK) break; + err = uListSort(files, alpha_sort); + if (err != STATUS_OK) break; + snprintf(buf, sizeof(buf), "Albums.%d.Count", i); + err = hdf_set_int_value(cgi->hdf, buf, uListLength(files)); + if (err != STATUS_OK) break; + for (x = 0; (x < 4) && (x < uListLength(files)); x++) + { + err = uListGet(files, x, (void *)&name); + if (err) break; + snprintf(buf, sizeof(buf), "Albums.%d.Images.%d", i, x); + err = export_image(cgi, buf, path, name); + if (err) break; + } + uListDestroy(&files, ULIST_FREE); + if (err != STATUS_OK) break; + snprintf(buf, sizeof(buf), "Albums.%d.Images", i); + err = scale_images (cgi, buf, thumb_width, thumb_height, 0); + if (err != STATUS_OK) break; + i++; + } + } + } + closedir(dp); + return nerr_pass(err); +} + +NEOERR *dowork_album (CGI *cgi, char *album) +{ + NEOERR *err; + char *base; + char buf[256]; + char path[_POSIX_PATH_MAX]; + int thumb_width, thumb_height; + int per_page, start, next, prev, last; + ULIST *files = NULL; + char *name; + int x; + + base = hdf_get_value (cgi->hdf, "BASEDIR", NULL); + if (base == NULL) + { + cgi_error (cgi, "No BASEDIR in imd file"); + return nerr_raise(CGIFinished, "Finished"); + } + thumb_width = hdf_get_int_value (cgi->hdf, "ThumbWidth", 120); + thumb_height = hdf_get_int_value (cgi->hdf, "ThumbWidth", 90); + per_page = hdf_get_int_value (cgi->hdf, "PerPage", 50); + start = hdf_get_int_value (cgi->hdf, "Query.start", 0); + + err = hdf_set_buf (cgi->hdf, "Album", url_escape(album)); + if (err != STATUS_OK) return nerr_pass(err); + err = hdf_set_value (cgi->hdf, "Album.Raw", album); + if (err != STATUS_OK) return nerr_pass(err); + + err = hdf_set_value (cgi->hdf, "Context", "album"); + if (err != STATUS_OK) return nerr_pass(err); + + snprintf (path, sizeof(path), "%s/%s", base, album); + err = dowork_album_overview(cgi, path); + if (err != STATUS_OK) return nerr_pass(err); + + err = load_images(path, &files, NULL, 0); + if (err != STATUS_OK) return nerr_pass (err); + err = uListSort(files, alpha_sort); + if (err != STATUS_OK) return nerr_pass (err); + err = hdf_set_int_value(cgi->hdf, "Album.Count", uListLength(files)); + if (err != STATUS_OK) return nerr_pass (err); + if (start > uListLength(files)) start = 0; + next = start + per_page; + if (next > uListLength(files)) next = uListLength(files); + prev = start - per_page; + if (prev < 0) prev = 0; + last = uListLength(files) - per_page; + if (last < 0) last = 0; + err = hdf_set_int_value(cgi->hdf, "Album.Start", start); + if (err != STATUS_OK) return nerr_pass (err); + err = hdf_set_int_value(cgi->hdf, "Album.Next", next); + if (err != STATUS_OK) return nerr_pass (err); + err = hdf_set_int_value(cgi->hdf, "Album.Prev", prev); + if (err != STATUS_OK) return nerr_pass (err); + err = hdf_set_int_value(cgi->hdf, "Album.Last", last); + if (err != STATUS_OK) return nerr_pass (err); + for (x = start; x < next; x++) + { + err = uListGet(files, x, (void *)&name); + if (err) break; + snprintf(buf, sizeof(buf), "Images.%d", x); + err = export_image(cgi, buf, path, name); + if (err) break; + } + uListDestroy(&files, ULIST_FREE); + if (err != STATUS_OK) return nerr_pass (err); + err = scale_images (cgi, "Images", thumb_width, thumb_height, 0); + if (err != STATUS_OK) return nerr_pass (err); + return STATUS_OK; +} + +NEOERR *dowork_image (CGI *cgi, char *image) +{ + NEOERR *err = STATUS_OK; + int maxW = 1024, maxH = 1024; + char *basepath = ""; + char *cache_basepath = "/tmp/.imgcache/"; + char srcpath[_POSIX_PATH_MAX] = ""; + char cachepath[_POSIX_PATH_MAX] = ""; + char buf[256]; + char *if_mod; + int i, l, quality; + struct stat s; + struct tm *t; + + if ((i = hdf_get_int_value(cgi->hdf, "Query.width", 0)) != 0) { + maxW = i; + } + + if ((i = hdf_get_int_value(cgi->hdf, "Query.height", 0)) != 0) { + maxH = i; + } + quality = hdf_get_int_value(cgi->hdf, "Query.quality", 0); + + if_mod = hdf_get_value(cgi->hdf, "HTTP.IfModifiedSince", NULL); + + basepath = hdf_get_value(cgi->hdf, "BASEDIR", NULL); + if (basepath == NULL) + { + cgi_error (cgi, "No BASEDIR in imd file"); + return nerr_raise(CGIFinished, "Finished"); + } + + snprintf (srcpath, sizeof(srcpath), "%s/%s", basepath, image); + snprintf (cachepath, sizeof(cachepath), "%s/%dx%d/%s", cache_basepath, + maxW, maxH,image); + + if (stat(srcpath, &s)) + { + cgiwrap_writef("Status: 404\nContent-Type: text/html\n\n"); + cgiwrap_writef("File %s not found.", srcpath); + return nerr_raise_errno(NERR_IO, "Unable to stat file %s", srcpath); + } + + t = gmtime(&(s.st_mtime)); + if (if_mod && later_than(t, if_mod)) + { + cgiwrap_writef("Status: 304\nContent-Type: text/html\n\n"); + cgiwrap_writef("Use Local Copy"); + return STATUS_OK; + } + + /* fprintf(stderr,"cachepath: %s\n",cachepath); */ + + l = strlen(srcpath); + if ((l>4 && !strcasecmp(srcpath+l-4, ".jpg")) || + (l>5 && !strcasecmp(srcpath+l-5, ".jpeg"))) + cgiwrap_writef("Content-Type: image/jpeg\n"); + else if (l>4 && !strcasecmp(srcpath+l-4, ".gif")) + cgiwrap_writef("Content-Type: image/gif\n"); + t = gmtime(&(s.st_mtime)); + strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", t); + cgiwrap_writef("Last-modified: %s\n\n", buf); + + fflush(stdout); + + err = scale_and_display_image(srcpath,maxW,maxH,cachepath,quality); + return nerr_pass(err); +} + +int main(int argc, char **argv, char **envp) +{ + NEOERR *err; + CGI *cgi; + char *image; + char *album; + char *imd_file; + char *cs_file; + char *picture; + + cgi_debug_init (argc,argv); + cgiwrap_init_std (argc, argv, envp); + + nerr_init(); + + err = cgi_init(&cgi, NULL); + if (err != STATUS_OK) + { + cgi_neo_error(cgi, err); + nerr_log_error(err); + return -1; + } + imd_file = hdf_get_value(cgi->hdf, "CGI.PathTranslated", NULL); + err = hdf_read_file (cgi->hdf, imd_file); + if (err != STATUS_OK) + { + cgi_neo_error(cgi, err); + nerr_log_error(err); + return -1; + } + + cs_file = hdf_get_value(cgi->hdf, "Template", NULL); + image = hdf_get_value(cgi->hdf, "Query.image", NULL); + album = hdf_get_value(cgi->hdf, "Query.album", ""); + picture = hdf_get_value(cgi->hdf, "Query.picture", NULL); + if (image) + { + err = dowork_image(cgi, image); + if (err) + { + nerr_log_error(err); + return -1; + } + } + else + { + if (!picture) + { + err = dowork_album (cgi, album); + } + else + { + err = dowork_picture (cgi, album, picture); + } + if (err != STATUS_OK) + { + if (nerr_handle(&err, CGIFinished)) + { + /* pass */ + } + } + else + { + err = cgi_display(cgi, cs_file); + if (err != STATUS_OK) + { + cgi_neo_error(cgi, err); + nerr_log_error(err); + return -1; + } + } + } + return 0; +} diff -Nbru clearsilver-0.4/imd/imd.cs clearsilver-0.5/imd/imd.cs --- clearsilver-0.4/imd/imd.cs Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/imd/imd.cs Mon Feb 11 12:16:23 2002 @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + +
src="1.gif">
width=8 src="3.gif"> height= src="?image=/&width=&height="> width=8 src="4.gif">
src="6.gif">
+ + + +<?cs var:Title ?><?cs if:Context == "album" ?> <?cs var:Album.Raw ?> <?cs var:Album.Start + #1 ?> - <?cs var:Album.Next ?> of <?cs var:Album.Count ?><?cs else ?> <?cs var:Album.Raw ?> +- <?cs var:Picture ?><?cs /if ?> + + + + + +
+ +

+
+ + + + + + + + +
+ ( images) +
+ + + + + + + + + + + + + + + + +
src="1.gif">
width=8 src="3.gif"> height= src="?image=//&width=&height="> width=8 src="4.gif">
src="6.gif">
+
+ +
+ + + +
+ #0 ?> + First + + First + +   + #0 ?> + Prev + + Prev + +   + - of +   + + Next + + Next + +   + + Last + + Last + +
+ + + +
+ + + + + + #PageWidth ?>
+ + + +
+
+ #0 ?> + First + + First + +   + #0 ?> + Prev + + Prev + +   + - of +   + + Next + + Next + +   + + Last + + Last + +
+ + + + -- + +
+ + + + + + + + + + + + + + + + +
src="1.gif">
width=18 src="3.gif"> height= src="?image=/&width=&height=&quality=1"> width=18 src="4.gif">
src="6.gif">
+
+ + + + + + + + +
+
+ +   Rotate: + Right - + Left - + Flip + + + + diff -Nbru clearsilver-0.4/imd/imdm.py clearsilver-0.5/imd/imdm.py --- clearsilver-0.4/imd/imdm.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/imd/imdm.py Sat Dec 30 01:57:16 2000 @@ -0,0 +1,209 @@ +#!/usr/local/bin/python +# +# imdm +# +# IMage Display Master +# +# This uses the affiliated C-cgi "imd" to build a caching image display +# server with only passive Apache cgis. +# +import sys,os,string +import cgi + +# this function should find the first four images inside a +# nested subdirectory + +albumstartfile = "/~jeske/Images/jeskealbum.imd" +imagestartfile = "/~jeske/Images/jeskealbum.imc" + +THUMB_WIDTH = 120 +THUMB_HEIGHT = 90 + +# ------------------------------------------------------------------------------------ +# +# utility functions + +def albumoverview(basedir,sub_dir,count = 4,skip = 0): + images = [] + + fulldir = os.path.join(basedir,sub_dir) + for a_entry in os.listdir(fulldir): + fullpath = os.path.join(fulldir,a_entry) + if os.path.isfile(fullpath): + if string.lower(string.split(a_entry,".")[-1]) in ["jpeg","jpg"]: + images.append(os.path.join(sub_dir,a_entry)) + elif os.path.isdir(fullpath): + images + albumoverview(basedir,os.path.join(sub_dir,a_entry),1) + if len(images) >= (count + skip): + return images[skip:] + + return images[skip:] + + +def makethumbnailimgtag(filename,width=THUMB_WIDTH,height=THUMB_HEIGHT): + global imagestartfile + return '' % (imagestartfile,filename,width,height) + +def makealbumurl(dir): + global albumstartfile + return "%s?album=%s" % (albumstartfile,dir) + +def makepictureurl(dir,picture): + global albumstartfile + return "%s?album=%s&picture=%s" % (albumstartfile,dir,picture) + +# ------------------------------------------------------------------------------------ +# +# picturedisplay + +def picturedisplay(basedir,album,picture): + sys.stdout.write("top " % albumstartfile) + + sys.stdout.write("-- %s" % (makealbumurl(album),album)) + + imagename = os.path.join(album,picture) + + sys.stdout.write("

") + + sys.stdout.write("
\n") + sys.stdout.write(makethumbnailimgtag(imagename,width=600,height=500)) + sys.stdout.write("
\n") + + images = albumoverview(basedir,album,count=500) + image_index = None + for x in range(len(images)): + if images[x] == imagename: + image_index = x + break + + if not image_index is None: + sys.stdout.write("
") + + # pre-images + for i in range(1,3): + pic_index = image_index - i + + picture_path = string.join(string.split(images[pic_index],'/')[1:],'/') + sys.stdout.write("" % (makepictureurl(album,picture_path),makethumbnailimgtag(images[pic_index]))) + + sys.stdout.write("
") + + # post-images + for i in range(1,3): + pic_index = image_index + i + if pic_index >= len(images): + pic_index = pic_index - len(images) + + picture_path = string.join(string.split(images[pic_index],'/')[1:],'/') + sys.stdout.write("" % (makepictureurl(album,picture_path), makethumbnailimgtag(images[pic_index]))) + sys.stdout.write("
%s%s
\n") + + # navigation + + +# ------------------------------------------------------------------------------------ +# +# albumdisplay + + + +def albumdisplay(basedir,album,columns=7,rows=5): + next_page = 0 + + + sys.stdout.write("
%s
" % album) + + imgcount = columns * rows + images = albumoverview(basedir,album,count=(imgcount + 1),skip=0) + + if len(images) > imgcount: + images = images[:-1] + next_page = 1 + + while images: + sys.stdout.write("
") + for a_col in range(columns): + if len(images): + picture_path = string.join(string.split(images[0],'/')[1:],'/') + sys.stdout.write("" % (makepictureurl(album,picture_path),makethumbnailimgtag(images[0]))) + images = images[1:] + sys.stdout.write("
%s
") + + if next_page: + sys.stdout.write("more...") + + +# ------------------------------------------------------------------------------------ +# +# topalbumoverview + +def topalbumoverview(dir): + for a_dir in os.listdir(dir): + if os.path.isdir(os.path.join(dir,a_dir)): + sys.stdout.write("
") + sys.stdout.write("") + + sys.stdout.write("" % (makealbumurl(a_dir),a_dir)) + + sys.stdout.write("
%s
") + + for a_file in albumoverview(dir,a_dir): + picture_path = string.join(string.split(a_file,'/')[1:],'/') + sys.stdout.write("\n" % (makepictureurl(a_dir,picture_path),makethumbnailimgtag(a_file))) + sys.stdout.write("
%s
\n

\n") + +# ------------------------------------------------------------------------------------ +# +# readvars() -- simple file format reader + +def readvars(filename): + vars = {} + data = open(filename,"rb").read() + lines = string.split(data,"\n") + for a_line in lines: + stripped_line = string.strip(a_line) + if not stripped_line or stripped_line[0] == "#": + continue + try: + key,value = string.split(a_line,"=") + vars[key] = value + except: + pass + return vars + +# ------------------------------------------------------------------------------------ +# +# main() + + +def main(): + global cgiform + cgiform = cgi.FieldStorage() + + sys.stdout.write("Content-Type: text/html\n\n") + sys.stdout.write("

HTML Image Viewer!

") + + myvars = readvars(os.environ['PATH_TRANSLATED']) + + sys.stderr.write(repr(myvars)) + + global albumstartfile, imagestartfile + albumstartfile = os.environ['PATH_INFO'] + imagestartfile = myvars['IMGSTARTFILE'] + BASEDIR = myvars['BASEDIR'] + + album = cgiform.getvalue('album',None) + picture = cgiform.getvalue('picture',None) + + if album is None: + topalbumoverview(BASEDIR) + elif picture is None: + albumdisplay(BASEDIR,album) + else: + picturedisplay(BASEDIR,album,picture) + +if __name__ == "__main__": + main() + + + diff -Nbru clearsilver-0.4/imd/test.in clearsilver-0.5/imd/test.in --- clearsilver-0.4/imd/test.in Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/imd/test.in Sat Dec 30 01:57:16 2000 @@ -0,0 +1,2 @@ +PATH_TRANSLATED=/home/blong/public_html/Images/test.imd +QUERY_STRING= diff -Nbru clearsilver-0.4/python/Makefile clearsilver-0.5/python/Makefile --- clearsilver-0.4/python/Makefile Mon Aug 6 15:16:45 2001 +++ clearsilver-0.5/python/Makefile Fri Mar 22 11:26:41 2002 @@ -13,6 +13,7 @@ ifeq ($(PYTHON_INC),) PYTHON_INC = -I/usr/include/python1.5 endif +PYTHON_INC += -I/usr/include/python1.5 CFLAGS += -I$(NEOTONIC_ROOT) $(PYTHON_INC) DLIBS += -lneo_cgi -lneo_cs -lneo_utl diff -Nbru clearsilver-0.4/python/neo_cgi.c clearsilver-0.5/python/neo_cgi.c --- clearsilver-0.4/python/neo_cgi.c Fri Aug 31 15:19:48 2001 +++ clearsilver-0.5/python/neo_cgi.c Sat Apr 13 17:49:50 2002 @@ -18,6 +18,8 @@ #include "cgi/cgiwrap.h" #include "cgi/date.h" #include "cgi/html.h" + +#define NEO_CGI_MODULE #include "p_neo_util.h" static PyObject *CGIFinishedException; @@ -283,7 +285,7 @@ char *name, *domain = NULL, *path = NULL; NEOERR *err; - if (!PyArg_ParseTuple(args, "s|ss:cookieClear(name, domain, path)", &name, domain, path)) + if (!PyArg_ParseTuple(args, "s|ss:cookieClear(name, domain, path)", &name, &domain, &path)) return NULL; err = cgi_cookie_clear (cgi, name, domain, path); @@ -307,7 +309,7 @@ Py_INCREF(Py_None); return Py_None; } - return PyFile_FromFile (fp, "name", "w+", NULL); + return PyFile_FromFile (fp, name, "w+", NULL); } static PyMethodDef CGIMethods[] = @@ -331,20 +333,37 @@ static PyObject * p_cgi_url_escape (PyObject *self, PyObject *args) { - char *s, *esc; + char *s, *esc, *o = NULL; NEOERR *err; PyObject *rv; - if (!PyArg_ParseTuple(args, "s:urlEscape(str)", &s)) + if (!PyArg_ParseTuple(args, "s|s:urlEscape(str, other=None)", &s, &o)) return NULL; - err = cgi_url_escape (s, &esc); + err = cgi_url_escape_more (s, &esc, o); if (err) return p_neo_error (err); rv = Py_BuildValue ("s", esc); free (esc); return rv; } +static PyObject * p_cgi_url_unescape (PyObject *self, PyObject *args) +{ + char *s; + PyObject *rv; + char *r; + + if (!PyArg_ParseTuple(args, "s:urlUnescape(str)", &s)) + return NULL; + + r = strdup(s); + if (r == NULL) return PyErr_NoMemory(); + cgi_url_unescape (r); + rv = Py_BuildValue ("s", r); + free (r); + return rv; +} + static PyObject * p_html_escape (PyObject *self, PyObject *args) { char *s, *esc; @@ -523,15 +542,6 @@ PyErr_SetString(PyExc_TypeError, "object.read() returned non-string"); } - if (n < 0 && result != NULL) { - int len = PyString_Size(result); - if (len == 0) { - Py_DECREF(result); - result = NULL; - PyErr_SetString(PyExc_EOFError, - "EOF on object.read()"); - } - } return result; } } @@ -547,7 +557,7 @@ if (buf == NULL) { PyErr_Clear(); - return 0; + return -1; } len = PyString_Size(buf); @@ -609,7 +619,7 @@ items = PyObject_GetAttrString(wrap->p_env, "items"); if (items == NULL) { - /* ne_warn ("p_iterenv: Unable to get items method"); */ + ne_warn ("p_iterenv: Unable to get items method"); PyErr_Clear(); return -1; } @@ -617,14 +627,21 @@ Py_DECREF(items); if (env_list == NULL) { - /* ne_warn ("p_iterenv: Unable to call items method"); */ + ne_warn ("p_iterenv: Unable to call items method"); PyErr_Clear(); return -1; } + if (x >= PyList_Size(env_list)) + { + *rk = NULL; + *rv = NULL; + Py_DECREF(env_list); + return 0; + } result = PyList_GetItem (env_list, x); if (result == NULL) { - /* ne_warn ("p_iterenv: Unable to get env %d", x); */ + ne_warn ("p_iterenv: Unable to get env %d", x); Py_DECREF(env_list); PyErr_Clear(); return -1; @@ -633,7 +650,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 %s,%s", k, v); Py_DECREF(env_list); PyErr_Clear(); return -1; @@ -793,9 +810,6 @@ static PyObject * p_update (PyObject *self, PyObject *args) { - PyObject *dict; - int i = 0; - if (_PyImport_FindExtension("neo_util","neo_util") == NULL) initneo_util(); @@ -810,6 +824,7 @@ { {"CGI", p_cgi_init, METH_VARARGS, NULL}, {"urlEscape", p_cgi_url_escape, METH_VARARGS, NULL}, + {"urlUnescape", p_cgi_url_unescape, METH_VARARGS, NULL}, {"htmlEscape", p_html_escape, METH_VARARGS, NULL}, {"text2html", p_text_html, METH_VARARGS, NULL}, {"cgiWrap", cgiwrap, METH_VARARGS, cgiwrap_doc}, @@ -822,6 +837,8 @@ void initneo_cgi(void) { PyObject *m, *d; + static void *NEO_PYTHON_API[P_NEO_CGI_POINTERS]; + PyObject *c_api_object; initneo_util(); _PyImport_FixupExtension("neo_util", "neo_util"); @@ -834,4 +851,18 @@ d = PyModule_GetDict(m); CGIFinishedException = PyErr_NewException("neo_cgi.CGIFinished", NULL, NULL); PyDict_SetItemString(d, "CGIFinished", CGIFinishedException); + + /* Initialize the C API Pointer array */ + NEO_PYTHON_API[P_HDF_TO_OBJECT_NUM] = (void *)p_hdf_to_object; + NEO_PYTHON_API[P_OBJECT_TO_HDF_NUM] = (void *)p_object_to_hdf; + NEO_PYTHON_API[P_NEO_ERROR_NUM] = (void *)p_neo_error; + + /* create a CObject containing the API pointer array's address */ + c_api_object = PyCObject_FromVoidPtr((void *)NEO_PYTHON_API, NULL); + if (c_api_object != NULL) { + /* create a name for this object in the module's namespace */ + PyDict_SetItemString(d, "_C_API", c_api_object); + Py_DECREF(c_api_object); + PyDict_SetItemString(d, "_C_API_NUM", PyInt_FromLong(P_NEO_CGI_POINTERS)); + } } diff -Nbru clearsilver-0.4/python/neo_cs.c clearsilver-0.5/python/neo_cs.c --- clearsilver-0.4/python/neo_cs.c Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/python/neo_cs.c Sat Apr 13 17:49:50 2002 @@ -14,6 +14,8 @@ #include "util/neo_str.h" #include "util/neo_hdf.h" #include "cs/cs.h" + +#define NEO_CGI_MODULE #include "p_neo_util.h" diff -Nbru clearsilver-0.4/python/neo_util.c clearsilver-0.5/python/neo_util.c --- clearsilver-0.4/python/neo_util.c Tue Oct 23 00:01:35 2001 +++ clearsilver-0.5/python/neo_util.c Sat Apr 13 17:49:50 2002 @@ -14,15 +14,27 @@ #include "util/neo_str.h" #include "util/neo_hdf.h" +#define NEO_CGI_MODULE +#include "p_neo_util.h" + static PyObject *NeoError; +static PyObject *NeoParseError; PyObject * p_neo_error (NEOERR *err) { STRING str; string_init (&str); + if (nerr_match(err, NERR_PARSE)) + { nerr_error_string (err, &str); + PyErr_SetString (NeoParseError, str.buf); + } + else + { + nerr_error_traceback (err, &str); PyErr_SetString (NeoError, str.buf); + } string_clear (&str); return NULL; } @@ -392,6 +404,25 @@ return rv; } +static PyObject * p_hdf_set_symlink (PyObject *self, PyObject *args) +{ + HDFObject *ho = (HDFObject *)self; + PyObject *rv; + char *src; + char *dest; + NEOERR *err; + + if (!PyArg_ParseTuple(args, "ss:copy(src, dest)", &src, &dest)) + return NULL; + + err = hdf_set_symlink (ho->data, src, dest); + 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}, @@ -410,12 +441,56 @@ {"removeTree", p_hdf_remove_tree, METH_VARARGS, NULL}, {"dump", p_hdf_dump, METH_VARARGS, NULL}, {"copy", p_hdf_copy, METH_VARARGS, NULL}, + {"setSymLink", p_hdf_set_symlink, METH_VARARGS, NULL}, {NULL, NULL} }; +static PyObject * p_escape (PyObject *self, PyObject *args) +{ + PyObject *rv; + char *s; + char *escape; + char *esc_char; + int buflen; + char *ret = NULL; + NEOERR *err; + + if (!PyArg_ParseTuple(args, "s#ss:escape(str, char, escape)", &s, &buflen, &esc_char, &escape)) + return NULL; + + err = neos_escape(s, buflen, esc_char[0], escape, &ret); + if (err) return p_neo_error(err); + + rv = Py_BuildValue("s", ret); + free(ret); + return rv; +} + +static PyObject * p_unescape (PyObject *self, PyObject *args) +{ + PyObject *rv; + char *s; + char *copy; + char *esc_char; + int buflen; + + if (!PyArg_ParseTuple(args, "s#s:unescape(str, char)", &s, &buflen, &esc_char)) + return NULL; + + copy = strdup(s); + if (copy == NULL) return PyErr_NoMemory(); + neos_unescape(copy, buflen, esc_char[0]); + + rv = Py_BuildValue("s", copy); + free(copy); + return rv; +} + static PyMethodDef UtilMethods[] = { {"HDF", p_hdf_init, METH_VARARGS, NULL}, + {"escape", p_escape, METH_VARARGS, NULL}, + {"unescape", p_unescape, METH_VARARGS, NULL}, {NULL, NULL} }; @@ -430,6 +505,8 @@ m = Py_InitModule("neo_util", UtilMethods); d = PyModule_GetDict(m); - NeoError = PyErr_NewException("neo_util.error", NULL, NULL); - PyDict_SetItemString(d, "error", NeoError); + NeoError = PyErr_NewException("neo_util.Error", NULL, NULL); + NeoParseError = PyErr_NewException("neo_util.ParseError", NULL, NULL); + PyDict_SetItemString(d, "Error", NeoError); + PyDict_SetItemString(d, "ParseError", NeoParseError); } diff -Nbru clearsilver-0.4/python/p_neo_util.h clearsilver-0.5/python/p_neo_util.h --- clearsilver-0.4/python/p_neo_util.h Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/python/p_neo_util.h Sat Apr 13 17:49:51 2002 @@ -11,10 +11,66 @@ #ifndef __P_NEO_UTIL_H_ #define __P_NEO_UTIL_H_ 1 -PyObject * p_neo_error (NEOERR *err); -PyObject * p_hdf_to_object (HDF *data, int dealloc); -HDF * p_object_to_hdf (PyObject *ho); +#include + +__BEGIN_DECLS + +/* external HDF object interface. */ + +#define P_HDF_TO_OBJECT_NUM 0 +#define P_HDF_TO_OBJECT_RETURN PyObject * +#define P_HDF_TO_OBJECT_PROTO (HDF *data, int dealloc) + +#define P_OBJECT_TO_HDF_NUM 1 +#define P_OBJECT_TO_HDF_RETURN HDF * +#define P_OBJECT_TO_HDF_PROTO (PyObject *ho) + +#define P_NEO_ERROR_NUM 2 +#define P_NEO_ERROR_RETURN PyObject * +#define P_NEO_ERROR_PROTO (NEOERR *err) + +#define P_NEO_CGI_POINTERS 3 + +#ifdef NEO_CGI_MODULE +P_HDF_TO_OBJECT_RETURN p_hdf_to_object P_HDF_TO_OBJECT_PROTO; +P_OBJECT_TO_HDF_RETURN p_object_to_hdf P_OBJECT_TO_HDF_PROTO; +P_NEO_ERROR_RETURN p_neo_error P_NEO_ERROR_PROTO; + +/* other functions */ + void initneo_util(void); void initneo_cs(void); + +#else +static void **NEO_PYTHON_API; + +#define p_hdf_to_object \ + (*(P_HDF_TO_OBJECT_RETURN (*)P_HDF_TO_OBJECT_PROTO) NEO_PYTHON_API[P_HDF_TO_OBJECT_NUM]) + +#define p_object_to_hdf \ + (*(P_OBJECT_TO_HDF_RETURN (*)P_OBJECT_TO_HDF_PROTO) NEO_PYTHON_API[P_OBJECT_TO_HDF_NUM]) + +#define p_neo_error \ + (*(P_NEO_ERROR_RETURN (*)P_NEO_ERROR_PROTO) NEO_PYTHON_API[P_NEO_ERROR_NUM]) + +#define import_neo_cgi() \ +{ \ + PyObject *module = PyImport_ImportModule("neo_cgi"); \ + if (module != NULL) { \ + PyObject *module_dict = PyModule_GetDict(module); \ + PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \ + PyObject *c_api_num_o = PyDict_GetItemString(module_dict, "_C_API_NUM"); \ + if (PyInt_AsLong(c_api_num_o) < P_NEO_CGI_POINTERS) { \ + PyErr_Format(PyExc_ImportError, "neo_cgi module doesn't match header compiled against, use of this module may cause a core dump: %ld < %ld", PyInt_AsLong(c_api_num_o), P_NEO_CGI_POINTERS); \ + } \ + if (PyCObject_Check(c_api_object)) { \ + NEO_PYTHON_API = (void **)PyCObject_AsVoidPtr(c_api_object); \ + } \ + } \ +} + +#endif + +__END_DECLS #endif /* __P_NEO_UTIL_H_ */ diff -Nbru clearsilver-0.4/rules.mk clearsilver-0.5/rules.mk --- clearsilver-0.4/rules.mk Mon Aug 6 15:16:45 2001 +++ clearsilver-0.5/rules.mk Sat Apr 13 11:59:01 2002 @@ -14,18 +14,20 @@ ## 2.7.7 instead DB2_INC = -I$(HOME)/src/db-2.7.7/dist DB2_LIB = -L$(HOME)/src/db-2.7.7/dist -ldb -PYTHON_INC = -I/neo/opt/include/python2.1 +PYTHON_INC = -I/neo/opt/include/python2.1 -I/neo/opt/include/python2.2 ## Programs MKDIR = mkdir -p RM = rm -f CC = gcc +CPP = g++ CFLAGS = -g -O2 -Wall -c -I$(NEOTONIC_ROOT) $(DB2_INC) -I/neo/opt/include OUTPUT_OPTION = -o $@ LD = $(CC) -o LDFLAGS = -L$(LIB_DIR) -LDSHARED = $(CC) -shared -fPic +LDSHARED = $(CC) -shared -fPi +CPPLDSHARED = $(CPP) -shared -fPic AR = $(MKDIR) $(LIB_DIR); ar -cr DEP_LIBS = $(DLIBS:-l%=$(LIB_DIR)lib%.a) @@ -40,7 +42,7 @@ .PHONY: depend depend: Makefile.depends -Makefile.depends: +Makefile.depends: $(NEOTONIC_ROOT)/rules.mk Makefile @echo "*******************************************" @echo "** Building Dependencies " @rm -f Makefile.depends diff -Nbru clearsilver-0.4/util/Makefile clearsilver-0.5/util/Makefile --- clearsilver-0.4/util/Makefile Mon Jun 25 04:24:40 2001 +++ clearsilver-0.5/util/Makefile Thu Feb 28 16:53:41 2002 @@ -7,8 +7,9 @@ include $(NEOTONIC_ROOT)rules.mk UTL_LIB = $(LIB_DIR)libneo_utl.a -UTL_SRC = neo_err.c neo_misc.c neo_test.c ulist.c neo_hdf.c neo_str.c \ - ulocks.c skiplist.c dict.c wdb.c neo_date.c rcfs.c +UTL_SRC = neo_err.c neo_files.c neo_misc.c neo_test.c ulist.c neo_hdf.c \ + neo_str.c ulocks.c skiplist.c dict.c wdb.c neo_date.c rcfs.c \ + wildmat.c UTL_OBJ = $(UTL_SRC:%.c=%.o) TARGETS = $(UTL_LIB) diff -Nbru clearsilver-0.4/util/neo_date.h clearsilver-0.5/util/neo_date.h --- clearsilver-0.4/util/neo_date.h Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/util/neo_date.h Thu Apr 18 14:42:33 2002 @@ -11,10 +11,14 @@ #ifndef _NEO_DATE_H_ #define _NEO_DATE_H_ 1 +__BEGIN_DECLS + /* UTC time_t -> struct tm in local timezone */ void neo_time_expand (const time_t tt, char *timezone, struct tm *ttm); /* local timezone struct tm -> time_t UTC */ time_t neo_time_compact (struct tm *ttm, char *timezone); + +__END_DECLS #endif /* _NEO_DATE_H_ */ diff -Nbru clearsilver-0.4/util/neo_err.c clearsilver-0.5/util/neo_err.c --- clearsilver-0.4/util/neo_err.c Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/util/neo_err.c Tue Mar 12 23:46:03 2002 @@ -226,6 +226,50 @@ { NEOERR *more; char buf[1024]; + char *err_name; + + if (err == STATUS_OK) + return; + + if (err == INTERNAL_ERR) + { + string_append (str, "Internal error"); + return; + } + + more = err; + while (more && more != INTERNAL_ERR) + { + err = more; + more = err->next; + if (err->error != NERR_PASS) + { + NEOERR *r; + if (err->error == 0) + { + err_name = buf; + snprintf (buf, sizeof (buf), "Unknown Error"); + } + else + { + r = uListGet (Errors, err->error - 1, (void *)&err_name); + if (r != STATUS_OK) + { + err_name = buf; + snprintf (buf, sizeof (buf), "Error %d", err->error); + } + } + + string_appendf(str, "%s: %s", err_name, err->desc); + return; + } + } +} + +void nerr_error_traceback (NEOERR *err, STRING *str) +{ + NEOERR *more; + char buf[1024]; char buf2[1024]; char *err_name; @@ -289,33 +333,55 @@ int nerr_handle (NEOERR **err, int type) { - if (*err == STATUS_OK && (NEOERR *)type == STATUS_OK) + NEOERR *walk = *err; + + while (walk != STATUS_OK && walk != INTERNAL_ERR) + { + + if (walk->error == type) + { + _err_free(*err); + *err = STATUS_OK; return 1; - if (*err == STATUS_OK) - return 0; + } + walk = walk->next; + } - if (*err == INTERNAL_ERR && (NEOERR *)type == INTERNAL_ERR) + if (walk == STATUS_OK && (NEOERR *)type == STATUS_OK) return 1; - if (*err == INTERNAL_ERR) + if (walk == STATUS_OK) return 0; - if (((*err)->error == NERR_PASS) && (type != NERR_PASS)) - { - int r = nerr_handle (&((*err)->next), type); - if (r) + if (walk == INTERNAL_ERR && (NEOERR *)type == INTERNAL_ERR) { - _err_free (*err); *err = STATUS_OK; return 1; } - } + if (walk == INTERNAL_ERR) + return 0; + + return 0; +} - if ((*err)->error == type) +int nerr_match (NEOERR *err, int type) +{ + while (err != STATUS_OK && err != INTERNAL_ERR) { - _err_free (*err); - *err = STATUS_OK; + + if (err->error == type) return 1; + err = err->next; } + + if (err == STATUS_OK && (NEOERR *)type == STATUS_OK) + return 1; + if (err == STATUS_OK) + return 0; + + if (err == INTERNAL_ERR && (NEOERR *)type == INTERNAL_ERR) + return 1; + if (err == INTERNAL_ERR) + return 0; return 0; } diff -Nbru clearsilver-0.4/util/neo_err.h clearsilver-0.5/util/neo_err.h --- clearsilver-0.4/util/neo_err.h Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/util/neo_err.h Tue Mar 12 23:42:32 2002 @@ -111,6 +111,7 @@ #include "neo_str.h" void nerr_error_string (NEOERR *err, STRING *str); +void nerr_error_traceback (NEOERR *err, STRING *str); /* function: nerr_ignore * description: you should only call this if you actually handle the @@ -123,6 +124,7 @@ NEOERR *nerr_init (void); int nerr_handle (NEOERR **err, NERR_TYPE type); +int nerr_match (NEOERR *err, NERR_TYPE type); __END_DECLS diff -Nbru clearsilver-0.4/util/neo_files.c clearsilver-0.5/util/neo_files.c --- clearsilver-0.4/util/neo_files.c Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/util/neo_files.c Thu Feb 28 16:53:41 2002 @@ -0,0 +1,237 @@ +/* + * Neotonic ClearSilver Templating System + * + * This code is made available under the terms of the + * Neotonic ClearSilver License. + * http://www.neotonic.com/clearsilver/license.hdf + * + * Copyright (C) 2001 by Brandon Long + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "neo_err.h" +#include "neo_misc.h" +#include "neo_files.h" +#include "wildmat.h" + +NEOERR *ne_mkdirs (char *path, mode_t mode) +{ + char mypath[_POSIX_PATH_MAX]; + int x; + int r; + + strncpy (mypath, path, sizeof(mypath)); + x = strlen(mypath); + if ((x < sizeof(mypath)) && (mypath[x-1] != '/')) + { + mypath[x] = '/'; + mypath[x+1] = '\0'; + } + + for (x = 1; mypath[x]; x++) + { + if (mypath[x] == '/') + { + mypath[x] = '\0'; + r = mkdir (mypath, mode); + if (r == -1 && errno != EEXIST) + { + return nerr_raise_errno(NERR_SYSTEM, "ne_mkdirs: mkdir(%s, %x) failed", mypath, mode); + } + mypath[x] = '/'; + } + } + return STATUS_OK; +} + +NEOERR *ne_load_file (char *path, char **str) +{ + struct stat s; + int fd; + int len; + + *str = NULL; + + if (stat(path, &s) == -1) + { + if (errno == ENOENT) + return nerr_raise (NERR_NOT_FOUND, "File %s not found", path); + return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path); + } + + fd = open (path, O_RDONLY); + if (fd == -1) + { + return nerr_raise_errno (NERR_SYSTEM, "Unable to open file %s", path); + } + len = s.st_size; + *str = (char *) malloc (len + 1); + + if (*str == NULL) + { + close(fd); + return nerr_raise (NERR_NOMEM, + "Unable to allocate memory (%d) to load file %s", s.st_size, path); + } + if (read (fd, *str, len) == -1) + { + close(fd); + free(*str); + return nerr_raise_errno (NERR_SYSTEM, "Unable to read file %s", path); + } + (*str)[len] = '\0'; + close(fd); + + return STATUS_OK; +} + +NEOERR *ne_save_file (char *path, char *str) +{ + NEOERR *err; + int fd; + int w, l; + + fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (fd == -1) + { + return nerr_raise_errno (NERR_IO, "Unable to create file %s", path); + } + l = strlen(str); + w = write (fd, str, l); + if (w != l) + { + err = nerr_raise_errno (NERR_IO, "Unable to write file %s", path); + close (fd); + return err; + } + close (fd); + + return STATUS_OK; +} + +NEOERR *ne_remove_dir (char *path) +{ + NEOERR *err; + DIR *dp; + struct stat s; + struct dirent *de; + char npath[_POSIX_PATH_MAX]; + + if (stat(path, &s) == -1) + { + if (errno == ENOENT) return STATUS_OK; + return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path); + } + if (!S_ISDIR(s.st_mode)) + { + return nerr_raise (NERR_ASSERT, "Path %s is not a directory", path); + } + dp = opendir(path); + if (dp == NULL) + return nerr_raise_errno (NERR_IO, "Unable to open directory %s", path); + while ((de = readdir (dp)) != NULL) + { + if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) + { + snprintf (npath, sizeof(npath), "%s/%s", path, de->d_name); + if (stat(npath, &s) == -1) + { + if (errno == ENOENT) continue; + closedir(dp); + return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", npath); + } + if (S_ISDIR(s.st_mode)) + { + err = ne_remove_dir(npath); + if (err) break; + } + else + { + if (unlink(npath) == -1) + { + if (errno == ENOENT) continue; + closedir(dp); + return nerr_raise_errno (NERR_SYSTEM, "Unable to unlink file %s", + npath); + } + } + } + } + closedir(dp); + if (rmdir(path) == -1) + { + return nerr_raise_errno (NERR_SYSTEM, "Unable to rmdir %s", path); + } + return STATUS_OK; +} + +NEOERR *ne_listdir(char *path, ULIST **files) +{ + return nerr_pass(ne_listdir_fmatch(path, files, NULL, NULL)); +} + +static int _glob_match(void *rock, char *filename) +{ + return wildmat(filename, rock); +} + +NEOERR *ne_listdir_match(char *path, ULIST **files, char *match) +{ + return nerr_pass(ne_listdir_fmatch(path, files, _glob_match, match)); +} + +NEOERR *ne_listdir_fmatch(char *path, ULIST **files, MATCH_FUNC fmatch, void *rock) +{ + DIR *dp; + struct dirent *de; + ULIST *myfiles = NULL; + NEOERR *err = STATUS_OK; + + if (files == NULL) + return nerr_raise(NERR_ASSERT, "Invalid call to ne_listdir_fmatch"); + + if (*files == NULL) + { + err = uListInit(&myfiles, 10, 0); + if (err) return nerr_pass(err); + } + else + { + myfiles = *files; + } + + if ((dp = opendir (path)) == NULL) + { + return nerr_raise_errno(NERR_IO, "Unable to opendir %s", path); + } + while ((de = readdir (dp)) != NULL) + { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + + if (fmatch != NULL && !fmatch(rock, de->d_name)) + continue; + + err = uListAppend(myfiles, strdup(de->d_name)); + if (err) break; + } + closedir(dp); + if (err && *files == NULL) + { + uListDestroy(&myfiles, ULIST_FREE); + } + else if (*files == NULL) + { + *files = myfiles; + } + return nerr_pass(err); +} diff -Nbru clearsilver-0.4/util/neo_files.h clearsilver-0.5/util/neo_files.h --- clearsilver-0.4/util/neo_files.h Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/util/neo_files.h Thu Feb 28 16:53:41 2002 @@ -0,0 +1,32 @@ +/* + * Neotonic ClearSilver Templating System + * + * This code is made available under the terms of the + * Neotonic ClearSilver License. + * http://www.neotonic.com/clearsilver/license.hdf + * + * Copyright (C) 2001 by Brandon Long + */ + +#ifndef __NEO_FILES_H_ +#define __NEO_FILES_H_ 1 + +__BEGIN_DECLS + +#include +#include +#include "util/ulist.h" + +typedef int (* MATCH_FUNC)(void *rock, char *filename); + +NEOERR *ne_mkdirs (char *path, mode_t mode); +NEOERR *ne_load_file (char *path, char **str); +NEOERR *ne_save_file (char *path, char *str); +NEOERR *ne_remove_dir (char *path); +NEOERR *ne_listdir(char *path, ULIST **files); +NEOERR *ne_listdir_match(char *path, ULIST **files, char *match); +NEOERR *ne_listdir_fmatch(char *path, ULIST **files, MATCH_FUNC fmatch, void *rock); + +__END_DECLS + +#endif /* __NEO_FILES_H_ */ diff -Nbru clearsilver-0.4/util/neo_hdf.c clearsilver-0.5/util/neo_hdf.c --- clearsilver-0.4/util/neo_hdf.c Wed Oct 10 17:26:13 2001 +++ clearsilver-0.5/util/neo_hdf.c Thu Apr 18 12:24:53 2002 @@ -19,6 +19,7 @@ #include "neo_err.h" #include "neo_hdf.h" #include "neo_str.h" +#include "ulist.h" static NEOERR *_alloc_hdf (HDF **hdf, char *name, size_t nlen, char *value, int dup, int wf, HDF *top) @@ -131,6 +132,11 @@ *node = NULL; if (hdf == NULL) return -1; + if (name == NULL || name[0] == '\0') + { + *node = hdf; + return 0; + } if (hdf->link) { @@ -448,6 +454,66 @@ return nerr_raise (NERR_NOT_FOUND, "Unable to find %s", src); } +/* grody bubble sort from Wheeler, but sorting a singly linked list + * is annoying */ +void hdf_sort_obj_bubble(HDF *h, int (*compareFunc)(HDF *, HDF *)) +{ + HDF *p, *c = hdf_obj_child(h); + HDF *prev; + int swapped; + + do { + swapped = 0; + for (p = c, prev = c; p && p->next; prev = p, p = p->next) { + if (compareFunc(p, p->next) > 0) { + HDF *tmp = p->next; + prev->next = tmp; + p->next = tmp->next; + tmp->next = p; + p = tmp; + swapped = 1; + } + } + } while (swapped); +} + +/* Ok, this version avoids the bubble sort by walking the level once to + * load them all into a ULIST, qsort'ing the list, and then dumping them + * back out... */ +NEOERR *hdf_sort_obj (HDF *h, int (*compareFunc)(const void *, const void *)) +{ + NEOERR *err = STATUS_OK; + ULIST *level = NULL; + HDF *p, *c; + int x; + + if (h == NULL) return STATUS_OK; + c = h->child; + if (c == NULL) return STATUS_OK; + + do { + err = uListInit(&level, 40, 0); + if (err) return nerr_pass(err); + for (p = c; p; p = p->next) { + err = uListAppend(level, p); + if (err) break; + } + err = uListSort(level, compareFunc); + if (err) break; + uListGet(level, 0, (void **)&c); + h->child = c; + for (x = 1; x < uListLength(level); x++) + { + uListGet(level, x, (void **)&p); + c->next = p; + p->next = NULL; + c = p; + } + } while (0); + uListDestroy(&level, 0); + return nerr_pass(err); +} + NEOERR* hdf_remove_tree (HDF *hdf, char *name) { HDF *hp = hdf; @@ -464,6 +530,9 @@ return STATUS_OK; } + lp = hdf; + ln = NULL; + n = name; s = strchr (n, '.'); x = (s == NULL) ? strlen(n) : s - n; @@ -932,19 +1001,37 @@ return nerr_pass (_hdf_read_string (hdf, &str, &line)); } +static int count_newlines (char *s) +{ + int i = 0; + char *n = s; + + n = strchr(s, '\n'); + while (n != NULL) + { + i++; + n = strchr(n+1, '\n'); + } + return i; +} + static NEOERR* hdf_read_file_fp (HDF *hdf, FILE *fp, char *path, int *line) { NEOERR *err; + STRING str; HDF *lower; char buf[4096]; char *s; char *name, *value; int l; - while (fgets(buf, sizeof(buf), fp) != NULL) + string_init(&str); + err = string_readline(&str, fp); + if (err) return nerr_pass(err); + while (str.len != 0) { (*line)++; - s = buf; + s = str.buf; SKIPWS(s); if (!strncmp(s, "#include ", 9)) { @@ -1048,7 +1135,7 @@ path, *line, name); while (fgets(m+msize, mmax-msize, fp) != NULL) { - if (!strncmp(value, m+msize, l) && isspace(m[msize+l])) + if (!strncmp(value, m+msize, l) && (m[msize+l] == '\r' || m[msize+l] == '\n')) { m[msize] = '\0'; break; @@ -1070,7 +1157,8 @@ free (m); return nerr_pass_ctx(err, "In file %s:%d", path, *line); } - + /* count the newlines so we know what line we're on... +1 for EOM */ + (*line) = (*line) + count_newlines(m) + 1; } else { @@ -1078,6 +1166,9 @@ path, *line, buf); } } + str.len = 0; + err = string_readline(&str, fp); + if (err) return nerr_pass(err); } return STATUS_OK; } @@ -1123,6 +1214,8 @@ int line = 0; char fpath[_POSIX_PATH_MAX]; + if (path == NULL) + return nerr_raise(NERR_ASSERT, "Can't read NULL file"); if (path[0] != '/') { err = hdf_search_path (hdf, path, fpath); diff -Nbru clearsilver-0.4/util/neo_hdf.h clearsilver-0.5/util/neo_hdf.h --- clearsilver-0.4/util/neo_hdf.h Fri Sep 14 16:45:46 2001 +++ clearsilver-0.5/util/neo_hdf.h Mon Apr 15 17:37:10 2002 @@ -50,6 +50,19 @@ NEOERR *hdf_set_symlink (HDF *hdf, char *src, char *dest); +/* + * 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. The current + * implementation uses a bubble sort, so be warned. + * Input: h - HDF node + * compareFunc - function which returns 1,0,-1 depending on some + * criteria. Given two children of h + * Output: None (h children will be sorted) + * Return: None + */ +NEOERR *hdf_sort_obj(HDF *h, int (*compareFunc)(const void *, const void *)); + NEOERR* hdf_read_file (HDF *hdf, char *path); NEOERR* hdf_write_file (HDF *hdf, char *path); diff -Nbru clearsilver-0.4/util/neo_misc.c clearsilver-0.5/util/neo_misc.c --- clearsilver-0.4/util/neo_misc.c Wed Jan 2 16:36:42 2002 +++ clearsilver-0.5/util/neo_misc.c Thu Feb 28 16:53:41 2002 @@ -10,18 +10,12 @@ #include #include -#include #include #include #include #include -#include #include #include -#include -#include -#include -#include #include "neo_err.h" #include "neo_misc.h" @@ -140,36 +134,6 @@ return f; } -NEOERR *ne_mkdirs (char *path, mode_t mode) -{ - char mypath[_POSIX_PATH_MAX]; - int x; - int r; - - strncpy (mypath, path, sizeof(mypath)); - x = strlen(mypath); - if ((x < sizeof(mypath)) && (mypath[x-1] != '/')) - { - mypath[x] = '/'; - mypath[x+1] = '\0'; - } - - for (x = 1; mypath[x]; x++) - { - if (mypath[x] == '/') - { - mypath[x] = '\0'; - r = mkdir (mypath, mode); - if (r == -1 && errno != EEXIST) - { - return nerr_raise_errno(NERR_SYSTEM, "ne_mkdirs: mkdir(%s, %x) failed", mypath, mode); - } - mypath[x] = '/'; - } - } - return STATUS_OK; -} - static const UINT32 CRCTable[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, @@ -230,124 +194,3 @@ return crc; } - -NEOERR *ne_load_file (char *path, char **str) -{ - struct stat s; - int fd; - int len; - - *str = NULL; - - if (stat(path, &s) == -1) - { - if (errno == ENOENT) - return nerr_raise (NERR_NOT_FOUND, "File %s not found", path); - return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path); - } - - fd = open (path, O_RDONLY); - if (fd == -1) - { - return nerr_raise_errno (NERR_SYSTEM, "Unable to open file %s", path); - } - len = s.st_size; - *str = (char *) malloc (len + 1); - - if (*str == NULL) - { - close(fd); - return nerr_raise (NERR_NOMEM, - "Unable to allocate memory (%d) to load file %s", s.st_size, path); - } - if (read (fd, *str, len) == -1) - { - close(fd); - free(*str); - return nerr_raise_errno (NERR_SYSTEM, "Unable to read file %s", path); - } - (*str)[len] = '\0'; - close(fd); - - return STATUS_OK; -} - -NEOERR *ne_save_file (char *path, char *str) -{ - NEOERR *err; - int fd; - int w, l; - - fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if (fd == -1) - { - return nerr_raise_errno (NERR_IO, "Unable to create file %s", path); - } - l = strlen(str); - w = write (fd, str, l); - if (w != l) - { - err = nerr_raise_errno (NERR_IO, "Unable to write file %s", path); - close (fd); - return err; - } - close (fd); - - return STATUS_OK; -} - -NEOERR *ne_remove_dir (char *path) -{ - NEOERR *err; - DIR *dp; - struct stat s; - struct dirent *de; - char npath[_POSIX_PATH_MAX]; - - if (stat(path, &s) == -1) - { - if (errno == ENOENT) return STATUS_OK; - return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path); - } - if (!S_ISDIR(s.st_mode)) - { - return nerr_raise (NERR_ASSERT, "Path %s is not a directory", path); - } - dp = opendir(path); - if (dp == NULL) - return nerr_raise_errno (NERR_IO, "Unable to open directory %s", path); - while ((de = readdir (dp)) != NULL) - { - if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) - { - snprintf (npath, sizeof(npath), "%s/%s", path, de->d_name); - if (stat(npath, &s) == -1) - { - if (errno == ENOENT) continue; - closedir(dp); - return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", npath); - } - if (S_ISDIR(s.st_mode)) - { - err = ne_remove_dir(npath); - if (err) break; - } - else - { - if (unlink(npath) == -1) - { - if (errno == ENOENT) continue; - closedir(dp); - return nerr_raise_errno (NERR_SYSTEM, "Unable to unlink file %s", - npath); - } - } - } - } - closedir(dp); - if (rmdir(path) == -1) - { - return nerr_raise_errno (NERR_SYSTEM, "Unable to rmdir %s", path); - } - return STATUS_OK; -} diff -Nbru clearsilver-0.4/util/neo_misc.h clearsilver-0.5/util/neo_misc.h --- clearsilver-0.4/util/neo_misc.h Mon Dec 17 23:17:05 2001 +++ clearsilver-0.5/util/neo_misc.h Thu Feb 28 16:53:41 2002 @@ -43,11 +43,7 @@ UINT8 *ne_stream_str (UINT8 *dest, char *s, int l); UINT8 *ne_unstream_str (char *s, int l, UINT8 *src); double ne_timef (void); -NEOERR *ne_mkdirs (char *path, mode_t mode); -NEOERR *ne_load_file (char *path, char **str); -NEOERR *ne_save_file (char *path, char *str); UINT32 ne_crc (UINT8 *data, UINT32 bytes); -NEOERR *ne_remove_dir (char *path); __END_DECLS diff -Nbru clearsilver-0.4/util/neo_str.c clearsilver-0.5/util/neo_str.c --- clearsilver-0.4/util/neo_str.c Mon Dec 17 23:17:05 2001 +++ clearsilver-0.5/util/neo_str.c Thu Apr 11 18:10:59 2002 @@ -121,7 +121,7 @@ err = string_check_length (str, l+1); if (err != STATUS_OK) return nerr_pass (err); - strncpy(str->buf + str->len, buf, l); + memcpy(str->buf + str->len, buf, l); str->len += l; str->buf[str->len] = '\0'; @@ -296,4 +296,122 @@ if (errcode == 0) return TRUE; return FALSE; +} + +NEOERR *string_readline (STRING *str, FILE *fp) +{ + NEOERR *err; + + /* minimum size for a readline is 256 above current position */ + err = string_check_length (str, str->len + 256); + if (err != STATUS_OK) return nerr_pass (err); + + while (fgets(str->buf + str->len, str->max - str->len, fp) != NULL) + { + str->len = strlen(str->buf); + if (str->buf[str->len-1] == '\n') break; + err = string_check_length (str, str->len + 256); + if (err != STATUS_OK) return nerr_pass (err); + } + return STATUS_OK; +} + +NEOERR* neos_escape(UINT8 *buf, int buflen, char esc_char, char *escape, char **esc) +{ + int nl = 0; + int l = 0; + int x = 0; + char *s; + int match = 0; + + while (l < buflen) + { + if (buf[l] == esc_char) + { + nl += 2; + } + else + { + x = 0; + while (escape[x]) + { + if (escape[x] == buf[l]) + { + nl +=2; + break; + } + x++; + } + } + nl++; + l++; + } + + s = (char *) malloc (sizeof(char) * (nl + 1)); + if (s == NULL) + return nerr_raise (NERR_NOMEM, "Unable to allocate memory to escape %s", + buf); + + nl = 0; l = 0; + while (l < buflen) + { + match = 0; + if (buf[l] == esc_char) + { + match = 1; + } + else + { + x = 0; + while (escape[x]) + { + if (escape[x] == buf[l]) + { + match = 1; + break; + } + x++; + } + } + if (match) + { + s[nl++] = esc_char; + s[nl++] = "0123456789ABCDEF"[buf[l] / 16]; + s[nl++] = "0123456789ABCDEF"[buf[l] % 16]; + l++; + } + else + { + s[nl++] = buf[l++]; + } + } + s[nl] = '\0'; + + *esc = s; + return STATUS_OK; +} + +UINT8 *neos_unescape (UINT8 *s, int buflen, char esc_char) +{ + int i = 0, o = 0; + + if (s == NULL) return s; + while (i < buflen) + { + if (s[i] == esc_char && (i+2 < buflen) && + isxdigit(s[i+1]) && isxdigit(s[i+2])) + { + UINT8 num; + num = (s[i+1] >= 'A') ? ((s[i+1] & 0xdf) - 'A') + 10 : (s[i+1] - '0'); + num *= 16; + num += (s[i+2] >= 'A') ? ((s[i+2] & 0xdf) - 'A') + 10 : (s[i+2] - '0'); + s[o++] = num; + i+=3; + } + else { + s[o++] = s[i++]; + } + } + if (i && o) s[o] = '\0'; + return s; } diff -Nbru clearsilver-0.4/util/neo_str.h clearsilver-0.5/util/neo_str.h --- clearsilver-0.4/util/neo_str.h Mon Dec 17 23:17:05 2001 +++ clearsilver-0.5/util/neo_str.h Thu Apr 11 18:10:59 2002 @@ -15,6 +15,7 @@ __BEGIN_DECLS #include +#include #include "util/neo_misc.h" /* This modifies the string its called with by replacing all the white @@ -30,7 +31,7 @@ typedef struct _string { - char *buf; + UINT8 *buf; int len; int max; } STRING; @@ -49,6 +50,7 @@ NEOERR *string_append_char (STRING *str, char c); NEOERR *string_appendf (STRING *str, char *fmt, ...); NEOERR *string_appendvf (STRING *str, char *fmt, va_list ap); +NEOERR *string_readline (STRING *str, FILE *fp); void string_clear (STRING *str); /* typedef struct _ulist ULIST; */ @@ -57,6 +59,9 @@ BOOL reg_search (char *re, char *str); + +NEOERR* neos_escape(UINT8 *buf, int buflen, char esc_char, char *escape, char **esc); +UINT8 *neos_unescape (UINT8 *s, int buflen, char esc_char); __END_DECLS diff -Nbru clearsilver-0.4/util/rcfs.c clearsilver-0.5/util/rcfs.c --- clearsilver-0.4/util/rcfs.c Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/util/rcfs.c Thu Feb 28 16:53:41 2002 @@ -24,6 +24,7 @@ #include "util/neo_err.h" #include "util/neo_misc.h" +#include "util/neo_files.h" #include "util/neo_hdf.h" #include "util/ulocks.h" #include "rcfs.h" diff -Nbru clearsilver-0.4/util/skiplist.c clearsilver-0.5/util/skiplist.c --- clearsilver-0.4/util/skiplist.c Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/util/skiplist.c Thu Apr 11 14:17:46 2002 @@ -37,7 +37,7 @@ #define SIZEOFITEM(max) (sizeof(struct skipItem) + \ ((max+1) * sizeof(skipItem))) -struct skipList { +struct skipList_struct { INT32 topLevel; /* current max level in any item */ INT32 levelHint; /* hint at level to start search */ skipItem header; /* header item (has all levels) */ @@ -361,7 +361,7 @@ UINT32 i; *skip = NULL; - if(! (list = calloc(1, sizeof(struct skipList)))) + if(! (list = calloc(1, sizeof(struct skipList_struct)))) return nerr_raise(NERR_NOMEM, "Unable to allocate memore for skiplist"); if (maxLevel == 0) diff -Nbru clearsilver-0.4/util/skiplist.h clearsilver-0.5/util/skiplist.h --- clearsilver-0.4/util/skiplist.h Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/util/skiplist.h Thu Apr 11 14:17:46 2002 @@ -17,6 +17,10 @@ #ifndef _SKIPLIST_H_ #define _SKIPLIST_H_ +#include + +__BEGIN_DECLS + /* * Larger values of means fewer levels and faster lookups, * but more variability in those lookup times (range limited from 2 to 4). @@ -27,11 +31,15 @@ * * I've capped at 20, which would be good for a minimum of * 1 million items on lists with == 2. + * + * + * Example + * skipNewList(&(my_wdb->ondisk), 0, 4, 2, 0, NULL, NULL); */ #define SKIP_MAXLEVEL 20 /* SKIP LIST TYPEDEFS */ -typedef struct skipList *skipList; +typedef struct skipList_struct *skipList; typedef void (*skipFreeValue)(void *value, void *ctx); NEOERR *skipNewList(skipList *skip, int threaded, int root, int maxLevel, @@ -146,4 +154,12 @@ * MT-Level: Safe if thread-safe. */ +__END_DECLS + #endif /* _SKIPLIST_H_ */ + + + + + + diff -Nbru clearsilver-0.4/util/test/Makefile clearsilver-0.5/util/test/Makefile --- clearsilver-0.4/util/test/Makefile Fri Dec 22 00:31:27 2000 +++ clearsilver-0.5/util/test/Makefile Thu Apr 18 12:24:55 2002 @@ -10,16 +10,30 @@ HDFTEST_SRC = hdftest.c HDFTEST_OBJ = $(HDFTEST_SRC:%.c=%.o) +LISTDIRTEST_EXE = listdir_test +LISTDIRTEST_SRC = listdir_test.c +LISTDIRTEST_OBJ = $(LISTDIRTEST_SRC:%.c=%.o) + +HDFCOPYTEST_EXE = hdf_copy_test +HDFCOPYTEST_SRC = hdf_copy_test.c +HDFCOPYTEST_OBJ = $(HDFCOPYTEST_SRC:%.c=%.o) + CFLAGS += -I$(NEOTONIC_ROOT)/util -LIBS += -L$(LIB_DIR) -lneo_utl # -lefence +LIBS += -L$(LIB_DIR) -lneo_utl -TARGETS = $(HDFTEST_EXE) +TARGETS = $(HDFTEST_EXE) $(LISTDIRTEST_EXE) $(HDFCOPYTEST_EXE) all: $(TARGETS) $(HDFTEST_EXE): $(HDFTEST_OBJ) $(NTR_LIB) $(LD) $@ $(HDFTEST_OBJ) $(LIBS) + +$(LISTDIRTEST_EXE): $(LISTDIRTEST_OBJ) $(NTR_LIB) + $(LD) $@ $(LISTDIRTEST_OBJ) $(LIBS) + +$(HDFCOPYTEST_EXE): $(HDFCOPYTEST_OBJ) $(NTR_LIB) + $(LD) $@ $(HDFCOPYTEST_OBJ) $(LIBS) -lefence clean: $(RM) *.o diff -Nbru clearsilver-0.4/util/test/hdf_copy_test.c clearsilver-0.5/util/test/hdf_copy_test.c --- clearsilver-0.4/util/test/hdf_copy_test.c Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/util/test/hdf_copy_test.c Thu Apr 18 12:24:55 2002 @@ -0,0 +1,37 @@ + +#include +#include + +int main(void) { + HDF *hdf_1; + HDF *hdf_2; + HDF *cur_node,*last_node; + + hdf_init(&hdf_1); + + hdf_read_file(hdf_1,"hdf_copy_test.hdf"); + + cur_node = hdf_get_obj(hdf_1,"Chart"); + last_node = cur_node; + + cur_node = hdf_get_obj(cur_node,"next_stage"); + while (hdf_get_obj(cur_node,"next_stage") && strcmp(hdf_get_value(cur_node,"Bucket.FieldId",""),"QUEUE")) { + last_node = cur_node; + cur_node = hdf_get_obj(cur_node,"next_stage"); + } + + if (hdf_get_obj(cur_node,"next_stage")) { + hdf_copy(hdf_1,"TempHolderPlace",hdf_get_obj(cur_node,"next_stage")); + } + ne_warn("Delete tree from node: %s", hdf_obj_name(last_node)); + hdf_remove_tree(last_node,"next_stage"); + + hdf_dump(hdf_1,NULL); + fprintf(stderr,"-----------------\n"); + + + hdf_copy(last_node,"next_stage",hdf_get_obj(hdf_1,"TempHolderPlace")); + hdf_dump(hdf_1,NULL); + + return 0; +} diff -Nbru clearsilver-0.4/util/test/hdf_copy_test.hdf clearsilver-0.5/util/test/hdf_copy_test.hdf --- clearsilver-0.4/util/test/hdf_copy_test.hdf Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/util/test/hdf_copy_test.hdf Thu Apr 18 11:46:44 2002 @@ -0,0 +1,50 @@ + +# -------------------------------------------------- +# this is an example definition of a chart pipeline +# + + +DataSource = outfile.sdb +DataSource { +# TODO: specify time range for the dataset.... +} + +DomainData { +# TODO: include data values for agents, queues, etc. +} + +Filters { +# TODO: configure filters to limit data +} + +Chart { + next_stage { + id = 1 + Type = Mux + Bucket = Discrete + Bucket.FieldId = QUEUE + Bucket.Dimension = Y + + next_stage { + id = 2 + Type = Mux + Bucket = Time + Bucket.FieldId = TIME + Bucket.Dimension = Y + + next_stage { + id = 3 + Type = Mux + Bucket = Discrete + Bucket.FieldId = AGENT + Bucket.Dimension = X + + next_stage { + id = 4 + Type = Accumulator + } + } + } + + } +} diff -Nbru clearsilver-0.4/util/test/hdftest.c clearsilver-0.5/util/test/hdftest.c --- clearsilver-0.4/util/test/hdftest.c Fri Dec 22 00:31:27 2000 +++ clearsilver-0.5/util/test/hdftest.c Mon Apr 15 17:37:11 2002 @@ -21,6 +21,15 @@ return 0; } +static int sortByName(const void *a, const void *b) { + HDF **ha = (HDF **)a; + HDF **hb = (HDF **)b; + + /* fprintf(stderr, "%s <=> %s\n", hdf_obj_name(*ha), hdf_obj_name(*hb)); */ + return strcasecmp(hdf_obj_name(*ha), hdf_obj_name(*hb)); +} + + int main(int argc, char *argv[]) { NEOERR *err; @@ -28,6 +37,7 @@ int x; char name[256]; char value[256]; + double tstart = 0; err = hdf_init(&hdf); if (err != STATUS_OK) @@ -75,7 +85,7 @@ hdf_dump(hdf, NULL); - err = hdf_get_int_value (hdf, "Beware.The.Ides", &x, 0); + x = hdf_get_int_value (hdf, "Beware.The.Ides", 0); if (err != STATUS_OK) { nerr_log_error(err); @@ -87,7 +97,7 @@ return -1; } - for (x = 0; x < 100; x++) + for (x = 0; x < 10000; x++) { rand_name(name, sizeof(name)); neot_rand_word(value, sizeof(value)); @@ -107,7 +117,11 @@ return -1; } - hdf_dump(hdf, NULL); + tstart = ne_timef(); + hdf_sort_obj(hdf, sortByName); + ne_warn("sort took %5.5fs", ne_timef() - tstart); + + /* hdf_dump(hdf, NULL); */ hdf_destroy(&hdf); diff -Nbru clearsilver-0.4/util/test/listdir_test.c clearsilver-0.5/util/test/listdir_test.c --- clearsilver-0.4/util/test/listdir_test.c Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/util/test/listdir_test.c Thu Feb 28 16:53:42 2002 @@ -0,0 +1,52 @@ + +#include +#include "util/neo_err.h" +#include "util/neo_misc.h" +#include "util/neo_files.h" + +int main(int argc, char **argv) +{ + char *path; + ULIST *files = NULL; + char *filename; + NEOERR *err; + int x; + + if (argc > 1) + path = argv[1]; + else + path = "."; + + ne_warn("Testing ne_listdir()"); + err = ne_listdir(path, &files); + if (err) + { + nerr_log_error(err); + return -1; + } + + for (x = 0; x < uListLength(files); x++) + { + err = uListGet(files, x, &filename); + printf("%s\n", filename); + } + + uListDestroy(&files, ULIST_FREE); + + ne_warn("Testing ne_listdir_match() with *.c"); + err = ne_listdir_match(path, &files, "*.c"); + if (err) + { + nerr_log_error(err); + return -1; + } + + for (x = 0; x < uListLength(files); x++) + { + err = uListGet(files, x, &filename); + printf("%s\n", filename); + } + + uListDestroy(&files, ULIST_FREE); + return 0; +} diff -Nbru clearsilver-0.4/util/ulist.c clearsilver-0.5/util/ulist.c --- clearsilver-0.4/util/ulist.c Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/util/ulist.c Thu Mar 28 10:35:43 2002 @@ -216,6 +216,29 @@ return STATUS_OK; } +void *uListSearch (ULIST *ul, const void *key, int + (*compareFunc)(const void *, const void*)) { + return bsearch(key, ul->items, ul->num, sizeof(void *), compareFunc); +} + +void *uListIn (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)) { + int i; + + for (i = 0; i < ul->num; ++i) { + if (!compareFunc(key, &ul->items[i])) { + return &ul->items[i]; + } + } + return NULL; +} + +int uListIndex (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)) { + void **p = uListIn(ul, key, compareFunc); + return p ? (p - ul->items) : -1; +} + + + NEOERR *uListDestroy (ULIST **ul, int flags) { if (flags & ULIST_FREE) @@ -254,5 +277,6 @@ int uListLength (ULIST *ul) { + if (ul == NULL) return 0; return ul->num; } diff -Nbru clearsilver-0.4/util/ulist.h clearsilver-0.5/util/ulist.h --- clearsilver-0.4/util/ulist.h Mon Aug 6 14:28:17 2001 +++ clearsilver-0.5/util/ulist.h Thu Mar 28 10:35:43 2002 @@ -36,6 +36,9 @@ NEOERR * uListSet (ULIST *ul, int x, void *data); NEOERR * uListReverse (ULIST *ul); NEOERR * uListSort (ULIST *ul, int (*compareFunc)(const void*, const void*)); +void *uListSearch (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)); +void *uListIn (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)); +int uListIndex (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)); NEOERR * uListDestroy (ULIST **ul, int flags); NEOERR * uListDestroyFunc (ULIST **ul, void (*destroyFunc)(void *)); diff -Nbru clearsilver-0.4/util/ulocks.c clearsilver-0.5/util/ulocks.c --- clearsilver-0.4/util/ulocks.c Wed Jan 2 16:36:31 2002 +++ clearsilver-0.5/util/ulocks.c Thu Feb 28 16:53:41 2002 @@ -17,6 +17,7 @@ #include "neo_err.h" #include "neo_misc.h" +#include "neo_files.h" #include "ulocks.h" NEOERR *fCreate(int *plock, char *file) diff -Nbru clearsilver-0.4/util/wildmat.c clearsilver-0.5/util/wildmat.c --- clearsilver-0.4/util/wildmat.c Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/util/wildmat.c Thu Feb 28 16:53:41 2002 @@ -0,0 +1,205 @@ +/* $Revision: 1.1 $ + ** + ** Do shell-style pattern matching for ?, \, [], and * characters. + ** Might not be robust in face of malformed patterns; e.g., "foo[a-" + ** could cause a segmentation violation. It is 8bit clean. + ** + ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. + ** Rich $alz is now . + ** April, 1991: Replaced mutually-recursive calls with in-line code + ** for the star character. + ** + ** Special thanks to Lars Mathiesen for the ABORT code. + ** This can greatly speed up failing wildcard patterns. For example: + ** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-* + ** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1 + ** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1 + ** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without + ** the ABORT code, it takes 22310 calls to fail. Ugh. The following + ** explanation is from Lars: + ** The precondition that must be fulfilled is that DoMatch will consume + ** at least one character in text. This is true if *p is neither '*' nor + ** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic + ** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With + ** FALSE, each star-loop has to run to the end of the text; with ABORT + ** only the last one does. + ** + ** Once the control of one instance of DoMatch enters the star-loop, that + ** instance will return either TRUE or ABORT, and any calling instance + ** will therefore return immediately after (without calling recursively + ** again). In effect, only one star-loop is ever active. It would be + ** possible to modify the code to maintain this context explicitly, + ** eliminating all recursive calls at the cost of some complication and + ** loss of clarity (and the ABORT stuff seems to be unclear enough by + ** itself). I think it would be unwise to try to get this into a + ** released version unless you have a good test data base to try it + ** out on. + */ + +#include +#include "neo_misc.h" + +#define ABORT -1 + + + /* What character marks an inverted character class? */ +#define NEGATE_CLASS '^' + /* Is "*" a common pattern? */ +#define OPTIMIZE_JUST_STAR + /* Do tar(1) matching rules, which ignore a trailing slash? */ +#undef MATCH_TAR_PATTERN + + +/* + ** Match text and p, return TRUE, FALSE, or ABORT. + */ + static int +DoMatch(register char *text, register char *p) +{ + register int last; + register int matched; + register int reverse; + + for ( ; *p; text++, p++) { + if (*text == '\0' && *p != '*') + return ABORT; + switch (*p) { + case '\\': + /* Literal match with following character. */ + p++; + /* FALLTHROUGH */ + default: + if (*text != *p) + return FALSE; + continue; + case '?': + /* Match anything. */ + continue; + case '*': + while (*++p == '*') + /* Consecutive stars act just like one. */ + continue; + if (*p == '\0') + /* Trailing star matches everything. */ + return TRUE; + while (*text) + if ((matched = DoMatch(text++, p)) != FALSE) + return matched; + return ABORT; + case '[': + reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE; + if (reverse) + /* Inverted character class. */ + p++; + matched = FALSE; + if (p[1] == ']' || p[1] == '-') + if (*++p == *text) + matched = TRUE; + for (last = *p; *++p && *p != ']'; last = *p) + /* This next line requires a good C compiler. */ + if (*p == '-' && p[1] != ']' + ? *text <= *++p && *text >= last : *text == *p) + matched = TRUE; + if (matched == reverse) + return FALSE; + continue; + } + } + +#ifdef MATCH_TAR_PATTERN + if (*text == '/') + return TRUE; +#endif /* MATCH_TAR_ATTERN */ + return *text == '\0'; +} + + +/* + ** Match text and p, return TRUE, FALSE, or ABORT. + */ +static int +DoMatchCaseInsensitive(register char *text, register char *p) +{ + register int last; + register int matched; + register int reverse; + + for ( ; *p; text++, p++) { + if (*text == '\0' && *p != '*') + return ABORT; + switch (*p) { + case '\\': + /* Literal match with following character. */ + p++; + /* FALLTHROUGH */ + default: + if (toupper(*text) != toupper(*p)) + return FALSE; + continue; + case '?': + /* Match anything. */ + continue; + case '*': + while (*++p == '*') + /* Consecutive stars act just like one. */ + continue; + if (*p == '\0') + /* Trailing star matches everything. */ + return TRUE; + while (*text) + if ((matched = DoMatchCaseInsensitive(text++, p)) != FALSE) + return matched; + return ABORT; + case '[': + reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE; + if (reverse) + /* Inverted character class. */ + p++; + matched = FALSE; + if (p[1] == ']' || p[1] == '-') + if (toupper(*++p) == toupper(*text)) + matched = TRUE; + for (last = toupper(*p); *++p && *p != ']'; last = toupper(*p)) + /* This next line requires a good C compiler. */ + if (*p == '-' && p[1] != ']' + ? toupper(*text) <= toupper(*++p) && toupper(*text) >= last : toupper(*text) == toupper(*p)) + matched = TRUE; + if (matched == reverse) + return FALSE; + continue; + } + } + +#ifdef MATCH_TAR_PATTERN + if (*text == '/') + return TRUE; +#endif /* MATCH_TAR_ATTERN */ + return *text == '\0'; +} + + +/* + ** User-level routine. Returns TRUE or FALSE. + */ +int +wildmat(char *text, char *p) +{ +#ifdef OPTIMIZE_JUST_STAR + if (p[0] == '*' && p[1] == '\0') + return TRUE; +#endif /* OPTIMIZE_JUST_STAR */ + return DoMatch(text, p) == TRUE; +} + +/* + ** User-level routine. Returns TRUE or FALSE. + */ +int +wildmatcase(char *text, char *p) +{ +#ifdef OPTIMIZE_JUST_STAR + if (p[0] == '*' && p[1] == '\0') + return TRUE; +#endif /* OPTIMIZE_JUST_STAR */ + return DoMatchCaseInsensitive(text, p) == TRUE; +} diff -Nbru clearsilver-0.4/util/wildmat.h clearsilver-0.5/util/wildmat.h --- clearsilver-0.4/util/wildmat.h Wed Dec 31 16:00:00 1969 +++ clearsilver-0.5/util/wildmat.h Thu Feb 28 16:53:41 2002 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 1986-1991 Rich Salz + * + */ + +#ifndef __WILDMAT_H_ +#define __WILDMAT_H_ 1 + +__BEGIN_DECLS + +int wildmat(char *text, char *p); +int wildmatcase(char *text, char *p); + +__END_DECLS + +#endif /* __WILDMAT_H_ */