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 + PROFILER_START = time.time() + PROFILER_ENABLED = 1 + PROFILER_DATA = [] + +def disable(): + global PROFILER_START + global PROFILER_ENABLED + global PROFILER_DATA + PROFILER_START = 0 + PROFILER_ENABLED = 0 + PROFILER_DATA = [] + +def hdfExport(prefix, hdf): + global PROFILER_DATA + n = 0 + for p in PROFILER_DATA: + hdf.setValue("%s.%d.when" % (prefix, n), "%5.2f" % (p.when)) + hdf.setValue("%s.%d.time" % (prefix, n), "%5.2f" % (p.length)) + hdf.setValue("%s.%d.klass" % (prefix, n), p.klass) + hdf.setValue("%s.%d.what" % (prefix, n), " " * p.depth + p.what) + hdf.setValue("%s.%d.where" % (prefix, n), neo_cgi.htmlEscape(p.where)) + +class Profiler: + def __init__ (self, klass, what): + global PROFILER_START + global PROFILER_ENABLED + global PROFILER_DATA + global PROFILER_DEPTH + if not PROFILER_ENABLED: return + self.when = time.time() - PROFILER_START + self.klass = klass + self.where = who_calls.pretty_who_calls() + self.what = what + self.length = 0 + self.depth = PROFILER_DEPTH + PROFILER_DEPTH = PROFILER_DEPTH + 1 + + PROFILER_DATA.append(self) + + def end(self): + global PROFILER_ENABLED + global PROFILER_DEPTH + if not PROFILER_ENABLED: return + self.length = time.time() - self.when - PROFILER_START + PROFILER_DEPTH = PROFILER_DEPTH - 1 + if PROFILER_DEPTH < 0: PROFILER_DEPTH = 0 + +class ProfilerCursor: + def __init__ (self, real_cursor): + self.real_cursor = real_cursor + + def execute (self, query, args=None): + p = Profiler("SQL", query) + r = self.real_cursor.execute(query, args) + p.end() + return r + + def __getattr__ (self, key): + return getattr(self.real_cursor, key) diff -Nru clearsilver-0.9.1/python/examples/base/who_calls.py clearsilver-0.9.2/python/examples/base/who_calls.py --- clearsilver-0.9.1/python/examples/base/who_calls.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/base/who_calls.py Sun Jun 15 18:54:49 2003 @@ -0,0 +1,141 @@ + +# who_calls.py +# by Sam Rushing for Medusa + +import string +import sys + +from log import * + +whoCallsError = "whoCallsError" + +#-------------------------------------------------------------- +# Example use: +# +# import who_calls +# log(who_calls.pretty_who_calls()) +# +#-------------------------------------------------------------- + +def test(): + for i in range(1,1000): + pretty_who_calls() + + print_top_100() + +def who_calls_helper(): + tinfo = [] + exc_info = sys.exc_info() + + f = exc_info[2].tb_frame.f_back + while f: + tinfo.append ( ( + f.f_code.co_filename, + f.f_code.co_name, + f.f_lineno ) + ) + f = f.f_back + + del exc_info + return tinfo + + +def who_calls(): + try: + raise whoCallsError + except whoCallsError: + tinfo = who_calls_helper() + return tinfo + +def pretty_who_calls(strip=0): + info = who_calls() + buf = [] + + for file,function,line in info[1 + strip:]: + buf.append(" %s(%s): %s()" % (file,line,function)) + + return string.join(buf,"\n") + +# --------------------------------------------------------------------------- +# used for debugging. +# --------------------------------------------------------------------------- + +def compact_traceback (): + t,v,tb = sys.exc_info() + tbinfo = [] + if tb is None: + # this should never happen, but then again, lots of things + # should never happen but do. + return (('','',''), str(t), str(v), 'traceback is None!!!') + while 1: + tbinfo.append ( + tb.tb_frame.f_code.co_filename, + tb.tb_frame.f_code.co_name, + str(tb.tb_lineno) + ) + tb = tb.tb_next + if not tb: + break + + # just to be safe + del tb + + file, function, line = tbinfo[-1] + info = '[' + string.join ( + map ( + lambda x: string.join (x, '|'), + tbinfo + ), + '] [' + ) + ']' + + return (file, function, line), str(t), str(v), info + +## ---------------------------------------------------- +## Refcount printing + +import sys +import types + +def real_get_refcounts(base = None, set_base = 0): + d = {} + sys.modules + # collect all classes + for modname,m in sys.modules.items(): + for sym in dir(m): + o = getattr (m, sym) + if type(o) is types.ClassType: + name = "%s:%s" % (modname,o.__name__) + cnt = sys.getrefcount (o) + if base: + if set_base: + base[name] = cnt + elif cnt > base.get(name, 0): + d[name] = cnt - base.get(name, 0) + else: + d[name] = cnt + return d + +def get_refcounts(base=None): + d = real_get_refcounts(base = base) + # sort by refcount + pairs = map (lambda x: (x[1],x[0]), d.items()) + pairs.sort() + pairs.reverse() + return pairs + +REFCOUNTS = {} + +def set_refcount_base(): + global REFCOUNTS + real_get_refcounts(REFCOUNTS, set_base = 1) + +def print_top_100(): + print_top_N(100) + +def print_top_N(N): + global REFCOUNTS + for n, c in get_refcounts(REFCOUNTS)[:N]: + log('%10d %s' % (n, c)) + + diff -Nru clearsilver-0.9.1/python/examples/handle_error.py clearsilver-0.9.2/python/examples/handle_error.py --- clearsilver-0.9.1/python/examples/handle_error.py Sun Jun 15 18:54:49 2003 +++ clearsilver-0.9.2/python/examples/handle_error.py Wed Dec 31 16:00:00 1969 @@ -1,91 +0,0 @@ - -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/hdfhelp.py clearsilver-0.9.2/python/examples/hdfhelp.py --- clearsilver-0.9.1/python/examples/hdfhelp.py Fri Mar 7 14:44:58 2003 +++ clearsilver-0.9.2/python/examples/hdfhelp.py Wed Dec 31 16:00:00 1969 @@ -1,108 +0,0 @@ -#!/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 UserList - -def renderDate(time_t_val): - if then_time is None: - then_time = 0 - then_time = int(then_time) - then_tuple = time.localtime(then_time) - 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/log.py clearsilver-0.9.2/python/examples/log.py --- clearsilver-0.9.1/python/examples/log.py Sun Jun 15 23:14:49 2003 +++ clearsilver-0.9.2/python/examples/log.py Wed Dec 31 16:00:00 1969 @@ -1,51 +0,0 @@ -#!/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/odb.py clearsilver-0.9.2/python/examples/odb.py --- clearsilver-0.9.1/python/examples/odb.py Fri Mar 7 14:44:58 2003 +++ clearsilver-0.9.2/python/examples/odb.py Wed Dec 31 16:00:00 1969 @@ -1,1471 +0,0 @@ -#!/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): - try: - return self._tables[key] - except KeyError: - raise AttributeError, "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/trans/README clearsilver-0.9.2/python/examples/trans/README --- clearsilver-0.9.1/python/examples/trans/README Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/trans/README Thu Aug 14 00:15:12 2003 @@ -0,0 +1,118 @@ +********************************* +* +* trans.py - language extraction toolkit +* +* - Brandon Long, David Jeske +* + +** Getting Started + +1) First you need to create a MySQL trans database for your application. + + > mysql -uroot + mysql> create database trans_data + mysql> quit + > mysql -uroot trans_data < trans.sql + +2) Then just run trans on the test data to verify that it is working.. + + > ./trans.py + + Check out the 'testroot/gen' directory. + +3) Then, in your application, make sure your CSPage setup equivilant is + doing the following: + + 1) Make sure "gen/tmpl/" and "gen/tmpl" are in hdf.loadpaths + before your template directories. This assures that the load will + prefer files in the language specific template directory first, + the language directory second, and your template directories last. + + 2) after loading your page-specific HDF file, be sure to + load "lang_.hdf" over the top. This will automatically + override HDF lang strings with the proper values from the translated + language files. + +4) Configure trans.py in the __init__ function (sorry for the hardcoded + stuff) + +5) When you want to translate into a new language, take the + 'strings_en.hdf' file and copy it to trans_XX.hdf. Translate + the strings in it, and then run: + + > ./trans.py --lang XX --load trans_XX.hdf + > ./trans.py + + Each time trans is run, it will dump the list of missing strings for + every language which has any strings at all. Simply follow the same + procedure above with the missing strings file to update the + translation in that language. + + +** About trans.py + +This tools allows you to (mostly) automatically extract language +strings from HTML Clearsilver templates, and from Clearsilver HDF +files. trans inserts all unique strings into a database, and +provides you facilities for exporting and importing the strings in the +database. trans then creates a 'gen' tree where your source files +reference language strings, and dumps lang_XX.hdf files which +define those strings. + + +Two mechanisms are used to find language strings: + +1) Any language string present in an HDF file should be marked + with the [Lang] attribute. For example: + + Menu.Name [Lang] = Start Here + + Trans will automatically replace this with a copy reference to + the lang hash-keyed string in the currently imported language. + + Menu.Name : Lang.L112414 + +2) Parsing of html attempts to find language strings automatically. + This allows you to leave most of your language strings in-tact + in your primary language, making working on your application + much easier. + + Some parts of HTML structure, including some tag attributes and + javascript, are too complicated for trans to automatically do + the right thing. In these cases, you must manually extract + the string into an HDF file and then reference it in your HTML. + + For example, in the following HTML/Clearsilver fragment, + the heading will be automatically identified, but the submit + button title cannot be extracted by trans safetly. + + + +

