File Annotation
Not logged in
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>
8ffd32c2b7 2007-10-28       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
8ef26c5e72 2007-11-03       drh: #endif
39aa870f8f 2007-10-14       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 */
39aa870f8f 2007-10-14       drh: #define SBSCONFIG_NSTACK   10         /* 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:   {...}   */
39aa870f8f 2007-10-14       drh: #define SBSTT_INTEGER     5    /* Integer including option sign */
39aa870f8f 2007-10-14       drh: #define SBSTT_INCOMPLETE  6    /* Unterminated string token */
39aa870f8f 2007-10-14       drh: #define SBSTT_UNKNOWN     7    /* Unknown token */
39aa870f8f 2007-10-14       drh: #define SBSTT_EOF         8    /* End of input */
8ef26c5e72 2007-11-03       drh: 
8ef26c5e72 2007-11-03       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;
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: */
39aa870f8f 2007-10-14       drh: void SbS_SetErrorMessage(struct Subscript *p, const char *zErr){
39aa870f8f 2007-10-14       drh:   int nErr = strlen(zErr);
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:   }
39aa870f8f 2007-10-14       drh:   memcpy(p->zErrMsg, zErr, nErr);
39aa870f8f 2007-10-14       drh:   p->zErrMsg[nErr] = 0;
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 */
39aa870f8f 2007-10-14       drh:   int *pLength             /* Write the length here */
39aa870f8f 2007-10-14       drh: ){
8ef26c5e72 2007-11-03       drh:   const SbSValue *pVal;
39aa870f8f 2007-10-14       drh: 
39aa870f8f 2007-10-14       drh:   pVal = sbs_fetch(&p->symTab, zKey, -1);
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
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;
8ef26c5e72 2007-11-03       drh:   a = SbS_StackValueInt(p, 0);
8ef26c5e72 2007-11-03       drh:   b = SbS_StackValueInt(p, 1);
92f6081d11 2007-11-03       drh:   switch( (int)pOp ){
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);
92f6081d11 2007-11-03       drh:   return 0;
92f6081d11 2007-11-03       drh: }
92f6081d11 2007-11-03       drh: 
92f6081d11 2007-11-03       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);
8c96ed62f5 2007-11-17       drh:   return 0;
929d28e358 2007-11-05       drh: }
929d28e358 2007-11-05       drh: 
929d28e358 2007-11-05       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.
92f6081d11 2007-11-03       drh: */
8c96ed62f5 2007-11-17       drh: static int existsCmd(struct Subscript *p, void *pNotUsed){
92f6081d11 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;
92f6081d11 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);
8ef26c5e72 2007-11-03       drh:   return 0;
8ef26c5e72 2007-11-03       drh: }
8ef26c5e72 2007-11-03       drh: 
8ef26c5e72 2007-11-03       drh: /*
8ef26c5e72 2007-11-03       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.
8ef26c5e72 2007-11-03       drh: */
8c96ed62f5 2007-11-17       drh: static int putsCmd(struct Subscript *p, void *pConvert){
8ef26c5e72 2007-11-03       drh:   int size;
8ef26c5e72 2007-11-03       drh:   const char *z;
8c96ed62f5 2007-11-17       drh:   char *zOut;
8ef26c5e72 2007-11-03       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:     }
8c96ed62f5 2007-11-17       drh:     if( g.cgiPanic ){
8c96ed62f5 2007-11-17       drh:       cgi_append_content(zOut, size);
8c96ed62f5 2007-11-17       drh:     }else{
e29abeff80 2007-11-20       drh:       printf("%.*s", size, zOut);
8c96ed62f5 2007-11-17       drh:     }
8c96ed62f5 2007-11-17       drh:     if( pConvert ){
8c96ed62f5 2007-11-17       drh:       free(zOut);
8c96ed62f5 2007-11-17       drh:     }
929d28e358 2007-11-05       drh:   }
8ef26c5e72 2007-11-03       drh:   SbS_Pop(p, 1);
8ef26c5e72 2007-11-03       drh:   return 0;
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    },
8c96ed62f5 2007-11-17       drh:   { "div",             bopCmd,               (void*)SBSOP_DIV    },
8c96ed62f5 2007-11-17       drh:   { "enable_output",   enableOutputCmd,      0                   },
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            },
8c96ed62f5 2007-11-17       drh:   { "linecount",       linecntCmd,           0                   },
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                   },
8c96ed62f5 2007-11-17       drh:   { "sub",             bopCmd,               (void*)SBSOP_SUB    },
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);
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:             }
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]=='[' ){
555911dff5 2007-11-21       drh:       if( enableOutput ){
555911dff5 2007-11-21       drh:         if( g.cgiPanic ){
555911dff5 2007-11-21       drh:           cgi_append_content(z, i);
555911dff5 2007-11-21       drh:         }else{
555911dff5 2007-11-21       drh:           fwrite(z, 1, i, stdout);
555911dff5 2007-11-21       drh:         }
e29abeff80 2007-11-20       drh:       }
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:   }
555911dff5 2007-11-21       drh:   if( i>0 && enableOutput ){
e29abeff80 2007-11-20       drh:     if( g.cgiPanic ){
e29abeff80 2007-11-20       drh:       cgi_append_content(z, i);
e29abeff80 2007-11-20       drh:     }else{
e29abeff80 2007-11-20       drh:       fwrite(z, 1, i, stdout);
e29abeff80 2007-11-20       drh:     }
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: }