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 */
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: ** Values are stored in the hash table as instances of the following
39aa870f8f 2007-10-14       drh: ** structure.
39aa870f8f 2007-10-14       drh: */
39aa870f8f 2007-10-14       drh: typedef struct SbSValue SbSValue;
39aa870f8f 2007-10-14       drh: struct SbSValue {
39aa870f8f 2007-10-14       drh:   int flags;        /* Bitmask of SBSVAL_* values */
39aa870f8f 2007-10-14       drh:   union {
39aa870f8f 2007-10-14       drh:     struct {
39aa870f8f 2007-10-14       drh:       int size;        /* Number of bytes in string, not counting final zero */
39aa870f8f 2007-10-14       drh:       char *z;         /* Pointer to string content */
39aa870f8f 2007-10-14       drh:     } str;          /* Value if SBSVAL_STR */
39aa870f8f 2007-10-14       drh:     struct {
8ef26c5e72 2007-11-03       drh:       int (*xVerb)(Subscript*, void*);     /* Function to do the work */
39aa870f8f 2007-10-14       drh:       void *pArg;                          /* 2nd parameter to xVerb */
39aa870f8f 2007-10-14       drh:     } verb;         /* Value if SBSVAL_VERB */
39aa870f8f 2007-10-14       drh:   } u;
39aa870f8f 2007-10-14       drh: };
39aa870f8f 2007-10-14       drh: #define SBSVAL_VERB    0x0001      /* Value stored in u.verb */
39aa870f8f 2007-10-14       drh: #define SBSVAL_STR     0x0002      /* Value stored in u.str */
39aa870f8f 2007-10-14       drh: #define SBSVAL_DYN     0x0004      /* u.str.z is dynamically allocated */
39aa870f8f 2007-10-14       drh: #define SBSVAL_EXEC    0x0008      /* u.str.z is a script */
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: /*
39aa870f8f 2007-10-14       drh: ** An entry in the hash table is an instance of this structure.
39aa870f8f 2007-10-14       drh: */
8ef26c5e72 2007-11-03       drh: typedef struct SbsHashEntry SbsHashEntry;
8ef26c5e72 2007-11-03       drh: struct SbsHashEntry {
8ef26c5e72 2007-11-03       drh:   SbsHashEntry *pNext;     /* Next entry with the same hash on zKey */
39aa870f8f 2007-10-14       drh:   SbSValue val;            /* The payload */
39aa870f8f 2007-10-14       drh:   int nKey;               /* Length of the key */
39aa870f8f 2007-10-14       drh:   char zKey[0];           /* The key */
39aa870f8f 2007-10-14       drh: };
39aa870f8f 2007-10-14       drh: 
39aa870f8f 2007-10-14       drh: /*
39aa870f8f 2007-10-14       drh: ** A hash table is an instance of the following structure.
39aa870f8f 2007-10-14       drh: */
8ef26c5e72 2007-11-03       drh: typedef struct SbsHashTab SbsHashTab;
8ef26c5e72 2007-11-03       drh: struct SbsHashTab {
8ef26c5e72 2007-11-03       drh:   SbsHashEntry *aHash[SBSCONFIG_NHASH];  /* The hash table */
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: ** An instance of the Subscript interpreter
39aa870f8f 2007-10-14       drh: */
39aa870f8f 2007-10-14       drh: struct Subscript {
39aa870f8f 2007-10-14       drh:   int nStack;                      /* Number of entries on stack */
8ef26c5e72 2007-11-03       drh:   SbsHashTab symTab;                /* The symbol table */
39aa870f8f 2007-10-14       drh:   char zErrMsg[SBSCONFIG_ERRSIZE];  /* Space to write an error message */
39aa870f8f 2007-10-14       drh:   SbSValue aStack[SBSCONFIG_NSTACK]; /* The stack */
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: /*
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: /*
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: 
8ef26c5e72 2007-11-03       drh: /*
8ef26c5e72 2007-11-03       drh: ** Subscript command:      INTEGER INTEGER max INTEGER
8ef26c5e72 2007-11-03       drh: */
8ef26c5e72 2007-11-03       drh: static int maxCmd(struct Subscript *p, void *pNotUsed){
8ef26c5e72 2007-11-03       drh:   int a, b;
8ef26c5e72 2007-11-03       drh:   if( SbS_RequireStack(p, 2, "max") ) return 1;
8ef26c5e72 2007-11-03       drh:   a = SbS_StackValueInt(p, 0);
8ef26c5e72 2007-11-03       drh:   b = SbS_StackValueInt(p, 1);
8ef26c5e72 2007-11-03       drh:   SbS_Pop(p, 2);
8ef26c5e72 2007-11-03       drh:   SbS_PushInt(p, a>b ? a : b);
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:      INTEGER INTEGER and INTEGER
8ef26c5e72 2007-11-03       drh: */
8ef26c5e72 2007-11-03       drh: static int andCmd(struct Subscript *p, void *pNotUsed){
8ef26c5e72 2007-11-03       drh:   int a, b;
8ef26c5e72 2007-11-03       drh:   if( SbS_RequireStack(p, 2, "max") ) return 1;
8ef26c5e72 2007-11-03       drh:   a = SbS_StackValueInt(p, 0);
8ef26c5e72 2007-11-03       drh:   b = SbS_StackValueInt(p, 1);
8ef26c5e72 2007-11-03       drh:   SbS_Pop(p, 2);
8ef26c5e72 2007-11-03       drh:   SbS_PushInt(p, a && b);
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
8ef26c5e72 2007-11-03       drh: */
8ef26c5e72 2007-11-03       drh: static int putsCmd(struct Subscript *p, void *pNotUsed){
8ef26c5e72 2007-11-03       drh:   int size;
8ef26c5e72 2007-11-03       drh:   const char *z;
8ef26c5e72 2007-11-03       drh:   if( SbS_RequireStack(p, 1, "puts") ) return 1;
8ef26c5e72 2007-11-03       drh:   z = SbS_StackValue(p, 0, &size);
8ef26c5e72 2007-11-03       drh:   printf("%.*s\n", size, z);
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 nCmd;
8ef26c5e72 2007-11-03       drh:   int (*xCmd)(Subscript*,void*);
8ef26c5e72 2007-11-03       drh: } aBuiltin[] = {
8ef26c5e72 2007-11-03       drh:   { "and",   3,    andCmd    },
8ef26c5e72 2007-11-03       drh:   { "max",   3,    maxCmd    },
8ef26c5e72 2007-11-03       drh:   { "not",   3,    notCmd    },
8ef26c5e72 2007-11-03       drh:   { "puts",  4,    putsCmd   },
8ef26c5e72 2007-11-03       drh:   { "set",   3,    setCmd    },
8ef26c5e72 2007-11-03       drh: };
8ffd32c2b7 2007-10-28       drh: 
39aa870f8f 2007-10-14       drh: 
39aa870f8f 2007-10-14       drh: /*
8ffd32c2b7 2007-10-28       drh: ** Create a new subscript interpreter
39aa870f8f 2007-10-14       drh: */
39aa870f8f 2007-10-14       drh: struct Subscript *SbS_Create(void){
39aa870f8f 2007-10-14       drh:   Subscript *p;
39aa870f8f 2007-10-14       drh: 
39aa870f8f 2007-10-14       drh:   p = malloc( sizeof(*p) );
39aa870f8f 2007-10-14       drh:   if( p ){
39aa870f8f 2007-10-14       drh:     memset(p, 0, sizeof(*p));
39aa870f8f 2007-10-14       drh:   }
39aa870f8f 2007-10-14       drh:   return p;
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);
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: {
8ef26c5e72 2007-11-03       drh:         const SbSValue *pVal = sbs_fetch(&p->symTab, (char*)zScript, n);
39aa870f8f 2007-10-14       drh:         if( pVal==0 ){
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;
8ef26c5e72 2007-11-03       drh:             int c = strncmp(zScript, aBuiltin[i].zCmd, n);
8ef26c5e72 2007-11-03       drh:             if( c==0 ){
8ef26c5e72 2007-11-03       drh:               rc = aBuiltin[i].xCmd(p, 0);
8ef26c5e72 2007-11-03       drh:               break;
8ef26c5e72 2007-11-03       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: /*
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;
8ef26c5e72 2007-11-03       drh:   if( g.argc<3 ){
8ef26c5e72 2007-11-03       drh:     usage("SCRIPT");
8ef26c5e72 2007-11-03       drh:   }
8ef26c5e72 2007-11-03       drh:   p = SbS_Create();
8ef26c5e72 2007-11-03       drh:   SbS_Eval(p, g.argv[2], strlen(g.argv[2]));
39aa870f8f 2007-10-14       drh: }