diff -Nru clearsilver-0.9.1/ClearSilver.h clearsilver-0.9.2/ClearSilver.h --- clearsilver-0.9.1/ClearSilver.h Mon Apr 14 16:05:07 2003 +++ clearsilver-0.9.2/ClearSilver.h Thu Jul 24 22:45:40 2003 @@ -14,6 +14,23 @@ #include "cs_config.h" +/* If you need these backward compatible definitions, define CS_COMPAT */ +/* These changed after v0.9.1 */ +#define CS_COMPAT 0 + +#if defined(CS_COMPAT) || !defined(HASH) +#define HASH NE_HASH +#define HASHNODE NE_HASHNODE +#define hash_init ne_hash_init +#define hash_destroy ne_hash_destroy +#define hash_lookup ne_hash_lookup +#define hash_has_key ne_hash_has_key +#define hash_remove ne_hash_remove +#define hash_next ne_hash_next +#define hash_str_comp ne_hash_str_comp +#define hash_str_hash ne_hash_str_hash +#endif /* CS_COMPAT */ + #include #include diff -Nru clearsilver-0.9.1/INSTALL clearsilver-0.9.2/INSTALL --- clearsilver-0.9.1/INSTALL Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/INSTALL Mon Aug 18 13:24:45 2003 @@ -0,0 +1,119 @@ +******************************************** +* +* Clearsilver INSTALL +* +* http://www.clearsilver.net +* +* Brandon Long, David Jeske +* +******************************************** + +1) Compile ------------------------------------------------ + +Simplest case: + +# ./configure +# make + +Options to configure: + --disable-compression Disables HTML Compression support + --enable-remote-debugger Enables remote X CGI debugging + --disable-apache Disables building of apache 1.3.x module + --with-apache=path Set location of Apache installation + --disable-python Disables building of python module + --with-python=path Set location of Python Includes + --disable-perl Disables building of perl module + --with-perl=path Set location of Perl binary + --disable-ruby Disables building of ruby module + --with-ruby=path Set location of Ruby binary + --disable-java Disables building of java module + --with-java=path Set location of J2SDK + --disable-csharp Disables building of csharp module + --with-csharp=path Set location of csharp + +--disable-compression: Currently, the CGI output code in the cgi +kit automatically attempts to detect whether the remote browser can +handle compressed data, and if it does, compresses the output for +text/html. This is run-time configurable via Config.CompressionEnabled. +Disabling it at compile time eliminates the dependency on libz. + +--enable-remote-debugger: The CGI kit contains code for remotely +debuggin CGI programs by launching an X based debugger (such as xxgdb or +ddd) at the X display you specify in the HTTP request. There are +controls such as a configurable list of allowed displays, but remote +debugging is disabled by default. + +The rest of the --disable/--with either disable a specific module, or +point ClearSilver at the right program to enable it. The configure +script will simple not build any module it can't find the right versions +of programs to build against. Alternatively, if you are making +ClearSilver part of your build environment, you can simple delete +whichever module directory you don't want, and the build will ignore it. + +For information about compiling on Windows under MingW and MSYS, see +python/README.txt + +The csharp wrapper was built with Mono (www.go-mono.com) and should work +with v0.24 and later (give or take). In theory, it should be fairly +simple to get this working on MS.Net as well. + +2) Install ------------------------------------------------ + +# make install + +The make install is relatively new, and just installs the +libraries/header files (and probably the perl and python modules, but +that's a guess) + +3) Example 1, Apache static.cgi ---------------------------------- + +"static.cgi" is a simple binary which will allow you to write static +HDF files, static ClearSilver templates, and render them. This is a +good way to get started and learn the clearsilver model and +syntax. Follow the steps below to install static.cgi into your Apache +configuration and then read the documentation while playing with +static files. + + http://www.clearsilver.net/docs/man_hdf.hdf + +Add the following to your Apache configuration and copy the +Clearsilver static.cgi binary from cgi/static.cgi into your Apache +cgi-bin directory. + + AddHandler cgi-script .cgi + Action cs-handler /cgi-bin/static.cgi + AddHandler cs-handler .cs + +Since any html file is a valid CS file, I also run with: + + AddHandler cs-handler .html + +* About static.cgi: + +static.cgi works by assuming that whatever file it was pointed at is a +CS template. It first tries to load common.hdf in the same directory, +then it tries to load some other hdf files, and then it parses and +displays the template file. + +Ie, if its pointed at foo.cs, it will load common.hdf, try to load +foo.cs.hdf, if that fails, it tries foo.hdf. If the hdf defines +CGI.StaticContent, it will assume that's the real template file (which +is how we use it on www.clearsilver.net, we just point at he .hdf files, +which define StaticContent as a wrapper.cs, which includes another file +defined in the .hdf file). + +4) Example 2, imd image server ------------------------------------ + +"imd" is a simple image server written with C and clearsilver. The imd +directory has a README on how to set up imd with Apache. + +5) Example 3, using with Python ----------------------------------- + +The clearsilver python wrapper comes with CSPage.py. This file +contains the CSPage superclass, and this file gives some pointers on +how to use the cs handler via python. A much more thorough example +is Scott Hassan's image_server, available from + + http://www.dotfunk.com/projects/image_server + + diff -Nru clearsilver-0.9.1/Makefile clearsilver-0.9.2/Makefile --- clearsilver-0.9.1/Makefile Mon Jul 7 23:33:47 2003 +++ clearsilver-0.9.2/Makefile Mon Aug 18 13:24:45 2003 @@ -105,9 +105,9 @@ mkdir -p $$mdir; \ done -CS_DISTDIR = clearsilver-0.9.1 -CS_LABEL = CLEARSILVER-0_9_1 -CS_FILES = LICENSE CS_LICENSE rules.mk.in Makefile util cs cgi python scripts mod_ecs imd java-jni perl ruby acconfig.h autogen.sh config.guess config.sub configure.in cs_config.h.in mkinstalldirs install-sh ClearSilver.h +CS_DISTDIR = clearsilver-0.9.2 +CS_LABEL = CLEARSILVER-0_9_2 +CS_FILES = LICENSE CS_LICENSE rules.mk.in Makefile util cs cgi python scripts mod_ecs imd java-jni perl ruby acconfig.h autogen.sh config.guess config.sub configure.in cs_config.h.in mkinstalldirs install-sh ClearSilver.h ports cs_dist: rm -rf $(CS_DISTDIR) cvs -q tag -F $(CS_LABEL) $(CS_FILES) diff -Nru clearsilver-0.9.1/cgi/Makefile clearsilver-0.9.2/cgi/Makefile --- clearsilver-0.9.1/cgi/Makefile Mon Apr 14 17:13:40 2003 +++ clearsilver-0.9.2/cgi/Makefile Thu Jul 24 22:46:11 2003 @@ -24,6 +24,7 @@ $(CGI_LIB): $(CGI_OBJ) $(AR) $@ $(CGI_OBJ) + $(RANLIB) $@ $(STATIC_EXE): $(STATIC_OBJ) $(DEP_LIBS) $(LD) $@ $(STATIC_OBJ) $(LIBS) diff -Nru clearsilver-0.9.1/cgi/cgi.c clearsilver-0.9.2/cgi/cgi.c --- clearsilver-0.9.1/cgi/cgi.c Sun Jun 29 22:32:58 2003 +++ clearsilver-0.9.2/cgi/cgi.c Mon Aug 18 13:41:08 2003 @@ -315,7 +315,7 @@ { if (buf[l] == '/' || buf[l] == '+' || buf[l] == '=' || buf[l] == '&' || buf[l] == '"' || buf[l] == '%' || buf[l] == '?' || buf[l] == '#' || - buf[l] < 32 || buf[l] > 122) + buf[l] == '<' || buf[l] == '>' || buf[l] < 32 || buf[l] > 122) { nl += 2; } @@ -354,7 +354,7 @@ { if (buf[l] == '/' || buf[l] == '+' || buf[l] == '=' || buf[l] == '&' || buf[l] == '"' || buf[l] == '%' || buf[l] == '?' || buf[l] == '#' || - buf[l] < 32 || buf[l] > 122) + buf[l] == '<' || buf[l] == '>' || buf[l] < 32 || buf[l] > 122) { match = 1; } @@ -1245,21 +1245,47 @@ return nerr_pass(err); } -static NEOERR *_html_escape_strfunc(unsigned char *str, unsigned char **ret) +NEOERR *cgi_html_escape_strfunc(unsigned char *str, unsigned char **ret) { return nerr_pass(html_escape_alloc(str, strlen(str), ret)); } -static NEOERR *_html_strip_strfunc(unsigned char *str, unsigned char **ret) +NEOERR *cgi_html_strip_strfunc(unsigned char *str, unsigned char **ret) { return nerr_pass(html_strip_alloc(str, strlen(str), ret)); } -static NEOERR *_text_html_strfunc(unsigned char *str, unsigned char **ret) +NEOERR *cgi_text_html_strfunc(unsigned char *str, unsigned char **ret) { return nerr_pass(convert_text_html_alloc(str, strlen(str), ret)); } +NEOERR *cgi_cs_init(CGI *cgi, CSPARSE **cs) +{ + NEOERR *err; + + *cs = NULL; + + do + { + err = cs_init (cs, cgi->hdf); + if (err != STATUS_OK) break; + err = cs_register_strfunc(*cs, "url_escape", cgi_url_escape); + if (err != STATUS_OK) break; + err = cs_register_strfunc(*cs, "html_escape", cgi_html_escape_strfunc); + if (err != STATUS_OK) break; + err = cs_register_strfunc(*cs, "text_html", cgi_text_html_strfunc); + if (err != STATUS_OK) break; + err = cs_register_strfunc(*cs, "js_escape", cgi_js_escape); + if (err != STATUS_OK) break; + err = cs_register_strfunc(*cs, "html_strip", cgi_html_strip_strfunc); + if (err != STATUS_OK) break; + } while (0); + + if (err && *cs) cs_destroy(cs); + return nerr_pass(err); +} + NEOERR *cgi_display (CGI *cgi, char *cs_file) { NEOERR *err = STATUS_OK; @@ -1281,13 +1307,13 @@ if (err != STATUS_OK) break; err = cs_register_strfunc(cs, "url_escape", cgi_url_escape); if (err != STATUS_OK) break; - err = cs_register_strfunc(cs, "html_escape", _html_escape_strfunc); + err = cs_register_strfunc(cs, "html_escape", cgi_html_escape_strfunc); if (err != STATUS_OK) break; - err = cs_register_strfunc(cs, "text_html", _text_html_strfunc); + err = cs_register_strfunc(cs, "text_html", cgi_text_html_strfunc); if (err != STATUS_OK) break; err = cs_register_strfunc(cs, "js_escape", cgi_js_escape); if (err != STATUS_OK) break; - err = cs_register_strfunc(cs, "html_strip", _html_strip_strfunc); + err = cs_register_strfunc(cs, "html_strip", cgi_html_strip_strfunc); if (err != STATUS_OK) break; err = cs_parse_file (cs, cs_file); if (err != STATUS_OK) break; diff -Nru clearsilver-0.9.1/cgi/cgi.h clearsilver-0.9.2/cgi/cgi.h --- clearsilver-0.9.1/cgi/cgi.h Mon Mar 31 18:59:45 2003 +++ clearsilver-0.9.2/cgi/cgi.h Thu Jul 17 12:44:08 2003 @@ -14,6 +14,7 @@ #include #include "util/neo_err.h" #include "util/neo_hdf.h" +#include "cs/cs.h" __BEGIN_DECLS @@ -113,6 +114,17 @@ * Return: None */ void cgi_destroy (CGI **cgi); + +/* + * Function: cgi_cs_init - initialize CS parser with the CGI defaults + * Description: cgi_cs_init initializes a CS parser with the CGI HDF + * context, and registers the standard CGI filters + * Input: cgi - a pointer a CGI struct allocated with cgi_init + * cs - a pointer to a CS struct pointer + * Output: cs - the allocated/initialized CS struct + * Return: NERR_NOMEM - no memory was available to render the template + */ +NEOERR *cgi_cs_init(CGI *cgi, CSPARSE **cs); /* * Function: cgi_display - render and display the CGI output to the user diff -Nru clearsilver-0.9.1/cgi/static.c clearsilver-0.9.2/cgi/static.c --- clearsilver-0.9.1/cgi/static.c Mon Apr 14 16:05:09 2003 +++ clearsilver-0.9.2/cgi/static.c Mon Aug 18 13:41:23 2003 @@ -55,6 +55,13 @@ return -1; } } + err = hdf_read_file (cgi->hdf, "common.hdf"); + if (err && !nerr_handle(&err, NERR_NOT_FOUND)) + { + cgi_neo_error(cgi, err); + nerr_log_error(err); + return -1; + } snprintf (hdf_file, sizeof(hdf_file), "%s.hdf", cs_file); err = hdf_read_file (cgi->hdf, hdf_file); if (err && !nerr_handle(&err, NERR_NOT_FOUND)) diff -Nru clearsilver-0.9.1/configure.in clearsilver-0.9.2/configure.in --- clearsilver-0.9.1/configure.in Tue Jun 17 14:20:40 2003 +++ clearsilver-0.9.2/configure.in Mon Aug 18 13:24:45 2003 @@ -6,6 +6,8 @@ AC_PROG_CC AC_PROG_CPP AC_PROG_LN_S +AC_CHECK_PROGS(AR, ar aal, ar) +AC_PROG_RANLIB AC_PROG_MAKE_SET AC_PROG_INSTALL @@ -87,13 +89,63 @@ dnl Check for missing re-entrant functions cs_cv_missing=no -AC_CHECK_FUNC(strtok_r, [AC_DEFINE(HAVE_STRTOK_R)], [cs_cv_missing=yes]) -AC_CHECK_FUNC(localtime_r, [AC_DEFINE(HAVE_LOCALTIME_R)], [cs_cv_missing=yes]) -AC_CHECK_FUNC(gmtime_r, [AC_DEFINE(HAVE_GMTIME_R)], [cs_cv_missing=yes]) +cs_cv_need_reentrant=no +dnl copied from libcurl +AC_CHECK_FUNCS(localtime_r, [ + AC_MSG_CHECKING(whether localtime_r is declared) + AC_EGREP_CPP(localtime_r,[ +#include ],[ + AC_DEFINE(HAVE_LOCALTIME_R) + AC_MSG_RESULT(yes)],[ + AC_MSG_RESULT(no) + AC_MSG_CHECKING(whether localtime_r with -D_REENTRANT is declared) + AC_EGREP_CPP(localtime_r,[ +#define _REENTRANT +#include ],[ + cs_cv_need_reentrant=yes + AC_MSG_RESULT(yes)],[ + cs_cv_missing=yes + AC_MSG_RESULT(no)])])]) + +AC_CHECK_FUNCS(gmtime_r, [ + AC_MSG_CHECKING(whether gmtime_r is declared) + AC_EGREP_CPP(gmtime_r,[ +#include ],[ + AC_DEFINE(HAVE_LOCALTIME_R) + AC_MSG_RESULT(yes)],[ + AC_MSG_RESULT(no) + AC_MSG_CHECKING(whether gmtime_r with -D_REENTRANT is declared) + AC_EGREP_CPP(gmtime_r,[ +#define _REENTRANT +#include ],[ + cs_cv_need_reentrant=yes + AC_MSG_RESULT(yes)],[ + cs_cv_missing=yes + AC_MSG_RESULT(no)])])]) + +AC_CHECK_FUNCS(strtok_r, [ + AC_MSG_CHECKING(whether strtok_r is declared) + AC_EGREP_CPP(strtok_r,[ +#include ],[ + AC_DEFINE(HAVE_LOCALTIME_R) + AC_MSG_RESULT(yes)],[ + AC_MSG_RESULT(no) + AC_MSG_CHECKING(whether strtok_r with -D_REENTRANT is declared) + AC_EGREP_CPP(strtok_r,[ +#define _REENTRANT +#include ],[ + cs_cv_need_reentrant=yes + AC_MSG_RESULT(yes)],[ + cs_cv_missing=yes + AC_MSG_RESULT(no)])])]) + AC_CHECK_FUNC(mkstemp, [AC_DEFINE(HAVE_MKSTEMP)], [cs_cv_missing=yes]) if test $cs_cv_missing = yes; then EXTRA_UTL_OBJS="$EXTRA_UTL_OBJS missing.o" fi +if test $cs_cv_need_reentrant = yes; then + CPPFLAGS="$CPPFLAGS -D_REENTRANT" +fi cs_cv_regex=yes AC_CHECK_FUNC(regexec, [AC_DEFINE(HAVE_REGEX)], [cs_cv_regex=no]) @@ -195,6 +247,9 @@ else for vers in $python_versions; do for path in $python_search_path; do + if test -x $path/bin/python$vers; then + python_bin=$path/bin/python$vers + fi if test -f $path/include/python$vers/Python.h; then python_inc=$path/include/python$vers python_lib="-L$path/lib/python$vers/config -lpython$vers" @@ -214,11 +269,13 @@ fi if test "x$python_inc" = "xno"; then AC_MSG_RESULT(not found) + PYTHON= PYTHON_INC= PYTHON_LIB= PYTHON_SITE= else AC_MSG_RESULT(found $python_inc) + PYTHON=$python_bin PYTHON_INC="-I$python_inc" PYTHON_LIB=$python_lib PYTHON_SITE=$python_site @@ -346,16 +403,53 @@ fi fi +dnl Check for C# library/includes +cs_cv_csharp=yes +AC_ARG_ENABLE(csharp, [ --disable-csharp Disables building of csharp module], + [if test $enableval = no; then + cs_cv_csharp=no; + AC_MSG_RESULT(Disabling csharp module) + fi]) +AC_ARG_WITH(csharp, [ --with-csharp=path Set location of csharp], [cs_cv_csharp_path="$withval"], [cs_cv_csharp_path=no]) +if test $cs_cv_csharp = yes; then + AC_MSG_CHECKING(for csharp path) + csharp_path=no + if test $cs_cv_csharp_path != "no" -a -d $cs_cv_csharp_path; then + csharp_path=$cs_cv_csharp_path + else + csharp_search_path="/neo/opt /usr/local /usr" + for path in $csharp_search_path; do + if test -f $path/bin/mcs; then + csharp_path=$path + break + fi + done + fi + if test "x$csharp_path" = "xno"; then + AC_MSG_RESULT(not found) + CSHARP_PATH= + else + AC_MSG_RESULT(found $csharp_path/bin/mcs) + CSHARP_PATH="$csharp_path" + BUILD_WRAPPERS="$BUILD_WRAPPERS dso csharp" + fi +fi + + +AC_SUBST(RANLIB) +AC_SUBST(AR) AC_SUBST(USE_MINGW32) AC_SUBST(APXS_PATH) AC_SUBST(PERL) AC_SUBST(RUBY) AC_SUBST(BUILD_WRAPPERS) AC_SUBST(JAVA_PATH) +AC_SUBST(PYTHON) AC_SUBST(PYTHON_INC) AC_SUBST(PYTHON_LIB) AC_SUBST(PYTHON_SITE) AC_SUBST(EXTRA_UTL_SRC) AC_SUBST(EXTRA_UTL_OBJS) +AC_SUBST(CSHARP_PATH) AC_OUTPUT(rules.mk) diff -Nru clearsilver-0.9.1/cs/Makefile clearsilver-0.9.2/cs/Makefile --- clearsilver-0.9.1/cs/Makefile Wed Jul 2 17:40:06 2003 +++ clearsilver-0.9.2/cs/Makefile Sun Jul 27 09:26:19 2003 @@ -33,6 +33,7 @@ $(CS_LIB): $(CS_OBJ) $(AR) $@ $(CS_OBJ) + $(RANLIB) $@ $(CSTEST_EXE): $(CSTEST_OBJ) $(CS_LIB) $(LD) $@ $(CSTEST_OBJ) $(LIBS) # -lefence @@ -58,10 +59,12 @@ for test in $(CS_TESTS); do \ rm -f $$test.out; \ ./cstest test.hdf $$test > $$test.out 2>&1; \ - diff --brief $$test.out $$test.gold; \ + diff --brief $$test.out $$test.gold 2>&1 > /dev/null; \ return_code=$$?; \ if [ $$return_code -ne 0 ]; then \ + diff $$test.gold $$test.out > $$test.err; \ echo "Failed Regression Test: $$test"; \ + echo " See $$test.out and $$test.err"; \ failed=1; \ fi; \ done; \ diff -Nru clearsilver-0.9.1/cs/cs.h clearsilver-0.9.2/cs/cs.h --- clearsilver-0.9.1/cs/cs.h Wed Jun 25 20:11:36 2003 +++ clearsilver-0.9.2/cs/cs.h Fri Aug 8 23:54:12 2003 @@ -41,6 +41,7 @@ #ifndef __CSHDF_H_ #define __CSHDF_H_ 1 +#include "util/neo_misc.h" #include "util/neo_err.h" #include "util/ulist.h" #include "util/neo_hdf.h" diff -Nru clearsilver-0.9.1/cs/csparse.c clearsilver-0.9.2/cs/csparse.c --- clearsilver-0.9.1/cs/csparse.c Mon Jul 7 23:33:28 2003 +++ clearsilver-0.9.2/cs/csparse.c Mon Aug 4 18:49:40 2003 @@ -1924,7 +1924,7 @@ } else if ((arg1.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) || (arg2.op_type & (CS_TYPE_NUM | CS_TYPE_VAR_NUM)) || - (expr->op_type & (CS_OP_AND | CS_OP_OR | CS_OP_SUB | CS_OP_MULT | CS_OP_DIV | CS_OP_MOD))) + (expr->op_type & (CS_OP_AND | CS_OP_OR | CS_OP_SUB | CS_OP_MULT | CS_OP_DIV | CS_OP_MOD | CS_OP_GT | CS_OP_GTE | CS_OP_LT | CS_OP_LTE ))) { /* eval as num */ err = eval_expr_num(parse, &arg1, &arg2, expr->op_type, result); diff -Nru clearsilver-0.9.1/cs/test.cs clearsilver-0.9.2/cs/test.cs --- clearsilver-0.9.1/cs/test.cs Wed Jul 2 18:04:16 2003 +++ clearsilver-0.9.2/cs/test.cs Sun Jul 27 09:57:42 2003 @@ -61,6 +61,12 @@ TestIf == else + +Correct, "1" == "1" + +WRONG, "1" != "1" + + between comments diff -Nru clearsilver-0.9.1/cs/test.cs.gold clearsilver-0.9.2/cs/test.cs.gold --- clearsilver-0.9.1/cs/test.cs.gold Wed Jul 2 18:04:16 2003 +++ clearsilver-0.9.2/cs/test.cs.gold Sun Jul 27 09:57:42 2003 @@ -106,6 +106,10 @@ +Correct, "1" == "1" + + + between comments diff -Nru clearsilver-0.9.1/cs/test4.cs clearsilver-0.9.2/cs/test4.cs --- clearsilver-0.9.1/cs/test4.cs Wed Jun 25 20:11:36 2003 +++ clearsilver-0.9.2/cs/test4.cs Sun Jul 27 09:26:19 2003 @@ -67,6 +67,20 @@ ERROR! "0" <= #5 + + + #14 ?> +ERROR! "9" > #14 + +right "9" > #14 + + + "14" ?> +ERROR! "9" > "14" + +right "9" > "14" + + diff -Nru clearsilver-0.9.1/cs/test4.cs.gold clearsilver-0.9.2/cs/test4.cs.gold --- clearsilver-0.9.1/cs/test4.cs.gold Thu Mar 28 17:40:56 2002 +++ clearsilver-0.9.2/cs/test4.cs.gold Sun Jul 27 09:59:05 2003 @@ -59,6 +59,16 @@ +right "9" > #14 + + + +right "9" > "14" + + + + + /box_bm_body_frm.cs?boxid=2&cur=1&idx_cur=1&split=1&filter=0&sort=t&sort_dir=u&from_search= diff -Nru clearsilver-0.9.1/cs_config.h.in clearsilver-0.9.2/cs_config.h.in --- clearsilver-0.9.1/cs_config.h.in Mon Apr 14 16:05:07 2003 +++ clearsilver-0.9.2/cs_config.h.in Fri Aug 8 23:55:25 2003 @@ -78,15 +78,9 @@ /* Does your system have the vsnprintf() call? */ #undef HAVE_VSNPRINTF -/* Does your system have the strtok_r() call? */ -#undef HAVE_STRTOK_R - /* Does your system have the localtime_r() call? */ #undef HAVE_LOCALTIME_R -/* Does your system have the gmtime_r() call? */ -#undef HAVE_GMTIME_R - /* Does your system have the mkstemp() call? */ #undef HAVE_MKSTEMP @@ -108,6 +102,12 @@ /* Define if you have the gettimeofday function. */ #undef HAVE_GETTIMEOFDAY +/* Define if you have the gmtime_r function. */ +#undef HAVE_GMTIME_R + +/* Define if you have the localtime_r function. */ +#undef HAVE_LOCALTIME_R + /* Define if you have the mktime function. */ #undef HAVE_MKTIME @@ -128,6 +128,9 @@ /* Define if you have the strtod function. */ #undef HAVE_STRTOD + +/* Define if you have the strtok_r function. */ +#undef HAVE_STRTOK_R /* Define if you have the strtol function. */ #undef HAVE_STRTOL diff -Nru clearsilver-0.9.1/csharp/CS.cs clearsilver-0.9.2/csharp/CS.cs --- clearsilver-0.9.1/csharp/CS.cs Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/csharp/CS.cs Mon Aug 11 14:37:10 2003 @@ -0,0 +1,145 @@ + +using System; +using System.Runtime.InteropServices; + +namespace Clearsilver { + +// opaque types +public unsafe struct HDF {}; +public unsafe struct NEOERR {}; + +public unsafe class Hdf { + + [DllImport("libneo", EntryPoint="hdf_init")] + private static extern unsafe NEOERR* hdf_init(HDF **foo); + + // NEOERR* hdf_set_value (HDF *hdf, char *name, char *value) + [DllImport("libneo")] + private static unsafe extern NEOERR* hdf_set_value(HDF *hdf, + [MarshalAs(UnmanagedType.LPStr)] + string name, + [MarshalAs(UnmanagedType.LPStr)] + string value); + + // char* hdf_get_value (HDF *hdf, char *name, char *defval) + + [DllImport("libneo")] + [return: MarshalAs(UnmanagedType.LPStr)] + private static unsafe extern string hdf_get_value(HDF *hdf, + [MarshalAs(UnmanagedType.LPStr)] + string name, + [MarshalAs(UnmanagedType.LPStr)] + string defval); + + // NEOERR* hdf_dump (HDF *hdf, char *prefix); + + [DllImport("libneo", EntryPoint="hdf_dump")] + private static extern void hdf_dump( + HDF *hdf, + [MarshalAs(UnmanagedType.LPStr)] + string prefix); + + // HDF* hdf_get_obj (HDF *hdf, char *name) + + [DllImport("libneo", EntryPoint="hdf_get_obj")] + private static extern HDF* hdf_get_obj( + HDF *hdf, + [MarshalAs(UnmanagedType.LPStr)] + string name); + + + // ----------------------------------------------------------- + + public HDF *hdf_root; + + public Hdf() { + NEOERR* err = hdf_init(&hdf_root); + // Console.WriteLine((int)hdf_root); + } + + public void setValue(string name,string value) { + NEOERR* err = hdf_set_value(hdf_root,name,value); + + } + public string getValue(string name,string defvalue) { + return hdf_get_value(hdf_root,name,defvalue); + } + + public void test() { + hdf_set_value(hdf_root,"b","1"); + // hdf_read_file(hdf_root,"test.hdf"); + // Console.WriteLine("b ", hdf_get_value(hdf_root,"b","5")); + hdf_dump(hdf_root,null); + + // HDF *n = hdf_get_obj(hdf_root,"b"); + // Console.WriteLine("object name {0}", + // Marshal.PtrToStringAnsi((IntPtr)n->name)); + } + +}; + +unsafe struct CSPARSE {}; + +public class CSTContext { + CSPARSE *csp; + unsafe public CSTContext(Hdf hdf) { + NEOERR *err = cs_init(&csp, hdf.hdf_root); + } + + [DllImport("libneo")] + extern static unsafe NEOERR *cs_init (CSPARSE **parse, HDF *hdf); + + public unsafe void parseFile(string filename) { + NEOERR* err = cs_parse_file(csp,filename); + } + + [DllImport("libneo")] + extern static unsafe NEOERR *cs_parse_file (CSPARSE *parse, + [MarshalAs(UnmanagedType.LPStr)] + string path); + +// [DllImport("libneo")] +// extern static unsafe NEOERR *cs_parse_string (CSPARSE *parse, +// char *buf, +// size_t blen); + + + // NEOERR *cs_render (CSPARSE *parse, void *ctx, CSOUTFUNC cb); + // typedef NEOERR* (*CSOUTFUNC)(void *ctx, char *more_str_bytes); + + [DllImport("libneo")] + extern static unsafe NEOERR *cs_render (CSPARSE *parse, + void *ctx, + [MarshalAs(UnmanagedType.FunctionPtr)] + CSOUTFUNC cb); + + private unsafe delegate NEOERR* CSOUTFUNC(void* ctx, sbyte* more_bytes); + + private class OutputBuilder { + private string output = ""; + public unsafe NEOERR* handleOutput(void* ctx, sbyte* more_bytes) { + // add the more_bytes to the current string buffer + + output += new String(more_bytes); + // Console.WriteLine("handleOutput called"); + return null; + } + public string result() { + return output; + } + } + + public unsafe string render() { + OutputBuilder ob = new OutputBuilder(); + NEOERR* err = cs_render(csp,null,new CSOUTFUNC(ob.handleOutput)); + return ob.result(); + } + + + [DllImport("libneo")] + extern static unsafe void cs_destroy (CSPARSE **parse); + +}; + + +} // namespace Clearsilver \ No newline at end of file diff -Nru clearsilver-0.9.1/csharp/Makefile clearsilver-0.9.2/csharp/Makefile --- clearsilver-0.9.1/csharp/Makefile Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/csharp/Makefile Mon Aug 11 14:37:10 2003 @@ -0,0 +1,64 @@ + +# default values.... + +CSHARP_CC=$(CSHARP_PATH)/bin/mcs +MONO_JIT=$(CSHARP_PATH)/bin/mono + +# common build environment + +ifeq ($(NEOTONIC_ROOT),) +NEOTONIC_ROOT = ../ +endif + +include $(NEOTONIC_ROOT)rules.mk + +# our targets + +TARGETS = clearsilver.dll cstest.exe csperftest.exe testcs + +all: $(TARGETS) + +clearsilver.dll: CS.cs + $(CSHARP_CC) -target:library --unsafe CS.cs -out:clearsilver.dll + +cstest.exe: clearsilver.dll ../dso/libneo.so cstest.cs + $(CSHARP_CC) -r:clearsilver.dll --unsafe cstest.cs + +csperftest.exe: clearsilver.dll ../dso/libneo.so csperftest.cs + $(CSHARP_CC) -r:clearsilver.dll --unsafe csperftest.cs + +perf: csperftest.exe + export LD_LIBRARY_PATH=../dso; \ + $(MONO_JIT) csperftest.exe + + +testcs: cstest.exe + @echo "Running csharp test" + @failed=0; \ + rm -f cstest.out; \ + export LD_LIBRARY_PATH=../dso; \ + $(MONO_JIT) cstest.exe > cstest.out; \ + diff cstest.out cstest.gold > /dev/null; \ + return_code=$$?; \ + if [ $$return_code -ne 0 ]; then \ + diff cstest.out cstest.gold > cstest.err; \ + echo "Failed csharp test: cstest.cs"; \ + echo " See cstest.out and cstest.err"; \ + failed=1; \ + fi; \ + if [ $$failed -eq 1 ]; then \ + exit 1; \ + fi; + @echo "Passed csharp test" + +gold: cstest.exe + export LD_LIBRARY_PATH=../dso; \ + $(MONO_JIT) cstest.exe > cstest.gold; + @echo "Generated gold files" + + +clean: + rm -f core.* + +distclean: + rm -f $(TARGETS) core.* Makefile.depend diff -Nru clearsilver-0.9.1/csharp/README clearsilver-0.9.2/csharp/README --- clearsilver-0.9.1/csharp/README Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/csharp/README Mon Aug 11 14:45:00 2003 @@ -0,0 +1,37 @@ +################################# +# +# C# Clearsilver wrapper +# +# David Jeske +# + +This wrapper was developed using the Mono project's C# implementation. +It isn't done, and it hasn't yet been tested with the MS C# +implementation, however, in theory it should work. Here are some salient +ideas behind this implementation: + +- I don't use IntPtr, because it is basically a void* that + removes type information and begs for coredumps to occur later. + +- I also don't use data marshaling for aggregate C-types. Instead I + merely access the structure members directly from C# unsafe code, just + like you would if this was C code. + +- The only data which is marshalled is function arguments and data which + is pulled out of or put into C-structures. + +- There are many things still todo before this is a fully working + module, but the basics are there. + + +TODO: + +- more tests (look at ruby/test/hdftest.rb for an example) +- do something better about mapping hdferror to exceptions +- recheck the function prototypes to make sure I'm handling all + arguments +- handle next(), prev() +- make iterator for child nodes +- allow registration of upload callbacks and data-formatters from C# +- open up access to other parts of cgi and util +- sample code for using inside mod_mono, includign CSPage.cs diff -Nru clearsilver-0.9.1/csharp/csperftest.cs clearsilver-0.9.2/csharp/csperftest.cs --- clearsilver-0.9.1/csharp/csperftest.cs Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/csharp/csperftest.cs Mon Aug 11 14:37:10 2003 @@ -0,0 +1,49 @@ +using System; +using System.Runtime.InteropServices; + +using Clearsilver; + + +public class CSPerfTest { + public delegate void test_function(int INDEX); + + public static void timefunk(String label, test_function f, int count) { + int start, end, elapsed; + start = Environment.TickCount; + f(count); + end = Environment.TickCount; + + elapsed = end-start; + + Console.WriteLine(label + " " + count + " elapsed: " + (elapsed / 1000.0)); + } + + public static unsafe int Main(string[] argv) { + Console.WriteLine("C# Clearsilver wrapper performance test"); + Hdf h = new Hdf(); + + h.setValue("foo.1","1"); + h.setValue("foo.2","2"); + + int call_count = 100000; + int start = Environment.TickCount; + for (int i=0;i + + \ No newline at end of file diff -Nru clearsilver-0.9.1/csharp/data_cstest.hdf clearsilver-0.9.2/csharp/data_cstest.hdf --- clearsilver-0.9.1/csharp/data_cstest.hdf Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/csharp/data_cstest.hdf Mon Aug 11 14:37:10 2003 @@ -0,0 +1 @@ +a=1 diff -Nru clearsilver-0.9.1/dso/Makefile clearsilver-0.9.2/dso/Makefile --- clearsilver-0.9.1/dso/Makefile Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/dso/Makefile Mon Aug 11 13:04:54 2003 @@ -0,0 +1,35 @@ + + +ifeq ($(NEOTONIC_ROOT),) +NEOTONIC_ROOT = ../ +endif + +include $(NEOTONIC_ROOT)rules.mk + +NEO_SO = libneo.so +NEO_STATIC_LIBS = + +LIBS += -L$(LIB_DIR) $(DLIBS) $(DB2_LIB) + + +TARGETS = $(NEO_SO) dsotest + +all: $(TARGETS) + +$(NEO_SO): $(NEO_STATIC_LIBS) $(DEP_LIBS) Makefile + /usr/bin/ld -rpath ../libs -shared -o libneo.so -whole-archive ../libs/libneo_cgi.a ../libs/libneo_cs.a ../libs/libneo_utl.a -no-whole-archive $(LIBS) + +# $(LDSHARED) -o $@ $(LDFLAGS) -Wl,-whole-archive $(DLIBS) + +install: all + $(NEOTONIC_ROOT)mkinstalldirs $(DESTDIR)$(PYTHON_SITE) + $(INSTALL) $(TARGETS) $(DESTDIR)$(PYTHON_SITE) + +dsotest: dsotest.c $(NEO_SO) + gcc -o dsotest dsotest.c -lneo -L. -I.. + +clean: + $(RM) *.o + +distclean: + $(RM) Makefile.depends $(TARGETS) *.o diff -Nru clearsilver-0.9.1/dso/README clearsilver-0.9.2/dso/README --- clearsilver-0.9.1/dso/README Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/dso/README Mon Aug 18 13:24:47 2003 @@ -0,0 +1,11 @@ + +08-18-2003 blong + +This directory builds a "dynamic shared object" or dso. In theory, you +could use this for various things, but in reality this is for the +Mono/CSharp module, which requires a shared library loadable by the C# +run time. + +Building this dso is very system specific, and this is currently very +Linux specific at the moment. Patches to build this on other platforms +are appreciated. diff -Nru clearsilver-0.9.1/dso/dsotest.c clearsilver-0.9.2/dso/dsotest.c --- clearsilver-0.9.1/dso/dsotest.c Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/dso/dsotest.c Mon Aug 11 13:04:54 2003 @@ -0,0 +1,17 @@ + +#include + + +int main() { + HDF *hdf; + NEOERR *err; + + err = hdf_init(&hdf); + + if (err) { + printf("error: %s\n", err->desc); + return 1; + } + + printf("success: 0x%X\n", hdf); +} diff -Nru clearsilver-0.9.1/imd/imd.c clearsilver-0.9.2/imd/imd.c --- clearsilver-0.9.1/imd/imd.c Mon Apr 14 16:05:28 2003 +++ clearsilver-0.9.2/imd/imd.c Tue Aug 5 12:12:51 2003 @@ -67,11 +67,7 @@ t[6] = '\0'; strcpy(mname,&t[3]); x = atoi(&t[7]); - /* Prevent - * wraparound - * from - * ambiguity - * */ + /* Prevent wraparound from ambiguity */ if(x < 70) x += 100; year = 1900 + x; @@ -153,6 +149,7 @@ { *height = data[pos+5] * 256 + data[pos+6]; *width = data[pos+7] * 256 + data[pos+8]; + ne_warn("%s: %dx%d", file, *width, *height); return 0; } pos += length; @@ -214,7 +211,8 @@ snprintf (rpath, _POSIX_PATH_MAX, "%s/%s", path, file); ch = strrchr(rpath, '.'); if ((!strcasecmp(ch, ".jpg")) || - (!strcasecmp(ch, ".jpeg"))) + (!strcasecmp(ch, ".jpeg")) || + (!strcasecmp(ch, ".thm"))) { is_jpeg = 1; } @@ -299,11 +297,13 @@ l = strlen(fname); if ((l>4 && !strcasecmp(fname+l-4, ".jpg")) || + (l>4 && !strcasecmp(fname+l-4, ".thm")) || (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) @@ -347,7 +347,7 @@ /* figure out if we need to scale it */ - if ((srcW > maxW) || (srcH > maxH)) { + if ((maxW && srcW > maxW) || (maxH && srcH > maxH)) { /* scale paramaters */ int dstX,dstY,dstW,dstH; /* Declare output file */ @@ -449,8 +449,7 @@ } } else { - ne_warn("How'd I get here?"); - return nerr_raise(NERR_ASSERT, "I shouldn't get here..."); + dispfile = fopen(fname,"rb"); } } @@ -459,6 +458,15 @@ char buf[8192]; int count; + + if (!fstat(fileno(dispfile), &s) && s.st_size) + { + cgiwrap_writef("Content-Length: %ld\n\n", s.st_size); + } + else + { + cgiwrap_writef("\n"); + } fseek(dispfile,0,SEEK_SET); @@ -477,55 +485,6 @@ 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; @@ -577,6 +536,7 @@ is_jpeg = 0; is_gif = 0; if ((l>4 && !strcasecmp(de->d_name+l-4, ".jpg")) || + (l>4 && !strcasecmp(de->d_name+l-4, ".thm")) || (l>5 && !strcasecmp(de->d_name+l-5, ".jpeg"))) is_jpeg = 1; else if (l>4 && !strcasecmp(de->d_name+l-4, ".gif")) @@ -611,7 +571,7 @@ int r, l; int width, height; char ipath[_POSIX_PATH_MAX]; - int is_jpeg = 0, is_gif = 0; + int is_jpeg = 0, is_gif = 0, is_thm = 0; l = strlen(file); if ((l>4 && !strcasecmp(file+l-4, ".jpg")) || @@ -619,12 +579,14 @@ is_jpeg = 1; else if (l>4 && !strcasecmp(file+l-4, ".gif")) is_gif = 1; + else if (l>4 && !strcasecmp(file+l-4, ".thm")) + is_thm = 1; snprintf (buf, sizeof(buf), "%s.%d", prefix, i); - err = hdf_set_buf (cgi->hdf, prefix, url_escape(file)); + err = hdf_set_value (cgi->hdf, prefix, file); if (err != STATUS_OK) return nerr_pass(err); snprintf (ipath, sizeof(ipath), "%s/%s", path, file); - if (is_jpeg) + if (is_jpeg || is_thm) r = jpeg_size(ipath, &width, &height); else r = gif_size(ipath, &width, &height); @@ -639,6 +601,14 @@ err = hdf_set_value (cgi->hdf, buf, num); if (err != STATUS_OK) return nerr_pass(err); } + if (is_thm) + { + strcpy(ipath, file); + strcpy(ipath+l-4, ".avi"); + snprintf(buf, sizeof(buf), "%s.avi", prefix); + err = hdf_set_value (cgi->hdf, buf, ipath); + if (err != STATUS_OK) return nerr_pass(err); + } return STATUS_OK; } @@ -702,13 +672,50 @@ return strcmp(*sa, *sb); } +static NEOERR *export_album_path(CGI *cgi, char *album, char *prefix) +{ + NEOERR *err = STATUS_OK; + char *p, *l; + int n = 0; + char buf[256]; + + l = album; + p = strchr(album, '/'); + + while (p != NULL) + { + *p = '\0'; + snprintf(buf, sizeof(buf), "%s.%d", prefix, n); + err = hdf_set_value(cgi->hdf, buf, l); + if (err) break; + snprintf(buf, sizeof(buf), "%s.%d.path", prefix, n++); + err = hdf_set_value(cgi->hdf, buf, album); + if (err) break; + *p = '/'; + l = p+1; + p = strchr(l, '/'); + } + if (err) return nerr_pass(err); + if (strlen(l)) + { + snprintf(buf, sizeof(buf), "%s.%d", prefix, n); + err = hdf_set_value(cgi->hdf, buf, l); + if (err) return nerr_pass(err); + snprintf(buf, sizeof(buf), "%s.%d.path", prefix, n++); + err = hdf_set_value(cgi->hdf, buf, album); + if (err) return nerr_pass(err); + } + + return STATUS_OK; +} + + 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; @@ -717,6 +724,7 @@ char t_pic[_POSIX_PATH_MAX]; char nfile[_POSIX_PATH_MAX]; char *ch; + char *avi = NULL; int rotate; ch = strrchr(picture, '/'); @@ -754,12 +762,13 @@ picture = strrchr(nfile, '/') + 1; } - err = hdf_set_buf (cgi->hdf, "Album", url_escape(album)); + err = hdf_set_value (cgi->hdf, "Album", 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); + err = export_album_path(cgi, album, "Album.Path"); + if (err) return nerr_pass(err); + err = hdf_set_value (cgi->hdf, "Picture", picture); if (err != STATUS_OK) return nerr_pass(err); err = load_images(path, &files, NULL, 0); @@ -806,9 +815,10 @@ y = x; while (y > pic_width) { - /* factor = factor * 2; */ - factor++; + factor = factor * 2; + /* factor++; */ y = x / factor; + ne_warn("factor = %d, y = %d", factor, y); } snprintf (buf, sizeof(buf), "%d", y); hdf_set_value (cgi->hdf, "Picture.width", buf); @@ -825,6 +835,12 @@ snprintf (buf, sizeof(buf), "%d", pic_height); hdf_set_value (cgi->hdf, "Picture.height", buf); } + snprintf (buf, sizeof(buf), "Show.%d.avi", i); + avi = hdf_get_value (cgi->hdf, buf, NULL); + if (avi) + { + err = hdf_set_value(cgi->hdf, "Picture.avi", avi); + } err = scale_images (cgi, "Show", thumb_width, thumb_height, 0); } @@ -833,6 +849,17 @@ return nerr_pass(err); } +static int is_album(void *rock, char *filename) +{ + char path[_POSIX_PATH_MAX]; + char *prefix = (char *)rock; + + if (filename[0] == '.') return 0; + snprintf(path, sizeof(path), "%s/%s", prefix, filename); + if (isdir(path)) return 1; + return 0; +} + NEOERR *dowork_album_overview (CGI *cgi, char *album) { NEOERR *err = STATUS_OK; @@ -840,55 +867,52 @@ struct dirent *de; char path[_POSIX_PATH_MAX]; char buf[256]; - int i = 0, x; + int i = 0, x, y; int thumb_width, thumb_height; ULIST *files = NULL; + ULIST *albums = 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)); - } + err = ne_listdir_fmatch(album, &albums, is_album, album); + if (err) return nerr_pass(err); - while ((de = readdir (dp)) != NULL) + + err = uListSort(albums, alpha_sort); + if (err) return nerr_pass(err); + for (y = 0; y < uListLength(albums); y++) { - if (de->d_name[0] != '.') + err = uListGet(albums, y, (void *)&name); + if (err) break; + + snprintf(path, sizeof(path), "%s/%s", album, name); + snprintf(buf, sizeof(buf), "Albums.%d", i); + err = hdf_set_value (cgi->hdf, buf, 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++) { - 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++; - } + 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); } @@ -915,14 +939,18 @@ 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)); + err = hdf_set_value (cgi->hdf, "Album", 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 = export_album_path(cgi, album, "Album.Path"); + if (err) 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); @@ -966,7 +994,7 @@ NEOERR *dowork_image (CGI *cgi, char *image) { NEOERR *err = STATUS_OK; - int maxW = 1024, maxH = 1024; + int maxW = 0, maxH = 0; char *basepath = ""; char *cache_basepath = "/tmp/.imgcache/"; char srcpath[_POSIX_PATH_MAX] = ""; @@ -1016,17 +1044,22 @@ /* fprintf(stderr,"cachepath: %s\n",cachepath); */ + ne_warn("srcpath: %s", srcpath); l = strlen(srcpath); if ((l>4 && !strcasecmp(srcpath+l-4, ".jpg")) || + (l>4 && !strcasecmp(srcpath+l-4, ".thm")) || (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"); + else if (l>4 && !strcasecmp(srcpath+l-4, ".avi")) + { + ne_warn("found avi"); + cgiwrap_writef("Content-Type: video/x-msvideo\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); + cgiwrap_writef("Last-modified: %s\n", buf); err = scale_and_display_image(srcpath,maxW,maxH,cachepath,quality); return nerr_pass(err); @@ -1042,11 +1075,13 @@ char *cs_file; char *picture; + ne_warn("Starting IMD"); cgi_debug_init (argc,argv); cgiwrap_init_std (argc, argv, envp); nerr_init(); + ne_warn("CGI init"); err = cgi_init(&cgi, NULL); if (err != STATUS_OK) { @@ -1055,6 +1090,7 @@ return -1; } imd_file = hdf_get_value(cgi->hdf, "CGI.PathTranslated", NULL); + ne_warn("Reading IMD file %s", imd_file); err = hdf_read_file (cgi->hdf, imd_file); if (err != STATUS_OK) { @@ -1091,6 +1127,12 @@ if (nerr_handle(&err, CGIFinished)) { /* pass */ + } + else + { + cgi_neo_error(cgi, err); + nerr_log_error(err); + return -1; } } else diff -Nru clearsilver-0.9.1/imd/imd.cs clearsilver-0.9.2/imd/imd.cs --- clearsilver-0.9.1/imd/imd.cs Mon Feb 11 12:16:23 2002 +++ clearsilver-0.9.2/imd/imd.cs Tue Aug 5 12:12:51 2003 @@ -7,7 +7,7 @@ width=8 src="3.gif"> - height= src="?image=/&width=&height="> + height= src="?image=/&width=&height="> width=8 src="4.gif"> @@ -23,16 +23,21 @@ - + + + + + / + + / + + - - -
-