Send us your Feedback

+
+ + +
+ + + + You must convert the above fragment into something like this: + + + +

Send us your Feedback

+
+ + +
+ + + + The "Lang.SendFeedback" item must be declared in your static page + HDF, and must be marked with the '[Lang]' attribute. + + Lang.SendFeedback [Lang] = Send Feedback + + diff -Nru clearsilver-0.9.1/python/examples/trans/TODO clearsilver-0.9.2/python/examples/trans/TODO --- clearsilver-0.9.1/python/examples/trans/TODO Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/trans/TODO Thu Aug 14 00:18:05 2003 @@ -0,0 +1,22 @@ +****************************** +** +** trans.py TODO +** +** David Jeske + +- create 'translation configuration file' which gets placed + in application root or template root directory. This should + specify all paramaters which are currently hardcoded in + trans.py. + + Require the user to supply this configuration file each time + trans is called. + +- extend database schema to handle more than one application + in a single trans database. + +- make web UI for browsing trans database + +- clearsilver/trans 'z-tag live language QA system' like + we had at egroups + diff -Nru clearsilver-0.9.1/python/examples/trans/db_trans.py clearsilver-0.9.2/python/examples/trans/db_trans.py --- clearsilver-0.9.1/python/examples/trans/db_trans.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/trans/db_trans.py Thu Aug 14 00:07:02 2003 @@ -0,0 +1,82 @@ + + +from odb import * +import profiler +import socket + +USER = 'root' +PASSWORD = '' +DATABASE = 'trans_data' + +class TransStringTable(Table): + # access patterns: + # -> lookup individual entries by string_id + # -> lookup entry by string + def _defineRows(self): + self.d_addColumn("string_id", kInteger, primarykey=1, autoincrement=1) + # we can't actually index this... but we can index part with myisam + self.d_addColumn("string", kBigString, indexed=1) + +## hmm, on second thought, storing this is in the database is kind +## of silly..., since it essentially could change with each run. It may +## not even be necessary to store this anywhere except in memory while +## trans is running +class TransLocTable(Table): + # access patterns: + # -> find "same" entry by filename/offset + # -> dump all locations for a version + # -> maybe: find all locations for a filename + def _defineRows(self): + self.d_addColumn("loc_id", kInteger, primarykey=1, autoincrement=1) + self.d_addColumn("string_id", kInteger, indexed=1) + self.d_addColumn("version", kInteger, default=0) + self.d_addColumn("filename", kVarString, 255, indexed=1) + self.d_addColumn("location", kVarString, 255) + # this can either be: + # ofs:x:y + # hdf:foo.bar.baz + +class TransMapTable(Table): + # access patterns: + # -> dump all for a language + # -> lookup entry by string_id/lang + def _defineRows(self): + self.d_addColumn("string_id", kInteger, primarykey=1) + self.d_addColumn("lang", kFixedString, 2, primarykey=1) + self.d_addColumn("string", kBigString) + +class DB(Database): + def __init__(self, db, debug=0): + self.db = db + self._cursor = None + self.debug = debug + + self.strings = TransStringTable(self, "nt_trans_strings") + self.locs = TransLocTable(self, "nt_trans_locs") + self.maps = TransMapTable(self, "nt_trans_maps") + + def defaultCursor(self): + # share one cursor for this db object! + if self._cursor is None: + if self.debug: + self._cursor = profiler.ProfilerCursor(self.db.cursor()) + else: + self._cursor = self.db.cursor() + + return self._cursor + +def trans_connect(host = 'localhost', debug=0): + # try to optimize connection if on this machine + if host != 'localhost': + local_name = socket.gethostname() + if string.find(local_name, '.') == -1: + local_name = local_name + ".neotonic.com" + if local_name == host: + host = 'localhost' + + if debug: p = profiler.Profiler("SQL", "Connect -- %s:trans" % (host)) + db = MySQLdb.connect(host = host, user=USER, passwd = PASSWORD, db=DATABASE) + if debug: p.end() + + retval = DB(db, debug=debug) + return retval diff -Nru clearsilver-0.9.1/python/examples/trans/testroot/tmpl/test1.cs clearsilver-0.9.2/python/examples/trans/testroot/tmpl/test1.cs --- clearsilver-0.9.1/python/examples/trans/testroot/tmpl/test1.cs Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/trans/testroot/tmpl/test1.cs Thu Aug 14 00:07:03 2003 @@ -0,0 +1,8 @@ + + + +

+This is an html file language string which should be translated..

