File Annotation
Not logged in
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** This file contains the implementation of all of the TH language
4ee9e31a2d 2008-02-13       drh: ** built-in commands.
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: ** All built-in commands are implemented using the public interface
4ee9e31a2d 2008-02-13       drh: ** declared in th.h, so this file serves as both a part of the language
4ee9e31a2d 2008-02-13       drh: ** implementation and an example of how to extend the language with
4ee9e31a2d 2008-02-13       drh: ** new commands.
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: #include "th.h"
4ee9e31a2d 2008-02-13       drh: #include <string.h>
4ee9e31a2d 2008-02-13       drh: #include <assert.h>
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg){
0c99a1554a 2008-10-24       drh:   Th_ErrorMessage(interp, "wrong # args: should be \"", zMsg, -1);
4ee9e31a2d 2008-02-13       drh:   return TH_ERROR;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   catch script ?varname?
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int catch_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int rc;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=2 && argc!=3 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "catch script ?varname?");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   rc = Th_Eval(interp, 0, argv[1], -1);
4ee9e31a2d 2008-02-13       drh:   if( argc==3 ){
4ee9e31a2d 2008-02-13       drh:     int nResult;
0c99a1554a 2008-10-24       drh:     const char *zResult = Th_GetResult(interp, &nResult);
4ee9e31a2d 2008-02-13       drh:     Th_SetVar(interp, argv[2], argl[2], zResult, nResult);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   Th_SetResultInt(interp, rc);
4ee9e31a2d 2008-02-13       drh:   return TH_OK;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN?
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int if_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int rc = TH_OK;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   int iCond;           /* Result of evaluating expression */
4ee9e31a2d 2008-02-13       drh:   int i;
4ee9e31a2d 2008-02-13       drh: 
0c99a1554a 2008-10-24       drh:   const char *zResult;
4ee9e31a2d 2008-02-13       drh:   int nResult;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc<3 ){
4ee9e31a2d 2008-02-13       drh:     goto wrong_args;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   for(i=0; i<argc && rc==TH_OK; i+=3){
4ee9e31a2d 2008-02-13       drh:     if( i>argc-3 ){
4ee9e31a2d 2008-02-13       drh:       i = argc-3;
4ee9e31a2d 2008-02-13       drh:       iCond = 1;
4ee9e31a2d 2008-02-13       drh:     }else{
4ee9e31a2d 2008-02-13       drh:       if( TH_OK!=Th_Expr(interp, argv[i+1], argl[i+1]) ){
4ee9e31a2d 2008-02-13       drh:         return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:       }
4ee9e31a2d 2008-02-13       drh:       zResult = Th_GetResult(interp, &nResult);
4ee9e31a2d 2008-02-13       drh:       rc = Th_ToInt(interp, zResult, nResult, &iCond);
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:     if( iCond && rc==TH_OK ){
4ee9e31a2d 2008-02-13       drh:       rc = Th_Eval(interp, 0, argv[i+2], -1);
4ee9e31a2d 2008-02-13       drh:       break;
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return rc;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: wrong_args:
4ee9e31a2d 2008-02-13       drh:   return Th_WrongNumArgs(interp, "if ...");
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   expr expr
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int expr_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   if( argc!=2 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "expr expression");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return Th_Expr(interp, argv[1], argl[1]);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** Evaluate the th1 script (zBody, nBody) in the local stack frame.
4ee9e31a2d 2008-02-13       drh: ** Return the result of the evaluation, except if the result
4ee9e31a2d 2008-02-13       drh: ** is TH_CONTINUE, return TH_OK instead.
4ee9e31a2d 2008-02-13       drh: */
0c99a1554a 2008-10-24       drh: static int eval_loopbody(Th_Interp *interp, const char *zBody, int nBody){
4ee9e31a2d 2008-02-13       drh:   int rc = Th_Eval(interp, 0, zBody, nBody);
4ee9e31a2d 2008-02-13       drh:   if( rc==TH_CONTINUE ){
4ee9e31a2d 2008-02-13       drh:     rc = TH_OK;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return rc;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   for init condition incr script
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int for_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int rc;
4ee9e31a2d 2008-02-13       drh:   int iCond;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=5 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "for init condition incr script");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* Evaluate the 'init' script */
4ee9e31a2d 2008-02-13       drh:   rc = Th_Eval(interp, 0, argv[1], -1);
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   while( rc==TH_OK
4ee9e31a2d 2008-02-13       drh:      && TH_OK==(rc = Th_Expr(interp, argv[2], -1))
4ee9e31a2d 2008-02-13       drh:      && TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond))
4ee9e31a2d 2008-02-13       drh:      && iCond
4ee9e31a2d 2008-02-13       drh:      && TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4]))
4ee9e31a2d 2008-02-13       drh:   ){
4ee9e31a2d 2008-02-13       drh:     rc = Th_Eval(interp, 0, argv[3], -1);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( rc==TH_BREAK ) rc = TH_OK;
4ee9e31a2d 2008-02-13       drh:   return rc;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   list ?arg1 ?arg2? ...?
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int list_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
0c99a1554a 2008-10-24       drh:   int *argl
0c99a1554a 2008-10-24       drh: ){
0c99a1554a 2008-10-24       drh:   char *zList = 0;
4ee9e31a2d 2008-02-13       drh:   int nList = 0;
4ee9e31a2d 2008-02-13       drh:   int i;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   for(i=1; i<argc; i++){
4ee9e31a2d 2008-02-13       drh:     Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   Th_SetResult(interp, zList, nList);
4ee9e31a2d 2008-02-13       drh:   Th_Free(interp, zList);
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return TH_OK;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   lindex list index
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int lindex_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int iElem;
4ee9e31a2d 2008-02-13       drh:   int rc;
4ee9e31a2d 2008-02-13       drh: 
0c99a1554a 2008-10-24       drh:   char **azElem;
4ee9e31a2d 2008-02-13       drh:   int *anElem;
4ee9e31a2d 2008-02-13       drh:   int nCount;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=3 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "lindex list index");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( TH_OK!=Th_ToInt(interp, argv[2], argl[2], &iElem) ){
4ee9e31a2d 2008-02-13       drh:     return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   rc = Th_SplitList(interp, argv[1], argl[1], &azElem, &anElem, &nCount);
4ee9e31a2d 2008-02-13       drh:   if( rc==TH_OK ){
4ee9e31a2d 2008-02-13       drh:     if( iElem<nCount && iElem>=0 ){
4ee9e31a2d 2008-02-13       drh:       Th_SetResult(interp, azElem[iElem], anElem[iElem]);
4ee9e31a2d 2008-02-13       drh:     }else{
4ee9e31a2d 2008-02-13       drh:       Th_SetResult(interp, 0, 0);
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:     Th_Free(interp, azElem);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return rc;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   llength list
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int llength_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int nElem;
4ee9e31a2d 2008-02-13       drh:   int rc;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=2 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "llength list");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   rc = Th_SplitList(interp, argv[1], argl[1], 0, 0, &nElem);
4ee9e31a2d 2008-02-13       drh:   if( rc==TH_OK ){
4ee9e31a2d 2008-02-13       drh:     Th_SetResultInt(interp, nElem);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return rc;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   set varname ?value?
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int set_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   if( argc!=2 && argc!=3 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "set varname ?value?");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc==3 ){
4ee9e31a2d 2008-02-13       drh:     Th_SetVar(interp, argv[1], argl[1], argv[2], argl[2]);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return Th_GetVar(interp, argv[1], argl[1]);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** When a new command is created using the built-in [proc] command, an
4ee9e31a2d 2008-02-13       drh: ** instance of the following structure is allocated and populated. A
4ee9e31a2d 2008-02-13       drh: ** pointer to the structure is passed as the context (second) argument
4ee9e31a2d 2008-02-13       drh: ** to function proc_call1() when the new command is executed.
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: typedef struct ProcDefn ProcDefn;
4ee9e31a2d 2008-02-13       drh: struct ProcDefn {
4ee9e31a2d 2008-02-13       drh:   int nParam;                /* Number of formal (non "args") parameters */
0c99a1554a 2008-10-24       drh:   char **azParam;           /* Parameter names */
4ee9e31a2d 2008-02-13       drh:   int *anParam;              /* Lengths of parameter names */
0c99a1554a 2008-10-24       drh:   char **azDefault;         /* Default values */
4ee9e31a2d 2008-02-13       drh:   int *anDefault;            /* Lengths of default values */
4ee9e31a2d 2008-02-13       drh:   int hasArgs;               /* True if there is an "args" parameter */
0c99a1554a 2008-10-24       drh:   char *zProgram;           /* Body of proc */
4ee9e31a2d 2008-02-13       drh:   int nProgram;              /* Number of bytes at zProgram */
0c99a1554a 2008-10-24       drh:   char *zUsage;             /* Usage message */
4ee9e31a2d 2008-02-13       drh:   int nUsage;                /* Number of bytes at zUsage */
4ee9e31a2d 2008-02-13       drh: };
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /* This structure is used to temporarily store arguments passed to an
4ee9e31a2d 2008-02-13       drh: ** invocation of a command created using [proc]. A pointer to an
4ee9e31a2d 2008-02-13       drh: ** instance is passed as the second argument to the proc_call2() function.
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: typedef struct ProcArgs ProcArgs;
4ee9e31a2d 2008-02-13       drh: struct ProcArgs {
4ee9e31a2d 2008-02-13       drh:   int argc;
0c99a1554a 2008-10-24       drh:   const char **argv;
4ee9e31a2d 2008-02-13       drh:   int *argl;
4ee9e31a2d 2008-02-13       drh: };
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** Each time a command created using [proc] is invoked, a new
4ee9e31a2d 2008-02-13       drh: ** th1 stack frame is allocated (for the proc's local variables) and
4ee9e31a2d 2008-02-13       drh: ** this function invoked.
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: ** Argument pContext1 points to the associated ProcDefn structure.
4ee9e31a2d 2008-02-13       drh: ** Argument pContext2  points to a ProcArgs structure that contains
4ee9e31a2d 2008-02-13       drh: ** the arguments passed to this specific invocation of the proc.
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int proc_call2(Th_Interp *interp, void *pContext1, void *pContext2){
4ee9e31a2d 2008-02-13       drh:   int i;
4ee9e31a2d 2008-02-13       drh:   ProcDefn *p = (ProcDefn *)pContext1;
4ee9e31a2d 2008-02-13       drh:   ProcArgs *pArgs = (ProcArgs *)pContext2;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* Check if there are the right number of arguments. If there are
4ee9e31a2d 2008-02-13       drh:   ** not, generate a usage message for the command.
4ee9e31a2d 2008-02-13       drh:   */
4ee9e31a2d 2008-02-13       drh:   if( (pArgs->argc>(p->nParam+1) && !p->hasArgs)
4ee9e31a2d 2008-02-13       drh:    || (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1])
4ee9e31a2d 2008-02-13       drh:   ){
0c99a1554a 2008-10-24       drh:     char *zUsage = 0;
4ee9e31a2d 2008-02-13       drh:     int nUsage = 0;
4ee9e31a2d 2008-02-13       drh:     Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]);
4ee9e31a2d 2008-02-13       drh:     Th_StringAppend(interp, &zUsage, &nUsage, p->zUsage, p->nUsage);
0c99a1554a 2008-10-24       drh:     Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"", 1);
4ee9e31a2d 2008-02-13       drh:     Th_WrongNumArgs(interp, zUsage);
4ee9e31a2d 2008-02-13       drh:     Th_Free(interp, zUsage);
4ee9e31a2d 2008-02-13       drh:     return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* Populate the formal proc parameters. */
4ee9e31a2d 2008-02-13       drh:   for(i=0; i<p->nParam; i++){
0c99a1554a 2008-10-24       drh:     const char *zVal;
4ee9e31a2d 2008-02-13       drh:     int nVal;
4ee9e31a2d 2008-02-13       drh:     if( pArgs->argc>(i+1) ){
4ee9e31a2d 2008-02-13       drh:       zVal = pArgs->argv[i+1];
4ee9e31a2d 2008-02-13       drh:       nVal = pArgs->argl[i+1];
4ee9e31a2d 2008-02-13       drh:     }else{
4ee9e31a2d 2008-02-13       drh:       zVal = p->azDefault[i];
4ee9e31a2d 2008-02-13       drh:       nVal = p->anDefault[i];
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:     Th_SetVar(interp, p->azParam[i], p->anParam[i], zVal, nVal);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* Populate the "args" parameter, if it exists */
4ee9e31a2d 2008-02-13       drh:   if( p->hasArgs ){
0c99a1554a 2008-10-24       drh:     char *zArgs = 0;
4ee9e31a2d 2008-02-13       drh:     int nArgs = 0;
4ee9e31a2d 2008-02-13       drh:     for(i=p->nParam+1; i<pArgs->argc; i++){
4ee9e31a2d 2008-02-13       drh:       Th_ListAppend(interp, &zArgs, &nArgs, pArgs->argv[i], pArgs->argl[i]);
4ee9e31a2d 2008-02-13       drh:     }
0c99a1554a 2008-10-24       drh:     Th_SetVar(interp, (const char *)"args", -1, zArgs, nArgs);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   Th_SetResult(interp, 0, 0);
4ee9e31a2d 2008-02-13       drh:   return Th_Eval(interp, 0, p->zProgram, p->nProgram);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** This function is the command callback registered for all commands
4ee9e31a2d 2008-02-13       drh: ** created using the [proc] command. The second argument, pContext,
4ee9e31a2d 2008-02-13       drh: ** is a pointer to the associated ProcDefn structure.
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int proc_call1(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *pContext,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int rc;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   ProcDefn *p = (ProcDefn *)pContext;
4ee9e31a2d 2008-02-13       drh:   ProcArgs procargs;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* Call function proc_call2(), which will call Th_Eval() to evaluate
4ee9e31a2d 2008-02-13       drh:   ** the body of the [proc], in a new Th stack frame. This is so that
4ee9e31a2d 2008-02-13       drh:   ** the proc body has its own local variable context.
4ee9e31a2d 2008-02-13       drh:   */
4ee9e31a2d 2008-02-13       drh:   procargs.argc = argc;
4ee9e31a2d 2008-02-13       drh:   procargs.argv = argv;
4ee9e31a2d 2008-02-13       drh:   procargs.argl = argl;
4ee9e31a2d 2008-02-13       drh:   rc = Th_InFrame(interp, proc_call2, (void *)p, (void *)&procargs);
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( rc==TH_RETURN ){
4ee9e31a2d 2008-02-13       drh:     rc = TH_OK;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return rc;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** This function is registered as the delete callback for all commands
4ee9e31a2d 2008-02-13       drh: ** created using the built-in [proc] command. It is called automatically
4ee9e31a2d 2008-02-13       drh: ** when a command created using [proc] is deleted.
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: ** It frees the ProcDefn structure allocated when the command was created.
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static void proc_del(Th_Interp *interp, void *pContext){
4ee9e31a2d 2008-02-13       drh:   ProcDefn *p = (ProcDefn *)pContext;
4ee9e31a2d 2008-02-13       drh:   Th_Free(interp, (void *)p->zUsage);
4ee9e31a2d 2008-02-13       drh:   Th_Free(interp, (void *)p);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   proc name arglist code
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int proc_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int rc;
4ee9e31a2d 2008-02-13       drh:   char *zName;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   ProcDefn *p;
4ee9e31a2d 2008-02-13       drh:   int nByte;
4ee9e31a2d 2008-02-13       drh:   int i;
0c99a1554a 2008-10-24       drh:   char *zSpace;
0c99a1554a 2008-10-24       drh: 
0c99a1554a 2008-10-24       drh:   char **azParam;
4ee9e31a2d 2008-02-13       drh:   int *anParam;
4ee9e31a2d 2008-02-13       drh:   int nParam;
4ee9e31a2d 2008-02-13       drh: 
0c99a1554a 2008-10-24       drh:   char *zUsage = 0;               /* Build up a usage message here */
4ee9e31a2d 2008-02-13       drh:   int nUsage = 0;                  /* Number of bytes at zUsage */
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=4 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "proc name arglist code");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( Th_SplitList(interp, argv[2], argl[2], &azParam, &anParam, &nParam) ){
4ee9e31a2d 2008-02-13       drh:     return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* Allocate the new ProcDefn structure. */
4ee9e31a2d 2008-02-13       drh:   nByte = sizeof(ProcDefn) +                        /* ProcDefn structure */
0c99a1554a 2008-10-24       drh:       (sizeof(char *) + sizeof(int)) * nParam +    /* azParam, anParam */
0c99a1554a 2008-10-24       drh:       (sizeof(char *) + sizeof(int)) * nParam +    /* azDefault, anDefault */
4ee9e31a2d 2008-02-13       drh:       argl[3] +                                     /* zProgram */
4ee9e31a2d 2008-02-13       drh:       argl[2];     /* Space for copies of parameter names and default values */
4ee9e31a2d 2008-02-13       drh:   p = (ProcDefn *)Th_Malloc(interp, nByte);
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* If the last parameter in the parameter list is "args", then set the
4ee9e31a2d 2008-02-13       drh:   ** ProcDefn.hasArgs flag. The "args" parameter does not require an
4ee9e31a2d 2008-02-13       drh:   ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
4ee9e31a2d 2008-02-13       drh:   */
4ee9e31a2d 2008-02-13       drh:   if( anParam[nParam-1]==4 && 0==memcmp(azParam[nParam-1], "args", 4) ){
4ee9e31a2d 2008-02-13       drh:     p->hasArgs = 1;
4ee9e31a2d 2008-02-13       drh:     nParam--;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   p->nParam    = nParam;
0c99a1554a 2008-10-24       drh:   p->azParam   = (char **)&p[1];
4ee9e31a2d 2008-02-13       drh:   p->anParam   = (int *)&p->azParam[nParam];
0c99a1554a 2008-10-24       drh:   p->azDefault = (char **)&p->anParam[nParam];
4ee9e31a2d 2008-02-13       drh:   p->anDefault = (int *)&p->azDefault[nParam];
0c99a1554a 2008-10-24       drh:   p->zProgram = (char *)&p->anDefault[nParam];
4ee9e31a2d 2008-02-13       drh:   memcpy(p->zProgram, argv[3], argl[3]);
4ee9e31a2d 2008-02-13       drh:   p->nProgram = argl[3];
4ee9e31a2d 2008-02-13       drh:   zSpace = &p->zProgram[p->nProgram];
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   for(i=0; i<nParam; i++){
0c99a1554a 2008-10-24       drh:     char **az;
4ee9e31a2d 2008-02-13       drh:     int *an;
4ee9e31a2d 2008-02-13       drh:     int n;
4ee9e31a2d 2008-02-13       drh:     if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){
4ee9e31a2d 2008-02-13       drh:       goto error_out;
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:     if( n<1 || n>2 ){
4ee9e31a2d 2008-02-13       drh:       const char expected[] = "expected parameter, got \"";
4ee9e31a2d 2008-02-13       drh:       Th_ErrorMessage(interp, expected, azParam[i], anParam[i]);
4ee9e31a2d 2008-02-13       drh:       Th_Free(interp, az);
4ee9e31a2d 2008-02-13       drh:       goto error_out;
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:     p->anParam[i] = an[0];
4ee9e31a2d 2008-02-13       drh:     p->azParam[i] = zSpace;
4ee9e31a2d 2008-02-13       drh:     memcpy(zSpace, az[0], an[0]);
4ee9e31a2d 2008-02-13       drh:     zSpace += an[0];
4ee9e31a2d 2008-02-13       drh:     if( n==2 ){
4ee9e31a2d 2008-02-13       drh:       p->anDefault[i] = an[1];
4ee9e31a2d 2008-02-13       drh:       p->azDefault[i] = zSpace;
4ee9e31a2d 2008-02-13       drh:       memcpy(zSpace, az[1], an[1]);
4ee9e31a2d 2008-02-13       drh:       zSpace += an[1];
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh: 
0c99a1554a 2008-10-24       drh:     Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ", 1);
4ee9e31a2d 2008-02-13       drh:     if( n==2 ){
0c99a1554a 2008-10-24       drh:       Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"?", 1);
4ee9e31a2d 2008-02-13       drh:       Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
0c99a1554a 2008-10-24       drh:       Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"?", 1);
4ee9e31a2d 2008-02-13       drh:     }else{
4ee9e31a2d 2008-02-13       drh:       Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:     Th_Free(interp, az);
4ee9e31a2d 2008-02-13       drh:   }
0c99a1554a 2008-10-24       drh:   assert( zSpace-(char *)p<=nByte );
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* If there is an "args" parameter, append it to the end of the usage
4ee9e31a2d 2008-02-13       drh:   ** message. Set ProcDefn.zUsage to point at the usage message. It will
4ee9e31a2d 2008-02-13       drh:   ** be freed along with the rest of the proc-definition by proc_del().
4ee9e31a2d 2008-02-13       drh:   */
4ee9e31a2d 2008-02-13       drh:   if( p->hasArgs ){
0c99a1554a 2008-10-24       drh:     Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ?args...?", -1);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   p->zUsage = zUsage;
4ee9e31a2d 2008-02-13       drh:   p->nUsage = nUsage;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* Register the new command with the th1 interpreter. */
4ee9e31a2d 2008-02-13       drh:   zName = (char *)argv[1];
4ee9e31a2d 2008-02-13       drh:   rc = Th_CreateCommand(interp, zName, proc_call1, (void *)p, proc_del);
4ee9e31a2d 2008-02-13       drh:   if( rc==TH_OK ){
4ee9e31a2d 2008-02-13       drh:     Th_SetResult(interp, 0, 0);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   Th_Free(interp, azParam);
4ee9e31a2d 2008-02-13       drh:   return TH_OK;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:  error_out:
4ee9e31a2d 2008-02-13       drh:   Th_Free(interp, azParam);
4ee9e31a2d 2008-02-13       drh:   Th_Free(interp, zUsage);
4ee9e31a2d 2008-02-13       drh:   return TH_ERROR;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   rename oldcmd newcmd
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int rename_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   if( argc!=3 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   break    ?value...?
4ee9e31a2d 2008-02-13       drh: **   continue ?value...?
4ee9e31a2d 2008-02-13       drh: **   ok       ?value...?
4ee9e31a2d 2008-02-13       drh: **   error    ?value...?
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int simple_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   if( argc!=1 && argc!=2 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "return ?value?");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( argc==2 ){
4ee9e31a2d 2008-02-13       drh:     Th_SetResult(interp, argv[1], argl[1]);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return (int)ctx;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   return ?-code code? ?value?
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int return_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int iCode = TH_RETURN;
4ee9e31a2d 2008-02-13       drh:   if( argc<1 || argc>4 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "return ?-code code? ?value?");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( argc>2 ){
4ee9e31a2d 2008-02-13       drh:     int rc = Th_ToInt(interp, argv[2], argl[2], &iCode);
4ee9e31a2d 2008-02-13       drh:     if( rc!=TH_OK ){
4ee9e31a2d 2008-02-13       drh:       return rc;
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( argc==2 || argc==4 ){
4ee9e31a2d 2008-02-13       drh:     Th_SetResult(interp, argv[argc-1], argl[argc-1]);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return iCode;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   string compare STRING1 STRING2
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int string_compare_command(
0c99a1554a 2008-10-24       drh:   Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
0c99a1554a 2008-10-24       drh: ){
0c99a1554a 2008-10-24       drh:   const char *zRight; int nRight;
0c99a1554a 2008-10-24       drh:   const char *zLeft; int nLeft;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   int i;
4ee9e31a2d 2008-02-13       drh:   int iRes = 0;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=4 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "string compare str1 str2");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   zLeft = argv[2];
4ee9e31a2d 2008-02-13       drh:   nLeft = argl[2];
4ee9e31a2d 2008-02-13       drh:   zRight = argv[3];
4ee9e31a2d 2008-02-13       drh:   nRight = argl[3];
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   for(i=0; iRes==0 && i<nLeft && i<nRight; i++){
4ee9e31a2d 2008-02-13       drh:     iRes = zLeft[i]-zRight[i];
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( iRes==0 ){
4ee9e31a2d 2008-02-13       drh:     iRes = nLeft-nRight;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( iRes<0 ) iRes = -1;
4ee9e31a2d 2008-02-13       drh:   if( iRes>0 ) iRes = 1;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return Th_SetResultInt(interp, iRes);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   string first NEEDLE HAYSTACK
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int string_first_command(
0c99a1554a 2008-10-24       drh:   Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
0c99a1554a 2008-10-24       drh: ){
0c99a1554a 2008-10-24       drh:   const char *zNeedle;
4ee9e31a2d 2008-02-13       drh:   int nNeedle;
0c99a1554a 2008-10-24       drh:   const char *zHaystack;
4ee9e31a2d 2008-02-13       drh:   int nHaystack;
4ee9e31a2d 2008-02-13       drh:   int i;
cd965de682 2009-01-24       drh:   int iRes = -1;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=4 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "string first needle haystack");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   zNeedle = argv[2];
4ee9e31a2d 2008-02-13       drh:   nNeedle = argl[2];
4ee9e31a2d 2008-02-13       drh:   zHaystack = argv[3];
4ee9e31a2d 2008-02-13       drh:   nHaystack = argl[3];
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   for(i=0; i<(nHaystack-nNeedle); i++){
4ee9e31a2d 2008-02-13       drh:     if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
4ee9e31a2d 2008-02-13       drh:       iRes = i;
4ee9e31a2d 2008-02-13       drh:       break;
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return Th_SetResultInt(interp, iRes);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   string is CLASS STRING
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int string_is_command(
0c99a1554a 2008-10-24       drh:   Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int i;
4ee9e31a2d 2008-02-13       drh:   int iRes = 1;
4ee9e31a2d 2008-02-13       drh:   if( argc!=4 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "string is class string");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( argl[2]!=5 || 0!=memcmp(argv[2], "alnum", 5) ){
4ee9e31a2d 2008-02-13       drh:     Th_ErrorMessage(interp, "Expected alnum, got: ", argv[2], argl[2]);
4ee9e31a2d 2008-02-13       drh:     return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   for(i=0; i<argl[3]; i++){
4ee9e31a2d 2008-02-13       drh:     if( !th_isalnum(argv[3][i]) ){
4ee9e31a2d 2008-02-13       drh:       iRes = 0;
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return Th_SetResultInt(interp, iRes);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   string last NEEDLE HAYSTACK
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int string_last_command(
0c99a1554a 2008-10-24       drh:   Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
0c99a1554a 2008-10-24       drh: ){
0c99a1554a 2008-10-24       drh:   const char *zNeedle;
4ee9e31a2d 2008-02-13       drh:   int nNeedle;
0c99a1554a 2008-10-24       drh:   const char *zHaystack;
4ee9e31a2d 2008-02-13       drh:   int nHaystack;
4ee9e31a2d 2008-02-13       drh:   int i;
cd965de682 2009-01-24       drh:   int iRes = -1;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=4 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "string first needle haystack");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   zNeedle = argv[2];
4ee9e31a2d 2008-02-13       drh:   nNeedle = argl[2];
4ee9e31a2d 2008-02-13       drh:   zHaystack = argv[3];
4ee9e31a2d 2008-02-13       drh:   nHaystack = argl[3];
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   for(i=nHaystack-nNeedle-1; i>=0; i--){
4ee9e31a2d 2008-02-13       drh:     if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
4ee9e31a2d 2008-02-13       drh:       iRes = i;
4ee9e31a2d 2008-02-13       drh:       break;
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return Th_SetResultInt(interp, iRes);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   string length STRING
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int string_length_command(
0c99a1554a 2008-10-24       drh:   Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   if( argc!=3 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "string length string");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return Th_SetResultInt(interp, argl[2]);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   string range STRING FIRST LAST
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int string_range_command(
0c99a1554a 2008-10-24       drh:   Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int iStart;
4ee9e31a2d 2008-02-13       drh:   int iEnd;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=5 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "string range string first last");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argl[4]==3 && 0==memcmp("end", argv[4], 3) ){
4ee9e31a2d 2008-02-13       drh:     iEnd = argl[2];
4ee9e31a2d 2008-02-13       drh:   }else if( Th_ToInt(interp, argv[4], argl[4], &iEnd) ){
4ee9e31a2d 2008-02-13       drh:     Th_ErrorMessage(
4ee9e31a2d 2008-02-13       drh:         interp, "Expected \"end\" or integer, got:", argv[4], argl[4]);
4ee9e31a2d 2008-02-13       drh:     return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( Th_ToInt(interp, argv[3], argl[3], &iStart) ){
4ee9e31a2d 2008-02-13       drh:     return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( iStart<0 ) iStart = 0;
4ee9e31a2d 2008-02-13       drh:   if( iEnd>=argl[2] ) iEnd = argl[2]-1;
4ee9e31a2d 2008-02-13       drh:   if( iStart>iEnd ) iEnd = iStart-1;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return Th_SetResult(interp, &argv[2][iStart], iEnd-iStart+1);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   string repeat STRING COUNT
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int string_repeat_command(
0c99a1554a 2008-10-24       drh:   Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int n;
4ee9e31a2d 2008-02-13       drh:   int i;
4ee9e31a2d 2008-02-13       drh:   int nByte;
0c99a1554a 2008-10-24       drh:   char *zByte;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=4 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "string repeat string n");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( Th_ToInt(interp, argv[3], argl[3], &n) ){
4ee9e31a2d 2008-02-13       drh:     return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   nByte = argl[2] * n;
4ee9e31a2d 2008-02-13       drh:   zByte = Th_Malloc(interp, nByte+1);
4ee9e31a2d 2008-02-13       drh:   for(i=0; i<nByte; i+=argl[2]){
4ee9e31a2d 2008-02-13       drh:     memcpy(&zByte[i], argv[2], argl[2]);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   Th_SetResult(interp, zByte, nByte);
4ee9e31a2d 2008-02-13       drh:   Th_Free(interp, zByte);
4ee9e31a2d 2008-02-13       drh:   return TH_OK;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   info exists VAR
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int info_exists_command(
0c99a1554a 2008-10-24       drh:   Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int rc;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=3 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "info exists var");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   rc = Th_GetVar(interp, argv[2], argl[2]);
4ee9e31a2d 2008-02-13       drh:   Th_SetResultInt(interp, rc?0:1);
4ee9e31a2d 2008-02-13       drh:   return TH_OK;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   unset VAR
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int unset_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   if( argc!=2 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "unset var");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return Th_UnsetVar(interp, argv[1], argl[1]);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: int Th_CallSubCommand(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl,
4ee9e31a2d 2008-02-13       drh:   Th_SubCommand *aSub
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int i;
4ee9e31a2d 2008-02-13       drh:   for(i=0; aSub[i].zName; i++){
0c99a1554a 2008-10-24       drh:     char *zName = (char *)aSub[i].zName;
4ee9e31a2d 2008-02-13       drh:     if( th_strlen(zName)==argl[1] && 0==memcmp(zName, argv[1], argl[1]) ){
4ee9e31a2d 2008-02-13       drh:       return aSub[i].xProc(interp, ctx, argc, argv, argl);
4ee9e31a2d 2008-02-13       drh:     }
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   Th_ErrorMessage(interp, "Expected sub-command, got:", argv[1], argl[1]);
4ee9e31a2d 2008-02-13       drh:   return TH_ERROR;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   string compare STR1 STR2
4ee9e31a2d 2008-02-13       drh: **   string first   NEEDLE HAYSTACK ?STARTINDEX?
4ee9e31a2d 2008-02-13       drh: **   string is      CLASS STRING
4ee9e31a2d 2008-02-13       drh: **   string last    NEEDLE HAYSTACK ?STARTINDEX?
4ee9e31a2d 2008-02-13       drh: **   string length  STRING
4ee9e31a2d 2008-02-13       drh: **   string range   STRING FIRST LAST
4ee9e31a2d 2008-02-13       drh: **   string repeat  STRING COUNT
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int string_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   Th_SubCommand aSub[] = {
4ee9e31a2d 2008-02-13       drh:     { "compare", string_compare_command },
4ee9e31a2d 2008-02-13       drh:     { "first",   string_first_command },
4ee9e31a2d 2008-02-13       drh:     { "is",      string_is_command },
4ee9e31a2d 2008-02-13       drh:     { "last",    string_last_command },
4ee9e31a2d 2008-02-13       drh:     { "length",  string_length_command },
4ee9e31a2d 2008-02-13       drh:     { "range",   string_range_command },
4ee9e31a2d 2008-02-13       drh:     { "repeat",  string_repeat_command },
4ee9e31a2d 2008-02-13       drh:     { 0, 0 }
4ee9e31a2d 2008-02-13       drh:   };
4ee9e31a2d 2008-02-13       drh:   return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   info exists VARNAME
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int info_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   Th_SubCommand aSub[] = {
4ee9e31a2d 2008-02-13       drh:     { "exists",  info_exists_command },
4ee9e31a2d 2008-02-13       drh:     { 0, 0 }
4ee9e31a2d 2008-02-13       drh:   };
4ee9e31a2d 2008-02-13       drh:   return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** Convert the script level frame specification (used by the commands
4ee9e31a2d 2008-02-13       drh: ** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as
4ee9e31a2d 2008-02-13       drh: ** used by Th_LinkVar() and Th_Eval(). If successful, write the integer
4ee9e31a2d 2008-02-13       drh: ** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR
4ee9e31a2d 2008-02-13       drh: ** and leave an error message in the interpreter result.
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int thToFrame(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
0c99a1554a 2008-10-24       drh:   const char *zFrame,
4ee9e31a2d 2008-02-13       drh:   int nFrame,
4ee9e31a2d 2008-02-13       drh:   int *piFrame
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int iFrame;
4ee9e31a2d 2008-02-13       drh:   if( th_isdigit(zFrame[0]) ){
4ee9e31a2d 2008-02-13       drh:     int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame);
4ee9e31a2d 2008-02-13       drh:     if( rc!=TH_OK ) return rc;
4ee9e31a2d 2008-02-13       drh:     iFrame = iFrame * -1;
4ee9e31a2d 2008-02-13       drh:   }else if( zFrame[0]=='#' ){
4ee9e31a2d 2008-02-13       drh:     int rc = Th_ToInt(interp, &zFrame[1], nFrame-1, &iFrame);
4ee9e31a2d 2008-02-13       drh:     if( rc!=TH_OK ) return rc;
4ee9e31a2d 2008-02-13       drh:     iFrame = iFrame + 1;
4ee9e31a2d 2008-02-13       drh:   }else{
4ee9e31a2d 2008-02-13       drh:     return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   *piFrame = iFrame;
4ee9e31a2d 2008-02-13       drh:   return TH_OK;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   uplevel ?LEVEL? SCRIPT
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int uplevel_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int iFrame = -1;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( argc!=2 && argc!=3 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp, "uplevel ?level? script...");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( argc==3 && TH_OK!=thToFrame(interp, argv[1], argl[1], &iFrame) ){
4ee9e31a2d 2008-02-13       drh:     return TH_ERROR;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return Th_Eval(interp, iFrame, argv[argc-1], -1);
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...?
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int upvar_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int iVar = 1;
4ee9e31a2d 2008-02-13       drh:   int iFrame = -1;
4ee9e31a2d 2008-02-13       drh:   int rc = TH_OK;
4ee9e31a2d 2008-02-13       drh:   int i;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){
4ee9e31a2d 2008-02-13       drh:     iVar++;
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   if( argc==iVar || (argc-iVar)%2 ){
4ee9e31a2d 2008-02-13       drh:     return Th_WrongNumArgs(interp,
4ee9e31a2d 2008-02-13       drh:         "upvar frame othervar myvar ?othervar myvar...?");
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   for(i=iVar; rc==TH_OK && i<argc; i=i+2){
4ee9e31a2d 2008-02-13       drh:     rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh:   return rc;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** TH Syntax:
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: **   breakpoint ARGS
4ee9e31a2d 2008-02-13       drh: **
4ee9e31a2d 2008-02-13       drh: ** This command does nothing at all. Its purpose in life is to serve
4ee9e31a2d 2008-02-13       drh: ** as a point for setting breakpoints in a debugger.
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: static int breakpoint_command(
4ee9e31a2d 2008-02-13       drh:   Th_Interp *interp,
4ee9e31a2d 2008-02-13       drh:   void *ctx,
4ee9e31a2d 2008-02-13       drh:   int argc,
0c99a1554a 2008-10-24       drh:   const char **argv,
4ee9e31a2d 2008-02-13       drh:   int *argl
4ee9e31a2d 2008-02-13       drh: ){
4ee9e31a2d 2008-02-13       drh:   int cnt = 0;
4ee9e31a2d 2008-02-13       drh:   cnt++;
4ee9e31a2d 2008-02-13       drh:   return TH_OK;
4ee9e31a2d 2008-02-13       drh: }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh: /*
4ee9e31a2d 2008-02-13       drh: ** Register the built-in th1 language commands with interpreter interp.
4ee9e31a2d 2008-02-13       drh: ** Usually this is called soon after interpreter creation.
4ee9e31a2d 2008-02-13       drh: */
4ee9e31a2d 2008-02-13       drh: int th_register_language(Th_Interp *interp){
4ee9e31a2d 2008-02-13       drh:   /* Array of built-in commands. */
4ee9e31a2d 2008-02-13       drh:   struct _Command {
4ee9e31a2d 2008-02-13       drh:     const char *zName;
4ee9e31a2d 2008-02-13       drh:     Th_CommandProc xProc;
4ee9e31a2d 2008-02-13       drh:     void *pContext;
4ee9e31a2d 2008-02-13       drh:   } aCommand[] = {
4ee9e31a2d 2008-02-13       drh:     {"catch",    catch_command,   0},
4ee9e31a2d 2008-02-13       drh:     {"expr",     expr_command,    0},
4ee9e31a2d 2008-02-13       drh:     {"for",      for_command,     0},
4ee9e31a2d 2008-02-13       drh:     {"if",       if_command,      0},
4ee9e31a2d 2008-02-13       drh:     {"info",     info_command,    0},
4ee9e31a2d 2008-02-13       drh:     {"lindex",   lindex_command,  0},
4ee9e31a2d 2008-02-13       drh:     {"list",     list_command,    0},
4ee9e31a2d 2008-02-13       drh:     {"llength",  llength_command, 0},
4ee9e31a2d 2008-02-13       drh:     {"proc",     proc_command,    0},
4ee9e31a2d 2008-02-13       drh:     {"rename",   rename_command,  0},
4ee9e31a2d 2008-02-13       drh:     {"set",      set_command,     0},
4ee9e31a2d 2008-02-13       drh:     {"string",   string_command,  0},
4ee9e31a2d 2008-02-13       drh:     {"unset",    unset_command,   0},
4ee9e31a2d 2008-02-13       drh:     {"uplevel",  uplevel_command, 0},
4ee9e31a2d 2008-02-13       drh:     {"upvar",    upvar_command,   0},
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:     {"breakpoint", breakpoint_command, 0},
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:     {"return",   return_command, 0},
4ee9e31a2d 2008-02-13       drh:     {"break",    simple_command, (void *)TH_BREAK},
4ee9e31a2d 2008-02-13       drh:     {"continue", simple_command, (void *)TH_CONTINUE},
4ee9e31a2d 2008-02-13       drh:     {"error",    simple_command, (void *)TH_ERROR},
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:     {0, 0}
4ee9e31a2d 2008-02-13       drh:   };
4ee9e31a2d 2008-02-13       drh:   int i;
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   /* Add the language commands. */
4ee9e31a2d 2008-02-13       drh:   for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
4ee9e31a2d 2008-02-13       drh:     void *ctx = aCommand[i].pContext;
4ee9e31a2d 2008-02-13       drh:     Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0);
4ee9e31a2d 2008-02-13       drh:   }
4ee9e31a2d 2008-02-13       drh: 
4ee9e31a2d 2008-02-13       drh:   return TH_OK;
4ee9e31a2d 2008-02-13       drh: }