-
+

- - - + + + + + @@ -172,24 +174,32 @@ +
+ + @@ -46,7 +51,7 @@ - + @@ -60,10 +65,8 @@
( images)
width=8 src="3.gif"> height= src="?image=//&width=&height="> height= src="?image=//&width=&height="> width=8 src="4.gif">
- -
#0 ?> First @@ -92,16 +95,13 @@
- - -
#PageWidth ?>
- +
@@ -134,22 +134,20 @@ - - --
width=18 src="3.gif"> height= src="?image=/&width=&height=&quality=1"> height= src="?image=/" AUTOSTART=true> height= src="?image=/&width=&height=&quality=1" dynsrc="?image=/&width=&height=&quality=1"> width=18 src="4.gif">
src="6.gif">
+ + Raw Video + + Raw Picture + +

- +
- +   Rotate: - Right - - Left - - Flip + Left - + Right - + Flip + diff -Nru clearsilver-0.9.1/java-jni/CSTest.java clearsilver-0.9.2/java-jni/CSTest.java --- clearsilver-0.9.1/java-jni/CSTest.java Thu Sep 19 22:55:30 2002 +++ clearsilver-0.9.2/java-jni/CSTest.java Mon Aug 18 13:09:20 2003 @@ -6,9 +6,6 @@ public static void main( String [] args ) throws IOException { org.clearsilver.HDF hdf = new org.clearsilver.HDF(); - System.out.print("hdfptr: "); - - System.out.println( hdf.hdfptr ); hdf.setValue("Foo.Bar","10"); hdf.setValue("Foo.Baz","20"); diff -Nru clearsilver-0.9.1/java-jni/Makefile clearsilver-0.9.2/java-jni/Makefile --- clearsilver-0.9.1/java-jni/Makefile Mon Apr 14 17:13:42 2003 +++ clearsilver-0.9.2/java-jni/Makefile Mon Aug 18 13:09:20 2003 @@ -40,8 +40,29 @@ CSTest.class: CSTest.java $(JAVAC) -classpath $(NEO_UTIL_JAVA_JAR) CSTest.java +gold: CSTest.class + @/bin/sh -c "LD_LIBRARY_PATH=$(NEOTONIC_ROOT)/java-jni; export LD_LIBRARY_PATH; CLASSPATH=$(NEO_UTIL_JAVA_JAR):.; export CLASSPATH; $(JAVA_PATH)/bin/java CSTest" > javatest.gold + @echo "Generated gold files" + test: CSTest.class - @/bin/sh -c "LD_LIBRARY_PATH=$(NEOTONIC_ROOT)/java-jni; export LD_LIBRARY_PATH; CLASSPATH=$(NEO_UTIL_JAVA_JAR):.; export CLASSPATH; $(JAVA_PATH)/bin/java CSTest" + @echo "Running java test" + @failed=0; \ + rm -f javatest.out; \ + LD_LIBRARY_PATH=$(NEOTONIC_ROOT)/java-jni; export LD_LIBRARY_PATH; \ + CLASSPATH=$(NEO_UTIL_JAVA_JAR):.; export CLASSPATH; \ + $(JAVA_PATH)/bin/java CSTest > javatest.out; \ + diff -brief javatest.out javatest.gold 2>%1 > /dev/null; \ + return_code=$$?; \ + if [ $$return_code -ne 0 ]; then \ + diff javatest.out javatest.gold > javatest.err; \ + echo "Failed Java Test: CSTest"; \ + echo " See javatest.out and javatest.err"; \ + failed=1; \ + fi; \ + if [ $$failed -eq 1 ]; then \ + exit 1; \ + fi; + @echo "Passed java test" CGI.h: CGI.class $(JAVAH) -jni CGI diff -Nru clearsilver-0.9.1/java-jni/javatest.gold clearsilver-0.9.2/java-jni/javatest.gold --- clearsilver-0.9.1/java-jni/javatest.gold Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/java-jni/javatest.gold Mon Aug 18 13:09:20 2003 @@ -0,0 +1,11 @@ +Foo.Bar = 10 +Foo.Baz = 20 + +---- +Foo.Bar: +Foo.Baz: + +---- +Foo.Bar:10 +Foo.Baz:20 + diff -Nru clearsilver-0.9.1/ports/rpm/clearsilver.spec clearsilver-0.9.2/ports/rpm/clearsilver.spec --- clearsilver-0.9.1/ports/rpm/clearsilver.spec Tue Jun 17 14:29:28 2003 +++ clearsilver-0.9.2/ports/rpm/clearsilver.spec Mon Aug 11 15:11:32 2003 @@ -3,14 +3,16 @@ # %define python_sitepath %(eval `python -c 'import sys; print "%%s/lib/python%%s/site-packages" %% (sys.exec_prefix, sys.version[:3])'`) +%define perl_sitearch %(eval "`perl -V:installsitearch`"; echo %$installsitearch) +%define apache_libexec %(eval `/httpd/bin/apxs -q LIBEXECDIR`) Summary: Neotonic ClearSilver Name: clearsilver -Version: 0.8.2 +Version: 0.9.2 Release: 1 Copyright: Open Source - Neotonic ClearSilver License (Apache 1.1 based) Group: Development/Libraries -Source: http://www.clearsilver.net/downloads/clearsilver-0.8.2.tar.gz +Source: http://www.clearsilver.net/downloads/clearsilver-0.9.2.tar.gz URL: http://www.clearsilver.net/ Vendor: Neotonic Software Corporation, Inc. Packager: Brandon Long @@ -69,6 +71,15 @@ The clearsilver-apache package provides an Apache 1.3.x module for loading ClearSilver CGI's as shared libraries. +%package ruby +Summary: Neotonic ClearSilver Apache Module +Group: Development/Libraries +Requires: clearsilver = %PACKAGE_VERSION +Requires: ruby >= 1.4.5 + +%description ruby +The clearsilver-ruby package provides a ruby interface to the +clearsilver templating system. %prep %setup @@ -123,4 +134,8 @@ %{__prefix}/lib/libclearsilver-jni.so %files apache -%{__prefix}/libexec/mod_ecs.so +%{apache_libexec}/mod_ecs.so + +%files ruby +%{ruby_sitepath}/%(ruby_version}/neo.rb +%{ruby_sitepath}/%(ruby_version}/$(ruby_arch}/hdf.so diff -Nru clearsilver-0.9.1/python/Makefile clearsilver-0.9.2/python/Makefile --- clearsilver-0.9.1/python/Makefile Mon Apr 14 17:13:45 2003 +++ clearsilver-0.9.2/python/Makefile Thu Jul 24 11:36:50 2003 @@ -23,9 +23,15 @@ all: $(TARGETS) -$(NEO_UTIL_SO): $(NEO_UTIL_OBJ) $(DEP_LIBS) +$(NEO_UTIL_SO): setup.py + $(PYTHON) setup.py build_ext --inplace + +OLD_NEO_UTIL_SO: $(LDSHARED) -o $@ $(LDFLAGS) $(NEO_UTIL_OBJ) $(LIBS) +setup: + $(PYTHON) setup.py build_ext --inplace + $(NEO_UTIL_PYD): $(NEO_UTIL_OBJ) $(DEP_LIBS) dllwrap --dllname neo_cgi.pyd --driver-name gcc \ --def neo_cgi.def -o neo_cgi.pyd \ @@ -42,3 +48,4 @@ distclean: $(RM) Makefile.depends $(TARGETS) *.o + $(RM) -r build diff -Nru clearsilver-0.9.1/python/examples/CSPage.py clearsilver-0.9.2/python/examples/CSPage.py --- clearsilver-0.9.1/python/examples/CSPage.py Sun Jun 15 18:54:49 2003 +++ clearsilver-0.9.2/python/examples/CSPage.py Wed Dec 31 16:00:00 1969 @@ -1,209 +0,0 @@ -#!/neo/opt/bin/python - -import neo_cgi -import sys, os, string -import time -from log import * - -# errors thrown... -NoPageName = "NoPageName" -NoDisplayMethod = "NoDisplayMethod" - -# errors signaled back to here -Redirected = "Redirected" -DisplayDone = "DisplayDone" -DisplayError = "DisplayError" - -class Context: - def __init__ (self): - self.argv = sys.argv - self.stdin = sys.stdin - self.stdout = sys.stdout - self.stderr = sys.stderr - self.environ = os.environ - -class CSPage: - def __init__(self, context, pagename=0,readDefaultHDF=1,israwpage=0): - if pagename == 0: - raise NoPageName, "missing pagename" - self.pagename = pagename - self.readDefaultHDF = readDefaultHDF - self._israwpage = israwpage - self.context = context - - self._error_template = None - - self.page_start_time = time.time() - neo_cgi.cgiWrap(context.stdin, context.stdout, context.environ) - neo_cgi.IgnoreEmptyFormVars(1) - self.ncgi = neo_cgi.CGI() - self.ncgi.parse() - self._path_num = 0 - domain = self.ncgi.hdf.getValue("CGI.ServerName","") - domain = self.ncgi.hdf.getValue("HTTP.Host", domain) - self.domain = domain - self.subclassinit() - self.setPaths([self.ncgi.hdf.getValue("CGI.DocumentRoot","")]) - - def subclassinit(self): - pass - - def setPaths(self, paths): - for path in paths: - self.ncgi.hdf.setValue("hdf.loadpaths.%d" % self._path_num, path) - self._path_num = self._path_num + 1 - - def redirectUri(self,redirectTo): - ncgi = self.ncgi - if ncgi.hdf.getIntValue("Cookie.debug",0) == 1: - ncgi.hdf.setValue("CGI.REDIRECT_TO",redirectTo) - ncgi.display("dbg/redirect.cs") - print "
"
-            print neo_cgi.htmlEscape(ncgi.hdf.dump())
-            print "
" - raise DisplayDone - - self.ncgi.redirectUri(redirectTo) - raise Redirected, "redirected To: %s" % redirectTo - - ## ---------------------------------- - ## methods to be overridden in subclass when necessary: - - def setup(self): - pass - - def display(self): - raise NoDisplayMethod, "no display method present in %s" % repr(self) - - def main(self): - self.setup() - self.handle_actions() - self.display() - - ## ---------------------------------- - - def handle_actions(self): - hdf = self.ncgi.hdf - hdfobj = hdf.getObj("Query.Action") - if hdfobj: - firstchild = hdfobj.child() - if firstchild: - action = firstchild.name() - if firstchild.next(): - raise "multiple actions present!!!" - - method_name = "Action_%s" % action - method = getattr(self,method_name) - apply(method,[]) - - def start(self): - SHOULD_DISPLAY = 1 - if self._israwpage: - SHOULD_DISPLAY = 0 - - ncgi = self.ncgi - - if self.readDefaultHDF: - try: - if not self.pagename is None: - ncgi.hdf.readFile("%s.hdf" % self.pagename) - except: - log("Error reading HDF file: %s.hdf" % (self.pagename)) - - DISPLAY_ERROR = 0 - ERROR_MESSAGE = "" - # call page main function! - try: - self.main() - except DisplayDone: - SHOULD_DISPLAY = 0 - except Redirected: - # catch redirect exceptions - SHOULD_DISPLAY = 0 - except DisplayError, num: - ncgi.hdf.setValue("Query.error", str(num)) - if self._error_template: - ncgi.hdf.setValue("Content", self._error_template) - else: - DISPLAY_ERROR = 1 - except: - SHOULD_DISPLAY = 0 - DISPLAY_ERROR = 1 - - import handle_error - handle_error.handleException("Display Failed!") - ERROR_MESSAGE = handle_error.exceptionString() - - if DISPLAY_ERROR: - print "Content-Type: text/html\n\n" - - # print the page - - print "

Error in Page

" - print "A copy of this error report has been submitted to the developers. " - print "The details of the error report are below." - - - print "
"
-            print neo_cgi.htmlEscape(ERROR_MESSAGE)
-            print "
\n" - # print debug info always on page error... - print "
\n" - print "
"
-            print neo_cgi.htmlEscape(ncgi.hdf.dump())
-            print "
" - - - etime = time.time() - self.page_start_time - ncgi.hdf.setValue("CGI.debug.execute_time","%f" % (etime)) - - if SHOULD_DISPLAY and self.pagename: - debug_output = ncgi.hdf.getIntValue("page.debug",ncgi.hdf.getIntValue("Cookie.debug",0)) - - if not debug_output: - ncgi.hdf.setValue("Config.CompressionEnabled","1") - - # default display - template_name = ncgi.hdf.getValue("Content","%s.cs" % self.pagename) - # ncgi.hdf.setValue ("cgiout.charset", "utf-8"); - - ncgi.display(template_name) - - # debug output - if debug_output: - print "
\n" - print "Execution Time: %5.3f

" % (etime) - print "
"
-		print neo_cgi.htmlEscape(ncgi.hdf.dump())
-		print "
" - # ncgi.hdf.setValue("hdf.DEBUG",ncgi.hdf.dump()) - # ncgi.display("debug.cs") - - script_name = ncgi.hdf.getValue("CGI.ScriptName","") - if script_name: - script_name = string.split(script_name,"/")[-1] - - log ("[%s] etime/dtime: %5.3f/%5.3f %s (%s)" % (self.domain, etime, time.time() - etime - self.page_start_time, script_name, self.pagename)) - - # a protected output function to catch the output errors that occur when - # the server is either restarted or the user pushes the stop button on the - # browser - def output(self, str): - try: - self.context.stdout.write(str) - except IOError, reason: - log("IOError: %s" % (repr(reason))) - raise DisplayDone - - - def allQuery (self, s): - l = [] - if self.ncgi.hdf.getValue ("Query.%s.0" % s, ""): - obj = self.ncgi.hdf.getChild ("Query.%s" % s) - while obj: - l.append(obj.value()) - obj = obj.next() - else: - t = self.ncgi.hdf.getValue ("Query.%s" % s, "") - if t: l.append(t) - return l diff -Nru clearsilver-0.9.1/python/examples/base/CSPage.py clearsilver-0.9.2/python/examples/base/CSPage.py --- clearsilver-0.9.1/python/examples/base/CSPage.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/base/CSPage.py Sun Aug 17 22:24:27 2003 @@ -0,0 +1,217 @@ +#!/neo/opt/bin/python + +import neo_cgi +import sys, os, string +import time +from log import * + +# errors thrown... +NoPageName = "NoPageName" +NoDisplayMethod = "NoDisplayMethod" + +# errors signaled back to here +Redirected = "Redirected" +DisplayDone = "DisplayDone" +DisplayError = "DisplayError" + +class Context: + def __init__ (self): + self.argv = sys.argv + self.stdin = sys.stdin + self.stdout = sys.stdout + self.stderr = sys.stderr + self.environ = os.environ + +class CSPage: + def __init__(self, context, pagename=0,readDefaultHDF=1,israwpage=0): + if pagename == 0: + raise NoPageName, "missing pagename" + self.pagename = pagename + self.readDefaultHDF = readDefaultHDF + self._israwpage = israwpage + self.context = context + + self._error_template = None + + self.page_start_time = time.time() + neo_cgi.cgiWrap(context.stdin, context.stdout, context.environ) + neo_cgi.IgnoreEmptyFormVars(1) + self.ncgi = neo_cgi.CGI() + self.ncgi.parse() + self._path_num = 0 + domain = self.ncgi.hdf.getValue("CGI.ServerName","") + domain = self.ncgi.hdf.getValue("HTTP.Host", domain) + self.domain = domain + self.subclassinit() + self.setPaths([self.ncgi.hdf.getValue("CGI.DocumentRoot","")]) + + def subclassinit(self): + pass + + def setPaths(self, paths): + for path in paths: + self.ncgi.hdf.setValue("hdf.loadpaths.%d" % self._path_num, path) + self._path_num = self._path_num + 1 + + def redirectUri(self,redirectTo): + ncgi = self.ncgi + if ncgi.hdf.getIntValue("Cookie.debug",0) == 1: + ncgi.hdf.setValue("CGI.REDIRECT_TO",redirectTo) + ncgi.display("dbg/redirect.cs") + print "
"
+            print neo_cgi.htmlEscape(ncgi.hdf.dump())
+            print "
" + raise DisplayDone + + self.ncgi.redirectUri(redirectTo) + raise Redirected, "redirected To: %s" % redirectTo + + ## ---------------------------------- + ## methods to be overridden in subclass when necessary: + + def setup(self): + pass + + def display(self): + raise NoDisplayMethod, "no display method present in %s" % repr(self) + + def main(self): + self.setup() + self.handle_actions() + self.display() + + ## ---------------------------------- + + def handle_actions(self): + hdf = self.ncgi.hdf + hdfobj = hdf.getObj("Query.Action") + if hdfobj: + firstchild = hdfobj.child() + if firstchild: + action = firstchild.name() + if firstchild.next(): + raise "multiple actions present!!!" + + method_name = "Action_%s" % action + method = getattr(self,method_name) + apply(method,[]) + + def start(self): + SHOULD_DISPLAY = 1 + if self._israwpage: + SHOULD_DISPLAY = 0 + + ncgi = self.ncgi + + if self.readDefaultHDF: + try: + if not self.pagename is None: + ncgi.hdf.readFile("%s.hdf" % self.pagename) + except: + log("Error reading HDF file: %s.hdf" % (self.pagename)) + + DISPLAY_ERROR = 0 + ERROR_MESSAGE = "" + # call page main function! + try: + self.main() + except DisplayDone: + SHOULD_DISPLAY = 0 + except Redirected: + # catch redirect exceptions + SHOULD_DISPLAY = 0 + except DisplayError, num: + ncgi.hdf.setValue("Query.error", str(num)) + if self._error_template: + ncgi.hdf.setValue("Content", self._error_template) + else: + DISPLAY_ERROR = 1 + except: + SHOULD_DISPLAY = 0 + DISPLAY_ERROR = 1 + + import handle_error + handle_error.handleException("Display Failed!") + ERROR_MESSAGE = handle_error.exceptionString() + + if DISPLAY_ERROR: + print "Content-Type: text/html\n\n" + + # print the page + + print "

Error in Page

" + print "A copy of this error report has been submitted to the developers. " + print "The details of the error report are below." + + + print "
"
+            print neo_cgi.htmlEscape(ERROR_MESSAGE)
+            print "
\n" + # print debug info always on page error... + print "
\n" + print "
"
+            print neo_cgi.htmlEscape(ncgi.hdf.dump())
+            print "
" + + + etime = time.time() - self.page_start_time + ncgi.hdf.setValue("CGI.debug.execute_time","%f" % (etime)) + + if SHOULD_DISPLAY and self.pagename: + debug_output = ncgi.hdf.getIntValue("page.debug",ncgi.hdf.getIntValue("Cookie.debug",0)) + + if not debug_output: + ncgi.hdf.setValue("Config.CompressionEnabled","1") + + # default display + template_name = ncgi.hdf.getValue("Content","%s.cs" % self.pagename) + # ncgi.hdf.setValue ("cgiout.charset", "utf-8"); + + try: + ncgi.display(template_name) + except: + print "Content-Type: text/html\n\n" + print "CSPage: Error occured" + import handle_error + print "
" + handle_error.exceptionString() + "
" + debug_output = 1 + + + # debug output + if debug_output: + print "
\n" + print "Execution Time: %5.3f

" % (etime) + print "
"
+		print neo_cgi.htmlEscape(ncgi.hdf.dump())
+		print "
" + # ncgi.hdf.setValue("hdf.DEBUG",ncgi.hdf.dump()) + # ncgi.display("debug.cs") + + script_name = ncgi.hdf.getValue("CGI.ScriptName","") + if script_name: + script_name = string.split(script_name,"/")[-1] + + log ("[%s] etime/dtime: %5.3f/%5.3f %s (%s)" % (self.domain, etime, time.time() - etime - self.page_start_time, script_name, self.pagename)) + + # a protected output function to catch the output errors that occur when + # the server is either restarted or the user pushes the stop button on the + # browser + def output(self, str): + try: + self.context.stdout.write(str) + except IOError, reason: + log("IOError: %s" % (repr(reason))) + raise DisplayDone + + + def allQuery (self, s): + l = [] + if self.ncgi.hdf.getValue ("Query.%s.0" % s, ""): + obj = self.ncgi.hdf.getChild ("Query.%s" % s) + while obj: + l.append(obj.value()) + obj = obj.next() + else: + t = self.ncgi.hdf.getValue ("Query.%s" % s, "") + if t: l.append(t) + return l diff -Nru clearsilver-0.9.1/python/examples/base/handle_error.py clearsilver-0.9.2/python/examples/base/handle_error.py --- clearsilver-0.9.1/python/examples/base/handle_error.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/base/handle_error.py Sun Jun 15 18:54:49 2003 @@ -0,0 +1,91 @@ + +import traceback, sys, string, time, socket, os +import who_calls + +DUMP_DIR = "/neo/data/bugs" + +Warning = "handle_error.Warning" + +# levels +LV_MESSAGE = "LV_MESSAGE" +LV_WARNING = "LV_WARNING" +LV_ERROR = "LV_ERROR" + +Count = 0 + +gErrorCount = 0 +DISABLE_DUMP = 0 + +def exceptionReason(): + return "%s.%s" % (str(sys.exc_type), str(sys.exc_value)) + +def exceptionString(): + tb_list = traceback.format_exception(sys.exc_type,sys.exc_value,sys.exc_traceback) + return string.join(tb_list,"") + + #### old way + import StringIO + ## get the traceback message + sfp = StringIO.StringIO() + traceback.print_exc(file=sfp) + exception = sfp.getvalue() + sfp.close() + + return exception + + +def handleException (msg=None, lvl=LV_ERROR, dump = 1): + global gErrorCount + gErrorCount = gErrorCount + 1 + + tb_list = traceback.format_exception(sys.exc_type,sys.exc_value,sys.exc_traceback) + if msg: + sys.stderr.write ("%s\n" % msg) + else: + msg = "Unhandled Exception" + + sys.stderr.write (string.join(tb_list,"")) + try: + if dump: dump_bug(lvl, "handleException", msg, string.join(tb_list, "")) + except: + handleException("Unable to dump_bug", dump = 0) + +def handleWarning (msg=""): + header = "*** handleWarning: %s\n" % msg + sys.stderr.write(header) + tb = who_calls.pretty_who_calls(strip=1) + "\n" + sys.stderr.write(tb) + + try: + dump_bug(LV_WARNING, "handleException", msg, tb) + except: + handleException("Unable to dump_bug", dump = 0) + +def dump_bug (level, etype, msg, location=None, nhdf=None): + global DISABLE_DUMP + if DISABLE_DUMP: return + + now = int(time.time()) + pid = os.getpid() + + import neo_cgi, neo_util + hdf = neo_util.HDF() + hdf.setValue("Required.Level", level) + hdf.setValue("Required.When", str(int(time.time()))) + hdf.setValue("Required.Type", etype) + hdf.setValue("Required.Title", msg) + hdf.setValue("Optional.Hostname", socket.gethostname()) + if location: + hdf.setValue("Optional.Location", location) + + for (key, value) in os.environ.items(): + hdf.setValue ("Environ.%s" % key, value) + + global Count + Count = Count + 1 + fname = "%d.%d_%d.%s" % (now, pid, Count, socket.gethostname()) + tpath = os.path.join (DUMP_DIR, "tmp", fname) + npath = os.path.join (DUMP_DIR, "new", fname) + hdf.writeFile(tpath) + os.rename(tpath, npath) + diff -Nru clearsilver-0.9.1/python/examples/base/hdfhelp.py clearsilver-0.9.2/python/examples/base/hdfhelp.py --- clearsilver-0.9.1/python/examples/base/hdfhelp.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/base/hdfhelp.py Sun Aug 17 22:24:27 2003 @@ -0,0 +1,144 @@ +#!/neo/opt/bin/python +# +# Copyright (C) 2001 by Neotonic Software Corporation +# All Rights Reserved. +# +# hdfhelp.py +# +# This code makes using odb with Clearsilver as "easy as stealing candy +# from a baby". - jeske +# +# How to use: +# +# rows = tbl.fetchAllRows() +# rows.hdfExport("CGI.rows", hdf_dataset) +# +# row = tbl.fetchRow( ('primary_key', value) ) +# row.hdfExport("CGI.row", hdf_dataset) +# +# How to setup: +# +# # define table +# class AgentsTable(odb.Table): +# def _defineRows(self): +# self.d_addColumn("agent_id",kInteger,None,primarykey = 1,autoincrement = 1) +# self.d_addColumn("login",kVarString,200,notnull=1) +# self.d_addColumn("ticket_count",kIncInteger,None) +# +# # make sure you return a subclass of hdfhelp.HdfRow +# +# def defaultRowClass(self): +# return hdfhelp.HdfRow +# def defaultRowListClass(self): +# return hdfhelp.HdfItemList +# + +import string +import neo_cgi +import neo_cs +import neo_util +import odb +import time + +import UserList + +SECS_IN_MIN = 60 +SECS_IN_HOUR = (SECS_IN_MIN * 60) +SECS_IN_DAY = (SECS_IN_HOUR * 24) +SECS_IN_WEEK = (SECS_IN_DAY * 7) +SECS_IN_MONTH = (SECS_IN_DAY * 30) + +kYearPos = 0 +kMonthPos = 1 +kDayPos = 2 +kHourPos = 3 +kMinutePos = 4 +kSecondPos = 5 +kWeekdayPos = 6 +kJulianDayPos = 7 +kDSTPos = 8 + + +def renderDate(then_time,day=0): + if then_time is None: + then_time = 0 + then_time = int(then_time) + if then_time == 0 or then_time == -1: + return "" + + then_tuple = time.localtime(then_time) + + now_tuple = time.localtime(time.time()) + + if day or (then_tuple[kHourPos]==0 and then_tuple[kMinutePos]==0 and then_tuple[kSecondPos]==0): + # it's just a date + if then_tuple[kYearPos] == now_tuple[kYearPos]: + # no year + return time.strftime("%m/%d",then_tuple) + else: + # add year + return time.strftime("%m/%d/%Y",then_tuple) + + else: + # it's a full time/date + + return time.strftime("%m/%d/%Y %H:%M%p",then_tuple) + +class HdfRow(odb.Row): + def hdfExport(self,prefix,hdf_dataset,skip_fields = None, translate_dict = None): + + for col_name,value in self.items(): + if skip_fields and (col_name in skip_fields): + continue + try: + name,col_type,col_options = self._table.getColumnDef(col_name) + except: + col_type = odb.kVarString + col_options = {} + + if (col_name != "value") and (value is not None): + if type(value) in [ type(0), type(0L) ]: + hdf_dataset.setValue(prefix + "." + col_name,"%d" % value) + else: + if translate_dict: + for k,v in translate_dict.items(): + value = string.replace(value,k,v) + hdf_dataset.setValue(prefix + "." + col_name,neo_cgi.htmlEscape(value)) + if col_options.get("int_date",0): + hdf_dataset.setValue(prefix + "." + col_name + ".string",renderDate(value)) + hdf_dataset.setValue(prefix + "." + col_name + ".day_string",renderDate(value,day=1)) + + + +class HdfItemList(UserList.UserList): + def hdfExport(self,prefix,hdf_dataset,*extra,**extranamed): + n = 0 + for row in self: + row.hdfExport("%s.%d" % (prefix,n),hdf_dataset,*extra,**extranamed) + n = n + 1 + + +def eval_cs(hdf,a_cs_string): + cs = neo_cs.CS(hdf) + try: + cs.parseStr(a_cs_string) + return cs.render() + except: + return "Error in CS tags: %s" % neo_cgi.htmlEscape(repr(a_cs_string)) + +# ---------------------------- + +def test(): + import neo_util + hdf = neo_util.HDF() + hdf.setValue("foo","1") + print eval_cs(hdf,"this should say 1 ===> ") + + +if __name__ == "__main__": + test() + + + + + diff -Nru clearsilver-0.9.1/python/examples/base/log.py clearsilver-0.9.2/python/examples/base/log.py --- clearsilver-0.9.1/python/examples/base/log.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/base/log.py Sun Jun 15 23:14:49 2003 @@ -0,0 +1,51 @@ +#!/neo/opt/bin/python + +# log.py + +import sys, time + +DEV = "development" +DEV_UPDATE = "update queries" +DEV_SELECT = "select queries" +DEV_REPORT = "report log" + +LOGGING_STATUS = { + DEV : 1, + DEV_UPDATE : 0, + DEV_SELECT : 0, + DEV_REPORT : 0} + +tstart = 0 + +def dlog(when,astr): + global LOGGING_STATUS + try: + if LOGGING_STATUS[when]: + log(astr) + except KeyError: + pass + +def tlog(astr): + global tstart + t = time.time() + if tstart == 0: + tstart = t + time_stamp = "%5.5f" % (t-tstart) + if len(astr): + if astr[-1] == "\n": + sys.stderr.write("[%s] %s" % (time_stamp, astr)) + else: + sys.stderr.write("[%s] %s\n" % (time_stamp, astr)) + +def log(astr): + if len(astr) > 1024: + astr = astr[:1024] + + t = time.time() + time_stamp = time.strftime("%m/%d %T", time.localtime(t)) + if len(astr): + if astr[-1] == "\n": + sys.stderr.write("[%s] %s" % (time_stamp, astr)) + else: + sys.stderr.write("[%s] %s\n" % (time_stamp, astr)) + # sys.stderr.flush() diff -Nru clearsilver-0.9.1/python/examples/base/odb.py clearsilver-0.9.2/python/examples/base/odb.py --- clearsilver-0.9.1/python/examples/base/odb.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/base/odb.py Sun Aug 17 22:24:27 2003 @@ -0,0 +1,1475 @@ +#!/neo/opt/bin/python +# +# odb.py +# +# Object Database Api +# +# Written by David Jeske , 2001/07. +# Inspired by eGroups' sqldb.py originally written by Scott Hassan circa 1998. +# +# Copyright (C) 2001, by David Jeske and Neotonic +# +# Goals: +# - a simple object-like interface to database data +# - database independent (someday) +# - relational-style "rigid schema definition" +# - object style easy-access +# +# Example: +# +# import odb +# import MySQLdb +# +# # define table +# class AgentsTable(odb.Table): +# def _defineRows(self): +# self.d_addColumn("agent_id",kInteger,None,primarykey = 1,autoincrement = 1) +# self.d_addColumn("login",kVarString,200,notnull=1) +# self.d_addColumn("ticket_count",kIncInteger,None) +# +# if __name__ == "__main__": +# # open database +# ndb = MySQLdb.connect(host = 'localhost', +# user='username', +# passwd = 'password', +# db='testdb') +# db = Database(ndb) +# tbl = AgentsTable(db,"agents") +# +# # create row +# agent_row = tbl.newRow() +# agent_row.login = "foo" +# agent_row.save() +# +# # fetch row (must use primary key) +# try: +# get_row = tbl.fetchRow( ('agent_id', agent_row.agent_id) ) +# except odb.eNoMatchingRows: +# print "this is bad, we should have found the row" +# +# # fetch rows (can return empty list) +# list_rows = tbl.fetchRows( ('login', "foo") ) +# + +import tstart + +import string +import sys, zlib +from log import * + +import MySQLdb + +eNoSuchColumn = "odb.eNoSuchColumn" +eNonUniqueMatchSpec = "odb.eNonUniqueMatchSpec" +eNoMatchingRows = "odb.eNoMatchingRows" +eInternalError = "odb.eInternalError" +eInvalidMatchSpec = "odb.eInvalidMatchSpec" +eInvalidData = "odb.eInvalidData" +eUnsavedObjectLost = "odb.eUnsavedObjectLost" +eDuplicateKey = "odb.eDuplicateKey" + +##################################### +# COLUMN TYPES +################ ###################### +# typename ####################### size data means: +# # # +kInteger = "kInteger" # - +kFixedString = "kFixedString" # size +kVarString = "kVarString" # maxsize +kBigString = "kBigString" # - +kIncInteger = "kIncInteger" # - +kDateTime = "kDateTime" +kTimeStamp = "kTimeStamp" + + +DEBUG = 0 + +############## +# Database +# +# this will ultimately turn into a mostly abstract base class for +# the DB adaptors for different database types.... +# + +class Database: + def __init__(self,db): + self._tables = {} + self.db = db + self._cursor = None + self.compression_enabled = 0 + + # __init__ = None + # list_tables = None # list_tables() -> ['a_table','b_table'] + # list_fields = None # list_fields(tbl_name) -> [' + # checkTable = None # checkTable + # createTable + + def defaultCursor(self): + if self._cursor is None: + self._cursor = self.db.cursor() + return self._cursor + + def escape(self,str): + return MySQLdb.escape_string(str) + def defaultRowClass(self): + return Row + + def defaultRowListClass(self): + # base type is list... + return list + + def addTable(self, attrname, tblname, tblclass, rowClass = None, check = 0, create = 0, rowListClass = None): + self._tables[attrname] = tblclass(self, tblname, rowClass=rowClass, check=check, create=create, rowListClass=rowListClass) + + def close(self): + for name, tbl in self._tables.items(): + tbl.db = None + self._tables = {} + if self.db is not None: + self.db.close() + self.db = None + + def __getattr__(self, key): + if key == "_tables": + raise AttributeError, "odb.Database: not initialized properly, self._tables does not exist" + + try: + table_dict = getattr(self,"_tables") + return table_dict[key] + except KeyError: + raise AttributeError, "odb.Database: unknown attribute %s" % (key) + + def beginTransaction(self, cursor=None): + if cursor is None: + cursor = self.defaultCursor() + dlog(DEV_UPDATE,"begin") + cursor.execute("begin") + + def commitTransaction(self, cursor=None): + if cursor is None: + cursor = self.defaultCursor() + dlog(DEV_UPDATE,"commit") + cursor.execute("commit") + + def rollbackTransaction(self, cursor=None): + if cursor is None: + cursor = self.defaultCursor() + dlog(DEV_UPDATE,"rollback") + cursor.execute("rollback") + +########################################## +# Table +# + + +class Table: + def subclassinit(self): + pass + def __init__(self,database,table_name,rowClass = None, check = 0, create = 0, rowListClass = None): + self.db = database + self.__table_name = table_name + if rowClass: + self.__defaultRowClass = rowClass + else: + self.__defaultRowClass = database.defaultRowClass() + + if rowListClass: + self.__defaultRowListClass = rowListClass + else: + self.__defaultRowListClass = database.defaultRowListClass() + + # get this stuff ready! + + self.__column_list = [] + self.__vcolumn_list = [] + self.__columns_locked = 0 + self.__has_value_column = 0 + + # this will be used during init... + self.__col_def_hash = None + self.__vcol_def_hash = None + self.__primary_key_list = None + self.__relations_by_table = {} + + # ask the subclass to def his rows + self._defineRows() + + # get ready to run! + self.__lockColumnsAndInit() + + self.subclassinit() + + if create: + self.db.createTable(self) + + if check: + self.db.checkTable(self) + + def getColumnDef(self,column_name): + try: + return self.__col_def_hash[column_name] + except KeyError: + try: + return self.__vcol_def_hash[column_name] + except KeyError: + raise eNoSuchColumn, "no column (%s) on table %s" % (column_name,self.__table_name) + + def getColumnList(self): + return self.__column_list + self.__vcolumn_list + + def databaseSizeForData_ColumnName_(self,data,col_name): + try: + col_def = self.__col_def_hash[col_name] + except KeyError: + try: + col_def = self.__vcol_def_hash[col_name] + except KeyError: + raise eNoSuchColumn, "no column (%s) on table %s" % (col_name,self.__table_name) + + c_name,c_type,c_options = col_def + + if c_type == kBigString: + if c_options.get("compress_ok",0) and self.db.compression_enabled: + z_size = len(zlib.compress(data,9)) + r_size = len(data) + if z_size < r_size: + return z_size + else: + return r_size + else: + return len(data) + else: + # really simplistic database size computation: + try: + a = data[0] + return len(data) + except: + return 4 + + + def columnType(self, col_name): + try: + col_def = self.__col_def_hash[col_name] + except KeyError: + try: + col_def = self.__vcol_def_hash[col_name] + except KeyError: + raise eNoSuchColumn, "no column (%s) on table %s" % (col_name,self.__table_name) + + c_name,c_type,c_options = col_def + return c_type + + def convertDataForColumn(self,data,col_name): + try: + col_def = self.__col_def_hash[col_name] + except KeyError: + try: + col_def = self.__vcol_def_hash[col_name] + except KeyError: + raise eNoSuchColumn, "no column (%s) on table %s" % (col_name,self.__table_name) + + c_name,c_type,c_options = col_def + + if c_type == kIncInteger: + raise eInvalidData, "invalid operation for column (%s:%s) on table (%s)" % (col_name,c_type,self.__table_name) + + if c_type == kInteger: + try: + if data is None: data = 0 + else: return long(data) + except (ValueError,TypeError): + raise eInvalidData, "invalid data (%s) for col (%s:%s) on table (%s)" % (repr(data),col_name,c_type,self.__table_name) + else: + if type(data) == type(long(0)): + return "%d" % data + else: + return str(data) + + def getPrimaryKeyList(self): + return self.__primary_key_list + + def getTableName(self): + return self.__table_name + def hasValueColumn(self): + return self.__has_value_column + + def hasColumn(self,name): + return self.__col_def_hash.has_key(name) + def hasVColumn(self,name): + return self.__vcol_def_hash.has_key(name) + + + def _defineRows(self): + raise "can't instantiate base odb.Table type, make a subclass and override _defineRows()" + + def __lockColumnsAndInit(self): + # add a 'odb_value column' before we lockdown the table def + if self.__has_value_column: + self.d_addColumn("odb_value",kBigText,default='') + + self.__columns_locked = 1 + # walk column list and make lookup hashes, primary_key_list, etc.. + + primary_key_list = [] + col_def_hash = {} + for a_col in self.__column_list: + name,type,options = a_col + col_def_hash[name] = a_col + if options.has_key('primarykey'): + primary_key_list.append(name) + + self.__col_def_hash = col_def_hash + self.__primary_key_list = primary_key_list + + # setup the value columns! + + if (not self.__has_value_column) and (len(self.__vcolumn_list) > 0): + raise "can't define vcolumns on table without ValueColumn, call d_addValueColumn() in your _defineRows()" + + vcol_def_hash = {} + for a_col in self.__vcolumn_list: + name,type,size_data,options = a_col + vcol_def_hash[name] = a_col + + self.__vcol_def_hash = vcol_def_hash + + + def __checkColumnLock(self): + if self.__columns_locked: + raise "can't change column definitions outside of subclass' _defineRows() method!" + + # table definition methods, these are only available while inside the + # subclass's _defineRows method + # + # Ex: + # + # import odb + # class MyTable(odb.Table): + # def _defineRows(self): + # self.d_addColumn("id",kInteger,primarykey = 1,autoincrement = 1) + # self.d_addColumn("name",kVarString,120) + # self.d_addColumn("type",kInteger, + # enum_values = { 0 : "alive", 1 : "dead" } + + def d_addColumn(self,col_name,ctype,size=None,primarykey = 0, notnull = 0,indexed=0, + default=None,unique=0,autoincrement=0,safeupdate=0,enum_values = None, + relations=None,compress_ok=0,int_date=0): + + self.__checkColumnLock() + + options = {} + options['default'] = default + if primarykey: + options['primarykey'] = primarykey + if indexed: + options['indexed'] = indexed + if unique: + options['unique'] = unique + if safeupdate: + options['safeupdate'] = safeupdate + if autoincrement: + options['autoincrement'] = autoincrement + if notnull: + options['notnull'] = notnull + if size: + options['size'] = size + if int_date: + if ctype != kInteger: + raise eInvalidData, "can't flag columns int_date unless they are kInteger" + else: + options['int_date'] = int_date + + if enum_values: + options['enum_values'] = enum_values + inv_enum_values = {} + for k,v in enum_values.items(): + if inv_enum_values.has_key(v): + raise eInvalidData, "enum_values paramater must be a 1 to 1 mapping for Table(%s)" % self.__table_name + else: + inv_enum_values[v] = k + options['inv_enum_values'] = inv_enum_values + if relations: + options['relations'] = relations + for a_relation in relations: + table, foreign_column_name = a_relation + if self.__relations_by_table.has_key(table): + raise eInvalidData, "multiple relations for the same foreign table are not yet supported" + self.__relations_by_table[table] = (col_name,foreign_column_name) + if compress_ok: + if ctype == kBigString: + options['compress_ok'] = 1 + else: + raise eInvalidData, "only kBigString fields can be compress_ok=1" + + self.__column_list.append( (col_name,ctype,options) ) + + + def d_addValueColumn(self): + self.__checkColumnLock() + self.__has_value_column = 1 + + def d_addVColumn(self,col_name,type,size=None,default=None): + self.__checkColumnLock() + + if (not self.__has_value_column): + raise "can't define VColumns on table without ValueColumn, call d_addValueColumn() first" + + options = {} + if default: + options['default'] = default + if size: + options['size'] = size + + self.__vcolumn_list.append( (col_name,type,options) ) + + ##################### + # _checkColMatchSpec(col_match_spec,should_match_unique_row = 0) + # + # raise an error if the col_match_spec contains invalid columns, or + # (in the case of should_match_unique_row) if it does not fully specify + # a unique row. + # + # NOTE: we don't currently support where clauses with value column fields! + # + + def _fixColMatchSpec(self,col_match_spec, should_match_unique_row = 0): + if type(col_match_spec) == type([]): + if type(col_match_spec[0]) != type((0,)): + raise eInvalidMatchSpec, "invalid types in match spec, use [(,)..] or (,)" + elif type(col_match_spec) == type((0,)): + col_match_spec = [ col_match_spec ] + elif type(col_match_spec) == type(None): + if should_match_unique_row: + raise eNonUniqueMatchSpec, "can't use a non-unique match spec (%s) here" % col_match_spec + else: + return None + else: + raise eInvalidMatchSpec, "invalid types in match spec, use [(,)..] or (,)" + + if should_match_unique_row: + unique_column_lists = [] + + # first the primary key list + my_primary_key_list = [] + for a_key in self.__primary_key_list: + my_primary_key_list.append(a_key) + + # then other unique keys + for a_col in self.__column_list: + col_name,a_type,options = a_col + if options.has_key('unique'): + unique_column_lists.append( (col_name, [col_name]) ) + + unique_column_lists.append( ('primary_key', my_primary_key_list) ) + + + new_col_match_spec = [] + for a_col in col_match_spec: + name,val = a_col + # newname = string.lower(name) + # what is this doing?? - jeske + newname = name + if not self.__col_def_hash.has_key(newname): + raise eNoSuchColumn, "no such column in match spec: '%s'" % newname + + new_col_match_spec.append( (newname,val) ) + + if should_match_unique_row: + for name,a_list in unique_column_lists: + try: + a_list.remove(newname) + except ValueError: + # it's okay if they specify too many columns! + pass + + if should_match_unique_row: + for name,a_list in unique_column_lists: + if len(a_list) == 0: + # we matched at least one unique colum spec! + # log("using unique column (%s) for query %s" % (name,col_match_spec)) + return new_col_match_spec + + raise eNonUniqueMatchSpec, "can't use a non-unique match spec (%s) here" % col_match_spec + + return new_col_match_spec + + def __buildWhereClause (self, col_match_spec,other_clauses = None): + sql_where_list = [] + + if not col_match_spec is None: + for m_col in col_match_spec: + m_col_name,m_col_val = m_col + c_name,c_type,c_options = self.__col_def_hash[m_col_name] + if c_type in (kIncInteger, kInteger): + try: + m_col_val_long = long(m_col_val) + except ValueError: + raise ValueError, "invalid literal for long(%s) in table %s" % (repr(m_col_val),self.__table_name) + + sql_where_list.append("%s = %d" % (c_name, m_col_val_long)) + else: + sql_where_list.append("%s = '%s'" % (c_name, self.db.escape(m_col_val))) + + if other_clauses is None: + pass + elif type(other_clauses) == type(""): + sql_where_list = sql_where_list + [other_clauses] + elif type(other_clauses) == type([]): + sql_where_list = sql_where_list + other_clauses + else: + raise eInvalidData, "unknown type of extra where clause: %s" % repr(other_clauses) + + return sql_where_list + + def __fetchRows(self,col_match_spec,cursor = None, where = None, order_by = None, limit_to = None, + skip_to = None, join = None): + if cursor is None: + cursor = self.db.defaultCursor() + + # build column list + sql_columns = [] + for name,t,options in self.__column_list: + sql_columns.append(name) + + # build join information + + joined_cols = [] + joined_cols_hash = {} + join_clauses = [] + if not join is None: + for a_table,retrieve_foreign_cols in join: + try: + my_col,foreign_col = self.__relations_by_table[a_table] + for a_col in retrieve_foreign_cols: + full_col_name = "%s.%s" % (my_col,a_col) + joined_cols_hash[full_col_name] = 1 + joined_cols.append(full_col_name) + sql_columns.append( full_col_name ) + + join_clauses.append(" left join %s as %s on %s=%s " % (a_table,my_col,my_col,foreign_col)) + + except KeyError: + eInvalidJoinSpec, "can't find table %s in defined relations for %s" % (a_table,self.__table_name) + + # start buildling SQL + sql = "select %s from %s" % (string.join(sql_columns,","), + self.__table_name) + + # add join clause + if join_clauses: + sql = sql + string.join(join_clauses," ") + + # add where clause elements + sql_where_list = self.__buildWhereClause (col_match_spec,where) + if sql_where_list: + sql = sql + " where %s" % (string.join(sql_where_list," and ")) + + # add order by clause + if order_by: + sql = sql + " order by %s " % string.join(order_by,",") + + # add limit + if not limit_to is None: + if not skip_to is None: + sql = sql + " limit %s, %s" % (skip_to,limit_to) + else: + sql = sql + " limit %s" % limit_to + else: + if not skip_to is None: + raise eInvalidData, "can't specify skip_to without limit_to in MySQL" + + dlog(DEV_SELECT,sql) + cursor.execute(sql) + + # create defaultRowListClass instance... + return_rows = self.__defaultRowListClass() + + # should do fetchmany! + all_rows = cursor.fetchall() + for a_row in all_rows: + data_dict = {} + + col_num = 0 + + # for a_col in cursor.description: + # (name,type_code,display_size,internal_size,precision,scale,null_ok) = a_col + for name in sql_columns: + if self.__col_def_hash.has_key(name) or joined_cols_hash.has_key(name): + # only include declared columns! + if self.__col_def_hash.has_key(name): + c_name,c_type,c_options = self.__col_def_hash[name] + if c_type == kBigString and c_options.get("compress_ok",0) and a_row[col_num]: + try: + a_col_data = zlib.decompress(a_row[col_num]) + except zlib.error: + a_col_data = a_row[col_num] + + data_dict[name] = a_col_data + else: + data_dict[name] = a_row[col_num] + + else: + data_dict[name] = a_row[col_num] + + col_num = col_num + 1 + + newrowobj = self.__defaultRowClass(self,data_dict,joined_cols = joined_cols) + + return_rows.append(newrowobj) + + return return_rows + + def __deleteRow(self,a_row,cursor = None): + if cursor is None: + cursor = self.db.defaultCursor() + + # build the where clause! + match_spec = a_row.getPKMatchSpec() + sql_where_list = self.__buildWhereClause (match_spec) + + sql = "delete from %s where %s" % (self.__table_name, + string.join(sql_where_list," and ")) + dlog(DEV_UPDATE,sql) + cursor.execute(sql) + + + def __updateRowList(self,a_row_list,cursor = None): + if cursor is None: + cursor = self.db.defaultCursor() + + for a_row in a_row_list: + update_list = a_row.changedList() + + # build the set list! + sql_set_list = [] + for a_change in update_list: + col_name,col_val,col_inc_val = a_change + c_name,c_type,c_options = self.__col_def_hash[col_name] + + if c_type != kIncInteger and col_val is None: + sql_set_list.append("%s = NULL" % c_name) + elif c_type == kIncInteger and col_inc_val is None: + sql_set_list.append("%s = 0" % c_name) + else: + if c_type == kInteger: + sql_set_list.append("%s = %d" % (c_name, long(col_val))) + elif c_type == kIncInteger: + sql_set_list.append("%s = %s + %d" % (c_name,c_name,long(col_inc_val))) + elif c_type == kBigString and c_options.get("compress_ok",0) and self.db.compression_enabled: + compressed_data = zlib.compress(col_val,9) + if len(compressed_data) < len(col_val): + sql_set_list.append("%s = '%s'" % (c_name, self.db.escape(compressed_data))) + else: + sql_set_list.append("%s = '%s'" % (c_name, self.db.escape(col_val))) + else: + sql_set_list.append("%s = '%s'" % (c_name, self.db.escape(col_val))) + + # build the where clause! + match_spec = a_row.getPKMatchSpec() + sql_where_list = self.__buildWhereClause (match_spec) + + if sql_set_list: + sql = "update %s set %s where %s" % (self.__table_name, + string.join(sql_set_list,","), + string.join(sql_where_list," and ")) + + dlog(DEV_UPDATE,sql) + try: + cursor.execute(sql) + except Exception, reason: + if string.find(str(reason), "Duplicate entry") != -1: + raise eDuplicateKey, reason + raise Exception, reason + a_row.markClean() + + def __insertRow(self,a_row_obj,cursor = None): + if cursor is None: + cursor = self.db.defaultCursor() + + sql_col_list = [] + sql_data_list = [] + auto_increment_column_name = None + + for a_col in self.__column_list: + name,type,options = a_col + + try: + data = a_row_obj[name] + + sql_col_list.append(name) + if data is None: + sql_data_list.append("NULL") + else: + if type == kInteger or type == kIncInteger: + sql_data_list.append("%d" % data) + elif type == kBigString and options.get("compress_ok",0) and self.db.compression_enabled: + compressed_data = zlib.compress(data,9) + if len(compressed_data) < len(data): + sql_data_list.append("'%s'" % self.db.escape(compressed_data)) + else: + sql_data_list.append("'%s'" % self.db.escape(data)) + else: + sql_data_list.append("'%s'" % self.db.escape(data)) + + except KeyError: + if options.has_key("autoincrement"): + if auto_increment_column_name: + raise eInternalError, "two autoincrement columns (%s,%s) in table (%s)" % (auto_increment_column_name, name,self.__table_name) + else: + auto_increment_column_name = name + + + sql = "insert into %s (%s) values (%s)" % (self.__table_name, + string.join(sql_col_list,","), + string.join(sql_data_list,",")) + + dlog(DEV_UPDATE,sql) + try: + cursor.execute(sql) + except Exception, reason: + if string.find(str(reason), "Duplicate entry") != -1: + raise eDuplicateKey, reason + raise Exception, reason + + if auto_increment_column_name: + a_row_obj[auto_increment_column_name] = cursor.insert_id() + + # ---------------------------------------------------- + # Helper methods for Rows... + # ---------------------------------------------------- + + + + ##################### + # r_deleteRow(a_row_obj,cursor = None) + # + # normally this is called from within the Row "delete()" method + # but you can call it yourself if you want + # + + def r_deleteRow(self,a_row_obj, cursor = None): + curs = cursor + self.__deleteRow(a_row_obj, cursor = curs) + + + ##################### + # r_updateRow(a_row_obj,cursor = None) + # + # normally this is called from within the Row "save()" method + # but you can call it yourself if you want + # + + def r_updateRow(self,a_row_obj, cursor = None): + curs = cursor + self.__updateRowList([a_row_obj], cursor = curs) + + ##################### + # InsertRow(a_row_obj,cursor = None) + # + # normally this is called from within the Row "save()" method + # but you can call it yourself if you want + # + + def r_insertRow(self,a_row_obj, cursor = None): + curs = cursor + self.__insertRow(a_row_obj, cursor = curs) + + + # ---------------------------------------------------- + # Public Methods + # ---------------------------------------------------- + + + + ##################### + # deleteRow(col_match_spec) + # + # The col_match_spec paramaters must include all primary key columns. + # + # Ex: + # a_row = tbl.fetchRow( ("order_id", 1) ) + # a_row = tbl.fetchRow( [ ("order_id", 1), ("enterTime", now) ] ) + + + def deleteRow(self,col_match_spec, where=None): + n_match_spec = self._fixColMatchSpec(col_match_spec) + cursor = self.db.defaultCursor() + + # build sql where clause elements + sql_where_list = self.__buildWhereClause (n_match_spec,where) + if not sql_where_list: + return + + sql = "delete from %s where %s" % (self.__table_name, string.join(sql_where_list," and ")) + + dlog(DEV_UPDATE,sql) + cursor.execute(sql) + + ##################### + # fetchRow(col_match_spec) + # + # The col_match_spec paramaters must include all primary key columns. + # + # Ex: + # a_row = tbl.fetchRow( ("order_id", 1) ) + # a_row = tbl.fetchRow( [ ("order_id", 1), ("enterTime", now) ] ) + + + def fetchRow(self, col_match_spec, cursor = None): + n_match_spec = self._fixColMatchSpec(col_match_spec, should_match_unique_row = 1) + + rows = self.__fetchRows(n_match_spec, cursor = cursor) + if len(rows) == 0: + raise eNoMatchingRows, "no row matches %s" % repr(n_match_spec) + + if len(rows) > 1: + raise eInternalError, "unique where clause shouldn't return > 1 row" + + return rows[0] + + + ##################### + # fetchRows(col_match_spec) + # + # Ex: + # a_row_list = tbl.fetchRows( ("order_id", 1) ) + # a_row_list = tbl.fetchRows( [ ("order_id", 1), ("enterTime", now) ] ) + + + def fetchRows(self, col_match_spec = None, cursor = None, where = None, order_by = None, limit_to = None, skip_to = None, join = None): + n_match_spec = self._fixColMatchSpec(col_match_spec) + + return self.__fetchRows(n_match_spec, + cursor = cursor, + where = where, + order_by = order_by, + limit_to = limit_to, + skip_to = skip_to, + join = join) + + def fetchRowCount (self, col_match_spec = None, cursor = None, where = None): + n_match_spec = self._fixColMatchSpec(col_match_spec) + + sql_where_list = self.__buildWhereClause (n_match_spec,where) + + sql = "select count(*) from %s" % self.__table_name + if sql_where_list: + sql = "%s where %s" % (sql,string.join(sql_where_list," and ")) + + if cursor is None: + cursor = self.db.defaultCursor() + dlog(DEV_SELECT,sql) + cursor.execute(sql) + try: + count, = cursor.fetchone() + except TypeError: + count = 0 + return count + + + ##################### + # fetchAllRows() + # + # Ex: + # a_row_list = tbl.fetchRows( ("order_id", 1) ) + # a_row_list = tbl.fetchRows( [ ("order_id", 1), ("enterTime", now) ] ) + + def fetchAllRows(self): + try: + return self.__fetchRows([]) + except eNoMatchingRows: + # else return empty list... + return self.__defaultRowListClass() + + def newRow(self): + row = self.__defaultRowClass(self,None,create=1) + for (cname, ctype, opts) in self.__column_list: + if opts['default'] is not None and ctype is not kIncInteger: + row[cname] = opts['default'] + return row + +class Row: + __instance_data_locked = 0 + def subclassinit(self): + pass + def __init__(self,_table,data_dict,create=0,joined_cols = None): + + self._inside_getattr = 0 # stop recursive __getattr__ + self._table = _table + self._should_insert = create + self._rowInactive = None + self._joinedRows = [] + + self.__pk_match_spec = None + self.__vcoldata = {} + self.__inc_coldata = {} + + self.__joined_cols_dict = {} + for a_col in joined_cols or []: + self.__joined_cols_dict[a_col] = 1 + + if create: + self.__coldata = {} + else: + if type(data_dict) != type({}): + raise eInternalError, "rowdict instantiate with bad data_dict" + self.__coldata = data_dict + self.__unpackVColumn() + + self.markClean() + + self.subclassinit() + self.__instance_data_locked = 1 + + def joinRowData(self,another_row): + self._joinedRows.append(another_row) + + def getPKMatchSpec(self): + return self.__pk_match_spec + + def markClean(self): + self.__vcolchanged = 0 + self.__colchanged_dict = {} + + for key in self.__inc_coldata.keys(): + self.__coldata[key] = self.__coldata.get(key, 0) + self.__inc_coldata[key] + + self.__inc_coldata = {} + + if not self._should_insert: + # rebuild primary column match spec + new_match_spec = [] + for col_name in self._table.getPrimaryKeyList(): + try: + rdata = self[col_name] + except KeyError: + raise eInternalError, "must have primary key data filled in to save %s:Row(col:%s)" % (self._table.getTableName(),col_name) + + new_match_spec.append( (col_name, rdata) ) + self.__pk_match_spec = new_match_spec + + def __unpackVColumn(self): + if self._table.hasValueColumn(): + pass + + def __packVColumn(self): + if self._table.hasValueColumn(): + pass + + ## ----- utility stuff ---------------------------------- + + def __del__(self): + # check for unsaved changes + changed_list = self.changedList() + if len(changed_list): + info = "unsaved Row for table (%s) lost, call discard() to avoid this error. Lost changes: %s\n" % (self._table.getTableName(), repr(changed_list)[:256]) + if 0: + raise eUnsavedObjectLost, info + else: + sys.stderr.write(info) + + + def __repr__(self): + return "Row from (%s): %s" % (self._table.getTableName(),repr(self.__coldata) + repr(self.__vcoldata)) + + ## ---- class emulation -------------------------------- + + def __getattr__(self,key): + if self._inside_getattr: + raise AttributeError, "recursively called __getattr__ (%s,%s)" % (key,self._table.getTableName()) + try: + self._inside_getattr = 1 + try: + return self[key] + except KeyError: + if self._table.hasColumn(key) or self._table.hasVColumn(key): + return None + else: + raise AttributeError, "unknown field '%s' in Row(%s)" % (key,self._table.getTableName()) + finally: + self._inside_getattr = 0 + + def __setattr__(self,key,val): + if not self.__instance_data_locked: + self.__dict__[key] = val + else: + my_dict = self.__dict__ + if my_dict.has_key(key): + my_dict[key] = val + else: + # try and put it into the rowdata + try: + self[key] = val + except KeyError, reason: + raise AttributeError, reason + + + ## ---- dict emulation --------------------------------- + + def __getitem__(self,key): + self.checkRowActive() + + try: + c_type = self._table.columnType(key) + except eNoSuchColumn: + # Ugh, this sucks, we can't determine the type for a joined + # row, so we just default to kVarString and let the code below + # determine if this is a joined column or not + c_type = kVarString + + if c_type == kIncInteger: + c_data = self.__coldata.get(key, 0) + if c_data is None: c_data = 0 + i_data = self.__inc_coldata.get(key, 0) + if i_data is None: i_data = 0 + return c_data + i_data + + try: + return self.__coldata[key] + except KeyError: + try: + return self.__vcoldata[key] + except KeyError: + for a_joined_row in self._joinedRows: + try: + return a_joined_row[key] + except KeyError: + pass + + raise KeyError, "unknown column %s in %s" % (key,self) + + def __setitem__(self,key,data): + self.checkRowActive() + + try: + newdata = self._table.convertDataForColumn(data,key) + except eNoSuchColumn, reason: + raise KeyError, reason + + if self._table.hasColumn(key): + self.__coldata[key] = newdata + self.__colchanged_dict[key] = 1 + elif self._table.hasVColumn(key): + self.__vcoldata[key] = newdata + self.__vcolchanged = 1 + else: + for a_joined_row in self._joinedRows: + try: + a_joined_row[key] = data + return + except KeyError: + pass + raise KeyError, "unknown column name %s" % key + + def __delitem__(self,key,data): + self.checkRowActive() + + if self.table.hasVColumn(key): + del self.__vcoldata[key] + else: + for a_joined_row in self._joinedRows: + try: + del a_joined_row[key] + return + except KeyError: + pass + raise KeyError, "unknown column name %s" % key + + + def copyFrom(self,source): + for name,t,options in self._table.getColumnList(): + if not options.has_key("autoincrement"): + self[name] = source[name] + + + # make sure that .keys(), and .items() come out in a nice order! + + def keys(self): + self.checkRowActive() + + key_list = [] + for name,t,options in self._table.getColumnList(): + key_list.append(name) + for name in self.__joined_cols_dict.keys(): + key_list.append(name) + + for a_joined_row in self._joinedRows: + key_list = key_list + a_joined_row.keys() + + return key_list + + + def items(self): + self.checkRowActive() + + item_list = [] + for name,t,options in self._table.getColumnList(): + item_list.append( (name,self[name]) ) + for name in self.__joined_cols_dict.keys(): + item_list.append( (name,self[name]) ) + + for a_joined_row in self._joinedRows: + item_list = item_list + a_joined_row.items() + + + return item_list + + def values(elf): + self.checkRowActive() + + value_list = self.__coldata.values() + self.__vcoldata.values() + + for a_joined_row in self._joinedRows: + value_list = value_list + a_joined_row.values() + + return value_list + + + def __len__(self): + self.checkRowActive() + + my_len = len(self.__coldata) + len(self.__vcoldata) + + for a_joined_row in self._joinedRows: + my_len = my_len + len(a_joined_row) + + return my_len + + def has_key(self,key): + self.checkRowActive() + + if self.__coldata.has_key(key) or self.__vcoldata.has_key(key): + return 1 + else: + + for a_joined_row in self._joinedRows: + if a_joined_row.has_key(key): + return 1 + return 0 + + def get(self,key,default = None): + self.checkRowActive() + + + + if self.__coldata.has_key(key): + return self.__coldata[key] + elif self.__vcoldata.has_key(key): + return self.__vcoldata[key] + else: + for a_joined_row in self._joinedRows: + try: + return a_joined_row.get(key,default) + except eNoSuchColumn: + pass + + if self._table.hasColumn(key): + return default + + raise eNoSuchColumn, "no such column %s" % key + + def inc(self,key,count=1): + self.checkRowActive() + + if self._table.hasColumn(key): + try: + self.__inc_coldata[key] = self.__inc_coldata[key] + count + except KeyError: + self.__inc_coldata[key] = count + + self.__colchanged_dict[key] = 1 + else: + raise AttributeError, "unknown field '%s' in Row(%s)" % (key,self._table.getTableName()) + + + ## ---------------------------------- + ## real interface + + + def fillDefaults(self): + for field_def in self._table.fieldList(): + name,type,size,options = field_def + if options.has_key("default"): + self[name] = options["default"] + + ############### + # changedList() + # + # returns a list of tuples for the columns which have changed + # + # changedList() -> [ ('name', 'fred'), ('age', 20) ] + + def changedList(self): + if self.__vcolchanged: + self.__packVColumn() + + changed_list = [] + for a_col in self.__colchanged_dict.keys(): + changed_list.append( (a_col,self.get(a_col,None),self.__inc_coldata.get(a_col,None)) ) + + return changed_list + + def discard(self): + self.__coldata = None + self.__vcoldata = None + self.__colchanged_dict = {} + self.__vcolchanged = 0 + + def delete(self,cursor = None): + self.checkRowActive() + + + fromTable = self._table + curs = cursor + fromTable.r_deleteRow(self,cursor=curs) + self._rowInactive = "deleted" + + def save(self,cursor = None): + toTable = self._table + + self.checkRowActive() + + if self._should_insert: + toTable.r_insertRow(self) + self._should_insert = 0 + self.markClean() # rebuild the primary key list + else: + curs = cursor + toTable.r_updateRow(self,cursor = curs) + + # the table will mark us clean! + # self.markClean() + + def checkRowActive(self): + if self._rowInactive: + raise eInvalidData, "row is inactive: %s" % self._rowInactive + + def databaseSizeForColumn(self,key): + return self._table.databaseSizeForData_ColumnName_(self[key],key) + +## ----------------------------------------------------------------------- +## T E S T S +## ----------------------------------------------------------------------- + + +def TEST(output=log): + LOGGING_STATUS[DEV_SELECT] = 1 + LOGGING_STATUS[DEV_UPDATE] = 1 + class AgentsTable(Table): + def _defineRows(self): + self.d_addColumn("agent_id",kInteger,None,primarykey = 1,autoincrement = 1) + self.d_addColumn("login",kVarString,200,notnull=1) + self.d_addColumn("ext_email",kVarString,200,notnull=1) + self.d_addColumn("hashed_pw",kVarString,20,notnull=1) + self.d_addColumn("name",kBigString,compress_ok=1) + self.d_addColumn("auth_level",kInteger,None) + self.d_addColumn("ticket_count",kIncInteger,None) + + + import MySQLdb + rdb = MySQLdb.connect(host = 'localhost',user='root', passwd = '', db='testdb') + ndb = MySQLdb.connect(host = 'localhost',user='trakken', passwd = 'trakpas', db='testdb') + db = Database(ndb) + + tbl = AgentsTable(db,"agents") + + cursor = rdb.cursor() + + # --------------------------------------------------------------- + # initialize + output("drop table agents") + try: + cursor.execute("drop table agents") # clean out the table + except MySQLdb.OperationalError: + pass + output("creating table") + cursor.execute("create table agents (agent_id integer not null primary key auto_increment, login varchar(200) not null, unique (login), ext_email varchar(200) not null, hashed_pw varchar(20) not null, name varchar(200), auth_level integer default 0, ticket_count integer default 0)") + + TEST_INSERT_COUNT = 5 + + # --------------------------------------------------------------- + # make sure we can catch a missing row + + try: + a_row = tbl.fetchRow( ("agent_id", 1000) ) + raise "test error" + except eNoMatchingRows: + pass + + output("PASSED! fetch missing row test") + + # -------------------------------------------------------------- + # create new rows and insert them + + for n in range(TEST_INSERT_COUNT): + new_id = n + 1 + + newrow = tbl.newRow() + newrow.name = "name #%d" % new_id + newrow.login = "name%d" % new_id + newrow.ext_email = "%d@name" % new_id + newrow.save() + if newrow.agent_id != new_id: + raise "new insert id (%s) does not match expected value (%d)" % (newrow.agent_id,new_id) + + output("PASSED! autoinsert test") + + # -------------------------------------------------------------- + # fetch one row + a_row = tbl.fetchRow( ("agent_id", 1) ) + + if a_row.name != "name #1": + raise "row data incorrect" + + output("PASSED! fetch one row test") + + # --------------------------------------------------------------- + # don't change and save it + # (i.e. the "dummy cursor" string should never be called!) + # + try: + a_row.save(cursor = "dummy cursor") + except AttributeError, reason: + raise "row tried to access cursor on save() when no changes were made!" + + output("PASSED! don't save when there are no changed") + + # --------------------------------------------------------------- + # change, save, load, test + + a_row.auth_level = 10 + a_row.save() + b_row = tbl.fetchRow( ("agent_id", 1) ) + if b_row.auth_level != 10: + raise "save and load failed" + + + output("PASSED! change, save, load") + + # -------------------------------------------------------------- + # access unknown attribute + try: + a = a_row.UNKNOWN_ATTRIBUTE + raise "test error" + except AttributeError, reason: + pass + + try: + a_row.UNKNOWN_ATTRIBUTE = 1 + raise "test error" + except AttributeError, reason: + pass + + output("PASSED! unknown attribute exception") + + # -------------------------------------------------------------- + # access unknown dict item + + try: + a = a_row["UNKNOWN_ATTRIBUTE"] + raise "test error" + except KeyError, reason: + pass + + try: + a_row["UNKNOWN_ATTRIBUTE"] = 1 + raise "test error" + except KeyError, reason: + pass + + output("PASSED! unknown dict item exception") + + # -------------------------------------------------------------- + # use wrong data for column type + + try: + a_row.agent_id = "this is a string" + raise "test error" + except eInvalidData, reason: + pass + + output("PASSED! invalid data for column type") + + # -------------------------------------------------------------- + # fetch 1 rows + + rows = tbl.fetchRows( ('agent_id', 1) ) + if len(rows) != 1: + raise "fetchRows() did not return 1 row!" % (TEST_INSERT_COUNT) + + output("PASSED! fetch one row") + + + # -------------------------------------------------------------- + # fetch All rows + + rows = tbl.fetchAllRows() + if len(rows) != TEST_INSERT_COUNT: + for a_row in rows: + output(repr(a_row)) + raise "fetchAllRows() did not return TEST_INSERT_COUNT(%d) rows!" % (TEST_INSERT_COUNT) + + output("PASSED! fetchall rows") + + + # -------------------------------------------------------------- + # delete row object + + row = tbl.fetchRow( ('agent_id', 1) ) + row.delete() + try: + row = tbl.fetchRow( ('agent_id', 1) ) + raise "delete failed to delete row!" + except eNoMatchingRows: + pass + + # -------------------------------------------------------------- + # table deleteRow() call + + row = tbl.fetchRow( ('agent_id',2) ) + tbl.deleteRow( ('agent_id', 2) ) + try: + row = tbl.fetchRow( ('agent_id',2) ) + raise "table delete failed" + except eNoMatchingRows: + pass + + # -------------------------------------------------------------- + # table deleteRow() call + + row = tbl.fetchRow( ('agent_id',3) ) + if row.databaseSizeForColumn('name') != len(row.name): + raise "databaseSizeForColumn('name') failed" + + # -------------------------------------------------------------- + # test inc fields + row = tbl.newRow() + new_id = 1092 + row.name = "name #%d" % new_id + row.login = "name%d" % new_id + row.ext_email = "%d@name" % new_id + row.inc('ticket_count') + row.save() + new_id = row.agent_id + + trow = tbl.fetchRow( ('agent_id',new_id) ) + if trow.ticket_count != 1: + raise "ticket_count didn't inc!" + + row.inc('ticket_count', count=2) + row.save() + trow = tbl.fetchRow( ('agent_id',new_id) ) + if trow.ticket_count != 3: + raise "ticket_count wrong, expected 3, got %d" % trow.ticket_count + + trow.inc('ticket_count') + trow.save() + if trow.ticket_count != 4: + raise "ticket_count wrong, expected 4, got %d" % trow.ticket_count + + output("\n==== ALL TESTS PASSED ====") + + +if __name__ == "__main__": + TEST() + diff -Nru clearsilver-0.9.1/python/examples/base/profiler.py clearsilver-0.9.2/python/examples/base/profiler.py --- clearsilver-0.9.1/python/examples/base/profiler.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/base/profiler.py Wed Aug 13 23:32:41 2003 @@ -0,0 +1,73 @@ + +import time +import who_calls +import neo_cgi + +PROFILER_DATA = [] +PROFILER_START = 0 +PROFILER_ENABLED = 0 +PROFILER_DEPTH = 0 + +def enable(): + global PROFILER_START + global PROFILER_ENABLED + global PROFILER_DATA + PROFI