+ + + diff -Nru clearsilver-0.9.1/python/examples/trans/testroot/tmpl/test1.hdf clearsilver-0.9.2/python/examples/trans/testroot/tmpl/test1.hdf --- clearsilver-0.9.1/python/examples/trans/testroot/tmpl/test1.hdf Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/trans/testroot/tmpl/test1.hdf Thu Aug 14 00:07:03 2003 @@ -0,0 +1,5 @@ + +hdfdata = This is hdf data, not language data + +hdflang [Lang] = This is a language string and should be translated + diff -Nru clearsilver-0.9.1/python/examples/trans/trans.py clearsilver-0.9.2/python/examples/trans/trans.py --- clearsilver-0.9.1/python/examples/trans/trans.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/trans/trans.py Thu Aug 14 00:15:12 2003 @@ -0,0 +1,594 @@ +#!/neo/opt/bin/python + +import sys, string, os, getopt, pwd, signal, time, re +import fcntl + +import tstart + +import db_trans +from log import * +import neo_cgi, neo_util +import odb + +eTransError = "eTransError" + +DONE = 0 +DEBUG = 0 + +TIER2_DIV = 11 +TIER1_DIV = 11 * TIER2_DIV + +if not DEBUG: LOGGING_STATUS[DEV_UPDATE] = 0 + +def handleSignal(*arg): + global DONE + DONE = 1 + +def usage(): + print "usage info!!" + +def exceptionString(): + import StringIO, traceback + + ## get the traceback message + sfp = StringIO.StringIO() + traceback.print_exc(file=sfp) + exception = sfp.getvalue() + sfp.close() + + return exception + +class TransLoc: + def __init__ (self, string_id, filename, location): + self.string_id = string_id + self.filename = filename + self.location = location + +class Translator: + _HTML_TAG_RE = None + _HTML_TAG_REGEX = '<[^!][^>]*?>' + _HTML_CMT_RE = None + _HTML_CMT_REGEX = '' + _CS_TAG_RE = None + _CS_TAG_REGEX = '<\\?.+?\\?>' + + def __init__ (self): + self.tdb = db_trans.trans_connect() + + # configuration data ...... + # - we should stop hardcoding this... - jeske + + self.root = "testroot" + self.languages = ['es', 'en'] + + self.ignore_paths = ['tmpl/m'] # common place for mockups + self.ignore_files = ['blah_ignore.cs'] # ignore clearsilver file + + # ignore clearsilver javascript files + self.ignore_patterns = ['tmpl/[^ ]*_js.cs'] + + # ............................ + + + if self.root is None: + raise "Unable to determine installation root" + + + if Translator._HTML_TAG_RE is None: + Translator._HTML_TAG_RE = re.compile(Translator._HTML_TAG_REGEX, re.MULTILINE | re.DOTALL) + if Translator._HTML_CMT_RE is None: + Translator._HTML_CMT_RE = re.compile(Translator._HTML_CMT_REGEX, re.MULTILINE | re.DOTALL) + if Translator._CS_TAG_RE is None: + Translator._CS_TAG_RE = re.compile(Translator._CS_TAG_REGEX, re.MULTILINE | re.DOTALL) + + self._html_state = 0 + + + def parseHTMLTag(self, data): + # this is only called if we see a full tag in one parse... + i = 0 + if len(data) == 0: return [] + if data[0] in '/?': return [] + while i < len(data) and data[i] not in ' \n\r\t>': i = i + 1 + if i == len(data): return [] + tag = data[:i].lower() + #print "Searching tag: %s" % data + #print "Found tag: %s" % tag + results = [] + attrfind = re.compile( + r'\s*([a-zA-Z_][-.a-zA-Z_0-9]*)(\s*=\s*' + r'(\'[^\']*\'|"[^"]*"|[^ \t\n<>]*))?') + k = i + attrs = {} + attrs_beg = {} + while k < len(data): + match = attrfind.match(data, k) + if not match: break + attrname, rest, attrvalue = match.group(1, 2, 3) + if not rest: + attrvalue = attrname + elif attrvalue[:1] == '\'' == attrvalue[-1:] or \ + attrvalue[:1] == '"' == attrvalue[-1:]: + attrvalue = attrvalue[1:-1] + attrname = attrname.lower() + if attrs.has_key(attrname): + log("Can't handle duplicate attrs: %s" % attrname) + attrs[attrname] = attrvalue + attrs_beg[attrname] = match.start(3) + k = match.end(0) + + find_l = [] + if tag == "input": + if attrs.get('type', "").lower() in ["submit", "button"]: + find_l.append((attrs.get('value', ''), attrs_beg.get('value', 0))) + + for s,k in find_l: + if s: + x = data[k:].find(s) + if x != -1: results.append((s, x+k, 1)) + + return results + + def parseHTML(self, data, reset=1): + if reset: self._html_state = 0 + if DEBUG: print "- %d ---------\n%s\n- E ---------" % (self._html_state, data) + + results = [] + i = 0 + n = len(data) + # if we had state from the last parse... find it + if self._html_state: + if self._html_state == 2: + x = string.find(data[i:], '-->') + l = 3 + else: + x = string.find(data[i:], '>') + l = 1 + if x == -1: return results + i = i + x + l + self._html_state = 0 + while i < n: + if DEBUG: print "MATCHING>%s') + tag_b = string.find(data[i:], '<') + tag_e = string.find(data[i:], '>') + if DEBUG: print "B> %d %d %d %d x and data[y] in string.whitespace: y-=1 + results.append((data[x:y+1], x, 1)) + if cmt_e == -1: # partial comment: + self._html_state = 2 + break + i = i + cmt_e + 3 + elif tag_b != -1: + x = i + y = i+tag_b-1 + while x < y and data[x] in string.whitespace: x+=1 + while y > x and data[y] in string.whitespace: y-=1 + results.append((data[x:y+1], x, 1)) + if tag_e == -1: # partial tag + self._html_state = 1 + break + h_results = self.parseHTMLTag(data[i+tag_b+1:i+tag_e]) + h_results = map(lambda x: (x[0], x[1] + i+tag_b+1, x[2]), h_results) + results = results + h_results + i = i + tag_e + 1 + else: + x = i + y = n-1 + while x < y and data[x] in string.whitespace: x+=1 + while y > x and data[y] in string.whitespace: y-=1 + results.append((data[x:y+1], x, 1)) + break + return results + + def parseCS(self, data): + results = [] + i = 0 + n = len(data) + while i < n: + m = Translator._CS_TAG_RE.search(data, i) + if not m: + # search for a partial... + x = string.find(data[i:], '') + s = string.replace(s, '&', '&') + for x in range (len (s)): + n = ord(s[x]) + if (n>47 and n<58) or (n>64 and n<91) or (n>96 and n<123): return 1 + return 0 + + def findString(self, s): + rows = self.tdb.strings.fetchRows( ('string', s) ) + if len(rows) == 0: + row = self.tdb.strings.newRow() + row.string = s + row.save() + return row.string_id + elif len(rows) > 1: + raise eTransError, "String %s exists multiple times!" % s + else: + return rows[0].string_id + + def loadStrings(self, one_file=None, verbose=0): + if one_file is not None: + strings = self.handleFile(one_file) + results = [(one_file, strings)] + else: + results = self.walkDirectory('tmpl') + uniq = {} + cnt = 0 + seen_hdf = {} + for fname, strings in results: + for (s, ofs, ishtml) in strings: + if s and string.strip(s): + l = len(s) + if ishtml: + s = self.cleanHtmlString(s) + if self.containsWords(s, ishtml): + if type(ofs) == type(""): # HDF + if seen_hdf.has_key(ofs): + if seen_hdf[ofs][0] != s: + log("Duplicate HDF Name %s:\n\t file %s = %s\n\t file %s = %s" % (ofs, seen_hdf[ofs][1], seen_hdf[ofs][0], fname, s)) + else: + seen_hdf[ofs] = (s, fname) + try: + uniq[s].append((fname, ofs, l)) + except KeyError: + uniq[s] = [(fname, ofs, l)] + cnt = cnt + 1 + print "%d strings, %d unique" % (cnt, len(uniq.keys())) + fp = open("map", 'w') + for (s, locs) in uniq.items(): + locs = map(lambda x: "%s:%s:%d" % x, locs) + fp.write('#: %s\n' % (string.join(locs, ','))) + fp.write('msgid=%s\n\n' % repr(s)) + + log("Loading strings/locations into database") + locations = [] + for (s, locs) in uniq.items(): + s_id = self.findString(s) + for (fname, ofs, l) in locs: + if type(ofs) == type(""): # ie, its HDF + location = "hdf:%s" % ofs + else: + location = "ofs:%d:%d" % (ofs, l) + loc_r = TransLoc(s_id, fname, location) + locations.append(loc_r) + return locations + + def stringsHDF(self, prefix, locations, lang='en', exist=0, tiered=0): + hdf = neo_util.HDF() + if exist and lang == 'en': return hdf + done = {} + locations.sort() + maps = self.tdb.maps.fetchRows( ('lang', lang) ) + maps_d = {} + for map in maps: + maps_d[int(map.string_id)] = map + strings = self.tdb.strings.fetchRows() + strings_d = {} + for string in strings: + strings_d[int(string.string_id)] = string + count = 0 + for loc in locations: + s_id = int(loc.string_id) + if done.has_key(s_id): continue + try: + s_row = maps_d[s_id] + if exist: continue + except KeyError: + try: + s_row = strings_d[s_id] + except KeyError: + log("Missing string_id %d, skipping" % s_id) + continue + count = count + 1 + if tiered: + hdf.setValue("%s.%d.%d.%s" % (prefix, int(s_id) / TIER1_DIV, int(s_id) / TIER2_DIV, s_id), s_row.string) + else: + hdf.setValue("%s.%s" % (prefix, s_id), s_row.string) + done[s_id] = 1 + if exist == 1: log("Missing %d strings for lang %s" % (count, lang)) + return hdf + + def dumpStrings(self, locations, lang=None): + log("Dumping strings to HDF") + if lang is None: + langs = ['en'] + sql = "select lang from nt_trans_maps group by lang" + cursor = self.tdb.defaultCursor() + cursor.execute(sql) + rows = cursor.fetchall() + for row in rows: + langs.append(row[0]) + else: + langs = [lang] + + for a_lang in langs: + hdf = self.stringsHDF('S', locations, a_lang) + hdf.writeFile("strings_%s.hdf" % a_lang) + + for a_lang in langs: + hdf = self.stringsHDF('S', locations, a_lang, exist=1) + if hdf.child(): + hdf.writeFile("strings_missing_%s.hdf" % a_lang) + + def fetchString(self, s_id, lang): + if lang == "hdf": + return "" % (int(s_id) / TIER1_DIV, int(s_id) / TIER2_DIV, s_id) + rows = self.tdb.maps.fetchRows( [('string_id', s_id), ('lang', lang)] ) + if len(rows) == 0: + try: + row = self.tdb.strings.fetchRow( ('string_id', s_id) ) + except odb.eNoMatchingRows: + log("Unable to find string id %s" % s_id) + raise eNoString + if lang != 'en': + log("Untranslated string for id %s" % s_id) + return row.string + else: + return rows[0].string + + def dumpFiles(self, locations, lang): + log("Dumping files for %s" % lang) + files = {} + for row in locations: + try: + files[row.filename].append(row) + except KeyError: + files[row.filename] = [row] + + hdf_map = [] + + os.system("rm -rf %s/gen/tmpl" % (self.root)) + for file in files.keys(): + fname = "%s/gen/%s" % (self.root, file) + try: + os.makedirs(os.path.dirname(fname)) + except OSError, reason: + if reason[0] != 17: + raise + do_hdf = 0 + x = string.rfind(file, '.') + if x != -1 and file[x:] == '.hdf': + do_hdf = 1 + ofs = [] + for loc in files[file]: + parts = string.split(loc.location, ':') + if len(parts) == 3 and parts[0] == 'ofs' and do_hdf == 0: + ofs.append((int(parts[1]), int(parts[2]), loc.string_id)) + elif len(parts) == 2 and parts[0] == 'hdf' and do_hdf == 1: + hdf_map.append((parts[1], loc.string_id)) + else: + log("Invalid location for loc_id %s" % loc.loc_id) + continue + if not do_hdf: + ofs.sort() + data = open(self.root + '/' + file).read() + # ok, now we split up the original data into sections + x = 0 + n = len(data) + out = [] + #sys.stderr.write("%s\n" % repr(ofs)) + while len(ofs): + if ofs[0][0] > x: + out.append(data[x:ofs[0][0]]) + x = ofs[0][0] + elif ofs[0][0] == x: + out.append(self.fetchString(ofs[0][2], lang)) + x = ofs[0][0] + ofs[0][1] + ofs = ofs[1:] + else: + log("How did we get here? %s x=%d ofs=%d sid=%d" % (file, x, ofs[0][0], ofs[0][2])) + log("Data[x:20]: %s" % data[x:20]) + log("Data[ofs:20]: %s" % data[ofs[0][0]:20]) + break + if n > x: + out.append(data[x:]) + odata = string.join(out, '') + open(fname, 'w').write(odata) + + if lang == "hdf": + langs = self.languages + else: + langs = [lang] + + for d_lang in langs: + # dumping the extracted strings + hdf = self.stringsHDF('Lang.Extracted', locations, d_lang, tiered=1) + fname = "%s/gen/tmpl/lang_%s.hdf" % (self.root, d_lang) + hdf.writeFile(fname) + data = open(fname).read() + fp = open(fname, 'w') + fp.write('## AUTOMATICALLY GENERATED -- DO NOT EDIT\n\n') + fp.write(data) + fp.write('\n#include "lang_map.hdf"\n') + + # dumping the hdf strings file + if d_lang == "en": + map_file = "%s/gen/tmpl/lang_map.hdf" % (self.root) + else: + map_file = "%s/gen/tmpl/%s/lang_map.hdf" % (self.root, d_lang) + try: + os.makedirs(os.path.dirname(map_file)) + except OSError, reason: + if reason[0] != 17: raise + map_hdf = neo_util.HDF() + for (name, s_id) in hdf_map: + str = hdf.getValue('Lang.Extracted.%d.%d.%s' % (int(s_id) / TIER1_DIV, int(s_id) / TIER2_DIV, s_id), '') + map_hdf.setValue(name, str) + map_hdf.writeFile(map_file) + + def loadMap(self, file, prefix, lang): + log("Loading map for language %s" % lang) + hdf = neo_util.HDF() + hdf.readFile(file) + obj = hdf.getChild(prefix) + updates = 0 + new_r = 0 + while obj is not None: + s_id = obj.name() + str = obj.value() + + try: + map_r = self.tdb.maps.fetchRow( [('string_id', s_id), ('lang', lang)]) + except odb.eNoMatchingRows: + map_r = self.tdb.maps.newRow() + map_r.string_id = s_id + map_r.lang = lang + new_r = new_r + 1 + + if map_r.string != str: + updates = updates + 1 + map_r.string = str + map_r.save() + + obj = obj.next() + log("New maps: %d Updates: %d" % (new_r, updates - new_r)) + + +def main(argv): + alist, args = getopt.getopt(argv[1:], "f:v:", ["help", "load=", "lang="]) + + one_file = None + verbose = 0 + load_file = None + lang = 'en' + for (field, val) in alist: + if field == "--help": + usage(argv[0]) + return -1 + if field == "-f": + one_file = val + if field == "-v": + verbose = int(val) + if field == "--load": + load_file = val + if field == "--lang": + lang = val + + + global DONE + + #signal.signal(signal.SIGTERM, handleSignal) + #signal.signal(signal.SIGINT, handleSignal) + + log("trans: start") + + start_time = time.time() + + try: + t = Translator() + if load_file: + t.loadMap(load_file, 'S', lang) + else: + locations = t.loadStrings(one_file, verbose=verbose) + t.dumpStrings(locations) + t.dumpFiles(locations, 'hdf') + except KeyboardInterrupt: + pass + except: + import handle_error + handle_error.handleException("Translation Error") + +if __name__ == "__main__": + main(sys.argv) diff -Nru clearsilver-0.9.1/python/examples/trans/trans.sql clearsilver-0.9.2/python/examples/trans/trans.sql --- clearsilver-0.9.1/python/examples/trans/trans.sql Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/trans/trans.sql Sun Aug 17 10:09:49 2003 @@ -0,0 +1,26 @@ +create table nt_trans_strings ( + string_id integer not null primary key auto_increment, + string text, + + index(string(150)) +); + +create table nt_trans_locs ( + loc_id integer not null primary key auto_increment, + string_id integer not null, + version integer default 0, + filename varchar(255), + location varchar(255), + + index(string_id), + index(filename) +) TYPE=INNODB; + +create table nt_trans_maps ( + map_id integer not null primary key auto_increment, + string_id integer not null, + lang char(2), + string text, + + index(string_id) +) TYPE=INNODB; diff -Nru clearsilver-0.9.1/python/examples/trans/tstart.py clearsilver-0.9.2/python/examples/trans/tstart.py --- clearsilver-0.9.1/python/examples/trans/tstart.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/examples/trans/tstart.py Sun Aug 17 09:50:07 2003 @@ -0,0 +1,13 @@ +# this starts up the T-environment... +# +# The root dir should point to the top of the python tree + + +import sys + +sys.path.insert(0, "../base") # pickup base libs + +sys.path.insert(0, "../../") # pickup neo_cgi.so + +# don't put anything above this because the path isn't +# extended yet... diff -Nru clearsilver-0.9.1/python/examples/who_calls.py clearsilver-0.9.2/python/examples/who_calls.py --- clearsilver-0.9.1/python/examples/who_calls.py Sun Jun 15 18:54:49 2003 +++ clearsilver-0.9.2/python/examples/who_calls.py Wed Dec 31 16:00:00 1969 @@ -1,141 +0,0 @@ - -# who_calls.py -# by Sam Rushing for Medusa - -import string -import sys - -from log import * - -whoCallsError = "whoCallsError" - -#-------------------------------------------------------------- -# Example use: -# -# import who_calls -# log(who_calls.pretty_who_calls()) -# -#-------------------------------------------------------------- - -def test(): - for i in range(1,1000): - pretty_who_calls() - - print_top_100() - -def who_calls_helper(): - tinfo = [] - exc_info = sys.exc_info() - - f = exc_info[2].tb_frame.f_back - while f: - tinfo.append ( ( - f.f_code.co_filename, - f.f_code.co_name, - f.f_lineno ) - ) - f = f.f_back - - del exc_info - return tinfo - - -def who_calls(): - try: - raise whoCallsError - except whoCallsError: - tinfo = who_calls_helper() - return tinfo - -def pretty_who_calls(strip=0): - info = who_calls() - buf = [] - - for file,function,line in info[1 + strip:]: - buf.append(" %s(%s): %s()" % (file,line,function)) - - return string.join(buf,"\n") - -# --------------------------------------------------------------------------- -# used for debugging. -# --------------------------------------------------------------------------- - -def compact_traceback (): - t,v,tb = sys.exc_info() - tbinfo = [] - if tb is None: - # this should never happen, but then again, lots of things - # should never happen but do. - return (('','',''), str(t), str(v), 'traceback is None!!!') - while 1: - tbinfo.append ( - tb.tb_frame.f_code.co_filename, - tb.tb_frame.f_code.co_name, - str(tb.tb_lineno) - ) - tb = tb.tb_next - if not tb: - break - - # just to be safe - del tb - - file, function, line = tbinfo[-1] - info = '[' + string.join ( - map ( - lambda x: string.join (x, '|'), - tbinfo - ), - '] [' - ) + ']' - - return (file, function, line), str(t), str(v), info - -## ---------------------------------------------------- -## Refcount printing - -import sys -import types - -def real_get_refcounts(base = None, set_base = 0): - d = {} - sys.modules - # collect all classes - for modname,m in sys.modules.items(): - for sym in dir(m): - o = getattr (m, sym) - if type(o) is types.ClassType: - name = "%s:%s" % (modname,o.__name__) - cnt = sys.getrefcount (o) - if base: - if set_base: - base[name] = cnt - elif cnt > base.get(name, 0): - d[name] = cnt - base.get(name, 0) - else: - d[name] = cnt - return d - -def get_refcounts(base=None): - d = real_get_refcounts(base = base) - # sort by refcount - pairs = map (lambda x: (x[1],x[0]), d.items()) - pairs.sort() - pairs.reverse() - return pairs - -REFCOUNTS = {} - -def set_refcount_base(): - global REFCOUNTS - real_get_refcounts(REFCOUNTS, set_base = 1) - -def print_top_100(): - print_top_N(100) - -def print_top_N(N): - global REFCOUNTS - for n, c in get_refcounts(REFCOUNTS)[:N]: - log('%10d %s' % (n, c)) - - diff -Nru clearsilver-0.9.1/python/neo_cgi.c clearsilver-0.9.2/python/neo_cgi.c --- clearsilver-0.9.1/python/neo_cgi.c Mon Apr 14 16:05:11 2003 +++ clearsilver-0.9.2/python/neo_cgi.c Thu Jul 17 12:44:09 2003 @@ -303,6 +303,20 @@ return PyFile_FromFile (fp, name, "w+", NULL); } +static PyObject * p_cgi_cs_init (PyObject *self, PyObject *args) +{ + CGI *cgi = ((CGIObject *) self)->cgi; + NEOERR *err; + CSPARSE *cs; + + if (!PyArg_ParseTuple(args, ":cs()")) + return NULL; + + err = cgi_cs_init(cgi, &cs); + if (err) return p_neo_error (err); + return p_cs_to_object(cs); +} + static PyMethodDef CGIMethods[] = { #if 0 @@ -319,6 +333,7 @@ {"cookieSet", (PyCFunction)p_cgi_cookie_set, METH_VARARGS|METH_KEYWORDS, NULL}, {"cookieClear", p_cgi_cookie_clear, METH_VARARGS, NULL}, {"filehandle", p_cgi_filehandle, METH_VARARGS, NULL}, + {"cs", p_cgi_cs_init, METH_VARARGS, NULL}, {NULL, NULL} }; diff -Nru clearsilver-0.9.1/python/p_neo_util.h clearsilver-0.9.2/python/p_neo_util.h --- clearsilver-0.9.1/python/p_neo_util.h Wed Apr 2 17:43:07 2003 +++ clearsilver-0.9.2/python/p_neo_util.h Thu Jul 17 12:44:09 2003 @@ -34,12 +34,18 @@ #define P_NEO_ERROR_RETURN PyObject * #define P_NEO_ERROR_PROTO (NEOERR *err) -#define P_NEO_CGI_POINTERS 3 +/* external CS object interface */ +#define P_CS_TO_OBJECT_NUM 3 +#define P_CS_TO_OBJECT_RETURN PyObject * +#define P_CS_TO_OBJECT_PROTO (CSPARSE *data) + +#define P_NEO_CGI_POINTERS 4 #ifdef NEO_CGI_MODULE P_HDF_TO_OBJECT_RETURN p_hdf_to_object P_HDF_TO_OBJECT_PROTO; P_OBJECT_TO_HDF_RETURN p_object_to_hdf P_OBJECT_TO_HDF_PROTO; P_NEO_ERROR_RETURN p_neo_error P_NEO_ERROR_PROTO; +P_CS_TO_OBJECT_RETURN p_cs_to_object P_CS_TO_OBJECT_PROTO; /* other functions */ @@ -57,6 +63,9 @@ #define p_neo_error \ (*(P_NEO_ERROR_RETURN (*)P_NEO_ERROR_PROTO) NEO_PYTHON_API[P_NEO_ERROR_NUM]) + +#define p_cs_to_object \ + (*(P_CS_TO_OBJECT_RETURN (*)P_CS_TO_OBJECT_PROTO) NEO_PYTHON_API[P_CS_TO_OBJECT_NUM]) #define import_neo_cgi() \ { \ diff -Nru clearsilver-0.9.1/python/setup.py clearsilver-0.9.2/python/setup.py --- clearsilver-0.9.1/python/setup.py Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/python/setup.py Thu Jul 24 11:36:50 2003 @@ -0,0 +1,85 @@ + +import os, string, re, sys +from distutils.core import setup, Extension + +VERSION = "0.9.1" +INC_DIRS = ["../"] +LIBRARIES = ["neo_cgi", "neo_cs", "neo_utl"] +LIB_DIRS = ["../libs"] + +## ARGGH!! It looks like you can only specify a single item on the +## command-line or in the setup.cfg file for options which take multiple +## lists... and it overrides what is defined here. So I have to do all +## the work of the configure file AGAIN here. At least its in python, +## which is easier... +## Actually, forget that, I'm just going to load and parse the rules.mk +## file and build what I need + +if not os.path.exists("../rules.mk"): + raise "You need to run configure first to generate the rules.mk file!" + +make_vars = {} +rules = open("../rules.mk").read() +for line in string.split(rules, "\n"): + parts = string.split(line, '=', 1) + if len(parts) != 2: continue + var, val = parts + var = var.strip() + make_vars[var] = val + if var == "CFLAGS": + matches = re.findall("-I(\S+)", val) + inserted = [] + for inc_path in matches: + # inc_path = match.group(1) + if inc_path not in INC_DIRS: + inserted.append(inc_path) + sys.stderr.write("adding inc_path %s\n" % inc_path) + INC_DIRS = inserted + INC_DIRS + elif var == "LIBS": + matches = re.findall("-l(\S+)", val) + inserted = [] + for lib in matches: + # lib = match.group(1) + if lib not in LIBRARIES: + inserted.append(lib) + sys.stderr.write("adding lib %s\n" % lib) + LIBRARIES = inserted + LIBRARIES + elif var == "LDFLAGS": + matches = re.findall("-L(\S+)", val) + inserted = [] + for lib_path in matches: + # lib_path = match.group(1) + if lib_path not in LIB_DIRS: + inserted.append(lib_path) + sys.stderr.write("adding lib_path %s\n" % lib_path) + LIB_DIRS = inserted + LIB_DIRS + +def expand_vars(vlist, vars): + nlist = [] + for val in vlist: + if val[:2] == "$(" and val[-1] == ")": + var = val[2:-1] + val = vars.get(val, "") + if val: nlist.append(val) + else: + nlist.append(val) + return nlist + +INC_DIRS = expand_vars(INC_DIRS, make_vars) +LIB_DIRS = expand_vars(LIB_DIRS, make_vars) +LIBRARIES = expand_vars(LIBRARIES, make_vars) + +setup(name="clearsilver", + version=VERSION, + description="Python ClearSilver Wrapper", + author="Brandon Long", + author_email="blong@fiction.net", + url="http://www.clearsilver.net/", + ext_modules=[Extension( + name="neo_cgi", + sources=["neo_cgi.c", "neo_cs.c", "neo_util.c"], + include_dirs=INC_DIRS, + library_dirs=LIB_DIRS, + libraries=LIBRARIES, + )] + ) diff -Nru clearsilver-0.9.1/ruby/Makefile clearsilver-0.9.2/ruby/Makefile --- clearsilver-0.9.1/ruby/Makefile Mon Jul 7 23:10:28 2003 +++ clearsilver-0.9.2/ruby/Makefile Mon Aug 11 15:03:56 2003 @@ -6,7 +6,7 @@ include $(NEOTONIC_ROOT)rules.mk -all: config.save ext/hdf/hdf.so test +all: config.save ext/hdf/hdf.so testrb config.save: install.rb $(RUBY) install.rb config -- --with-hdf-include=../../.. --with-hdf-lib=../../../libs @@ -17,13 +17,34 @@ ext/hdf/hdf.so: config.save $(RUBY) install.rb setup -test: ext/hdf/hdf.so - $(RUBY) -Ilib -Iext/hdf test/hdftest.rb +gold: ext/hdf/hdf.so + $(RUBY) -Ilib -Iext/hdf test/hdftest.rb > hdftest.gold; + @echo "Generated gold files" + +testrb: ext/hdf/hdf.so + @echo "Running ruby test" + @failed=0; \ + rm -f hdftest.out; \ + $(RUBY) -Ilib -Iext/hdf test/hdftest.rb > hdftest.out; \ + diff -brief hdftest.out hdftest.gold 2>%1 > /dev/null; \ + return_code=$$?; \ + if [ $$return_code -ne 0 ]; then \ + diff hdftest.out hdftest.gold > hdftest.err; \ + echo "Failed Ruby Test: hdftest.rb"; \ + echo " See hdftest.out and hdftest.err"; \ + failed=1; \ + fi; \ + if [ $$failed -eq 1 ]; then \ + exit 1; \ + fi; + @echo "Passed ruby test" + install: all + $(RUBY) install.rb install clean: - $(RM) ext/hdf/*.o + $(RM) ext/hdf/*.o ext/hdf/*.so distclean: $(RM) Makefile.depends config.save ext/hdf/hdf.so diff -Nru clearsilver-0.9.1/ruby/ext/hdf/neo_cs.c clearsilver-0.9.2/ruby/ext/hdf/neo_cs.c --- clearsilver-0.9.1/ruby/ext/hdf/neo_cs.c Mon Jul 7 23:10:29 2003 +++ clearsilver-0.9.2/ruby/ext/hdf/neo_cs.c Fri Aug 8 23:54:14 2003 @@ -17,6 +17,8 @@ VALUE r_neo_error(NEOERR *err); +#define Srb_raise(val) rb_raise(eHdfError, "%s/%d %s",__FILE__,__LINE__,RSTRING(val)->ptr) + static void c_free (CSPARSE *csd) { if (csd) { cs_destroy (&csd); @@ -39,7 +41,7 @@ err = cs_init (&cs, hdf); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); r_cs = Data_Wrap_Struct(class, 0, c_free, cs); rb_obj_call_init(r_cs, 0, NULL); @@ -55,7 +57,7 @@ path = STR2CSTR(oPath); err = cs_parse_file (cs, path); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -72,10 +74,11 @@ /* This should be changed to use memory from the gc */ ms = strdup(s); - if (ms == NULL) rb_raise(rb_eException, "out of memory"); + if (ms == NULL) rb_raise(rb_eNoMemError, "out of memory"); err = cs_parse_string (cs, ms, l); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -98,14 +101,14 @@ string_init(&str); err = cs_render (cs, &str, render_cb); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); rv = rb_str_new2(str.buf); string_clear (&str); return rv; } -void Init_Cs() { +void Init_cs() { cCs = rb_define_class_under(mNeotonic, "Cs", rb_cObject); rb_define_singleton_method(cCs, "new", c_new, 1); diff -Nru clearsilver-0.9.1/ruby/ext/hdf/neo_util.c clearsilver-0.9.2/ruby/ext/hdf/neo_util.c --- clearsilver-0.9.1/ruby/ext/hdf/neo_util.c Mon Jul 7 23:10:29 2003 +++ clearsilver-0.9.2/ruby/ext/hdf/neo_util.c Fri Aug 8 23:54:14 2003 @@ -9,12 +9,14 @@ */ #include +#include #include "ClearSilver.h" VALUE mNeotonic; static VALUE cHdf; VALUE eHdfError; +#define Srb_raise(val) rb_raise(eHdfError, "%s/%d %s",__FILE__,__LINE__,RSTRING(val)->ptr) VALUE r_neo_error (NEOERR *err) { @@ -22,20 +24,16 @@ VALUE errstr; string_init (&str); + nerr_error_string (err, &str); + errstr = rb_str_new2(str.buf); + /* if (nerr_match(err, NERR_PARSE)) { - nerr_error_string (err, &str); - errstr = rb_str_new2(str.buf); - string_clear(&str); - return errstr; } else { - nerr_error_traceback (err, &str); - errstr = rb_str_new2(str.buf); - string_clear(&str); - return errstr; } + */ string_clear (&str); - return Qnil; + return errstr; } static void h_free(void *p) { @@ -55,7 +53,7 @@ VALUE r_hdf; err = hdf_init (&hdf); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); r_hdf = Data_Wrap_Struct(class, 0, h_free, hdf); rb_obj_call_init(r_hdf, 0, NULL); @@ -101,7 +99,7 @@ value = STR2CSTR(oValue); err = hdf_set_attr(hdf, name, key, value); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -119,7 +117,7 @@ err = hdf_set_value (hdf, name, value); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -293,7 +291,7 @@ path=STR2CSTR(oPath); err = hdf_read_file (hdf, path); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -309,7 +307,8 @@ path=STR2CSTR(oPath); err = hdf_write_file (hdf, path); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -325,7 +324,7 @@ path=STR2CSTR(oPath); err = hdf_write_file_atomic (hdf, path); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -340,7 +339,7 @@ name = STR2CSTR(oName); err = hdf_remove_tree (hdf, name); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -357,7 +356,7 @@ Data_Get_Struct(self, HDF, hdf); err = hdf_dump_str (hdf, NULL, 0, &str); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); rv = rb_str_new2(str.buf); string_clear (&str); @@ -375,7 +374,7 @@ err = hdf_write_string (hdf, &s); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); rv = rb_str_new2(s); if (s) free(s); @@ -396,7 +395,7 @@ err = hdf_read_string_ignore (hdf, s, ignore); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -416,7 +415,7 @@ if (src == NULL) rb_raise(eHdfError, "second argument must be an Hdf object"); err = hdf_copy (hdf, name, src); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -433,7 +432,7 @@ dest = STR2CSTR(oDest); err = hdf_set_symlink (hdf, src, dest); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); return self; } @@ -454,7 +453,7 @@ err = neos_escape(s, buflen, esc_char[0], escape, &ret); - if (err) rb_raise(eHdfError, "%s", r_neo_error(err)); + if (err) Srb_raise(r_neo_error(err)); rv = rb_str_new2(ret); free(ret); @@ -474,7 +473,7 @@ /* This should be changed to use memory from the gc */ copy = strdup(s); - if (copy == NULL) rb_raise(rb_eException, "out of memory"); + if (copy == NULL) rb_raise(rb_eNoMemError, "out of memory"); neos_unescape(copy, buflen, esc_char[0]); @@ -516,7 +515,12 @@ rb_define_singleton_method(cHdf, "escape", h_escape, 3); rb_define_singleton_method(cHdf, "unescape", h_unescape, 3); - eHdfError = rb_define_class_under(mNeotonic, "HdfError", rb_eException); + eHdfError = rb_define_class_under(mNeotonic, "HdfError", +#if RUBY_VERSION_MINOR >= 6 + rb_eStandardError); +#else + rb_eException); +#endif - Init_Cs(); + Init_cs(); } diff -Nru clearsilver-0.9.1/ruby/hdftest.gold clearsilver-0.9.2/ruby/hdftest.gold --- clearsilver-0.9.1/ruby/hdftest.gold Wed Dec 31 16:00:00 1969 +++ clearsilver-0.9.2/ruby/hdftest.gold Mon Aug 11 13:04:56 2003 @@ -0,0 +1,27 @@ +1 = farming +2 = sewing +3 = bowling +party.1 [Drool="True"] = baloons +party.2 [Pink] = noise makers +party.3 << EOM +telling long +stories +EOM +arf.1 = farming +arf.2 = sewing +arf.3 = bowling +arf.party.1 [Drool="True"] = baloons +arf.party.2 [Pink] = noise makers +arf.party.3 << EOM +telling long +stories +EOM +party.2 attr (Pink=1) +This is a funny test. farming. + +baloons + +noise makers + +telling long +stories diff -Nru clearsilver-0.9.1/ruby/test/hdftest.rb clearsilver-0.9.2/ruby/test/hdftest.rb --- clearsilver-0.9.1/ruby/test/hdftest.rb Tue Jun 17 14:20:14 2003 +++ clearsilver-0.9.2/ruby/test/hdftest.rb Fri Aug 8 23:54:16 2003 @@ -31,7 +31,6 @@ " - c = Neo::Cs.new q c.parse_string(s) diff -Nru clearsilver-0.9.1/rules.mk.in clearsilver-0.9.2/rules.mk.in --- clearsilver-0.9.1/rules.mk.in Tue Jun 17 14:20:40 2003 +++ clearsilver-0.9.2/rules.mk.in Mon Aug 11 14:37:09 2003 @@ -1,3 +1,11 @@ +############################################################ +# +# rules.mk is A U T O G E N E R A T E D +# +# you must edit: rules.mk.in +# +############################################################ + ## ## Global Makefile Rules ## @@ -48,6 +56,7 @@ PYTHON_LIB = @PYTHON_LIB@ PYTHON_SITE = @PYTHON_SITE@ JAVA_PATH = @JAVA_PATH@ +CSHARP_PATH = @CSHARP_PATH@ ## Programs @SET_MAKE@ @@ -60,6 +69,7 @@ JAVAH = $(JAVA_PATH)/bin/javah JAR = $(JAVA_PATH)/bin/jar APXS = @APXS_PATH@ +PYTHON = @PYTHON@ PERL = @PERL@ RUBY = @RUBY@ @@ -70,7 +80,8 @@ LDFLAGS = -L$(LIB_DIR) @LDFLAGS@ LDSHARED = $(CC) -shared -fPic CPPLDSHARED = $(CPP) -shared -fPic -AR = ar -cr +AR = @AR@ cr +RANLIB = @RANLIB@ DEP_LIBS = $(DLIBS:-l%=$(LIB_DIR)lib%.a) LIBS = @LIBS@ LS = /bin/ls @@ -78,6 +89,11 @@ BUILD_WRAPPERS = @BUILD_WRAPPERS@ EXTRA_UTL_OBJS = @EXTRA_UTL_OBJS@ EXTRA_UTL_SRC = @EXTRA_UTL_SRC@ + +## I don't really feel like writing a configure thing for this yet +ifeq ($(OSNAME),SunOS) +LDSHARED = ld -G -fPIC +endif ## --------------win32 options diff -Nru clearsilver-0.9.1/util/Makefile clearsilver-0.9.2/util/Makefile --- clearsilver-0.9.1/util/Makefile Mon Apr 14 17:13:46 2003 +++ clearsilver-0.9.2/util/Makefile Thu Jul 24 22:46:15 2003 @@ -19,6 +19,7 @@ $(UTL_LIB): $(UTL_OBJ) $(AR) $@ $(UTL_OBJ) + $(RANLIB) $@ install: all $(NEOTONIC_ROOT)mkinstalldirs $(DESTDIR)$(cs_includedir)/util diff -Nru clearsilver-0.9.1/util/neo_hash.c clearsilver-0.9.2/util/neo_hash.c --- clearsilver-0.9.1/util/neo_hash.c Wed Apr 2 15:06:35 2003 +++ clearsilver-0.9.2/util/neo_hash.c Thu Jul 24 22:45:02 2003 @@ -17,27 +17,27 @@ #include "neo_err.h" #include "neo_hash.h" -static NEOERR *hash_resize(HASH *hash); -static HASHNODE **hash_lookup_node (HASH *hash, void *key, UINT32 *hashv); +static NEOERR *_hash_resize(NE_HASH *hash); +static NE_HASHNODE **_hash_lookup_node (NE_HASH *hash, void *key, UINT32 *hashv); -NEOERR *hash_init (HASH **hash, HASH_FUNC hash_func, COMP_FUNC comp_func) +NEOERR *ne_hash_init (NE_HASH **hash, NE_HASH_FUNC hash_func, NE_COMP_FUNC comp_func) { - HASH *my_hash = NULL; + NE_HASH *my_hash = NULL; - my_hash = (HASH *) calloc(1, sizeof(HASH)); + my_hash = (NE_HASH *) calloc(1, sizeof(NE_HASH)); if (my_hash == NULL) - return nerr_raise(NERR_NOMEM, "Unable to allocate memory for HASH"); + return nerr_raise(NERR_NOMEM, "Unable to allocate memory for NE_HASH"); my_hash->size = 256; my_hash->num = 0; my_hash->hash_func = hash_func; my_hash->comp_func = comp_func; - my_hash->nodes = (HASHNODE **) calloc (my_hash->size, sizeof(HASHNODE *)); + my_hash->nodes = (NE_HASHNODE **) calloc (my_hash->size, sizeof(NE_HASHNODE *)); if (my_hash->nodes == NULL) { free(my_hash); - return nerr_raise(NERR_NOMEM, "Unable to allocate memory for HASHNODES"); + return nerr_raise(NERR_NOMEM, "Unable to allocate memory for NE_HASHNODES"); } *hash = my_hash; @@ -45,10 +45,10 @@ return STATUS_OK; } -void hash_destroy (HASH **hash) +void ne_hash_destroy (NE_HASH **hash) { - HASH *my_hash; - HASHNODE *node, *next; + NE_HASH *my_hash; + NE_HASHNODE *node, *next; int x; if (hash == NULL || *hash == NULL) @@ -72,12 +72,12 @@ *hash = NULL; } -NEOERR *hash_insert(HASH *hash, void *key, void *value) +NEOERR *ne_hash_insert(NE_HASH *hash, void *key, void *value) { UINT32 hashv; - HASHNODE **node; + NE_HASHNODE **node; - node = hash_lookup_node(hash, key, &hashv); + node = _hash_lookup_node(hash, key, &hashv); if (*node) { @@ -85,9 +85,9 @@ } else { - *node = (HASHNODE *) malloc(sizeof(HASHNODE)); + *node = (NE_HASHNODE *) malloc(sizeof(NE_HASHNODE)); if (node == NULL) - return nerr_raise(NERR_NOMEM, "Unable to allocate HASHNODE"); + return nerr_raise(NERR_NOMEM, "Unable to allocate NE_HASHNODE"); (*node)->hashv = hashv; (*node)->key = key; @@ -96,51 +96,53 @@ } hash->num++; - return hash_resize(hash); + return _hash_resize(hash); } -void *hash_lookup(HASH *hash, void *key) +void *ne_hash_lookup(NE_HASH *hash, void *key) { - HASHNODE *node; + NE_HASHNODE *node; - node = *hash_lookup_node(hash, key, NULL); + node = *_hash_lookup_node(hash, key, NULL); return (node) ? node->value : NULL; } -void *hash_remove(HASH *hash, void *key) +void *ne_hash_remove(NE_HASH *hash, void *key) { - HASHNODE **node; + NE_HASHNODE **node, *remove; void *value = NULL; - node = hash_lookup_node(hash, key, NULL); + node = _hash_lookup_node(hash, key, NULL); if (*node) { - value = (*node)->value; - free((*node)); - *node = NULL; + remove = *node; + *node = remove->next; + value = remove->value; + free(remove); + hash->num--; } return value; } -int hash_has_key(HASH *hash, void *key) +int ne_hash_has_key(NE_HASH *hash, void *key) { - HASHNODE *node; + NE_HASHNODE *node; - node = *hash_lookup_node(hash, key, NULL); + node = *_hash_lookup_node(hash, key, NULL); if (node) return 1; return 0; } -void *hash_next(HASH *hash, void **key) +void *ne_hash_next(NE_HASH *hash, void **key) { - HASHNODE **node = 0; + NE_HASHNODE **node = 0; UINT32 hashv, bucket; if (*key) { - node = hash_lookup_node(hash, key, NULL); + node = _hash_lookup_node(hash, key, NULL); if (*node) { @@ -180,10 +182,10 @@ return NULL; } -static HASHNODE **hash_lookup_node (HASH *hash, void *key, UINT32 *o_hashv) +static NE_HASHNODE **_hash_lookup_node (NE_HASH *hash, void *key, UINT32 *o_hashv) { UINT32 hashv, bucket; - HASHNODE **node; + NE_HASHNODE **node; hashv = hash->hash_func(key); if (o_hashv) *o_hashv = hashv; @@ -209,10 +211,10 @@ } /* Ok, we're doing some weirdness here... */ -static NEOERR *hash_resize(HASH *hash) +static NEOERR *_hash_resize(NE_HASH *hash) { - HASHNODE **new_nodes; - HASHNODE *entry, *prev; + NE_HASHNODE **new_nodes; + NE_HASHNODE *entry, *prev; int x, next_bucket; int orig_size = hash->size; UINT32 hash_mask; @@ -221,9 +223,9 @@ return STATUS_OK; /* We always double in size */ - new_nodes = (HASHNODE **) realloc (hash->nodes, (hash->size*2) * sizeof(HASHNODE)); + new_nodes = (NE_HASHNODE **) realloc (hash->nodes, (hash->size*2) * sizeof(NE_HASHNODE)); if (new_nodes == NULL) - return nerr_raise(NERR_NOMEM, "Unable to allocate memory to resize HASH"); + return nerr_raise(NERR_NOMEM, "Unable to allocate memory to resize NE_HASH"); hash->nodes = new_nodes; orig_size = hash->size; @@ -268,12 +270,12 @@ return STATUS_OK; } -int hash_str_comp(const void *a, const void *b) +int ne_hash_str_comp(const void *a, const void *b) { return !strcmp((const char *)a, (const char *)b); } -UINT32 hash_str_hash(const void *a) +UINT32 ne_hash_str_hash(const void *a) { return ne_crc((char *)a, strlen((const char *)a)); } diff -Nru clearsilver-0.9.1/util/neo_hash.h clearsilver-0.9.2/util/neo_hash.h --- clearsilver-0.9.1/util/neo_hash.h Wed Apr 2 15:06:35 2003 +++ clearsilver-0.9.2/util/neo_hash.h Thu Jul 24 22:45:02 2003 @@ -16,37 +16,37 @@ #include #include "util/neo_misc.h" -typedef UINT32 (*HASH_FUNC)(const void *); -typedef int (*COMP_FUNC)(const void *, const void *); +typedef UINT32 (*NE_HASH_FUNC)(const void *); +typedef int (*NE_COMP_FUNC)(const void *, const void *); -typedef struct _HASHNODE +typedef struct _NE_HASHNODE { void *key; void *value; UINT32 hashv; - struct _HASHNODE *next; -} HASHNODE; + struct _NE_HASHNODE *next; +} NE_HASHNODE; typedef struct _HASH { UINT32 size; UINT32 num; - HASHNODE **nodes; - HASH_FUNC hash_func; - COMP_FUNC comp_func; -} HASH; + NE_HASHNODE **nodes; + NE_HASH_FUNC hash_func; + NE_COMP_FUNC comp_func; +} NE_HASH; -NEOERR *hash_init (HASH **hash, HASH_FUNC hash_func, COMP_FUNC comp_func); -void hash_destroy (HASH **hash); -NEOERR *hash_insert(HASH *hash, void *key, void *value); -void *hash_lookup(HASH *hash, void *key); -int hash_has_key(HASH *hash, void *key); -void *hash_remove(HASH *hash, void *key); -void *hash_next(HASH *hash, void **key); +NEOERR *ne_hash_init (NE_HASH **hash, NE_HASH_FUNC hash_func, NE_COMP_FUNC comp_func); +void ne_hash_destroy (NE_HASH **hash); +NEOERR *ne_hash_insert(NE_HASH *hash, void *key, void *value); +void *ne_hash_lookup(NE_HASH *hash, void *key); +int ne_hash_has_key(NE_HASH *hash, void *key); +void *ne_hash_remove(NE_HASH *hash, void *key); +void *ne_hash_next(NE_HASH *hash, void **key); -int hash_str_comp(const void *a, const void *b); -UINT32 hash_str_hash(const void *a); +int ne_hash_str_comp(const void *a, const void *b); +UINT32 ne_hash_str_hash(const void *a); __END_DECLS diff -Nru clearsilver-0.9.1/util/neo_hdf.c clearsilver-0.9.2/util/neo_hdf.c --- clearsilver-0.9.1/util/neo_hdf.c Wed Apr 2 15:07:36 2003 +++ clearsilver-0.9.2/util/neo_hdf.c Mon Aug 18 13:40:03 2003 @@ -138,7 +138,7 @@ } if ((*hdf)->hash != NULL) { - hash_destroy(&(*hdf)->hash); + ne_hash_destroy(&(*hdf)->hash); } free (*hdf); *hdf = NULL; @@ -223,7 +223,7 @@ { hash_key.name = n; hash_key.name_len = x; - hp = hash_lookup(parent->hash, &hash_key); + hp = ne_hash_lookup(parent->hash, &hash_key); } else { @@ -507,20 +507,20 @@ NEOERR *err; HDF *child; - err = hash_init(&(hdf->hash), hash_hdf_hash, hash_hdf_comp); + err = ne_hash_init(&(hdf->hash), hash_hdf_hash, hash_hdf_comp); if (err) return nerr_pass(err); child = hdf->child; while (child) { - err = hash_insert(hdf->hash, child, child); + err = ne_hash_insert(hdf->hash, child, child); if (err) return nerr_pass(err); child = child->next; } return STATUS_OK; } -NEOERR* _set_value (HDF *hdf, char *name, char *value, int dup, int wf, int link, HDF_ATTR *attr, HDF **set_node) +static NEOERR* _set_value (HDF *hdf, char *name, char *value, int dup, int wf, int link, HDF_ATTR *attr, HDF **set_node) { NEOERR *err; HDF *hn, *hp, *hs; @@ -614,7 +614,7 @@ { hash_key.name = n; hash_key.name_len = x; - hp = hash_lookup(hn->hash, &hash_key); + hp = ne_hash_lookup(hn->hash, &hash_key); hs = hn->last_child; } else @@ -673,7 +673,7 @@ } else if (hn->hash != NULL) { - err = hash_insert(hn->hash, hp, hp); + err = ne_hash_insert(hn->hash, hp, hp); if (err) return nerr_pass(err); } } @@ -775,6 +775,16 @@ return nerr_raise (NERR_NOT_FOUND, "Unable to find %s", src); } +NEOERR* hdf_get_node (HDF *hdf, char *name, HDF **ret) +{ + _walk_hdf(hdf, name, ret); + if (*ret == NULL) + { + return nerr_pass(_set_value (hdf, name, NULL, 0, 1, 0, NULL, ret)); + } + return STATUS_OK; +} + /* Ok, this version avoids the bubble sort by walking the level once to * load them all into a ULIST, qsort'ing the list, and then dumping them * back out... */ @@ -815,7 +825,7 @@ NEOERR* hdf_remove_tree (HDF *hdf, char *name) { HDF *hp = hdf; - HDF *lp = NULL, *ln = NULL; + HDF *lp = NULL, *ln = NULL; /* last parent, last node */ int x = 0; char *s = name; char *n = name; @@ -841,11 +851,10 @@ { if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x)) { - break; + break; } else { - lp = NULL; ln = hp; hp = hp->next; } @@ -864,14 +873,18 @@ x = (s == NULL) ? strlen(n) : s - n; } - if (lp) + if (lp->hash != NULL) { - lp->child = hp->next; - hp->next = NULL; + ne_hash_remove(lp->hash, hp); } - else if (ln) + if (ln) { ln->next = hp->next; + hp->next = NULL; + } + else + { + lp->child = hp->next; hp->next = NULL; } _dealloc_hdf (&hp); diff -Nru clearsilver-0.9.1/util/neo_hdf.h clearsilver-0.9.2/util/neo_hdf.h --- clearsilver-0.9.1/util/neo_hdf.h Mon Mar 31 17:45:54 2003 +++ clearsilver-0.9.2/util/neo_hdf.h Mon Aug 18 13:40:03 2003 @@ -45,7 +45,7 @@ /* the following HASH is used when we reach more than FORCE_HASH_AT * elements */ - HASH *hash; + NE_HASH *hash; /* When using the HASH, we need to know where to append new children */ struct _hdf *last_child; } HDF; @@ -58,6 +58,9 @@ NEOERR* hdf_get_copy (HDF *hdf, char *name, char **value, char *defval); HDF* hdf_get_obj (HDF *hdf, char *name); +/* Always returns the node (except on NOMEM error). Creates if + * necessary */ +NEOERR * hdf_get_node (HDF *hdf, char *name, HDF **ret); HDF* hdf_get_child (HDF *hdf, char *name); HDF_ATTR* hdf_get_attr (HDF *hdf, char *name); NEOERR* hdf_set_attr (HDF *hdf, char *name, char *key, char *value); diff -Nru clearsilver-0.9.1/util/neo_misc.h clearsilver-0.9.2/util/neo_misc.h --- clearsilver-0.9.1/util/neo_misc.h Wed Apr 2 19:03:01 2003 +++ clearsilver-0.9.2/util/neo_misc.h Fri Aug 8 23:54:17 2003 @@ -13,6 +13,7 @@ #include #include +#include "cs_config.h" /* Fix Up for systems that don't define these standard things... */ #ifndef __BEGIN_DECLS diff -Nru clearsilver-0.9.1/util/neo_net.h clearsilver-0.9.2/util/neo_net.h --- clearsilver-0.9.1/util/neo_net.h Wed Oct 23 18:13:21 2002 +++ clearsilver-0.9.2/util/neo_net.h Thu Jul 24 11:35:13 2003 @@ -48,7 +48,7 @@ NEOERR *net_write_str(NSOCK *sock, char *s); NEOERR *net_write_int(NSOCK *sock, int i); NEOERR *net_flush(NSOCK *sock); -void net_shutdown(); +void net_shutdown(void); __END_DECLS