39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Copyright (c) 2007 D. Richard Hipp 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** This program is free software; you can redistribute it and/or 39aa870f8f 2007-10-14 drh: ** modify it under the terms of the GNU General Public 39aa870f8f 2007-10-14 drh: ** License version 2 as published by the Free Software Foundation. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** This program is distributed in the hope that it will be useful, 39aa870f8f 2007-10-14 drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of 39aa870f8f 2007-10-14 drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 39aa870f8f 2007-10-14 drh: ** General Public License for more details. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** You should have received a copy of the GNU General Public 39aa870f8f 2007-10-14 drh: ** License along with this library; if not, write to the 39aa870f8f 2007-10-14 drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, 39aa870f8f 2007-10-14 drh: ** Boston, MA 02111-1307, USA. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** Author contact information: 39aa870f8f 2007-10-14 drh: ** drh@hwaci.com 39aa870f8f 2007-10-14 drh: ** http://www.hwaci.com/drh/ 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ******************************************************************************* 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** This file contains an implementation of the "subscript" interpreter. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** Subscript attempts to be an extremely light-weight scripting 39aa870f8f 2007-10-14 drh: ** language. It contains the barest of bare essentials. It is 39aa870f8f 2007-10-14 drh: ** stack-based and forth-like. Everything is in a single global 39aa870f8f 2007-10-14 drh: ** namespace. There is only a single datatype of zero-terminated 8ffd32c2b7 2007-10-28 drh: ** string. The stack is of fixed, limited depth. The symbal table 39aa870f8f 2007-10-14 drh: ** is of a limited and fixed size. 8ffd32c2b7 2007-10-28 drh: ** 8ffd32c2b7 2007-10-28 drh: ** TOKENS: 8ffd32c2b7 2007-10-28 drh: ** 8ffd32c2b7 2007-10-28 drh: ** * All tokens are separated from each other by whitespace. 8ffd32c2b7 2007-10-28 drh: ** * Leading and trailing whitespace is ignored. 8ffd32c2b7 2007-10-28 drh: ** * Text within nested {...} is a single string token. The outermost 8ffd32c2b7 2007-10-28 drh: ** curly braces are not part of the token. 8ffd32c2b7 2007-10-28 drh: ** * An identifier with a leading "/" is a string token. 8ffd32c2b7 2007-10-28 drh: ** * A token that looks like a number is a string token. 8ffd32c2b7 2007-10-28 drh: ** * An identifier token is called a "verb". 8ffd32c2b7 2007-10-28 drh: ** 8ffd32c2b7 2007-10-28 drh: ** PROCESSING: 8ffd32c2b7 2007-10-28 drh: ** 8ffd32c2b7 2007-10-28 drh: ** * The input is divided into tokens. Whitespace is discarded. 8ffd32c2b7 2007-10-28 drh: ** String and verb tokens are passed into the engine. 8ffd32c2b7 2007-10-28 drh: ** * String tokens are pushed onto the stack. 8ffd32c2b7 2007-10-28 drh: ** * If a verb token corresponds to a procedure, that procedure is 8ffd32c2b7 2007-10-28 drh: ** run. The procedure might use, pop, or pull elements from 8ffd32c2b7 2007-10-28 drh: ** the stack. 8ffd32c2b7 2007-10-28 drh: ** * If a verb token corresponds to a variable, the value of that 8ffd32c2b7 2007-10-28 drh: ** variable is pushed onto the stack. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** This module attempts to be completely self-contained so that it can 39aa870f8f 2007-10-14 drh: ** be portable to other projects. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: #include "config.h" 39aa870f8f 2007-10-14 drh: #include "subscript.h" 39aa870f8f 2007-10-14 drh: #include <assert.h> 39aa870f8f 2007-10-14 drh: 8ef26c5e72 2007-11-03 drh: #if INTERFACE 8ef26c5e72 2007-11-03 drh: typedef struct Subscript Subscript; 8ef26c5e72 2007-11-03 drh: #define SBS_OK 0 8ef26c5e72 2007-11-03 drh: #define SBS_ERROR 1 fb358ca492 2007-11-24 drh: #define SBS_RETURN 2 fb358ca492 2007-11-24 drh: #define SBS_BREAK 3 8ef26c5e72 2007-11-03 drh: #endif 8ef26c5e72 2007-11-03 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Configuration constants 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: #define SBSCONFIG_NHASH 41 /* Size of the hash table */ a5e4e1ba96 2007-11-24 drh: #define SBSCONFIG_NSTACK 20 /* Maximum stack depth */ 39aa870f8f 2007-10-14 drh: #define SBSCONFIG_ERRSIZE 100 /* Maximum size of an error message */ 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Available token types: 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: #define SBSTT_WHITESPACE 1 /* ex: \040 */ 39aa870f8f 2007-10-14 drh: #define SBSTT_NAME 2 /* ex: /abcde */ 39aa870f8f 2007-10-14 drh: #define SBSTT_VERB 3 /* ex: abcde */ 39aa870f8f 2007-10-14 drh: #define SBSTT_STRING 4 /* ex: {...} */ a5e4e1ba96 2007-11-24 drh: #define SBSTT_QUOTED 5 /* ex: "...\n..." */ a5e4e1ba96 2007-11-24 drh: #define SBSTT_INTEGER 6 /* Integer including option sign */ a5e4e1ba96 2007-11-24 drh: #define SBSTT_INCOMPLETE 7 /* Unterminated string token */ a5e4e1ba96 2007-11-24 drh: #define SBSTT_UNKNOWN 8 /* Unknown token */ a5e4e1ba96 2007-11-24 drh: #define SBSTT_EOF 9 /* End of input */ 929d28e358 2007-11-05 drh: 929d28e358 2007-11-05 drh: /* 929d28e358 2007-11-05 drh: ** Values are stored in the hash table as instances of the following 929d28e358 2007-11-05 drh: ** structure. 929d28e358 2007-11-05 drh: */ 929d28e358 2007-11-05 drh: typedef struct SbSValue SbSValue; 929d28e358 2007-11-05 drh: struct SbSValue { 929d28e358 2007-11-05 drh: int flags; /* Bitmask of SBSVAL_* values */ 929d28e358 2007-11-05 drh: union { 929d28e358 2007-11-05 drh: struct { 929d28e358 2007-11-05 drh: int size; /* Number of bytes in string, not counting final zero */ 929d28e358 2007-11-05 drh: char *z; /* Pointer to string content */ 929d28e358 2007-11-05 drh: } str; /* Value if SBSVAL_STR */ 929d28e358 2007-11-05 drh: struct { 929d28e358 2007-11-05 drh: int (*xVerb)(Subscript*, void*); /* Function to do the work */ 929d28e358 2007-11-05 drh: void *pArg; /* 2nd parameter to xVerb */ 929d28e358 2007-11-05 drh: } verb; /* Value if SBSVAL_VERB */ 929d28e358 2007-11-05 drh: } u; 929d28e358 2007-11-05 drh: }; 929d28e358 2007-11-05 drh: #define SBSVAL_VERB 0x0001 /* Value stored in u.verb */ 929d28e358 2007-11-05 drh: #define SBSVAL_STR 0x0002 /* Value stored in u.str */ 929d28e358 2007-11-05 drh: #define SBSVAL_DYN 0x0004 /* u.str.z is dynamically allocated */ 929d28e358 2007-11-05 drh: #define SBSVAL_EXEC 0x0008 /* u.str.z is a script */ 929d28e358 2007-11-05 drh: 929d28e358 2007-11-05 drh: /* 929d28e358 2007-11-05 drh: ** An entry in the hash table is an instance of this structure. 929d28e358 2007-11-05 drh: */ 929d28e358 2007-11-05 drh: typedef struct SbsHashEntry SbsHashEntry; 929d28e358 2007-11-05 drh: struct SbsHashEntry { 929d28e358 2007-11-05 drh: SbsHashEntry *pNext; /* Next entry with the same hash on zKey */ 929d28e358 2007-11-05 drh: SbSValue val; /* The payload */ 929d28e358 2007-11-05 drh: int nKey; /* Length of the key */ 34af72801d 2007-11-23 drh: char zKey[1]; /* The key */ 929d28e358 2007-11-05 drh: }; 929d28e358 2007-11-05 drh: 929d28e358 2007-11-05 drh: /* 929d28e358 2007-11-05 drh: ** A hash table is an instance of the following structure. 929d28e358 2007-11-05 drh: */ 929d28e358 2007-11-05 drh: typedef struct SbsHashTab SbsHashTab; 929d28e358 2007-11-05 drh: struct SbsHashTab { 929d28e358 2007-11-05 drh: SbsHashEntry *aHash[SBSCONFIG_NHASH]; /* The hash table */ 929d28e358 2007-11-05 drh: }; 929d28e358 2007-11-05 drh: 929d28e358 2007-11-05 drh: /* 929d28e358 2007-11-05 drh: ** An instance of the Subscript interpreter 929d28e358 2007-11-05 drh: */ 929d28e358 2007-11-05 drh: struct Subscript { 8c96ed62f5 2007-11-17 drh: int nStack; /* Number of entries on stack */ 8c96ed62f5 2007-11-17 drh: SbsHashTab symTab; /* The symbol table */ 8c96ed62f5 2007-11-17 drh: char zErrMsg[SBSCONFIG_ERRSIZE]; /* Space to write an error message */ 929d28e358 2007-11-05 drh: SbSValue aStack[SBSCONFIG_NSTACK]; /* The stack */ 929d28e358 2007-11-05 drh: }; 929d28e358 2007-11-05 drh: 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Given an input string z of length n, identify the token that 39aa870f8f 2007-10-14 drh: ** starts at z[0]. Write the token type into *pTokenType and 39aa870f8f 2007-10-14 drh: ** return the length of the token. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: static int sbs_next_token(const char *z, int n, int *pTokenType){ 39aa870f8f 2007-10-14 drh: int c; 39aa870f8f 2007-10-14 drh: if( n<=0 || z[0]==0 ){ 39aa870f8f 2007-10-14 drh: *pTokenType = SBSTT_EOF; 39aa870f8f 2007-10-14 drh: return 0; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: c = z[0]; 39aa870f8f 2007-10-14 drh: if( isspace(c) ){ 39aa870f8f 2007-10-14 drh: int i; 39aa870f8f 2007-10-14 drh: *pTokenType = SBSTT_WHITESPACE; 39aa870f8f 2007-10-14 drh: for(i=1; i<n && isspace(z[i]); i++){} 39aa870f8f 2007-10-14 drh: return i; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: if( c=='#' ){ 39aa870f8f 2007-10-14 drh: int i; 39aa870f8f 2007-10-14 drh: for(i=1; i<n && z[i] && z[i-1]!='\n'; i++){} 39aa870f8f 2007-10-14 drh: *pTokenType = SBSTT_WHITESPACE; 39aa870f8f 2007-10-14 drh: return i; a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: if( c=='"' ){ a5e4e1ba96 2007-11-24 drh: int i; a5e4e1ba96 2007-11-24 drh: for(i=1; i<n && z[i] && z[i]!='"'; i++){ a5e4e1ba96 2007-11-24 drh: if( z[i]=='\\' && i<n-1 ){ i++; } a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: if( z[i]=='"' ){ a5e4e1ba96 2007-11-24 drh: *pTokenType = SBSTT_QUOTED; a5e4e1ba96 2007-11-24 drh: return i+1; a5e4e1ba96 2007-11-24 drh: }else{ a5e4e1ba96 2007-11-24 drh: *pTokenType = SBSTT_INCOMPLETE; a5e4e1ba96 2007-11-24 drh: return i; a5e4e1ba96 2007-11-24 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: if( c=='{' ){ 39aa870f8f 2007-10-14 drh: int depth = 1; 39aa870f8f 2007-10-14 drh: int i; 39aa870f8f 2007-10-14 drh: for(i=1; i<n && z[i]; i++){ 39aa870f8f 2007-10-14 drh: if( z[i]=='{' ){ 39aa870f8f 2007-10-14 drh: depth++; 39aa870f8f 2007-10-14 drh: }else if( z[i]=='}' ){ 39aa870f8f 2007-10-14 drh: depth--; 39aa870f8f 2007-10-14 drh: if( depth==0 ){ 39aa870f8f 2007-10-14 drh: i++; 39aa870f8f 2007-10-14 drh: break; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: if( depth ){ 39aa870f8f 2007-10-14 drh: *pTokenType = SBSTT_INCOMPLETE; 39aa870f8f 2007-10-14 drh: }else{ 39aa870f8f 2007-10-14 drh: *pTokenType = SBSTT_STRING; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: return i; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: if( c=='/' && n>=2 && isalpha(z[1]) ){ 39aa870f8f 2007-10-14 drh: int i; 39aa870f8f 2007-10-14 drh: for(i=2; i<n && (isalnum(z[i]) || z[i]=='_'); i++){} 39aa870f8f 2007-10-14 drh: *pTokenType = SBSTT_NAME; 39aa870f8f 2007-10-14 drh: return i; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: if( isalpha(c) ){ 39aa870f8f 2007-10-14 drh: int i; 39aa870f8f 2007-10-14 drh: for(i=1; i<n && (isalnum(z[i]) || z[i]=='_'); i++){} 39aa870f8f 2007-10-14 drh: *pTokenType = SBSTT_VERB; 39aa870f8f 2007-10-14 drh: return i; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: if( isdigit(c) || ((c=='-' || c=='+') && n>=2 && isdigit(z[1])) ){ 39aa870f8f 2007-10-14 drh: int i; 39aa870f8f 2007-10-14 drh: for(i=1; i<n && isdigit(z[i]); i++){} 39aa870f8f 2007-10-14 drh: *pTokenType = SBSTT_INTEGER; 39aa870f8f 2007-10-14 drh: return i; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: *pTokenType = SBSTT_UNKNOWN; 39aa870f8f 2007-10-14 drh: return 1; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Release any memory allocated by a value. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: static void sbs_value_reset(SbSValue *p){ 39aa870f8f 2007-10-14 drh: if( p->flags & SBSVAL_DYN ){ 39aa870f8f 2007-10-14 drh: free(p->u.str.z); 39aa870f8f 2007-10-14 drh: p->flags = SBSVAL_STR; 39aa870f8f 2007-10-14 drh: p->u.str.z = ""; 39aa870f8f 2007-10-14 drh: p->u.str.size = 0; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Compute a hash on a string. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: static int sbs_hash(const char *z, int n){ 39aa870f8f 2007-10-14 drh: int h = 0; 39aa870f8f 2007-10-14 drh: int i; 39aa870f8f 2007-10-14 drh: for(i=0; i<n; i++){ 39aa870f8f 2007-10-14 drh: h ^= (h<<1) | z[i]; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: h &= 0x7ffffff; 39aa870f8f 2007-10-14 drh: return h % SBSCONFIG_NHASH; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Look up a value in the hash table. Return a pointer to the value. 39aa870f8f 2007-10-14 drh: ** Return NULL if not found. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: static const SbSValue *sbs_fetch( 8ef26c5e72 2007-11-03 drh: SbsHashTab *pHash, 39aa870f8f 2007-10-14 drh: const char *zKey, 39aa870f8f 2007-10-14 drh: int nKey 39aa870f8f 2007-10-14 drh: ){ 39aa870f8f 2007-10-14 drh: int h; 8ef26c5e72 2007-11-03 drh: SbsHashEntry *p; 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: if( nKey<0 ) nKey = strlen(zKey); 39aa870f8f 2007-10-14 drh: h = sbs_hash(zKey, nKey); 39aa870f8f 2007-10-14 drh: for(p = pHash->aHash[h]; p; p=p->pNext){ 39aa870f8f 2007-10-14 drh: if( p->nKey==nKey && memcmp(p->zKey,zKey,nKey)==0 ){ 39aa870f8f 2007-10-14 drh: return &p->val; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: return 0; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Store a value in the hash table. Overwrite any prior value stored 39aa870f8f 2007-10-14 drh: ** under the same name. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** If the value in the 4th argument needs to be reset or freed, 39aa870f8f 2007-10-14 drh: ** the hash table will take over responsibiliity for doing so. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: static int sbs_store( 8ef26c5e72 2007-11-03 drh: SbsHashTab *pHash, /* Insert into this hash table */ 8ef26c5e72 2007-11-03 drh: const char *zKey, /* The key */ 8ef26c5e72 2007-11-03 drh: int nKey, /* Size of the key */ 39aa870f8f 2007-10-14 drh: const SbSValue *pValue /* The value to be stored */ 39aa870f8f 2007-10-14 drh: ){ 39aa870f8f 2007-10-14 drh: int h; 8ef26c5e72 2007-11-03 drh: SbsHashEntry *p, *pNew; 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: if( nKey<0 ) nKey = strlen(zKey); 39aa870f8f 2007-10-14 drh: h = sbs_hash(zKey, nKey); 39aa870f8f 2007-10-14 drh: for(p = pHash->aHash[h]; p; p=p->pNext){ 39aa870f8f 2007-10-14 drh: if( p->nKey==nKey && memcmp(p->zKey,zKey,nKey)==0 ){ 39aa870f8f 2007-10-14 drh: sbs_value_reset(&p->val); 39aa870f8f 2007-10-14 drh: memcpy(&p->val, pValue, sizeof(p->val)); 39aa870f8f 2007-10-14 drh: return SBS_OK; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: pNew = malloc( sizeof(*pNew) + nKey ); 39aa870f8f 2007-10-14 drh: if( pNew ){ 39aa870f8f 2007-10-14 drh: pNew->nKey = nKey; 39aa870f8f 2007-10-14 drh: memcpy(pNew->zKey, zKey, nKey+1); 39aa870f8f 2007-10-14 drh: memcpy(&pNew->val, pValue, sizeof(pNew->val)); 39aa870f8f 2007-10-14 drh: pNew->pNext = pHash->aHash[h]; 39aa870f8f 2007-10-14 drh: pHash->aHash[h] = pNew; 39aa870f8f 2007-10-14 drh: return SBS_OK; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: return SBS_ERROR; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Reset a hash table. 39aa870f8f 2007-10-14 drh: */ 8ef26c5e72 2007-11-03 drh: static void sbs_hash_reset(SbsHashTab *pHash){ 39aa870f8f 2007-10-14 drh: int i; 8ef26c5e72 2007-11-03 drh: SbsHashEntry *p, *pNext; 39aa870f8f 2007-10-14 drh: for(i=0; i<SBSCONFIG_NHASH; i++){ 39aa870f8f 2007-10-14 drh: for(p=pHash->aHash[i]; p; p=pNext){ 39aa870f8f 2007-10-14 drh: pNext = p->pNext; 39aa870f8f 2007-10-14 drh: sbs_value_reset(&p->val); 39aa870f8f 2007-10-14 drh: free(p); 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: memset(pHash, 0, sizeof(*pHash)); 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Push a value onto the stack of an interpreter 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: static int sbs_push(Subscript *p, SbSValue *pVal){ 39aa870f8f 2007-10-14 drh: if( p->nStack>=SBSCONFIG_NSTACK ){ 39aa870f8f 2007-10-14 drh: sqlite3_snprintf(SBSCONFIG_ERRSIZE, p->zErrMsg, "stack overflow"); 39aa870f8f 2007-10-14 drh: return SBS_ERROR; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: p->aStack[p->nStack++] = *pVal; 39aa870f8f 2007-10-14 drh: return SBS_OK; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 929d28e358 2007-11-05 drh: ** Create a new subscript interpreter. Return a pointer to the 929d28e358 2007-11-05 drh: ** new interpreter, or return NULL if malloc fails. 929d28e358 2007-11-05 drh: */ 929d28e358 2007-11-05 drh: struct Subscript *SbS_Create(void){ 929d28e358 2007-11-05 drh: Subscript *p; 929d28e358 2007-11-05 drh: p = malloc( sizeof(*p) ); 929d28e358 2007-11-05 drh: if( p ){ 929d28e358 2007-11-05 drh: memset(p, 0, sizeof(*p)); 929d28e358 2007-11-05 drh: } 929d28e358 2007-11-05 drh: return p; 8ffd32c2b7 2007-10-28 drh: } 8ffd32c2b7 2007-10-28 drh: 8ffd32c2b7 2007-10-28 drh: /* 8ffd32c2b7 2007-10-28 drh: ** Destroy an subscript interpreter 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: void SbS_Destroy(struct Subscript *p){ 39aa870f8f 2007-10-14 drh: int i; 39aa870f8f 2007-10-14 drh: sbs_hash_reset(&p->symTab); 39aa870f8f 2007-10-14 drh: for(i=0; i<p->nStack; i++){ 39aa870f8f 2007-10-14 drh: sbs_value_reset(&p->aStack[i]); 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: free(p); 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Set the error message for an interpreter. Verb implementations 39aa870f8f 2007-10-14 drh: ** use this routine when they encounter an error. 39aa870f8f 2007-10-14 drh: */ fb358ca492 2007-11-24 drh: void SbS_SetErrorMessage(struct Subscript *p, const char *zErr, ...){ fb358ca492 2007-11-24 drh: int nErr; fb358ca492 2007-11-24 drh: char *zMsg; fb358ca492 2007-11-24 drh: va_list ap; fb358ca492 2007-11-24 drh: fb358ca492 2007-11-24 drh: va_start(ap, zErr); fb358ca492 2007-11-24 drh: zMsg = vmprintf(zErr, ap); fb358ca492 2007-11-24 drh: va_end(ap); fb358ca492 2007-11-24 drh: nErr = strlen(zMsg); 39aa870f8f 2007-10-14 drh: if( nErr>sizeof(p->zErrMsg)-1 ){ 39aa870f8f 2007-10-14 drh: nErr = sizeof(p->zErrMsg)-1; 39aa870f8f 2007-10-14 drh: } fb358ca492 2007-11-24 drh: memcpy(p->zErrMsg, zMsg, nErr); 39aa870f8f 2007-10-14 drh: p->zErrMsg[nErr] = 0; fb358ca492 2007-11-24 drh: free(zMsg); 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Return a pointer to the current error message for the 39aa870f8f 2007-10-14 drh: ** interpreter. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: const char *SbS_GetErrorMessage(struct Subscript *p){ 39aa870f8f 2007-10-14 drh: return p->zErrMsg; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Add a new verb the given interpreter 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: int SbS_AddVerb( 39aa870f8f 2007-10-14 drh: struct Subscript *p, 39aa870f8f 2007-10-14 drh: const char *zVerb, 39aa870f8f 2007-10-14 drh: int (*xVerb)(struct Subscript*,void*), 39aa870f8f 2007-10-14 drh: void *pArg 39aa870f8f 2007-10-14 drh: ){ 39aa870f8f 2007-10-14 drh: SbSValue v; 39aa870f8f 2007-10-14 drh: v.flags = SBSVAL_VERB; 39aa870f8f 2007-10-14 drh: v.u.verb.xVerb = xVerb; 39aa870f8f 2007-10-14 drh: v.u.verb.pArg = pArg; 39aa870f8f 2007-10-14 drh: return sbs_store(&p->symTab, zVerb, -1, &v); 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 555911dff5 2007-11-21 drh: ** Store a value in an interpreter variable. 555911dff5 2007-11-21 drh: */ 555911dff5 2007-11-21 drh: int SbS_Store( 555911dff5 2007-11-21 drh: struct Subscript *p, /* Store into this interpreter */ 555911dff5 2007-11-21 drh: const char *zName, /* Name of the variable */ 555911dff5 2007-11-21 drh: const char *zValue, /* Value of the variable */ 34af72801d 2007-11-23 drh: int persistence /* 0: static. 1: ephemeral. 2: dynamic */ 555911dff5 2007-11-21 drh: ){ 555911dff5 2007-11-21 drh: SbSValue v; 555911dff5 2007-11-21 drh: v.flags = SBSVAL_STR; 555911dff5 2007-11-21 drh: v.u.str.size = strlen(zValue); 34af72801d 2007-11-23 drh: if( persistence==1 ){ 555911dff5 2007-11-21 drh: v.u.str.z = mprintf("%s", zValue); 555911dff5 2007-11-21 drh: }else{ 2a707334c9 2007-11-22 drh: v.u.str.z = (char*)zValue; 34af72801d 2007-11-23 drh: } 34af72801d 2007-11-23 drh: if( persistence>0 ){ 34af72801d 2007-11-23 drh: v.flags |= SBSVAL_DYN; 555911dff5 2007-11-21 drh: } 555911dff5 2007-11-21 drh: return sbs_store(&p->symTab, zName, -1, &v); 8ef26c5e72 2007-11-03 drh: } 8ef26c5e72 2007-11-03 drh: 8ef26c5e72 2007-11-03 drh: /* 39aa870f8f 2007-10-14 drh: ** Push a string value onto the stack. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** If the 4th parameter is 0, then the string is static. 39aa870f8f 2007-10-14 drh: ** If the 4th parameter is non-zero then the string was obtained 39aa870f8f 2007-10-14 drh: ** from malloc and Subscript will take responsibility for freeing 39aa870f8f 2007-10-14 drh: ** it. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** Return 0 on success and non-zero if there is an error. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: int SbS_Push( 39aa870f8f 2007-10-14 drh: struct Subscript *p, /* Push onto this interpreter */ 8ef26c5e72 2007-11-03 drh: char *z, /* String value to push */ 8ef26c5e72 2007-11-03 drh: int n, /* Length of the string, or -1 */ 8ef26c5e72 2007-11-03 drh: int dyn /* If true, z was obtained from malloc */ 39aa870f8f 2007-10-14 drh: ){ 39aa870f8f 2007-10-14 drh: SbSValue v; 39aa870f8f 2007-10-14 drh: v.flags = SBSVAL_STR; 8ef26c5e72 2007-11-03 drh: if( dyn ){ 39aa870f8f 2007-10-14 drh: v.flags |= SBSVAL_DYN; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: if( n<0 ) n = strlen(z); 39aa870f8f 2007-10-14 drh: v.u.str.size = n; 39aa870f8f 2007-10-14 drh: v.u.str.z = z; 39aa870f8f 2007-10-14 drh: return sbs_push(p, &v); 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Push an integer value onto the stack. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** This routine really just converts the integer into a string 39aa870f8f 2007-10-14 drh: ** then calls SbS_Push. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: int SbS_PushInt(struct Subscript *p, int iVal){ 39aa870f8f 2007-10-14 drh: if( iVal==0 ){ 39aa870f8f 2007-10-14 drh: return SbS_Push(p, "0", 1, 0); 39aa870f8f 2007-10-14 drh: }else if( iVal==1 ){ 39aa870f8f 2007-10-14 drh: return SbS_Push(p, "1", 1, 0); 39aa870f8f 2007-10-14 drh: }else{ 39aa870f8f 2007-10-14 drh: char *z; 39aa870f8f 2007-10-14 drh: int n; 39aa870f8f 2007-10-14 drh: char zVal[50]; 39aa870f8f 2007-10-14 drh: sprintf(zVal, "%d", iVal); 39aa870f8f 2007-10-14 drh: n = strlen(zVal); 39aa870f8f 2007-10-14 drh: z = malloc( n+1 ); 39aa870f8f 2007-10-14 drh: if( z ){ 39aa870f8f 2007-10-14 drh: strcpy(z, zVal); 39aa870f8f 2007-10-14 drh: return SbS_Push(p, z, n, 1); 39aa870f8f 2007-10-14 drh: }else{ 39aa870f8f 2007-10-14 drh: return SBS_ERROR; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Pop and destroy zero or more values from the stack. 39aa870f8f 2007-10-14 drh: ** Return the number of values remaining on the stack after 39aa870f8f 2007-10-14 drh: ** the pops occur. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: int SbS_Pop(struct Subscript *p, int N){ 39aa870f8f 2007-10-14 drh: while( N>0 && p->nStack>0 ){ 39aa870f8f 2007-10-14 drh: p->nStack--; 39aa870f8f 2007-10-14 drh: sbs_value_reset(&p->aStack[p->nStack]); 39aa870f8f 2007-10-14 drh: N--; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: return p->nStack; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Return the N-th element of the stack. 0 is the top of the stack. 39aa870f8f 2007-10-14 drh: ** 1 is the first element down. 2 is the second element. And so forth. 39aa870f8f 2007-10-14 drh: ** Return NULL if there is no N-th element. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** The pointer returned is only valid until the value is popped 39aa870f8f 2007-10-14 drh: ** from the stack. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: const char *SbS_StackValue(struct Subscript *p, int N, int *pSize){ 39aa870f8f 2007-10-14 drh: SbSValue *pVal; 39aa870f8f 2007-10-14 drh: if( N<0 || N>=p->nStack ){ 39aa870f8f 2007-10-14 drh: return 0; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: pVal = &p->aStack[p->nStack-N-1]; 39aa870f8f 2007-10-14 drh: if( (pVal->flags & SBSVAL_STR)==0 ){ 39aa870f8f 2007-10-14 drh: return 0; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: *pSize = pVal->u.str.size; 39aa870f8f 2007-10-14 drh: return pVal->u.str.z; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** A convenience routine for extracting an integer value from the 39aa870f8f 2007-10-14 drh: ** stack. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: int SbS_StackValueInt(struct Subscript *p, int N){ 39aa870f8f 2007-10-14 drh: int n, v; 39aa870f8f 2007-10-14 drh: int isNeg = 0; 8ef26c5e72 2007-11-03 drh: const char *z = SbS_StackValue(p, N, &n); 39aa870f8f 2007-10-14 drh: v = 0; 39aa870f8f 2007-10-14 drh: if( n==0 ) return 0; 39aa870f8f 2007-10-14 drh: if( z[0]=='-' ){ 39aa870f8f 2007-10-14 drh: isNeg = 1; 39aa870f8f 2007-10-14 drh: z++; 39aa870f8f 2007-10-14 drh: n--; 39aa870f8f 2007-10-14 drh: }else if( z[0]=='+' ){ 39aa870f8f 2007-10-14 drh: z++; 39aa870f8f 2007-10-14 drh: n--; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: while( n>0 && isdigit(z[0]) ){ 39aa870f8f 2007-10-14 drh: v = v*10 + z[0] - '0'; 39aa870f8f 2007-10-14 drh: z++; 39aa870f8f 2007-10-14 drh: n--; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: if( isNeg ){ 39aa870f8f 2007-10-14 drh: v = -v; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: return v; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Retrieve the value of a variable from the interpreter. Return 39aa870f8f 2007-10-14 drh: ** NULL if no such variable is defined. 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** The returned string is not necessarily (probably not) zero-terminated. 39aa870f8f 2007-10-14 drh: ** The string may be deallocated the next time anything is done to 39aa870f8f 2007-10-14 drh: ** the interpreter. Make a copy if you need it to persist. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: const char *SbS_Fetch( 39aa870f8f 2007-10-14 drh: struct Subscript *p, /* The interpreter we are interrogating */ 39aa870f8f 2007-10-14 drh: const char *zKey, /* Name of the variable. Case sensitive */ fb358ca492 2007-11-24 drh: int nKey, /* Length of the key */ 39aa870f8f 2007-10-14 drh: int *pLength /* Write the length here */ 39aa870f8f 2007-10-14 drh: ){ 8ef26c5e72 2007-11-03 drh: const SbSValue *pVal; 8ef26c5e72 2007-11-03 drh: fb358ca492 2007-11-24 drh: pVal = sbs_fetch(&p->symTab, zKey, nKey); 39aa870f8f 2007-10-14 drh: if( pVal==0 || (pVal->flags & SBSVAL_STR)==0 ){ 39aa870f8f 2007-10-14 drh: *pLength = 0; 39aa870f8f 2007-10-14 drh: return 0; 39aa870f8f 2007-10-14 drh: }else{ 39aa870f8f 2007-10-14 drh: *pLength = pVal->u.str.size; 39aa870f8f 2007-10-14 drh: return pVal->u.str.z; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Generate an error and return non-zero if the stack has 39aa870f8f 2007-10-14 drh: ** fewer than N elements. This is utility routine used in 39aa870f8f 2007-10-14 drh: ** the implementation of verbs. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: int SbS_RequireStack(struct Subscript *p, int N, const char *zCmd){ 8ef26c5e72 2007-11-03 drh: if( p->nStack>=N ) return 0; 39aa870f8f 2007-10-14 drh: sqlite3_snprintf(sizeof(p->zErrMsg), p->zErrMsg, 39aa870f8f 2007-10-14 drh: "\"%s\" requires at least %d stack elements - only found %d", 39aa870f8f 2007-10-14 drh: zCmd, N, p->nStack); 39aa870f8f 2007-10-14 drh: return 1; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 8ef26c5e72 2007-11-03 drh: ** Subscript command: STRING NAME set 39aa870f8f 2007-10-14 drh: ** 39aa870f8f 2007-10-14 drh: ** Write the value of STRING into variable called NAME. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: static int setCmd(Subscript *p, void *pNotUsed){ 39aa870f8f 2007-10-14 drh: SbSValue *pTos; 39aa870f8f 2007-10-14 drh: SbSValue *pNos; 39aa870f8f 2007-10-14 drh: if( SbS_RequireStack(p, 2, "set") ) return SBS_ERROR; 8ef26c5e72 2007-11-03 drh: pTos = &p->aStack[--p->nStack]; 8ef26c5e72 2007-11-03 drh: pNos = &p->aStack[--p->nStack]; 39aa870f8f 2007-10-14 drh: sbs_store(&p->symTab, pTos->u.str.z, pTos->u.str.size, pNos); 39aa870f8f 2007-10-14 drh: sbs_value_reset(pTos); 39aa870f8f 2007-10-14 drh: return 0; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 8ef26c5e72 2007-11-03 drh: /* 8ef26c5e72 2007-11-03 drh: ** Subscript command: INTEGER not INTEGER 8ef26c5e72 2007-11-03 drh: */ 8ef26c5e72 2007-11-03 drh: static int notCmd(struct Subscript *p, void *pNotUsed){ 8ef26c5e72 2007-11-03 drh: int n; 8ef26c5e72 2007-11-03 drh: if( SbS_RequireStack(p, 1, "not") ) return 1; 8ef26c5e72 2007-11-03 drh: n = SbS_StackValueInt(p, 0); 8ef26c5e72 2007-11-03 drh: SbS_Pop(p, 1); 8ef26c5e72 2007-11-03 drh: SbS_PushInt(p, !n); 8ef26c5e72 2007-11-03 drh: return 0; 8ef26c5e72 2007-11-03 drh: } 8ef26c5e72 2007-11-03 drh: 92f6081d11 2007-11-03 drh: #define SBSOP_ADD 1 92f6081d11 2007-11-03 drh: #define SBSOP_SUB 2 92f6081d11 2007-11-03 drh: #define SBSOP_MUL 3 92f6081d11 2007-11-03 drh: #define SBSOP_DIV 4 92f6081d11 2007-11-03 drh: #define SBSOP_AND 5 92f6081d11 2007-11-03 drh: #define SBSOP_OR 6 92f6081d11 2007-11-03 drh: #define SBSOP_MIN 7 92f6081d11 2007-11-03 drh: #define SBSOP_MAX 8 a5e4e1ba96 2007-11-24 drh: #define SBSOP_EQ 9 a5e4e1ba96 2007-11-24 drh: #define SBSOP_NE 10 a5e4e1ba96 2007-11-24 drh: #define SBSOP_LT 11 a5e4e1ba96 2007-11-24 drh: #define SBSOP_GT 12 a5e4e1ba96 2007-11-24 drh: #define SBSOP_LE 13 a5e4e1ba96 2007-11-24 drh: #define SBSOP_GE 14 92f6081d11 2007-11-03 drh: 92f6081d11 2007-11-03 drh: /* 92f6081d11 2007-11-03 drh: ** Subscript command: INTEGER INTEGER <binary-op> INTEGER 92f6081d11 2007-11-03 drh: */ 92f6081d11 2007-11-03 drh: static int bopCmd(struct Subscript *p, void *pOp){ 92f6081d11 2007-11-03 drh: int a, b, c; 92f6081d11 2007-11-03 drh: if( SbS_RequireStack(p, 2, "BINARY-OP") ) return 1; a5e4e1ba96 2007-11-24 drh: a = SbS_StackValueInt(p, 1); a5e4e1ba96 2007-11-24 drh: b = SbS_StackValueInt(p, 0); 92f6081d11 2007-11-03 drh: switch( (int)pOp ){ a5e4e1ba96 2007-11-24 drh: case SBSOP_EQ: c = a==b; break; a5e4e1ba96 2007-11-24 drh: case SBSOP_NE: c = a!=b; break; a5e4e1ba96 2007-11-24 drh: case SBSOP_LT: c = a<b; break; a5e4e1ba96 2007-11-24 drh: case SBSOP_LE: c = a<=b; break; a5e4e1ba96 2007-11-24 drh: case SBSOP_GT: c = a>b; break; a5e4e1ba96 2007-11-24 drh: case SBSOP_GE: c = a>=b; break; 92f6081d11 2007-11-03 drh: case SBSOP_ADD: c = a+b; break; 92f6081d11 2007-11-03 drh: case SBSOP_SUB: c = a-b; break; 92f6081d11 2007-11-03 drh: case SBSOP_MUL: c = a*b; break; 92f6081d11 2007-11-03 drh: case SBSOP_DIV: c = b!=0 ? a/b : 0; break; 92f6081d11 2007-11-03 drh: case SBSOP_AND: c = a && b; break; 929d28e358 2007-11-05 drh: case SBSOP_OR: c = a || b; break; 92f6081d11 2007-11-03 drh: case SBSOP_MIN: c = a<b ? a : b; break; 92f6081d11 2007-11-03 drh: case SBSOP_MAX: c = a<b ? b : a; break; 92f6081d11 2007-11-03 drh: } 8ef26c5e72 2007-11-03 drh: SbS_Pop(p, 2); 92f6081d11 2007-11-03 drh: SbS_PushInt(p, c); 8ef26c5e72 2007-11-03 drh: return 0; 8ef26c5e72 2007-11-03 drh: } 8ef26c5e72 2007-11-03 drh: 8ef26c5e72 2007-11-03 drh: /* a5e4e1ba96 2007-11-24 drh: ** Subscript command: STRING STRING streq INTEGER a5e4e1ba96 2007-11-24 drh: */ a5e4e1ba96 2007-11-24 drh: static int streqCmd(struct Subscript *p, void *pOp){ a5e4e1ba96 2007-11-24 drh: int c, nA, nB; a5e4e1ba96 2007-11-24 drh: const char *A, *B; a5e4e1ba96 2007-11-24 drh: a5e4e1ba96 2007-11-24 drh: if( SbS_RequireStack(p, 2, "BINARY-OP") ) return 1; a5e4e1ba96 2007-11-24 drh: A = SbS_StackValue(p, 1, &nA); a5e4e1ba96 2007-11-24 drh: B = SbS_StackValue(p, 0, &nB); a5e4e1ba96 2007-11-24 drh: c = nA==nB && memcmp(A,B,nA)==0; 8ef26c5e72 2007-11-03 drh: SbS_Pop(p, 2); 8c96ed62f5 2007-11-17 drh: SbS_PushInt(p, c); 8c96ed62f5 2007-11-17 drh: return 0; 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: /* 929d28e358 2007-11-05 drh: ** Subscript command: STRING hascap INTEGER 929d28e358 2007-11-05 drh: ** 929d28e358 2007-11-05 drh: ** Return true if the user has all of the capabilities listed. 929d28e358 2007-11-05 drh: */ 929d28e358 2007-11-05 drh: static int hascapCmd(struct Subscript *p, void *pNotUsed){ 929d28e358 2007-11-05 drh: const char *z; 8c96ed62f5 2007-11-17 drh: int n, a; 929d28e358 2007-11-05 drh: if( SbS_RequireStack(p, 1, "hascap") ) return 1; 929d28e358 2007-11-05 drh: z = SbS_StackValue(p, 0, &n); 929d28e358 2007-11-05 drh: a = login_has_capability(z, n); 929d28e358 2007-11-05 drh: SbS_Pop(p, 1); 929d28e358 2007-11-05 drh: SbS_PushInt(p, a); 8c96ed62f5 2007-11-17 drh: return 0; 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: /* 8c96ed62f5 2007-11-17 drh: ** Subscript command: STRING linecount INTEGER 8c96ed62f5 2007-11-17 drh: ** 8c96ed62f5 2007-11-17 drh: ** Return one more than the number of \n characters in STRING. 8c96ed62f5 2007-11-17 drh: */ 8c96ed62f5 2007-11-17 drh: static int linecntCmd(struct Subscript *p, void *pNotUsed){ 8c96ed62f5 2007-11-17 drh: const char *z; 8c96ed62f5 2007-11-17 drh: int size, n, i; 8c96ed62f5 2007-11-17 drh: if( SbS_RequireStack(p, 1, "linecount") ) return 1; 8c96ed62f5 2007-11-17 drh: z = SbS_StackValue(p, 0, &size); 8c96ed62f5 2007-11-17 drh: for(n=1, i=0; i<size; i++){ 8c96ed62f5 2007-11-17 drh: if( z[i]=='\n' ) n++; 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: SbS_Pop(p, 1); 8c96ed62f5 2007-11-17 drh: SbS_PushInt(p, n); a5e4e1ba96 2007-11-24 drh: return 0; a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: a5e4e1ba96 2007-11-24 drh: /* a5e4e1ba96 2007-11-24 drh: ** Subscript command: STRING length INTEGER a5e4e1ba96 2007-11-24 drh: ** a5e4e1ba96 2007-11-24 drh: ** Return one more than the number characters in STRING. a5e4e1ba96 2007-11-24 drh: */ a5e4e1ba96 2007-11-24 drh: static int lengthCmd(struct Subscript *p, void *pNotUsed){ 92f6081d11 2007-11-03 drh: int size; a5e4e1ba96 2007-11-24 drh: if( SbS_RequireStack(p, 1, "length") ) return 1; a5e4e1ba96 2007-11-24 drh: SbS_StackValue(p, 0, &size); a5e4e1ba96 2007-11-24 drh: SbS_Pop(p, 1); a5e4e1ba96 2007-11-24 drh: SbS_PushInt(p, size); 8ef26c5e72 2007-11-03 drh: return 0; 8ef26c5e72 2007-11-03 drh: } 8ef26c5e72 2007-11-03 drh: 8ef26c5e72 2007-11-03 drh: /* 8c96ed62f5 2007-11-17 drh: ** Subscript command: NAME exists INTEGER 8c96ed62f5 2007-11-17 drh: ** 8c96ed62f5 2007-11-17 drh: ** Return TRUE if the variable NAME exists. 8c96ed62f5 2007-11-17 drh: */ 8c96ed62f5 2007-11-17 drh: static int existsCmd(struct Subscript *p, void *pNotUsed){ 8ef26c5e72 2007-11-03 drh: const char *z; 8c96ed62f5 2007-11-17 drh: int size, x; 8c96ed62f5 2007-11-17 drh: if( SbS_RequireStack(p, 1, "exists") ) return 1; 8ef26c5e72 2007-11-03 drh: z = SbS_StackValue(p, 0, &size); 8c96ed62f5 2007-11-17 drh: x = sbs_fetch(&p->symTab, (char*)z, size)!=0; 8c96ed62f5 2007-11-17 drh: SbS_Pop(p, 1); 8c96ed62f5 2007-11-17 drh: SbS_PushInt(p, x); 8c96ed62f5 2007-11-17 drh: return 0; 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: /* 8c96ed62f5 2007-11-17 drh: ** Subscript command: VALUE NAME get VALUE 8c96ed62f5 2007-11-17 drh: ** 8c96ed62f5 2007-11-17 drh: ** Push the value of varible NAME onto the stack if it exists. 8c96ed62f5 2007-11-17 drh: ** If NAME does not exist, puts VALUE onto the stack instead. 8c96ed62f5 2007-11-17 drh: */ 8c96ed62f5 2007-11-17 drh: static int getCmd(Subscript *p, void *pNotUsed){ 8c96ed62f5 2007-11-17 drh: const char *zName; 8c96ed62f5 2007-11-17 drh: int nName; 8c96ed62f5 2007-11-17 drh: const SbSValue *pVal; 8c96ed62f5 2007-11-17 drh: int rc = 0; 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: if( SbS_RequireStack(p, 2, "get") ) return SBS_ERROR; 8c96ed62f5 2007-11-17 drh: zName = SbS_StackValue(p, 0, &nName); 8c96ed62f5 2007-11-17 drh: pVal = sbs_fetch(&p->symTab, (char*)zName, nName); 8c96ed62f5 2007-11-17 drh: if( pVal!=0 && (pVal->flags & SBSVAL_STR)!=0 ){ 8c96ed62f5 2007-11-17 drh: SbS_Pop(p, 2); 8c96ed62f5 2007-11-17 drh: rc = SbS_Push(p, pVal->u.str.z, pVal->u.str.size, 0); 929d28e358 2007-11-05 drh: }else{ 8c96ed62f5 2007-11-17 drh: SbS_Pop(p, 1); 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: return rc; 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: /* 8c96ed62f5 2007-11-17 drh: ** True if output is enabled. False if disabled. 8c96ed62f5 2007-11-17 drh: */ 8c96ed62f5 2007-11-17 drh: static int enableOutput = 1; 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: /* 8c96ed62f5 2007-11-17 drh: ** Subscript command: BOOLEAN enable_output 8c96ed62f5 2007-11-17 drh: ** 8c96ed62f5 2007-11-17 drh: ** Enable or disable the puts and hputs commands. 8c96ed62f5 2007-11-17 drh: */ 8c96ed62f5 2007-11-17 drh: static int enableOutputCmd(struct Subscript *p, void *pNotUsed){ 8c96ed62f5 2007-11-17 drh: if( SbS_RequireStack(p, 1, "enable_output") ) return 1; 8c96ed62f5 2007-11-17 drh: enableOutput = SbS_StackValueInt(p, 0)!=0; 8c96ed62f5 2007-11-17 drh: SbS_Pop(p, 1); 8c96ed62f5 2007-11-17 drh: return 0; 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: /* fb358ca492 2007-11-24 drh: ** Send text to the appropriate output: Either to the console fb358ca492 2007-11-24 drh: ** or to the CGI reply buffer. fb358ca492 2007-11-24 drh: */ fb358ca492 2007-11-24 drh: static void sendText(const char *z, int n){ fb358ca492 2007-11-24 drh: if( enableOutput && n ){ fb358ca492 2007-11-24 drh: if( n<0 ) n = strlen(z); fb358ca492 2007-11-24 drh: if( g.cgiPanic ){ fb358ca492 2007-11-24 drh: cgi_append_content(z, n); fb358ca492 2007-11-24 drh: }else{ fb358ca492 2007-11-24 drh: fwrite(z, 1, n, stdout); fb358ca492 2007-11-24 drh: } fb358ca492 2007-11-24 drh: } fb358ca492 2007-11-24 drh: } fb358ca492 2007-11-24 drh: fb358ca492 2007-11-24 drh: /* 8c96ed62f5 2007-11-17 drh: ** Subscript command: STRING puts 8c96ed62f5 2007-11-17 drh: ** Subscript command: STRING html 8c96ed62f5 2007-11-17 drh: ** 8c96ed62f5 2007-11-17 drh: ** Output STRING as HTML (html) or unchanged (puts). 8c96ed62f5 2007-11-17 drh: ** Pop it from the stack. 8c96ed62f5 2007-11-17 drh: */ 8c96ed62f5 2007-11-17 drh: static int putsCmd(struct Subscript *p, void *pConvert){ 8c96ed62f5 2007-11-17 drh: int size; 8c96ed62f5 2007-11-17 drh: const char *z; 8c96ed62f5 2007-11-17 drh: char *zOut; 8c96ed62f5 2007-11-17 drh: if( SbS_RequireStack(p, 1, "puts") ) return 1; 8c96ed62f5 2007-11-17 drh: if( enableOutput ){ 8c96ed62f5 2007-11-17 drh: z = SbS_StackValue(p, 0, &size); 8c96ed62f5 2007-11-17 drh: if( pConvert ){ 8c96ed62f5 2007-11-17 drh: zOut = htmlize(z, size); 8c96ed62f5 2007-11-17 drh: size = strlen(zOut); 8c96ed62f5 2007-11-17 drh: }else{ 8c96ed62f5 2007-11-17 drh: zOut = (char*)z; 8c96ed62f5 2007-11-17 drh: } fb358ca492 2007-11-24 drh: sendText(zOut, size); 8c96ed62f5 2007-11-17 drh: if( pConvert ){ 8c96ed62f5 2007-11-17 drh: free(zOut); 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: SbS_Pop(p, 1); 8c96ed62f5 2007-11-17 drh: return 0; 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: fb358ca492 2007-11-24 drh: /* fb358ca492 2007-11-24 drh: ** Subscript command: STRING wiki fb358ca492 2007-11-24 drh: ** fb358ca492 2007-11-24 drh: ** Render the input string as wiki. fb358ca492 2007-11-24 drh: */ fb358ca492 2007-11-24 drh: static int wikiCmd(struct Subscript *p, void *pConvert){ fb358ca492 2007-11-24 drh: int size; fb358ca492 2007-11-24 drh: const char *z; fb358ca492 2007-11-24 drh: if( SbS_RequireStack(p, 1, "wiki") ) return 1; fb358ca492 2007-11-24 drh: if( enableOutput ){ fb358ca492 2007-11-24 drh: Blob src; fb358ca492 2007-11-24 drh: z = SbS_StackValue(p, 0, &size); fb358ca492 2007-11-24 drh: blob_init(&src, z, size); fb358ca492 2007-11-24 drh: wiki_convert(&src, 0, WIKI_INLINE); fb358ca492 2007-11-24 drh: blob_reset(&src); 929d28e358 2007-11-05 drh: } 8ef26c5e72 2007-11-03 drh: SbS_Pop(p, 1); fb358ca492 2007-11-24 drh: return 0; fb358ca492 2007-11-24 drh: } fb358ca492 2007-11-24 drh: fb358ca492 2007-11-24 drh: /* fb358ca492 2007-11-24 drh: ** Subscript command: NAME TEXT-LIST NUMLINES combobox fb358ca492 2007-11-24 drh: ** fb358ca492 2007-11-24 drh: ** Generate an HTML combobox. NAME is both the name of the fb358ca492 2007-11-24 drh: ** CGI parameter and the name of a variable that contains the fb358ca492 2007-11-24 drh: ** currently selected value. TEXT-LIST is a list of possible fb358ca492 2007-11-24 drh: ** values for the combobox. NUMLINES is 1 for a true combobox. fb358ca492 2007-11-24 drh: ** If NUMLINES is greater than one then the display is a listbox fb358ca492 2007-11-24 drh: ** with the number of lines given. fb358ca492 2007-11-24 drh: */ fb358ca492 2007-11-24 drh: static int comboboxCmd(struct Subscript *p, void *NotUsed){ fb358ca492 2007-11-24 drh: if( SbS_RequireStack(p, 3, "combobox") ) return 1; fb358ca492 2007-11-24 drh: if( enableOutput ){ fb358ca492 2007-11-24 drh: int height; fb358ca492 2007-11-24 drh: Blob list, elem; fb358ca492 2007-11-24 drh: char *zName, *zList; fb358ca492 2007-11-24 drh: int nName, nList, nValue; fb358ca492 2007-11-24 drh: const char *zValue; fb358ca492 2007-11-24 drh: char *z, *zH; fb358ca492 2007-11-24 drh: fb358ca492 2007-11-24 drh: height = SbS_StackValueInt(p, 0); fb358ca492 2007-11-24 drh: zList = (char*)SbS_StackValue(p, 1, &nList); fb358ca492 2007-11-24 drh: blob_init(&list, zList, nList); fb358ca492 2007-11-24 drh: zName = (char*)SbS_StackValue(p, 2, &nName); fb358ca492 2007-11-24 drh: zValue = SbS_Fetch(p, zName, nName, &nValue); d913179b82 2007-11-24 drh: z = mprintf("<select name=\"%z\" size=\"%d\">", d913179b82 2007-11-24 drh: htmlize(zName, nName), height); fb358ca492 2007-11-24 drh: sendText(z, -1); fb358ca492 2007-11-24 drh: free(z); fb358ca492 2007-11-24 drh: while( blob_token(&list, &elem) ){ d913179b82 2007-11-24 drh: zH = htmlize(blob_buffer(&elem), blob_size(&elem)); fb358ca492 2007-11-24 drh: if( zValue && blob_size(&elem)==nValue fb358ca492 2007-11-24 drh: && memcmp(zValue, blob_buffer(&elem), nValue)==0 ){ fb358ca492 2007-11-24 drh: z = mprintf("<option value=\"%s\" selected>%s</option>", zH, zH); fb358ca492 2007-11-24 drh: }else{ fb358ca492 2007-11-24 drh: z = mprintf("<option value=\"%s\">%s</option>", zH, zH); fb358ca492 2007-11-24 drh: } fb358ca492 2007-11-24 drh: free(zH); fb358ca492 2007-11-24 drh: sendText(z, -1); fb358ca492 2007-11-24 drh: free(z); fb358ca492 2007-11-24 drh: } fb358ca492 2007-11-24 drh: sendText("</select>", -1); fb358ca492 2007-11-24 drh: blob_reset(&list); fb358ca492 2007-11-24 drh: } fb358ca492 2007-11-24 drh: SbS_Pop(p, 3); 8ef26c5e72 2007-11-03 drh: return 0; fb358ca492 2007-11-24 drh: } fb358ca492 2007-11-24 drh: a5e4e1ba96 2007-11-24 drh: /* a5e4e1ba96 2007-11-24 drh: ** Subscript command: STRING BOOLEAN if a5e4e1ba96 2007-11-24 drh: ** a5e4e1ba96 2007-11-24 drh: ** Evaluate STRING as a script if BOOLEAN is true. a5e4e1ba96 2007-11-24 drh: */ a5e4e1ba96 2007-11-24 drh: static int ifCmd(struct Subscript *p, void *pNotUsed){ a5e4e1ba96 2007-11-24 drh: int cond; a5e4e1ba96 2007-11-24 drh: int rc = SBS_OK; a5e4e1ba96 2007-11-24 drh: a5e4e1ba96 2007-11-24 drh: if( SbS_RequireStack(p, 2, "if") ) return 1; a5e4e1ba96 2007-11-24 drh: cond = SbS_StackValueInt(p, 0); a5e4e1ba96 2007-11-24 drh: if( cond ){ a5e4e1ba96 2007-11-24 drh: SbSValue script = p->aStack[p->nStack-2]; a5e4e1ba96 2007-11-24 drh: p->aStack[p->nStack-2].flags = 0; a5e4e1ba96 2007-11-24 drh: SbS_Pop(p, 2); a5e4e1ba96 2007-11-24 drh: rc = SbS_Eval(p, script.u.str.z, script.u.str.size); a5e4e1ba96 2007-11-24 drh: sbs_value_reset(&script); a5e4e1ba96 2007-11-24 drh: }else{ a5e4e1ba96 2007-11-24 drh: SbS_Pop(p, 2); a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: return rc; a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: a5e4e1ba96 2007-11-24 drh: /* a5e4e1ba96 2007-11-24 drh: ** Subscript command: ... STRING COUNT concat STRING a5e4e1ba96 2007-11-24 drh: ** a5e4e1ba96 2007-11-24 drh: ** Concatenate COUNT strings into a single string and leave a5e4e1ba96 2007-11-24 drh: ** the concatenation on the stack. a5e4e1ba96 2007-11-24 drh: */ a5e4e1ba96 2007-11-24 drh: static int concatCmd(struct Subscript *p, void *pNotUsed){ a5e4e1ba96 2007-11-24 drh: int count; a5e4e1ba96 2007-11-24 drh: int nByte; a5e4e1ba96 2007-11-24 drh: char *z; a5e4e1ba96 2007-11-24 drh: int i, j; a5e4e1ba96 2007-11-24 drh: a5e4e1ba96 2007-11-24 drh: if( SbS_RequireStack(p, 1, "concat") ) return SBS_ERROR; a5e4e1ba96 2007-11-24 drh: count = SbS_StackValueInt(p, 0); a5e4e1ba96 2007-11-24 drh: if( SbS_RequireStack(p, count+1, "concat") ) return SBS_ERROR; a5e4e1ba96 2007-11-24 drh: SbS_Pop(p, 1); a5e4e1ba96 2007-11-24 drh: nByte = 1; a5e4e1ba96 2007-11-24 drh: for(i=p->nStack-count; i<p->nStack; i++){ a5e4e1ba96 2007-11-24 drh: nByte += p->aStack[i].u.str.size; a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: z = malloc(nByte); a5e4e1ba96 2007-11-24 drh: if( z==0 ){ fossil_panic("out of memory"); } a5e4e1ba96 2007-11-24 drh: for(j=0, i=p->nStack-count; i<p->nStack; i++){ a5e4e1ba96 2007-11-24 drh: nByte = p->aStack[i].u.str.size; a5e4e1ba96 2007-11-24 drh: memcpy(&z[j], p->aStack[i].u.str.z, nByte); a5e4e1ba96 2007-11-24 drh: j += nByte; a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: z[j] = 0; a5e4e1ba96 2007-11-24 drh: SbS_Pop(p, count); a5e4e1ba96 2007-11-24 drh: SbS_Push(p, z, j, 1); a5e4e1ba96 2007-11-24 drh: return SBS_OK; 8ef26c5e72 2007-11-03 drh: } 8ef26c5e72 2007-11-03 drh: 8ef26c5e72 2007-11-03 drh: 8ef26c5e72 2007-11-03 drh: /* 8ef26c5e72 2007-11-03 drh: ** A table of built-in commands 8ef26c5e72 2007-11-03 drh: */ 8ef26c5e72 2007-11-03 drh: static const struct { 8ef26c5e72 2007-11-03 drh: const char *zCmd; 8ef26c5e72 2007-11-03 drh: int (*xCmd)(Subscript*,void*); 92f6081d11 2007-11-03 drh: void *pArg; 8ef26c5e72 2007-11-03 drh: } aBuiltin[] = { 8c96ed62f5 2007-11-17 drh: { "add", bopCmd, (void*)SBSOP_AND }, 8c96ed62f5 2007-11-17 drh: { "and", bopCmd, (void*)SBSOP_AND }, fb358ca492 2007-11-24 drh: { "combobox", comboboxCmd, 0, }, a5e4e1ba96 2007-11-24 drh: { "concat", concatCmd, 0, }, 8c96ed62f5 2007-11-17 drh: { "div", bopCmd, (void*)SBSOP_DIV }, 8c96ed62f5 2007-11-17 drh: { "enable_output", enableOutputCmd, 0 }, a5e4e1ba96 2007-11-24 drh: { "eq", bopCmd, (void*)SBSOP_EQ }, 8c96ed62f5 2007-11-17 drh: { "exists", existsCmd, 0, }, 8c96ed62f5 2007-11-17 drh: { "get", getCmd, 0, }, 8c96ed62f5 2007-11-17 drh: { "hascap", hascapCmd, 0 }, 8c96ed62f5 2007-11-17 drh: { "html", putsCmd, (void*)1 }, a5e4e1ba96 2007-11-24 drh: { "if", ifCmd, 0, }, a5e4e1ba96 2007-11-24 drh: { "le", bopCmd, (void*)SBSOP_LE }, a5e4e1ba96 2007-11-24 drh: { "length", lengthCmd, 0 }, 8c96ed62f5 2007-11-17 drh: { "linecount", linecntCmd, 0 }, a5e4e1ba96 2007-11-24 drh: { "lt", bopCmd, (void*)SBSOP_LT }, 8c96ed62f5 2007-11-17 drh: { "max", bopCmd, (void*)SBSOP_MAX }, 8c96ed62f5 2007-11-17 drh: { "min", bopCmd, (void*)SBSOP_MIN }, 8c96ed62f5 2007-11-17 drh: { "mul", bopCmd, (void*)SBSOP_MUL }, 8c96ed62f5 2007-11-17 drh: { "not", notCmd, 0 }, 8c96ed62f5 2007-11-17 drh: { "or", bopCmd, (void*)SBSOP_OR }, 8c96ed62f5 2007-11-17 drh: { "puts", putsCmd, 0 }, 8c96ed62f5 2007-11-17 drh: { "set", setCmd, 0 }, a5e4e1ba96 2007-11-24 drh: { "streq", streqCmd, 0 }, 8c96ed62f5 2007-11-17 drh: { "sub", bopCmd, (void*)SBSOP_SUB }, fb358ca492 2007-11-24 drh: { "wiki", wikiCmd, 0, }, 8ef26c5e72 2007-11-03 drh: }; 8ef26c5e72 2007-11-03 drh: 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 929d28e358 2007-11-05 drh: ** Compare a zero-terminated string zPattern against 929d28e358 2007-11-05 drh: ** an unterminated string zStr of length nStr. 8c96ed62f5 2007-11-17 drh: ** 8c96ed62f5 2007-11-17 drh: ** Return less than, equal to, or greater than zero if 8c96ed62f5 2007-11-17 drh: ** zPattern is less than, equal to, or greater than zStr. 39aa870f8f 2007-10-14 drh: */ 929d28e358 2007-11-05 drh: static int compare_cmd(const char *zPattern, const char *zStr, int nStr){ 929d28e358 2007-11-05 drh: int c = strncmp(zPattern, zStr, nStr); 929d28e358 2007-11-05 drh: if( c==0 && zPattern[nStr]!=0 ){ 8c96ed62f5 2007-11-17 drh: c = 1; 39aa870f8f 2007-10-14 drh: } 929d28e358 2007-11-05 drh: return c; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: 39aa870f8f 2007-10-14 drh: /* 39aa870f8f 2007-10-14 drh: ** Evaluate the script given by the first nScript bytes of zScript[]. 39aa870f8f 2007-10-14 drh: ** Return 0 on success and non-zero for an error. 39aa870f8f 2007-10-14 drh: */ 39aa870f8f 2007-10-14 drh: int SbS_Eval(struct Subscript *p, const char *zScript, int nScript){ 39aa870f8f 2007-10-14 drh: int rc = SBS_OK; 39aa870f8f 2007-10-14 drh: if( nScript<0 ) nScript = strlen(zScript); 39aa870f8f 2007-10-14 drh: while( nScript>0 && rc==SBS_OK ){ 39aa870f8f 2007-10-14 drh: int n; 39aa870f8f 2007-10-14 drh: int ttype; 8ef26c5e72 2007-11-03 drh: n = sbs_next_token(zScript, nScript, &ttype); 8c96ed62f5 2007-11-17 drh: 8c96ed62f5 2007-11-17 drh: #if 0 8c96ed62f5 2007-11-17 drh: { 8c96ed62f5 2007-11-17 drh: int i, nElem; 8c96ed62f5 2007-11-17 drh: const char *zElem; 8c96ed62f5 2007-11-17 drh: if( p->nStack>0 ){ 8c96ed62f5 2007-11-17 drh: printf("STACK:"); 8c96ed62f5 2007-11-17 drh: for(i=0; i<p->nStack; i++){ 8c96ed62f5 2007-11-17 drh: zElem = SbS_StackValue(p, i, &nElem); 8c96ed62f5 2007-11-17 drh: printf(" [%.*s]", nElem, zElem); 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: printf("\n"); 8c96ed62f5 2007-11-17 drh: } 555911dff5 2007-11-21 drh: printf("TOKEN(%d): [%.*s]\n", ttype, n, zScript); 8c96ed62f5 2007-11-17 drh: } 8c96ed62f5 2007-11-17 drh: #endif 8c96ed62f5 2007-11-17 drh: 39aa870f8f 2007-10-14 drh: switch( ttype ){ 39aa870f8f 2007-10-14 drh: case SBSTT_WHITESPACE: { 39aa870f8f 2007-10-14 drh: break; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: case SBSTT_EOF: { 39aa870f8f 2007-10-14 drh: nScript = 0; 39aa870f8f 2007-10-14 drh: break; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: case SBSTT_INCOMPLETE: 39aa870f8f 2007-10-14 drh: case SBSTT_UNKNOWN: { 39aa870f8f 2007-10-14 drh: rc = SBS_ERROR; 39aa870f8f 2007-10-14 drh: nScript = n; 39aa870f8f 2007-10-14 drh: break; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: case SBSTT_INTEGER: { 8ef26c5e72 2007-11-03 drh: rc = SbS_Push(p, (char*)zScript, n, 0); 39aa870f8f 2007-10-14 drh: break; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: case SBSTT_NAME: { 8ef26c5e72 2007-11-03 drh: rc = SbS_Push(p, (char*)&zScript[1], n-1, 0); 39aa870f8f 2007-10-14 drh: break; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: case SBSTT_STRING: { 8ef26c5e72 2007-11-03 drh: rc = SbS_Push(p, (char*)&zScript[1], n-2, 0); 8ef26c5e72 2007-11-03 drh: break; 8ef26c5e72 2007-11-03 drh: } a5e4e1ba96 2007-11-24 drh: case SBSTT_QUOTED: { a5e4e1ba96 2007-11-24 drh: char *z = mprintf("%.*s", n-2, &zScript[1]); a5e4e1ba96 2007-11-24 drh: int i, j; a5e4e1ba96 2007-11-24 drh: for(i=j=0; z[i]; i++, j++){ a5e4e1ba96 2007-11-24 drh: int c = z[i]; a5e4e1ba96 2007-11-24 drh: if( c=='\\' && z[i+1] ){ a5e4e1ba96 2007-11-24 drh: c = z[++i]; a5e4e1ba96 2007-11-24 drh: if( c=='n' ){ a5e4e1ba96 2007-11-24 drh: c = '\n'; a5e4e1ba96 2007-11-24 drh: }else if( c>='0' && c<='7' ){ a5e4e1ba96 2007-11-24 drh: int k; a5e4e1ba96 2007-11-24 drh: c -= '0'; a5e4e1ba96 2007-11-24 drh: for(k=1; k<3 && z[i+k]>='0' && z[i+k]<='7'; k++){ a5e4e1ba96 2007-11-24 drh: c = c*8 + z[i+k] - '0'; a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: i += k-1; a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: z[j] = c; a5e4e1ba96 2007-11-24 drh: } a5e4e1ba96 2007-11-24 drh: z[j] = 0; a5e4e1ba96 2007-11-24 drh: rc = SbS_Push(p, z, j, 1); 39aa870f8f 2007-10-14 drh: break; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: case SBSTT_VERB: { a67fbd784d 2007-11-03 drh: /* First look up the verb in the hash table */ 8ef26c5e72 2007-11-03 drh: const SbSValue *pVal = sbs_fetch(&p->symTab, (char*)zScript, n); 39aa870f8f 2007-10-14 drh: if( pVal==0 ){ a67fbd784d 2007-11-03 drh: /* If the verb is not in the hash table, look for a a67fbd784d 2007-11-03 drh: ** built-in command */ 8ef26c5e72 2007-11-03 drh: int upr = sizeof(aBuiltin)/sizeof(aBuiltin[0]) - 1; 8ef26c5e72 2007-11-03 drh: int lwr = 0; 39aa870f8f 2007-10-14 drh: rc = SBS_ERROR; 8ef26c5e72 2007-11-03 drh: while( upr>=lwr ){ 8ef26c5e72 2007-11-03 drh: int i = (upr+lwr)/2; 929d28e358 2007-11-05 drh: int c = compare_cmd(aBuiltin[i].zCmd, zScript, n); 8ef26c5e72 2007-11-03 drh: if( c==0 ){ 92f6081d11 2007-11-03 drh: rc = aBuiltin[i].xCmd(p, aBuiltin[i].pArg); 8ef26c5e72 2007-11-03 drh: break; 8c96ed62f5 2007-11-17 drh: }else if( c>0 ){ 8ef26c5e72 2007-11-03 drh: upr = i-1; 8ef26c5e72 2007-11-03 drh: }else{ 8ef26c5e72 2007-11-03 drh: lwr = i+1; 8ef26c5e72 2007-11-03 drh: } a67fbd784d 2007-11-03 drh: } a67fbd784d 2007-11-03 drh: if( upr<lwr ){ fb358ca492 2007-11-24 drh: SbS_SetErrorMessage(p, "unknown verb: %.*s", n, zScript); 8ef26c5e72 2007-11-03 drh: } 39aa870f8f 2007-10-14 drh: }else if( pVal->flags & SBSVAL_VERB ){ 39aa870f8f 2007-10-14 drh: rc = pVal->u.verb.xVerb(p, pVal->u.verb.pArg); 39aa870f8f 2007-10-14 drh: }else if( pVal->flags & SBSVAL_EXEC ){ 39aa870f8f 2007-10-14 drh: rc = SbS_Eval(p, pVal->u.str.z, pVal->u.str.size); 39aa870f8f 2007-10-14 drh: }else{ 8ef26c5e72 2007-11-03 drh: rc = SbS_Push(p, pVal->u.str.z, pVal->u.str.size, 0); 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: break; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: zScript += n; 39aa870f8f 2007-10-14 drh: nScript -= n; 39aa870f8f 2007-10-14 drh: } 39aa870f8f 2007-10-14 drh: return rc; 8ef26c5e72 2007-11-03 drh: } 8ef26c5e72 2007-11-03 drh: 8ef26c5e72 2007-11-03 drh: /* e29abeff80 2007-11-20 drh: ** The z[] input contains text mixed with subscript scripts. e29abeff80 2007-11-20 drh: ** The subscript scripts are contained within [...]. This routine e29abeff80 2007-11-20 drh: ** processes the template and writes the results on either e29abeff80 2007-11-20 drh: ** stdout or into CGI. e29abeff80 2007-11-20 drh: */ e29abeff80 2007-11-20 drh: int SbS_Render(struct Subscript *p, const char *z){ e29abeff80 2007-11-20 drh: int i = 0; e29abeff80 2007-11-20 drh: int rc = SBS_OK; e29abeff80 2007-11-20 drh: while( z[i] ){ e29abeff80 2007-11-20 drh: if( z[i]=='[' ){ fb358ca492 2007-11-24 drh: sendText(z, i); e29abeff80 2007-11-20 drh: z += i+1; e29abeff80 2007-11-20 drh: for(i=0; z[i] && z[i]!=']'; i++){} e29abeff80 2007-11-20 drh: rc = SbS_Eval(p, z, i); e29abeff80 2007-11-20 drh: if( rc!=SBS_OK ) break; e29abeff80 2007-11-20 drh: if( z[i] ) i++; e29abeff80 2007-11-20 drh: z += i; e29abeff80 2007-11-20 drh: i = 0; e29abeff80 2007-11-20 drh: }else{ e29abeff80 2007-11-20 drh: i++; e29abeff80 2007-11-20 drh: } e29abeff80 2007-11-20 drh: } fb358ca492 2007-11-24 drh: if( rc==SBS_ERROR ){ fb358ca492 2007-11-24 drh: sendText("<hr><p><font color=\"red\"><b>ERROR: ", -1); fb358ca492 2007-11-24 drh: sendText(SbS_GetErrorMessage(p), -1); fb358ca492 2007-11-24 drh: sendText("</b></font></p>", -1); fb358ca492 2007-11-24 drh: }else{ fb358ca492 2007-11-24 drh: sendText(z, i); e29abeff80 2007-11-20 drh: } e29abeff80 2007-11-20 drh: return rc; e29abeff80 2007-11-20 drh: } e29abeff80 2007-11-20 drh: e29abeff80 2007-11-20 drh: /* 8ef26c5e72 2007-11-03 drh: ** COMMAND: test-subscript 8ef26c5e72 2007-11-03 drh: */ 8ef26c5e72 2007-11-03 drh: void test_subscript(void){ 8ef26c5e72 2007-11-03 drh: Subscript *p; e29abeff80 2007-11-20 drh: Blob in; 8ef26c5e72 2007-11-03 drh: if( g.argc<3 ){ e29abeff80 2007-11-20 drh: usage("FILE"); 8ef26c5e72 2007-11-03 drh: } e29abeff80 2007-11-20 drh: blob_zero(&in); e29abeff80 2007-11-20 drh: blob_read_from_file(&in, g.argv[2]); 8ef26c5e72 2007-11-03 drh: p = SbS_Create(); e29abeff80 2007-11-20 drh: SbS_Render(p, blob_str(&in)); 39aa870f8f 2007-10-14 drh: }