File Annotation
Not logged in
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** Copyright (c) 2008 D. Richard Hipp
13e16c824a 2008-02-13       drh: **
13e16c824a 2008-02-13       drh: ** This program is free software; you can redistribute it and/or
13e16c824a 2008-02-13       drh: ** modify it under the terms of the GNU General Public
13e16c824a 2008-02-13       drh: ** License version 2 as published by the Free Software Foundation.
13e16c824a 2008-02-13       drh: **
13e16c824a 2008-02-13       drh: ** This program is distributed in the hope that it will be useful,
13e16c824a 2008-02-13       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13e16c824a 2008-02-13       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13e16c824a 2008-02-13       drh: ** General Public License for more details.
13e16c824a 2008-02-13       drh: **
13e16c824a 2008-02-13       drh: ** You should have received a copy of the GNU General Public
13e16c824a 2008-02-13       drh: ** License along with this library; if not, write to the
13e16c824a 2008-02-13       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
13e16c824a 2008-02-13       drh: ** Boston, MA  02111-1307, USA.
13e16c824a 2008-02-13       drh: **
13e16c824a 2008-02-13       drh: ** Author contact information:
13e16c824a 2008-02-13       drh: **   drh@hwaci.com
13e16c824a 2008-02-13       drh: **   http://www.hwaci.com/drh/
13e16c824a 2008-02-13       drh: **
13e16c824a 2008-02-13       drh: *******************************************************************************
13e16c824a 2008-02-13       drh: **
13e16c824a 2008-02-13       drh: ** This file contains an interface between the TH scripting language
13e16c824a 2008-02-13       drh: ** (an independent project) and fossil.
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: #include "config.h"
13e16c824a 2008-02-13       drh: #include "th_main.h"
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** Global variable counting the number of outstanding calls to malloc()
13e16c824a 2008-02-13       drh: ** made by the th1 implementation. This is used to catch memory leaks
13e16c824a 2008-02-13       drh: ** in the interpreter. Obviously, it also means th1 is not threadsafe.
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: static int nOutstandingMalloc = 0;
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** Implementations of malloc() and free() to pass to the interpreter.
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: static void *xMalloc(unsigned int n){
13e16c824a 2008-02-13       drh:   void *p = malloc(n);
13e16c824a 2008-02-13       drh:   if( p ){
13e16c824a 2008-02-13       drh:     nOutstandingMalloc++;
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh:   return p;
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: static void xFree(void *p){
13e16c824a 2008-02-13       drh:   if( p ){
13e16c824a 2008-02-13       drh:     nOutstandingMalloc--;
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh:   free(p);
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: static Th_Vtab vtab = { xMalloc, xFree };
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** True if output is enabled.  False if disabled.
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: static int enableOutput = 1;
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** TH command:     enable_output BOOLEAN
13e16c824a 2008-02-13       drh: **
13e16c824a 2008-02-13       drh: ** Enable or disable the puts and hputs commands.
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: static int enableOutputCmd(
13e16c824a 2008-02-13       drh:   Th_Interp *interp,
13e16c824a 2008-02-13       drh:   void *p,
13e16c824a 2008-02-13       drh:   int argc,
13e16c824a 2008-02-13       drh:   const unsigned char **argv,
13e16c824a 2008-02-13       drh:   int *argl
13e16c824a 2008-02-13       drh: ){
13e16c824a 2008-02-13       drh:   if( argc!=2 ){
13e16c824a 2008-02-13       drh:     return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh:   return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** Send text to the appropriate output:  Either to the console
13e16c824a 2008-02-13       drh: ** or to the CGI reply buffer.
13e16c824a 2008-02-13       drh: */
ffe92f1a2f 2008-02-13       drh: static void sendText(const char *z, int n, int encode){
13e16c824a 2008-02-13       drh:   if( enableOutput && n ){
13e16c824a 2008-02-13       drh:     if( n<0 ) n = strlen(z);
ffe92f1a2f 2008-02-13       drh:     if( encode ){
ffe92f1a2f 2008-02-13       drh:       z = htmlize(z, n);
ffe92f1a2f 2008-02-13       drh:       n = strlen(z);
ffe92f1a2f 2008-02-13       drh:     }
13e16c824a 2008-02-13       drh:     if( g.cgiPanic ){
13e16c824a 2008-02-13       drh:       cgi_append_content(z, n);
13e16c824a 2008-02-13       drh:     }else{
13e16c824a 2008-02-13       drh:       fwrite(z, 1, n, stdout);
13e16c824a 2008-02-13       drh:     }
ffe92f1a2f 2008-02-13       drh:     if( encode ) free((char*)z);
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** TH command:     puts STRING
13e16c824a 2008-02-13       drh: ** TH command:     html STRING
13e16c824a 2008-02-13       drh: **
13e16c824a 2008-02-13       drh: ** Output STRING as HTML (html) or unchanged (puts).
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: static int putsCmd(
13e16c824a 2008-02-13       drh:   Th_Interp *interp,
13e16c824a 2008-02-13       drh:   void *pConvert,
13e16c824a 2008-02-13       drh:   int argc,
13e16c824a 2008-02-13       drh:   const unsigned char **argv,
13e16c824a 2008-02-13       drh:   int *argl
13e16c824a 2008-02-13       drh: ){
13e16c824a 2008-02-13       drh:   if( argc!=2 ){
13e16c824a 2008-02-13       drh:     return Th_WrongNumArgs(interp, "puts STRING");
13e16c824a 2008-02-13       drh:   }
ffe92f1a2f 2008-02-13       drh:   sendText((char*)argv[1], argl[1], pConvert!=0);
13e16c824a 2008-02-13       drh:   return TH_OK;
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** TH command:      wiki STRING
13e16c824a 2008-02-13       drh: **
13e16c824a 2008-02-13       drh: ** Render the input string as wiki.
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: static int wikiCmd(
13e16c824a 2008-02-13       drh:   Th_Interp *interp,
13e16c824a 2008-02-13       drh:   void *p,
13e16c824a 2008-02-13       drh:   int argc,
13e16c824a 2008-02-13       drh:   const unsigned char **argv,
13e16c824a 2008-02-13       drh:   int *argl
13e16c824a 2008-02-13       drh: ){
13e16c824a 2008-02-13       drh:   if( argc!=2 ){
ffe92f1a2f 2008-02-13       drh:     return Th_WrongNumArgs(interp, "wiki STRING");
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh:   if( enableOutput ){
13e16c824a 2008-02-13       drh:     Blob src;
13e16c824a 2008-02-13       drh:     blob_init(&src, (char*)argv[1], argl[1]);
13e16c824a 2008-02-13       drh:     wiki_convert(&src, 0, WIKI_INLINE);
13e16c824a 2008-02-13       drh:     blob_reset(&src);
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh:   return TH_OK;
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
46e6a03232 2008-05-16       drh: ** TH command:      htmlize STRING
46e6a03232 2008-05-16       drh: **
46e6a03232 2008-05-16       drh: ** Escape all characters of STRING which have special meaning in HTML.
46e6a03232 2008-05-16       drh: ** Return a new string result.
46e6a03232 2008-05-16       drh: */
46e6a03232 2008-05-16       drh: static int htmlizeCmd(
46e6a03232 2008-05-16       drh:   Th_Interp *interp,
46e6a03232 2008-05-16       drh:   void *p,
46e6a03232 2008-05-16       drh:   int argc,
46e6a03232 2008-05-16       drh:   const unsigned char **argv,
46e6a03232 2008-05-16       drh:   int *argl
46e6a03232 2008-05-16       drh: ){
46e6a03232 2008-05-16       drh:   char *zOut;
46e6a03232 2008-05-16       drh:   if( argc!=2 ){
46e6a03232 2008-05-16       drh:     return Th_WrongNumArgs(interp, "htmlize STRING");
46e6a03232 2008-05-16       drh:   }
46e6a03232 2008-05-16       drh:   zOut = htmlize((char*)argv[1], argl[1]);
46e6a03232 2008-05-16       drh:   Th_SetResult(interp, (unsigned char*)zOut, -1);
46e6a03232 2008-05-16       drh:   free(zOut);
46e6a03232 2008-05-16       drh:   return TH_OK;
46e6a03232 2008-05-16       drh: }
46e6a03232 2008-05-16       drh: 
46e6a03232 2008-05-16       drh: /*
46e6a03232 2008-05-16       drh: ** TH command:      date
46e6a03232 2008-05-16       drh: **
46e6a03232 2008-05-16       drh: ** Return a string which is the current time and date.
46e6a03232 2008-05-16       drh: */
46e6a03232 2008-05-16       drh: static int dateCmd(
46e6a03232 2008-05-16       drh:   Th_Interp *interp,
46e6a03232 2008-05-16       drh:   void *p,
46e6a03232 2008-05-16       drh:   int argc,
46e6a03232 2008-05-16       drh:   const unsigned char **argv,
46e6a03232 2008-05-16       drh:   int *argl
46e6a03232 2008-05-16       drh: ){
46e6a03232 2008-05-16       drh:   char *zOut = db_text("??", "SELECT datetime('now')");
46e6a03232 2008-05-16       drh:   Th_SetResult(interp, (unsigned char*)zOut, -1);
46e6a03232 2008-05-16       drh:   free(zOut);
46e6a03232 2008-05-16       drh:   return TH_OK;
46e6a03232 2008-05-16       drh: }
46e6a03232 2008-05-16       drh: 
46e6a03232 2008-05-16       drh: /*
ffe92f1a2f 2008-02-13       drh: ** TH command:     hascap STRING
ffe92f1a2f 2008-02-13       drh: **
ffe92f1a2f 2008-02-13       drh: ** Return true if the user has all of the capabilities listed in STRING.
ffe92f1a2f 2008-02-13       drh: */
ffe92f1a2f 2008-02-13       drh: static int hascapCmd(
ffe92f1a2f 2008-02-13       drh:   Th_Interp *interp,
ffe92f1a2f 2008-02-13       drh:   void *p,
ffe92f1a2f 2008-02-13       drh:   int argc,
ffe92f1a2f 2008-02-13       drh:   const unsigned char **argv,
ffe92f1a2f 2008-02-13       drh:   int *argl
ffe92f1a2f 2008-02-13       drh: ){
ffe92f1a2f 2008-02-13       drh:   if( argc!=2 ){
ffe92f1a2f 2008-02-13       drh:     return Th_WrongNumArgs(interp, "hascap STRING");
ffe92f1a2f 2008-02-13       drh:   }
ffe92f1a2f 2008-02-13       drh:   Th_SetResultInt(interp, login_has_capability((char*)argv[1],argl[1]));
ffe92f1a2f 2008-02-13       drh:   return TH_OK;
ffe92f1a2f 2008-02-13       drh: }
ffe92f1a2f 2008-02-13       drh: 
ffe92f1a2f 2008-02-13       drh: /*
3122fc4c7e 2008-02-14       drh: ** TH1 command:  combobox NAME TEXT-LIST NUMLINES
3122fc4c7e 2008-02-14       drh: **
3122fc4c7e 2008-02-14       drh: ** Generate an HTML combobox.  NAME is both the name of the
3122fc4c7e 2008-02-14       drh: ** CGI parameter and the name of a variable that contains the
3122fc4c7e 2008-02-14       drh: ** currently selected value.  TEXT-LIST is a list of possible
3122fc4c7e 2008-02-14       drh: ** values for the combobox.  NUMLINES is 1 for a true combobox.
3122fc4c7e 2008-02-14       drh: ** If NUMLINES is greater than one then the display is a listbox
3122fc4c7e 2008-02-14       drh: ** with the number of lines given.
3122fc4c7e 2008-02-14       drh: */
3122fc4c7e 2008-02-14       drh: static int comboboxCmd(
3122fc4c7e 2008-02-14       drh:   Th_Interp *interp,
3122fc4c7e 2008-02-14       drh:   void *p,
3122fc4c7e 2008-02-14       drh:   int argc,
3122fc4c7e 2008-02-14       drh:   const unsigned char **argv,
3122fc4c7e 2008-02-14       drh:   int *argl
3122fc4c7e 2008-02-14       drh: ){
3122fc4c7e 2008-02-14       drh:   if( argc!=4 ){
3122fc4c7e 2008-02-14       drh:     return Th_WrongNumArgs(interp, "combobox NAME TEXT-LIST NUMLINES");
3122fc4c7e 2008-02-14       drh:   }
3122fc4c7e 2008-02-14       drh:   if( enableOutput ){
3122fc4c7e 2008-02-14       drh:     int height;
3122fc4c7e 2008-02-14       drh:     Blob list, elem, name;
3122fc4c7e 2008-02-14       drh:     int nValue;
3122fc4c7e 2008-02-14       drh:     const char *zValue;
3122fc4c7e 2008-02-14       drh:     char *z, *zH;
3122fc4c7e 2008-02-14       drh: 
3122fc4c7e 2008-02-14       drh:     if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
3122fc4c7e 2008-02-14       drh:     blob_init(&list, (char*)argv[2], argl[2]);
3122fc4c7e 2008-02-14       drh:     blob_init(&name, (char*)argv[1], argl[1]);
3122fc4c7e 2008-02-14       drh:     zValue = Th_Fetch(blob_str(&name), &nValue);
3122fc4c7e 2008-02-14       drh:     z = mprintf("<select name=\"%z\" size=\"%d\">",
3122fc4c7e 2008-02-14       drh:                  htmlize(blob_buffer(&name), blob_size(&name)), height);
3122fc4c7e 2008-02-14       drh:     sendText(z, -1, 0);
3122fc4c7e 2008-02-14       drh:     free(z);
3122fc4c7e 2008-02-14       drh:     blob_reset(&name);
3122fc4c7e 2008-02-14       drh:     while( blob_token(&list, &elem) ){
3122fc4c7e 2008-02-14       drh:       zH = htmlize(blob_buffer(&elem), blob_size(&elem));
3122fc4c7e 2008-02-14       drh:       if( zValue && blob_size(&elem)==nValue
3122fc4c7e 2008-02-14       drh:              && memcmp(zValue, blob_buffer(&elem), nValue)==0 ){
3122fc4c7e 2008-02-14       drh:         z = mprintf("<option value=\"%s\" selected>%s</option>", zH, zH);
3122fc4c7e 2008-02-14       drh:       }else{
3122fc4c7e 2008-02-14       drh:         z = mprintf("<option value=\"%s\">%s</option>", zH, zH);
3122fc4c7e 2008-02-14       drh:       }
3122fc4c7e 2008-02-14       drh:       free(zH);
3122fc4c7e 2008-02-14       drh:       sendText(z, -1, 0);
3122fc4c7e 2008-02-14       drh:       free(z);
3122fc4c7e 2008-02-14       drh:     }
3122fc4c7e 2008-02-14       drh:     sendText("</select>", -1, 0);
3122fc4c7e 2008-02-14       drh:     blob_reset(&list);
3122fc4c7e 2008-02-14       drh:   }
3122fc4c7e 2008-02-14       drh:   return TH_OK;
3122fc4c7e 2008-02-14       drh: }
3122fc4c7e 2008-02-14       drh: 
3122fc4c7e 2008-02-14       drh: /*
3122fc4c7e 2008-02-14       drh: ** TH1 command:     linecount STRING MAX MIN
3122fc4c7e 2008-02-14       drh: **
3122fc4c7e 2008-02-14       drh: ** Return one more than the number of \n characters in STRING.  But
3122fc4c7e 2008-02-14       drh: ** never return less than MIN or more than MAX.
3122fc4c7e 2008-02-14       drh: */
3122fc4c7e 2008-02-14       drh: static int linecntCmd(
3122fc4c7e 2008-02-14       drh:   Th_Interp *interp,
3122fc4c7e 2008-02-14       drh:   void *p,
3122fc4c7e 2008-02-14       drh:   int argc,
3122fc4c7e 2008-02-14       drh:   const unsigned char **argv,
3122fc4c7e 2008-02-14       drh:   int *argl
3122fc4c7e 2008-02-14       drh: ){
3122fc4c7e 2008-02-14       drh:   const uchar *z;
3122fc4c7e 2008-02-14       drh:   int size, n, i;
3122fc4c7e 2008-02-14       drh:   int iMin, iMax;
3122fc4c7e 2008-02-14       drh:   if( argc!=4 ){
3122fc4c7e 2008-02-14       drh:     return Th_WrongNumArgs(interp, "linecount STRING MAX MIN");
3122fc4c7e 2008-02-14       drh:   }
3122fc4c7e 2008-02-14       drh:   if( Th_ToInt(interp, argv[2], argl[2], &iMax) ) return TH_ERROR;
3122fc4c7e 2008-02-14       drh:   if( Th_ToInt(interp, argv[3], argl[3], &iMin) ) return TH_ERROR;
3122fc4c7e 2008-02-14       drh:   z = argv[1];
3122fc4c7e 2008-02-14       drh:   size = argl[1];
3122fc4c7e 2008-02-14       drh:   for(n=1, i=0; i<size; i++){
3122fc4c7e 2008-02-14       drh:     if( z[i]=='\n' ){
3122fc4c7e 2008-02-14       drh:       n++;
3122fc4c7e 2008-02-14       drh:       if( n>=iMax ) break;
3122fc4c7e 2008-02-14       drh:     }
3122fc4c7e 2008-02-14       drh:   }
3122fc4c7e 2008-02-14       drh:   if( n<iMin ) n = iMin;
3122fc4c7e 2008-02-14       drh:   if( n>iMax ) n = iMax;
3122fc4c7e 2008-02-14       drh:   Th_SetResultInt(interp, n);
3122fc4c7e 2008-02-14       drh:   return TH_OK;
3122fc4c7e 2008-02-14       drh: }
3122fc4c7e 2008-02-14       drh: 
3122fc4c7e 2008-02-14       drh: /*
13e16c824a 2008-02-13       drh: ** Make sure the interpreter has been initialized.
13e16c824a 2008-02-13       drh: */
fde1d82372 2008-02-13       drh: void Th_FossilInit(void){
13e16c824a 2008-02-13       drh:   static struct _Command {
13e16c824a 2008-02-13       drh:     const char *zName;
13e16c824a 2008-02-13       drh:     Th_CommandProc xProc;
13e16c824a 2008-02-13       drh:     void *pContext;
13e16c824a 2008-02-13       drh:   } aCommand[] = {
3122fc4c7e 2008-02-14       drh:     {"combobox",      comboboxCmd,          0},
13e16c824a 2008-02-13       drh:     {"enable_output", enableOutputCmd,      0},
3122fc4c7e 2008-02-14       drh:     {"linecount",     linecntCmd,           0},
ffe92f1a2f 2008-02-13       drh:     {"hascap",        hascapCmd,            0},
46e6a03232 2008-05-16       drh:     {"htmlize",       htmlizeCmd,           0},
46e6a03232 2008-05-16       drh:     {"date",          dateCmd,              0},
13e16c824a 2008-02-13       drh:     {"html",          putsCmd,              0},
13e16c824a 2008-02-13       drh:     {"puts",          putsCmd,       (void*)1},
13e16c824a 2008-02-13       drh:     {"wiki",          wikiCmd,              0},
13e16c824a 2008-02-13       drh:   };
fde1d82372 2008-02-13       drh:   if( g.interp==0 ){
13e16c824a 2008-02-13       drh:     int i;
fde1d82372 2008-02-13       drh:     g.interp = Th_CreateInterp(&vtab);
fde1d82372 2008-02-13       drh:     th_register_language(g.interp);       /* Basic scripting commands. */
13e16c824a 2008-02-13       drh:     for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
fde1d82372 2008-02-13       drh:       Th_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc,
13e16c824a 2008-02-13       drh:                        aCommand[i].pContext, 0);
13e16c824a 2008-02-13       drh:     }
3ad9a5e210 2008-02-13       drh:   }
3ad9a5e210 2008-02-13       drh: }
3ad9a5e210 2008-02-13       drh: 
3ad9a5e210 2008-02-13       drh: /*
fde1d82372 2008-02-13       drh: ** Store a string value in a variable in the interpreter.
fde1d82372 2008-02-13       drh: */
fde1d82372 2008-02-13       drh: void Th_Store(const char *zName, const char *zValue){
fde1d82372 2008-02-13       drh:   Th_FossilInit();
fde1d82372 2008-02-13       drh:   Th_SetVar(g.interp, (uchar*)zName, -1, (uchar*)zValue, strlen(zValue));
fde1d82372 2008-02-13       drh: }
fde1d82372 2008-02-13       drh: 
fde1d82372 2008-02-13       drh: /*
68c24b1857 2008-05-16       drh: ** Unset a variable.
68c24b1857 2008-05-16       drh: */
68c24b1857 2008-05-16       drh: void Th_Unstore(const char *zName){
68c24b1857 2008-05-16       drh:   if( g.interp ){
68c24b1857 2008-05-16       drh:     Th_UnsetVar(g.interp, (uchar*)zName, -1);
68c24b1857 2008-05-16       drh:   }
3122fc4c7e 2008-02-14       drh: }
3122fc4c7e 2008-02-14       drh: 
3122fc4c7e 2008-02-14       drh: /*
fde1d82372 2008-02-13       drh: ** Retrieve a string value from the interpreter.  If no such
fde1d82372 2008-02-13       drh: ** variable exists, return NULL.
3ad9a5e210 2008-02-13       drh: */
fde1d82372 2008-02-13       drh: char *Th_Fetch(const char *zName, int *pSize){
fde1d82372 2008-02-13       drh:   int rc;
fde1d82372 2008-02-13       drh:   Th_FossilInit();
3122fc4c7e 2008-02-14       drh:   rc = Th_GetVar(g.interp, (uchar*)zName, -1);
fde1d82372 2008-02-13       drh:   if( rc==TH_OK ){
3122fc4c7e 2008-02-14       drh:     return (char*)Th_GetResult(g.interp, pSize);
fde1d82372 2008-02-13       drh:   }else{
fde1d82372 2008-02-13       drh:     return 0;
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** Return true if the string begins with the TH1 begin-script
13e16c824a 2008-02-13       drh: ** tag:  <th1>.
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: static int isBeginScriptTag(const char *z){
13e16c824a 2008-02-13       drh:   return z[0]=='<'
13e16c824a 2008-02-13       drh:       && (z[1]=='t' || z[1]=='T')
13e16c824a 2008-02-13       drh:       && (z[2]=='h' || z[2]=='H')
13e16c824a 2008-02-13       drh:       && z[3]=='1'
13e16c824a 2008-02-13       drh:       && z[4]=='>';
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** Return true if the string begins with the TH1 end-script
13e16c824a 2008-02-13       drh: ** tag:  </th1>.
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: static int isEndScriptTag(const char *z){
13e16c824a 2008-02-13       drh:   return z[0]=='<'
13e16c824a 2008-02-13       drh:       && z[1]=='/'
13e16c824a 2008-02-13       drh:       && (z[2]=='t' || z[2]=='T')
13e16c824a 2008-02-13       drh:       && (z[3]=='h' || z[3]=='H')
13e16c824a 2008-02-13       drh:       && z[4]=='1'
13e16c824a 2008-02-13       drh:       && z[5]=='>';
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
3ad9a5e210 2008-02-13       drh: ** If string z[0...] contains a valid variable name, return
3ad9a5e210 2008-02-13       drh: ** the number of characters in that name.  Otherwise, return 0.
3ad9a5e210 2008-02-13       drh: */
3ad9a5e210 2008-02-13       drh: static int validVarName(const char *z){
3ad9a5e210 2008-02-13       drh:   int i = 0;
ffe92f1a2f 2008-02-13       drh:   int inBracket = 0;
ffe92f1a2f 2008-02-13       drh:   if( z[0]=='<' ){
ffe92f1a2f 2008-02-13       drh:     inBracket = 1;
ffe92f1a2f 2008-02-13       drh:     z++;
ffe92f1a2f 2008-02-13       drh:   }
3ad9a5e210 2008-02-13       drh:   if( z[0]==':' && z[1]==':' && isalpha(z[2]) ){
3ad9a5e210 2008-02-13       drh:     z += 3;
ffe92f1a2f 2008-02-13       drh:     i += 3;
3ad9a5e210 2008-02-13       drh:   }else if( isalpha(z[0]) ){
3ad9a5e210 2008-02-13       drh:     z ++;
ffe92f1a2f 2008-02-13       drh:     i += 1;
3ad9a5e210 2008-02-13       drh:   }else{
3ad9a5e210 2008-02-13       drh:     return 0;
3ad9a5e210 2008-02-13       drh:   }
3ad9a5e210 2008-02-13       drh:   while( isalnum(z[0]) || z[0]=='_' ){
3ad9a5e210 2008-02-13       drh:     z++;
3ad9a5e210 2008-02-13       drh:     i++;
3ad9a5e210 2008-02-13       drh:   }
ffe92f1a2f 2008-02-13       drh:   if( inBracket ){
ffe92f1a2f 2008-02-13       drh:     if( z[0]!='>' ) return 0;
ffe92f1a2f 2008-02-13       drh:     i += 2;
ffe92f1a2f 2008-02-13       drh:   }
3ad9a5e210 2008-02-13       drh:   return i;
3ad9a5e210 2008-02-13       drh: }
3ad9a5e210 2008-02-13       drh: 
3ad9a5e210 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** The z[] input contains text mixed with TH1 scripts.
ffe92f1a2f 2008-02-13       drh: ** The TH1 scripts are contained within <th1>...</th1>.
ffe92f1a2f 2008-02-13       drh: ** TH1 variables are $aaa or $<aaa>.  The first form of
ffe92f1a2f 2008-02-13       drh: ** variable is literal.  The second is run through htmlize
ffe92f1a2f 2008-02-13       drh: ** before being inserted.
ffe92f1a2f 2008-02-13       drh: **
ffe92f1a2f 2008-02-13       drh: ** This routine processes the template and writes the results
ffe92f1a2f 2008-02-13       drh: ** on either stdout or into CGI.
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: int Th_Render(const char *z){
13e16c824a 2008-02-13       drh:   int i = 0;
3ad9a5e210 2008-02-13       drh:   int n;
13e16c824a 2008-02-13       drh:   int rc = TH_OK;
3ad9a5e210 2008-02-13       drh:   uchar *zResult;
fde1d82372 2008-02-13       drh:   Th_FossilInit();
13e16c824a 2008-02-13       drh:   while( z[i] ){
3ad9a5e210 2008-02-13       drh:     if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
ffe92f1a2f 2008-02-13       drh:       const char *zVar;
ffe92f1a2f 2008-02-13       drh:       int nVar;
ffe92f1a2f 2008-02-13       drh:       sendText(z, i, 0);
ffe92f1a2f 2008-02-13       drh:       if( z[i+1]=='<' ){
ffe92f1a2f 2008-02-13       drh:         /* Variables of the form $<aaa> */
ffe92f1a2f 2008-02-13       drh:         zVar = &z[i+2];
ffe92f1a2f 2008-02-13       drh:         nVar = n-2;
ffe92f1a2f 2008-02-13       drh:       }else{
ffe92f1a2f 2008-02-13       drh:         /* Variables of the form $aaa */
ffe92f1a2f 2008-02-13       drh:         zVar = &z[i+1];
ffe92f1a2f 2008-02-13       drh:         nVar = n;
ffe92f1a2f 2008-02-13       drh:       }
fde1d82372 2008-02-13       drh:       rc = Th_GetVar(g.interp, (uchar*)zVar, nVar);
3ad9a5e210 2008-02-13       drh:       z += i+1+n;
3ad9a5e210 2008-02-13       drh:       i = 0;
fde1d82372 2008-02-13       drh:       zResult = (uchar*)Th_GetResult(g.interp, &n);
ffe92f1a2f 2008-02-13       drh:       sendText((char*)zResult, n, n>nVar);
3ad9a5e210 2008-02-13       drh:     }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
ffe92f1a2f 2008-02-13       drh:       sendText(z, i, 0);
13e16c824a 2008-02-13       drh:       z += i+5;
13e16c824a 2008-02-13       drh:       for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
fde1d82372 2008-02-13       drh:       rc = Th_Eval(g.interp, 0, (const uchar*)z, i);
fde1d82372 2008-02-13       drh:       if( rc!=TH_OK ) break;
13e16c824a 2008-02-13       drh:       z += i;
13e16c824a 2008-02-13       drh:       if( z[0] ){ z += 6; }
13e16c824a 2008-02-13       drh:       i = 0;
13e16c824a 2008-02-13       drh:     }else{
13e16c824a 2008-02-13       drh:       i++;
13e16c824a 2008-02-13       drh:     }
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh:   if( rc==TH_ERROR ){
ffe92f1a2f 2008-02-13       drh:     sendText("<hr><p><font color=\"red\"><b>ERROR: ", -1, 0);
fde1d82372 2008-02-13       drh:     zResult = (uchar*)Th_GetResult(g.interp, &n);
ffe92f1a2f 2008-02-13       drh:     sendText((char*)zResult, n, 1);
ffe92f1a2f 2008-02-13       drh:     sendText("</b></font></p>", -1, 0);
13e16c824a 2008-02-13       drh:   }else{
ffe92f1a2f 2008-02-13       drh:     sendText(z, i, 0);
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh:   return rc;
13e16c824a 2008-02-13       drh: }
13e16c824a 2008-02-13       drh: 
13e16c824a 2008-02-13       drh: /*
13e16c824a 2008-02-13       drh: ** COMMAND: test-th-render
13e16c824a 2008-02-13       drh: */
13e16c824a 2008-02-13       drh: void test_th_render(void){
13e16c824a 2008-02-13       drh:   Blob in;
13e16c824a 2008-02-13       drh:   if( g.argc<3 ){
13e16c824a 2008-02-13       drh:     usage("FILE");
13e16c824a 2008-02-13       drh:   }
13e16c824a 2008-02-13       drh:   blob_zero(&in);
13e16c824a 2008-02-13       drh:   blob_read_from_file(&in, g.argv[2]);
13e16c824a 2008-02-13       drh:   Th_Render(blob_str(&in));
13e16c824a 2008-02-13       drh: }