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: f55c6a1b62 2008-10-24 drh: /* f55c6a1b62 2008-10-24 drh: ** Generate a TH1 trace message if debugging is enabled. f55c6a1b62 2008-10-24 drh: */ f55c6a1b62 2008-10-24 drh: void Th_Trace(const char *zFormat, ...){ f55c6a1b62 2008-10-24 drh: va_list ap; f55c6a1b62 2008-10-24 drh: va_start(ap, zFormat); f55c6a1b62 2008-10-24 drh: blob_vappendf(&g.thLog, zFormat, ap); f55c6a1b62 2008-10-24 drh: va_end(ap); f55c6a1b62 2008-10-24 drh: } f55c6a1b62 2008-10-24 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, 0c99a1554a 2008-10-24 drh: const 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, 0c99a1554a 2008-10-24 drh: const 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, 0c99a1554a 2008-10-24 drh: const 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, 0c99a1554a 2008-10-24 drh: const 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]); 0c99a1554a 2008-10-24 drh: Th_SetResult(interp, 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, 0c99a1554a 2008-10-24 drh: const 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')"); 0c99a1554a 2008-10-24 drh: Th_SetResult(interp, 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, 0c99a1554a 2008-10-24 drh: const char **argv, ffe92f1a2f 2008-02-13 drh: int *argl ffe92f1a2f 2008-02-13 drh: ){ f55c6a1b62 2008-10-24 drh: int rc; ffe92f1a2f 2008-02-13 drh: if( argc!=2 ){ ffe92f1a2f 2008-02-13 drh: return Th_WrongNumArgs(interp, "hascap STRING"); f55c6a1b62 2008-10-24 drh: } f55c6a1b62 2008-10-24 drh: rc = login_has_capability((char*)argv[1],argl[1]); f55c6a1b62 2008-10-24 drh: if( g.thTrace ){ f55c6a1b62 2008-10-24 drh: Th_Trace("[hascap %.*h] => %d<br />\n", argl[1], argv[1], rc); 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, 0c99a1554a 2008-10-24 drh: const 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; 0c99a1554a 2008-10-24 drh: Blob name; 3122fc4c7e 2008-02-14 drh: int nValue; 3122fc4c7e 2008-02-14 drh: const char *zValue; 3122fc4c7e 2008-02-14 drh: char *z, *zH; 0c99a1554a 2008-10-24 drh: int nElem; 0c99a1554a 2008-10-24 drh: int *aszElem; 0c99a1554a 2008-10-24 drh: char **azElem; 0c99a1554a 2008-10-24 drh: int i; 3122fc4c7e 2008-02-14 drh: 3122fc4c7e 2008-02-14 drh: if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR; 0c99a1554a 2008-10-24 drh: Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem); 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); 0c99a1554a 2008-10-24 drh: for(i=0; i<nElem; i++){ 0c99a1554a 2008-10-24 drh: zH = htmlize((char*)azElem[i], aszElem[i]); 0c99a1554a 2008-10-24 drh: if( zValue && aszElem[i]==nValue 0c99a1554a 2008-10-24 drh: && memcmp(zValue, azElem[i], 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); 0c99a1554a 2008-10-24 drh: Th_Free(interp, azElem); 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, 0c99a1554a 2008-10-24 drh: const char **argv, 3122fc4c7e 2008-02-14 drh: int *argl 3122fc4c7e 2008-02-14 drh: ){ 0c99a1554a 2008-10-24 drh: const char *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: /* f55c6a1b62 2008-10-24 drh: ** Make sure the interpreter has been initialized. Initialize it if f55c6a1b62 2008-10-24 drh: ** it has not been already. f55c6a1b62 2008-10-24 drh: ** f55c6a1b62 2008-10-24 drh: ** The interpreter is stored in the g.interp global variable. 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(); 449559394a 2008-07-20 drh: if( zValue ){ f55c6a1b62 2008-10-24 drh: if( g.thTrace ){ f55c6a1b62 2008-10-24 drh: Th_Trace("set %h {%h}<br />\n", zName, zValue); f55c6a1b62 2008-10-24 drh: } f55c6a1b62 2008-10-24 drh: Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue)); 449559394a 2008-07-20 drh: } 68c24b1857 2008-05-16 drh: } 68c24b1857 2008-05-16 drh: 68c24b1857 2008-05-16 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 ){ 0c99a1554a 2008-10-24 drh: Th_UnsetVar(g.interp, (char*)zName, -1); 68c24b1857 2008-05-16 drh: } fde1d82372 2008-02-13 drh: } fde1d82372 2008-02-13 drh: fde1d82372 2008-02-13 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(); 0c99a1554a 2008-10-24 drh: rc = Th_GetVar(g.interp, (char*)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; 0c99a1554a 2008-10-24 drh: char *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: } 0c99a1554a 2008-10-24 drh: rc = Th_GetVar(g.interp, (char*)zVar, nVar); 3ad9a5e210 2008-02-13 drh: z += i+1+n; 3ad9a5e210 2008-02-13 drh: i = 0; 0c99a1554a 2008-10-24 drh: zResult = (char*)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++){} 0c99a1554a 2008-10-24 drh: rc = Th_Eval(g.interp, 0, (const char*)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); 0c99a1554a 2008-10-24 drh: zResult = (char*)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: }