/[dtapublic]/projs/ets/trunk/src/c_tcl_base_7_5_w_mods/tclbasic.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tcl_base_7_5_w_mods/tclbasic.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

projs/trunk/shared_source/tcl_base/tclbasic.c revision 42 by dashley, Fri Oct 14 01:50:00 2016 UTC projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclbasic.c revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tcl_base/tclbasic.c,v 1.1.1.1 2001/06/13 04:33:43 dtashley Exp $ */  
   
 /*  
  * tclBasic.c --  
  *  
  *      Contains the basic facilities for TCL command interpretation,  
  *      including interpreter creation and deletion, command creation  
  *      and deletion, and command parsing and execution.  
  *  
  * Copyright (c) 1987-1994 The Regents of the University of California.  
  * Copyright (c) 1994-1997 Sun Microsystems, Inc.  
  * Copyright (c) 1998-1999 by Scriptics Corporation.  
  *  
  * See the file "license.terms" for information on usage and redistribution  
  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.  
  *  
  * RCS: @(#) $Id: tclbasic.c,v 1.1.1.1 2001/06/13 04:33:43 dtashley Exp $  
  */  
   
 #include "tclInt.h"  
 #include "tclCompile.h"  
 #ifndef TCL_GENERIC_ONLY  
 #   include "tclPort.h"  
 #endif  
   
 /*  
  * Static procedures in this file:  
  */  
   
 static void             DeleteInterpProc _ANSI_ARGS_((Tcl_Interp *interp));  
 static void             ProcessUnexpectedResult _ANSI_ARGS_((  
                             Tcl_Interp *interp, int returnCode));  
 static void             RecordTracebackInfo _ANSI_ARGS_((  
                             Tcl_Interp *interp, Tcl_Obj *objPtr,  
                             int numSrcBytes));  
   
 extern TclStubs tclStubs;  
   
 /*  
  * The following structure defines the commands in the Tcl core.  
  */  
   
 typedef struct {  
     char *name;                 /* Name of object-based command. */  
     Tcl_CmdProc *proc;          /* String-based procedure for command. */  
     Tcl_ObjCmdProc *objProc;    /* Object-based procedure for command. */  
     CompileProc *compileProc;   /* Procedure called to compile command. */  
     int isSafe;                 /* If non-zero, command will be present  
                                  * in safe interpreter. Otherwise it will  
                                  * be hidden. */  
 } CmdInfo;  
   
 /*  
  * The built-in commands, and the procedures that implement them:  
  */  
   
 static CmdInfo builtInCmds[] = {  
     /*  
      * Commands in the generic core. Note that at least one of the proc or  
      * objProc members should be non-NULL. This avoids infinitely recursive  
      * calls between TclInvokeObjectCommand and TclInvokeStringCommand if a  
      * command name is computed at runtime and results in the name of a  
      * compiled command.  
      */  
   
     {"append",          (Tcl_CmdProc *) NULL,   Tcl_AppendObjCmd,  
         (CompileProc *) NULL,           1},  
     {"array",           (Tcl_CmdProc *) NULL,   Tcl_ArrayObjCmd,  
         (CompileProc *) NULL,           1},  
     {"binary",          (Tcl_CmdProc *) NULL,   Tcl_BinaryObjCmd,  
         (CompileProc *) NULL,           1},  
     {"break",           (Tcl_CmdProc *) NULL,   Tcl_BreakObjCmd,  
         TclCompileBreakCmd,             1},  
     {"case",            (Tcl_CmdProc *) NULL,   Tcl_CaseObjCmd,  
         (CompileProc *) NULL,           1},  
     {"catch",           (Tcl_CmdProc *) NULL,   Tcl_CatchObjCmd,          
         TclCompileCatchCmd,             1},  
     {"clock",           (Tcl_CmdProc *) NULL,   Tcl_ClockObjCmd,  
         (CompileProc *) NULL,           1},  
     {"concat",          (Tcl_CmdProc *) NULL,   Tcl_ConcatObjCmd,  
         (CompileProc *) NULL,           1},  
     {"continue",        (Tcl_CmdProc *) NULL,   Tcl_ContinueObjCmd,  
         TclCompileContinueCmd,          1},  
     {"encoding",        (Tcl_CmdProc *) NULL,   Tcl_EncodingObjCmd,  
         (CompileProc *) NULL,           0},  
     {"error",           (Tcl_CmdProc *) NULL,   Tcl_ErrorObjCmd,  
         (CompileProc *) NULL,           1},  
     {"eval",            (Tcl_CmdProc *) NULL,   Tcl_EvalObjCmd,  
         (CompileProc *) NULL,           1},  
     {"exit",            (Tcl_CmdProc *) NULL,   Tcl_ExitObjCmd,  
         (CompileProc *) NULL,           0},  
     {"expr",            (Tcl_CmdProc *) NULL,   Tcl_ExprObjCmd,  
         TclCompileExprCmd,              1},  
     {"fcopy",           (Tcl_CmdProc *) NULL,   Tcl_FcopyObjCmd,  
         (CompileProc *) NULL,           1},  
     {"fileevent",       (Tcl_CmdProc *) NULL,   Tcl_FileEventObjCmd,  
         (CompileProc *) NULL,           1},  
     {"for",             (Tcl_CmdProc *) NULL,   Tcl_ForObjCmd,  
         TclCompileForCmd,               1},  
     {"foreach",         (Tcl_CmdProc *) NULL,   Tcl_ForeachObjCmd,  
         TclCompileForeachCmd,           1},  
     {"format",          (Tcl_CmdProc *) NULL,   Tcl_FormatObjCmd,  
         (CompileProc *) NULL,           1},  
     {"global",          (Tcl_CmdProc *) NULL,   Tcl_GlobalObjCmd,  
         (CompileProc *) NULL,           1},  
     {"if",              (Tcl_CmdProc *) NULL,   Tcl_IfObjCmd,  
         TclCompileIfCmd,                1},  
     {"incr",            (Tcl_CmdProc *) NULL,   Tcl_IncrObjCmd,  
         TclCompileIncrCmd,              1},  
     {"info",            (Tcl_CmdProc *) NULL,   Tcl_InfoObjCmd,  
         (CompileProc *) NULL,           1},  
     {"join",            (Tcl_CmdProc *) NULL,   Tcl_JoinObjCmd,  
         (CompileProc *) NULL,           1},  
     {"lappend",         (Tcl_CmdProc *) NULL,   Tcl_LappendObjCmd,  
         (CompileProc *) NULL,           1},  
     {"lindex",          (Tcl_CmdProc *) NULL,   Tcl_LindexObjCmd,  
         (CompileProc *) NULL,           1},  
     {"linsert",         (Tcl_CmdProc *) NULL,   Tcl_LinsertObjCmd,  
         (CompileProc *) NULL,           1},  
     {"list",            (Tcl_CmdProc *) NULL,   Tcl_ListObjCmd,  
         (CompileProc *) NULL,           1},  
     {"llength",         (Tcl_CmdProc *) NULL,   Tcl_LlengthObjCmd,  
         (CompileProc *) NULL,           1},  
     {"load",            (Tcl_CmdProc *) NULL,   Tcl_LoadObjCmd,  
         (CompileProc *) NULL,           0},  
     {"lrange",          (Tcl_CmdProc *) NULL,   Tcl_LrangeObjCmd,  
         (CompileProc *) NULL,           1},  
     {"lreplace",        (Tcl_CmdProc *) NULL,   Tcl_LreplaceObjCmd,  
         (CompileProc *) NULL,           1},  
     {"lsearch",         (Tcl_CmdProc *) NULL,   Tcl_LsearchObjCmd,  
         (CompileProc *) NULL,           1},  
     {"lsort",           (Tcl_CmdProc *) NULL,   Tcl_LsortObjCmd,  
         (CompileProc *) NULL,           1},  
     {"namespace",       (Tcl_CmdProc *) NULL,   Tcl_NamespaceObjCmd,  
         (CompileProc *) NULL,           1},  
     {"package",         (Tcl_CmdProc *) NULL,   Tcl_PackageObjCmd,  
         (CompileProc *) NULL,           1},  
     {"proc",            (Tcl_CmdProc *) NULL,   Tcl_ProcObjCmd,  
         (CompileProc *) NULL,           1},  
     {"regexp",          (Tcl_CmdProc *) NULL,   Tcl_RegexpObjCmd,  
         (CompileProc *) NULL,           1},  
     {"regsub",          (Tcl_CmdProc *) NULL,   Tcl_RegsubObjCmd,  
         (CompileProc *) NULL,           1},  
     {"rename",          (Tcl_CmdProc *) NULL,   Tcl_RenameObjCmd,  
         (CompileProc *) NULL,           1},  
     {"return",          (Tcl_CmdProc *) NULL,   Tcl_ReturnObjCmd,        
         (CompileProc *) NULL,           1},  
     {"scan",            (Tcl_CmdProc *) NULL,   Tcl_ScanObjCmd,  
         (CompileProc *) NULL,           1},  
     {"set",             (Tcl_CmdProc *) NULL,   Tcl_SetObjCmd,  
         TclCompileSetCmd,               1},  
     {"split",           (Tcl_CmdProc *) NULL,   Tcl_SplitObjCmd,  
         (CompileProc *) NULL,           1},  
     {"string",          (Tcl_CmdProc *) NULL,   Tcl_StringObjCmd,  
         (CompileProc *) NULL,           1},  
     {"subst",           (Tcl_CmdProc *) NULL,   Tcl_SubstObjCmd,  
         (CompileProc *) NULL,           1},  
     {"switch",          (Tcl_CmdProc *) NULL,   Tcl_SwitchObjCmd,        
         (CompileProc *) NULL,           1},  
     {"trace",           (Tcl_CmdProc *) NULL,   Tcl_TraceObjCmd,  
         (CompileProc *) NULL,           1},  
     {"unset",           (Tcl_CmdProc *) NULL,   Tcl_UnsetObjCmd,          
         (CompileProc *) NULL,           1},  
     {"uplevel",         (Tcl_CmdProc *) NULL,   Tcl_UplevelObjCmd,        
         (CompileProc *) NULL,           1},  
     {"upvar",           (Tcl_CmdProc *) NULL,   Tcl_UpvarObjCmd,          
         (CompileProc *) NULL,           1},  
     {"variable",        (Tcl_CmdProc *) NULL,   Tcl_VariableObjCmd,  
         (CompileProc *) NULL,           1},  
     {"while",           (Tcl_CmdProc *) NULL,   Tcl_WhileObjCmd,  
         TclCompileWhileCmd,             1},  
   
     /*  
      * Commands in the UNIX core:  
      */  
   
 #ifndef TCL_GENERIC_ONLY  
     {"after",           (Tcl_CmdProc *) NULL,   Tcl_AfterObjCmd,  
         (CompileProc *) NULL,           1},  
     {"cd",              (Tcl_CmdProc *) NULL,   Tcl_CdObjCmd,  
         (CompileProc *) NULL,           0},  
     {"close",           (Tcl_CmdProc *) NULL,   Tcl_CloseObjCmd,  
         (CompileProc *) NULL,           1},  
     {"eof",             (Tcl_CmdProc *) NULL,   Tcl_EofObjCmd,  
         (CompileProc *) NULL,           1},  
     {"fblocked",        (Tcl_CmdProc *) NULL,   Tcl_FblockedObjCmd,  
         (CompileProc *) NULL,           1},  
     {"fconfigure",      (Tcl_CmdProc *) NULL,   Tcl_FconfigureObjCmd,  
         (CompileProc *) NULL,           0},  
     {"file",            (Tcl_CmdProc *) NULL,   Tcl_FileObjCmd,  
         (CompileProc *) NULL,           0},  
     {"flush",           (Tcl_CmdProc *) NULL,   Tcl_FlushObjCmd,  
         (CompileProc *) NULL,           1},  
     {"gets",            (Tcl_CmdProc *) NULL,   Tcl_GetsObjCmd,  
         (CompileProc *) NULL,           1},  
     {"glob",            (Tcl_CmdProc *) NULL,   Tcl_GlobObjCmd,  
         (CompileProc *) NULL,           0},  
     {"open",            (Tcl_CmdProc *) NULL,   Tcl_OpenObjCmd,  
         (CompileProc *) NULL,           0},  
     {"pid",             (Tcl_CmdProc *) NULL,   Tcl_PidObjCmd,  
         (CompileProc *) NULL,           1},  
     {"puts",            (Tcl_CmdProc *) NULL,   Tcl_PutsObjCmd,  
         (CompileProc *) NULL,           1},  
     {"pwd",             (Tcl_CmdProc *) NULL,   Tcl_PwdObjCmd,  
         (CompileProc *) NULL,           0},  
     {"read",            (Tcl_CmdProc *) NULL,   Tcl_ReadObjCmd,  
         (CompileProc *) NULL,           1},  
     {"seek",            (Tcl_CmdProc *) NULL,   Tcl_SeekObjCmd,  
         (CompileProc *) NULL,           1},  
     {"socket",          (Tcl_CmdProc *) NULL,   Tcl_SocketObjCmd,  
         (CompileProc *) NULL,           0},  
     {"tell",            (Tcl_CmdProc *) NULL,   Tcl_TellObjCmd,  
         (CompileProc *) NULL,           1},  
     {"time",            (Tcl_CmdProc *) NULL,   Tcl_TimeObjCmd,  
         (CompileProc *) NULL,           1},  
     {"update",          (Tcl_CmdProc *) NULL,   Tcl_UpdateObjCmd,  
         (CompileProc *) NULL,           1},  
     {"vwait",           (Tcl_CmdProc *) NULL,   Tcl_VwaitObjCmd,  
         (CompileProc *) NULL,           1},  
       
 #ifdef MAC_TCL  
     {"beep",            (Tcl_CmdProc *) NULL,   Tcl_BeepObjCmd,  
         (CompileProc *) NULL,           0},  
     {"echo",            Tcl_EchoCmd,            (Tcl_ObjCmdProc *) NULL,  
         (CompileProc *) NULL,           0},  
     {"ls",              (Tcl_CmdProc *) NULL,   Tcl_LsObjCmd,  
         (CompileProc *) NULL,           0},  
     {"resource",        (Tcl_CmdProc *) NULL,   Tcl_ResourceObjCmd,  
         (CompileProc *) NULL,           1},  
     {"source",          (Tcl_CmdProc *) NULL,   Tcl_MacSourceObjCmd,  
         (CompileProc *) NULL,           0},  
 #else  
     {"exec",            (Tcl_CmdProc *) NULL,   Tcl_ExecObjCmd,  
         (CompileProc *) NULL,           0},  
     {"source",          (Tcl_CmdProc *) NULL,   Tcl_SourceObjCmd,  
         (CompileProc *) NULL,           0},  
 #endif /* MAC_TCL */  
       
 #endif /* TCL_GENERIC_ONLY */  
     {NULL,              (Tcl_CmdProc *) NULL,   (Tcl_ObjCmdProc *) NULL,  
         (CompileProc *) NULL,           0}  
 };  
   
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_CreateInterp --  
  *  
  *      Create a new TCL command interpreter.  
  *  
  * Results:  
  *      The return value is a token for the interpreter, which may be  
  *      used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or  
  *      Tcl_DeleteInterp.  
  *  
  * Side effects:  
  *      The command interpreter is initialized with an empty variable  
  *      table and the built-in commands.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tcl_Interp *  
 Tcl_CreateInterp()  
 {  
     Interp *iPtr;  
     Tcl_Interp *interp;  
     Command *cmdPtr;  
     BuiltinFunc *builtinFuncPtr;  
     MathFunc *mathFuncPtr;  
     Tcl_HashEntry *hPtr;  
     CmdInfo *cmdInfoPtr;  
     int i;  
     union {  
         char c[sizeof(short)];  
         short s;  
     } order;  
 #ifdef TCL_COMPILE_STATS  
     ByteCodeStats *statsPtr;  
 #endif /* TCL_COMPILE_STATS */  
   
     TclInitSubsystems(NULL);  
   
     /*  
      * Panic if someone updated the CallFrame structure without  
      * also updating the Tcl_CallFrame structure (or vice versa).  
      */    
   
     if (sizeof(Tcl_CallFrame) != sizeof(CallFrame)) {  
         /*NOTREACHED*/  
         panic("Tcl_CallFrame and CallFrame are not the same size");  
     }  
   
     /*  
      * Initialize support for namespaces and create the global namespace  
      * (whose name is ""; an alias is "::"). This also initializes the  
      * Tcl object type table and other object management code.  
      */  
   
     iPtr = (Interp *) ckalloc(sizeof(Interp));  
     interp = (Tcl_Interp *) iPtr;  
   
     iPtr->result                = iPtr->resultSpace;  
     iPtr->freeProc              = NULL;  
     iPtr->errorLine             = 0;  
     iPtr->objResultPtr          = Tcl_NewObj();  
     Tcl_IncrRefCount(iPtr->objResultPtr);  
     iPtr->handle                = TclHandleCreate(iPtr);  
     iPtr->globalNsPtr           = NULL;  
     iPtr->hiddenCmdTablePtr     = NULL;  
     iPtr->interpInfo            = NULL;  
     Tcl_InitHashTable(&iPtr->mathFuncTable, TCL_STRING_KEYS);  
   
     iPtr->numLevels = 0;  
     iPtr->maxNestingDepth = 1000;  
     iPtr->framePtr = NULL;  
     iPtr->varFramePtr = NULL;  
     iPtr->activeTracePtr = NULL;  
     iPtr->returnCode = TCL_OK;  
     iPtr->errorInfo = NULL;  
     iPtr->errorCode = NULL;  
   
     iPtr->appendResult = NULL;  
     iPtr->appendAvl = 0;  
     iPtr->appendUsed = 0;  
   
     Tcl_InitHashTable(&iPtr->packageTable, TCL_STRING_KEYS);  
     iPtr->packageUnknown = NULL;  
     iPtr->cmdCount = 0;  
     iPtr->termOffset = 0;  
     TclInitLiteralTable(&(iPtr->literalTable));  
     iPtr->compileEpoch = 0;  
     iPtr->compiledProcPtr = NULL;  
     iPtr->resolverPtr = NULL;  
     iPtr->evalFlags = 0;  
     iPtr->scriptFile = NULL;  
     iPtr->flags = 0;  
     iPtr->tracePtr = NULL;  
     iPtr->assocData = (Tcl_HashTable *) NULL;  
     iPtr->execEnvPtr = NULL;          /* set after namespaces initialized */  
     iPtr->emptyObjPtr = Tcl_NewObj(); /* another empty object */  
     Tcl_IncrRefCount(iPtr->emptyObjPtr);  
     iPtr->resultSpace[0] = 0;  
   
     iPtr->globalNsPtr = NULL;   /* force creation of global ns below */  
     iPtr->globalNsPtr = (Namespace *) Tcl_CreateNamespace(interp, "",  
             (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL);  
     if (iPtr->globalNsPtr == NULL) {  
         panic("Tcl_CreateInterp: can't create global namespace");  
     }  
   
     /*  
      * Initialize support for code compilation and execution. We call  
      * TclCreateExecEnv after initializing namespaces since it tries to  
      * reference a Tcl variable (it links to the Tcl "tcl_traceExec"  
      * variable).  
      */  
   
     iPtr->execEnvPtr = TclCreateExecEnv(interp);  
   
     /*  
      * Initialize the compilation and execution statistics kept for this  
      * interpreter.  
      */  
   
 #ifdef TCL_COMPILE_STATS  
     statsPtr = &(iPtr->stats);  
     statsPtr->numExecutions = 0;  
     statsPtr->numCompilations = 0;  
     statsPtr->numByteCodesFreed = 0;  
     (VOID *) memset(statsPtr->instructionCount, 0,  
             sizeof(statsPtr->instructionCount));  
   
     statsPtr->totalSrcBytes = 0.0;  
     statsPtr->totalByteCodeBytes = 0.0;  
     statsPtr->currentSrcBytes = 0.0;  
     statsPtr->currentByteCodeBytes = 0.0;  
     (VOID *) memset(statsPtr->srcCount, 0, sizeof(statsPtr->srcCount));  
     (VOID *) memset(statsPtr->byteCodeCount, 0,  
             sizeof(statsPtr->byteCodeCount));  
     (VOID *) memset(statsPtr->lifetimeCount, 0,  
             sizeof(statsPtr->lifetimeCount));  
       
     statsPtr->currentInstBytes   = 0.0;  
     statsPtr->currentLitBytes    = 0.0;  
     statsPtr->currentExceptBytes = 0.0;  
     statsPtr->currentAuxBytes    = 0.0;  
     statsPtr->currentCmdMapBytes = 0.0;  
       
     statsPtr->numLiteralsCreated    = 0;  
     statsPtr->totalLitStringBytes   = 0.0;  
     statsPtr->currentLitStringBytes = 0.0;  
     (VOID *) memset(statsPtr->literalCount, 0,  
             sizeof(statsPtr->literalCount));  
 #endif /* TCL_COMPILE_STATS */      
   
     /*  
      * Initialise the stub table pointer.  
      */  
   
     iPtr->stubTable = &tclStubs;  
   
       
     /*  
      * Create the core commands. Do it here, rather than calling  
      * Tcl_CreateCommand, because it's faster (there's no need to check for  
      * a pre-existing command by the same name). If a command has a  
      * Tcl_CmdProc but no Tcl_ObjCmdProc, set the Tcl_ObjCmdProc to  
      * TclInvokeStringCommand. This is an object-based wrapper procedure  
      * that extracts strings, calls the string procedure, and creates an  
      * object for the result. Similarly, if a command has a Tcl_ObjCmdProc  
      * but no Tcl_CmdProc, set the Tcl_CmdProc to TclInvokeObjectCommand.  
      */  
   
     for (cmdInfoPtr = builtInCmds;  cmdInfoPtr->name != NULL;  
             cmdInfoPtr++) {  
         int new;  
         Tcl_HashEntry *hPtr;  
   
         if ((cmdInfoPtr->proc == (Tcl_CmdProc *) NULL)  
                 && (cmdInfoPtr->objProc == (Tcl_ObjCmdProc *) NULL)  
                 && (cmdInfoPtr->compileProc == (CompileProc *) NULL)) {  
             panic("Tcl_CreateInterp: builtin command with NULL string and object command procs and a NULL compile proc\n");  
         }  
           
         hPtr = Tcl_CreateHashEntry(&iPtr->globalNsPtr->cmdTable,  
                 cmdInfoPtr->name, &new);  
         if (new) {  
             cmdPtr = (Command *) ckalloc(sizeof(Command));  
             cmdPtr->hPtr = hPtr;  
             cmdPtr->nsPtr = iPtr->globalNsPtr;  
             cmdPtr->refCount = 1;  
             cmdPtr->cmdEpoch = 0;  
             cmdPtr->compileProc = cmdInfoPtr->compileProc;  
             if (cmdInfoPtr->proc == (Tcl_CmdProc *) NULL) {  
                 cmdPtr->proc = TclInvokeObjectCommand;  
                 cmdPtr->clientData = (ClientData) cmdPtr;  
             } else {  
                 cmdPtr->proc = cmdInfoPtr->proc;  
                 cmdPtr->clientData = (ClientData) NULL;  
             }  
             if (cmdInfoPtr->objProc == (Tcl_ObjCmdProc *) NULL) {  
                 cmdPtr->objProc = TclInvokeStringCommand;  
                 cmdPtr->objClientData = (ClientData) cmdPtr;  
             } else {  
                 cmdPtr->objProc = cmdInfoPtr->objProc;  
                 cmdPtr->objClientData = (ClientData) NULL;  
             }  
             cmdPtr->deleteProc = NULL;  
             cmdPtr->deleteData = (ClientData) NULL;  
             cmdPtr->deleted = 0;  
             cmdPtr->importRefPtr = NULL;  
             Tcl_SetHashValue(hPtr, cmdPtr);  
         }  
     }  
   
     /*  
      * Register the builtin math functions.  
      */  
   
     i = 0;  
     for (builtinFuncPtr = builtinFuncTable;  builtinFuncPtr->name != NULL;  
             builtinFuncPtr++) {  
         Tcl_CreateMathFunc((Tcl_Interp *) iPtr, builtinFuncPtr->name,  
                 builtinFuncPtr->numArgs, builtinFuncPtr->argTypes,  
                 (Tcl_MathProc *) NULL, (ClientData) 0);  
         hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable,  
                 builtinFuncPtr->name);  
         if (hPtr == NULL) {  
             panic("Tcl_CreateInterp: Tcl_CreateMathFunc incorrectly registered '%s'", builtinFuncPtr->name);  
             return NULL;  
         }  
         mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);  
         mathFuncPtr->builtinFuncIndex = i;  
         i++;  
     }  
     iPtr->flags |= EXPR_INITIALIZED;  
   
     /*  
      * Do Multiple/Safe Interps Tcl init stuff  
      */  
   
     TclInterpInit(interp);  
   
     /*  
      * We used to create the "errorInfo" and "errorCode" global vars at this  
      * point because so much of the Tcl implementation assumes they already  
      * exist. This is not quite enough, however, since they can be unset  
      * at any time.  
      *  
      * There are 2 choices:  
      *    + Check every place where a GetVar of those is used  
      *      and the NULL result is not checked (like in tclLoad.c)  
      *    + Make SetVar,... NULL friendly  
      * We choose the second option because :  
      *    + It is easy and low cost to check for NULL pointer before  
      *      calling strlen()  
      *    + It can be helpfull to other people using those API  
      *    + Passing a NULL value to those closest 'meaning' is empty string  
      *      (specially with the new objects where 0 bytes strings are ok)  
      * So the following init is commented out:              -- dl  
      *  
      * (void) Tcl_SetVar2((Tcl_Interp *)iPtr, "errorInfo", (char *) NULL,  
      *       "", TCL_GLOBAL_ONLY);  
      * (void) Tcl_SetVar2((Tcl_Interp *)iPtr, "errorCode", (char *) NULL,  
      *       "NONE", TCL_GLOBAL_ONLY);  
      */  
   
 #ifndef TCL_GENERIC_ONLY  
     TclSetupEnv(interp);  
 #endif  
   
     /*  
      * Compute the byte order of this machine.  
      */  
   
     order.s = 1;  
     Tcl_SetVar2(interp, "tcl_platform", "byteOrder",  
             ((order.c[0] == 1) ? "littleEndian" : "bigEndian"),  
             TCL_GLOBAL_ONLY);  
   
     /*  
      * Set up other variables such as tcl_version and tcl_library  
      */  
   
     Tcl_SetVar(interp, "tcl_patchLevel", TCL_PATCH_LEVEL, TCL_GLOBAL_ONLY);  
     Tcl_SetVar(interp, "tcl_version", TCL_VERSION, TCL_GLOBAL_ONLY);  
     Tcl_TraceVar2(interp, "tcl_precision", (char *) NULL,  
             TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,  
             TclPrecTraceProc, (ClientData) NULL);  
     TclpSetVariables(interp);  
   
 #ifdef TCL_THREADS  
     /*  
      * The existence of the "threaded" element of the tcl_platform array indicates  
      * that this particular Tcl shell has been compiled with threads turned on.  
      * Using "info exists tcl_platform(threaded)" a Tcl script can introspect on the  
      * interpreter level of thread safety.  
      */  
   
   
     Tcl_SetVar2(interp, "tcl_platform", "threaded", "1",  
             TCL_GLOBAL_ONLY);  
 #endif  
   
     /*  
      * Register Tcl's version number.  
      */  
   
     Tcl_PkgProvideEx(interp, "Tcl", TCL_VERSION, (ClientData) &tclStubs);  
       
 #ifdef Tcl_InitStubs  
 #undef Tcl_InitStubs  
 #endif  
     Tcl_InitStubs(interp, TCL_VERSION, 1);  
   
     return interp;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclHideUnsafeCommands --  
  *  
  *      Hides base commands that are not marked as safe from this  
  *      interpreter.  
  *  
  * Results:  
  *      TCL_OK if it succeeds, TCL_ERROR else.  
  *  
  * Side effects:  
  *      Hides functionality in an interpreter.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclHideUnsafeCommands(interp)  
     Tcl_Interp *interp;         /* Hide commands in this interpreter. */  
 {  
     register CmdInfo *cmdInfoPtr;  
   
     if (interp == (Tcl_Interp *) NULL) {  
         return TCL_ERROR;  
     }  
     for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {  
         if (!cmdInfoPtr->isSafe) {  
             Tcl_HideCommand(interp, cmdInfoPtr->name, cmdInfoPtr->name);  
         }  
     }  
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tcl_CallWhenDeleted --  
  *  
  *      Arrange for a procedure to be called before a given  
  *      interpreter is deleted. The procedure is called as soon  
  *      as Tcl_DeleteInterp is called; if Tcl_CallWhenDeleted is  
  *      called on an interpreter that has already been deleted,  
  *      the procedure will be called when the last Tcl_Release is  
  *      done on the interpreter.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      When Tcl_DeleteInterp is invoked to delete interp,  
  *      proc will be invoked.  See the manual entry for  
  *      details.  
  *  
  *--------------------------------------------------------------  
  */  
   
 void  
 Tcl_CallWhenDeleted(interp, proc, clientData)  
     Tcl_Interp *interp;         /* Interpreter to watch. */  
     Tcl_InterpDeleteProc *proc; /* Procedure to call when interpreter  
                                  * is about to be deleted. */  
     ClientData clientData;      /* One-word value to pass to proc. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     static int assocDataCounter = 0;  
 #ifdef TCL_THREADS  
     static Tcl_Mutex assocMutex;  
 #endif  
     int new;  
     char buffer[32 + TCL_INTEGER_SPACE];  
     AssocData *dPtr = (AssocData *) ckalloc(sizeof(AssocData));  
     Tcl_HashEntry *hPtr;  
   
     Tcl_MutexLock(&assocMutex);  
     sprintf(buffer, "Assoc Data Key #%d", assocDataCounter);  
     assocDataCounter++;  
     Tcl_MutexUnlock(&assocMutex);  
   
     if (iPtr->assocData == (Tcl_HashTable *) NULL) {  
         iPtr->assocData = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));  
         Tcl_InitHashTable(iPtr->assocData, TCL_STRING_KEYS);  
     }  
     hPtr = Tcl_CreateHashEntry(iPtr->assocData, buffer, &new);  
     dPtr->proc = proc;  
     dPtr->clientData = clientData;  
     Tcl_SetHashValue(hPtr, dPtr);  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tcl_DontCallWhenDeleted --  
  *  
  *      Cancel the arrangement for a procedure to be called when  
  *      a given interpreter is deleted.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      If proc and clientData were previously registered as a  
  *      callback via Tcl_CallWhenDeleted, they are unregistered.  
  *      If they weren't previously registered then nothing  
  *      happens.  
  *  
  *--------------------------------------------------------------  
  */  
   
 void  
 Tcl_DontCallWhenDeleted(interp, proc, clientData)  
     Tcl_Interp *interp;         /* Interpreter to watch. */  
     Tcl_InterpDeleteProc *proc; /* Procedure to call when interpreter  
                                  * is about to be deleted. */  
     ClientData clientData;      /* One-word value to pass to proc. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     Tcl_HashTable *hTablePtr;  
     Tcl_HashSearch hSearch;  
     Tcl_HashEntry *hPtr;  
     AssocData *dPtr;  
   
     hTablePtr = iPtr->assocData;  
     if (hTablePtr == (Tcl_HashTable *) NULL) {  
         return;  
     }  
     for (hPtr = Tcl_FirstHashEntry(hTablePtr, &hSearch); hPtr != NULL;  
             hPtr = Tcl_NextHashEntry(&hSearch)) {  
         dPtr = (AssocData *) Tcl_GetHashValue(hPtr);  
         if ((dPtr->proc == proc) && (dPtr->clientData == clientData)) {  
             ckfree((char *) dPtr);  
             Tcl_DeleteHashEntry(hPtr);  
             return;  
         }  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_SetAssocData --  
  *  
  *      Creates a named association between user-specified data, a delete  
  *      function and this interpreter. If the association already exists  
  *      the data is overwritten with the new data. The delete function will  
  *      be invoked when the interpreter is deleted.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Sets the associated data, creates the association if needed.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tcl_SetAssocData(interp, name, proc, clientData)  
     Tcl_Interp *interp;         /* Interpreter to associate with. */  
     char *name;                 /* Name for association. */  
     Tcl_InterpDeleteProc *proc; /* Proc to call when interpreter is  
                                  * about to be deleted. */  
     ClientData clientData;      /* One-word value to pass to proc. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     AssocData *dPtr;  
     Tcl_HashEntry *hPtr;  
     int new;  
   
     if (iPtr->assocData == (Tcl_HashTable *) NULL) {  
         iPtr->assocData = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));  
         Tcl_InitHashTable(iPtr->assocData, TCL_STRING_KEYS);  
     }  
     hPtr = Tcl_CreateHashEntry(iPtr->assocData, name, &new);  
     if (new == 0) {  
         dPtr = (AssocData *) Tcl_GetHashValue(hPtr);  
     } else {  
         dPtr = (AssocData *) ckalloc(sizeof(AssocData));  
     }  
     dPtr->proc = proc;  
     dPtr->clientData = clientData;  
   
     Tcl_SetHashValue(hPtr, dPtr);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_DeleteAssocData --  
  *  
  *      Deletes a named association of user-specified data with  
  *      the specified interpreter.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Deletes the association.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tcl_DeleteAssocData(interp, name)  
     Tcl_Interp *interp;                 /* Interpreter to associate with. */  
     char *name;                         /* Name of association. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     AssocData *dPtr;  
     Tcl_HashEntry *hPtr;  
   
     if (iPtr->assocData == (Tcl_HashTable *) NULL) {  
         return;  
     }  
     hPtr = Tcl_FindHashEntry(iPtr->assocData, name);  
     if (hPtr == (Tcl_HashEntry *) NULL) {  
         return;  
     }  
     dPtr = (AssocData *) Tcl_GetHashValue(hPtr);  
     if (dPtr->proc != NULL) {  
         (dPtr->proc) (dPtr->clientData, interp);  
     }  
     ckfree((char *) dPtr);  
     Tcl_DeleteHashEntry(hPtr);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_GetAssocData --  
  *  
  *      Returns the client data associated with this name in the  
  *      specified interpreter.  
  *  
  * Results:  
  *      The client data in the AssocData record denoted by the named  
  *      association, or NULL.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 ClientData  
 Tcl_GetAssocData(interp, name, procPtr)  
     Tcl_Interp *interp;                 /* Interpreter associated with. */  
     char *name;                         /* Name of association. */  
     Tcl_InterpDeleteProc **procPtr;     /* Pointer to place to store address  
                                          * of current deletion callback. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     AssocData *dPtr;  
     Tcl_HashEntry *hPtr;  
   
     if (iPtr->assocData == (Tcl_HashTable *) NULL) {  
         return (ClientData) NULL;  
     }  
     hPtr = Tcl_FindHashEntry(iPtr->assocData, name);  
     if (hPtr == (Tcl_HashEntry *) NULL) {  
         return (ClientData) NULL;  
     }  
     dPtr = (AssocData *) Tcl_GetHashValue(hPtr);  
     if (procPtr != (Tcl_InterpDeleteProc **) NULL) {  
         *procPtr = dPtr->proc;  
     }  
     return dPtr->clientData;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_InterpDeleted --  
  *  
  *      Returns nonzero if the interpreter has been deleted with a call  
  *      to Tcl_DeleteInterp.  
  *  
  * Results:  
  *      Nonzero if the interpreter is deleted, zero otherwise.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tcl_InterpDeleted(interp)  
     Tcl_Interp *interp;  
 {  
     return (((Interp *) interp)->flags & DELETED) ? 1 : 0;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_DeleteInterp --  
  *  
  *      Ensures that the interpreter will be deleted eventually. If there  
  *      are no Tcl_Preserve calls in effect for this interpreter, it is  
  *      deleted immediately, otherwise the interpreter is deleted when  
  *      the last Tcl_Preserve is matched by a call to Tcl_Release. In either  
  *      case, the procedure runs the currently registered deletion callbacks.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The interpreter is marked as deleted. The caller may still use it  
  *      safely if there are calls to Tcl_Preserve in effect for the  
  *      interpreter, but further calls to Tcl_Eval etc in this interpreter  
  *      will fail.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tcl_DeleteInterp(interp)  
     Tcl_Interp *interp;         /* Token for command interpreter (returned  
                                  * by a previous call to Tcl_CreateInterp). */  
 {  
     Interp *iPtr = (Interp *) interp;  
   
     /*  
      * If the interpreter has already been marked deleted, just punt.  
      */  
   
     if (iPtr->flags & DELETED) {  
         return;  
     }  
       
     /*  
      * Mark the interpreter as deleted. No further evals will be allowed.  
      */  
   
     iPtr->flags |= DELETED;  
   
     /*  
      * Ensure that the interpreter is eventually deleted.  
      */  
   
     Tcl_EventuallyFree((ClientData) interp,  
             (Tcl_FreeProc *) DeleteInterpProc);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * DeleteInterpProc --  
  *  
  *      Helper procedure to delete an interpreter. This procedure is  
  *      called when the last call to Tcl_Preserve on this interpreter  
  *      is matched by a call to Tcl_Release. The procedure cleans up  
  *      all resources used in the interpreter and calls all currently  
  *      registered interpreter deletion callbacks.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Whatever the interpreter deletion callbacks do. Frees resources  
  *      used by the interpreter.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 DeleteInterpProc(interp)  
     Tcl_Interp *interp;                 /* Interpreter to delete. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     Tcl_HashEntry *hPtr;  
     Tcl_HashSearch search;  
     Tcl_HashTable *hTablePtr;  
     ResolverScheme *resPtr, *nextResPtr;  
   
     /*  
      * Punt if there is an error in the Tcl_Release/Tcl_Preserve matchup.  
      */  
       
     if (iPtr->numLevels > 0) {  
         panic("DeleteInterpProc called with active evals");  
     }  
   
     /*  
      * The interpreter should already be marked deleted; otherwise how  
      * did we get here?  
      */  
   
     if (!(iPtr->flags & DELETED)) {  
         panic("DeleteInterpProc called on interpreter not marked deleted");  
     }  
   
     TclHandleFree(iPtr->handle);  
   
     /*  
      * Dismantle everything in the global namespace except for the  
      * "errorInfo" and "errorCode" variables. These remain until the  
      * namespace is actually destroyed, in case any errors occur.  
      *    
      * Dismantle the namespace here, before we clear the assocData. If any  
      * background errors occur here, they will be deleted below.  
      */  
       
     TclTeardownNamespace(iPtr->globalNsPtr);  
   
     /*  
      * Delete all the hidden commands.  
      */  
       
     hTablePtr = iPtr->hiddenCmdTablePtr;  
     if (hTablePtr != NULL) {  
         /*  
          * Non-pernicious deletion.  The deletion callbacks will not be  
          * allowed to create any new hidden or non-hidden commands.  
          * Tcl_DeleteCommandFromToken() will remove the entry from the  
          * hiddenCmdTablePtr.  
          */  
           
         hPtr = Tcl_FirstHashEntry(hTablePtr, &search);  
         for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {  
             Tcl_DeleteCommandFromToken(interp,  
                     (Tcl_Command) Tcl_GetHashValue(hPtr));  
         }  
         Tcl_DeleteHashTable(hTablePtr);  
         ckfree((char *) hTablePtr);  
     }  
     /*  
      * Tear down the math function table.  
      */  
   
     for (hPtr = Tcl_FirstHashEntry(&iPtr->mathFuncTable, &search);  
              hPtr != NULL;  
              hPtr = Tcl_NextHashEntry(&search)) {  
         ckfree((char *) Tcl_GetHashValue(hPtr));  
     }  
     Tcl_DeleteHashTable(&iPtr->mathFuncTable);  
   
     /*  
      * Invoke deletion callbacks; note that a callback can create new  
      * callbacks, so we iterate.  
      */  
   
     while (iPtr->assocData != (Tcl_HashTable *) NULL) {  
         AssocData *dPtr;  
           
         hTablePtr = iPtr->assocData;  
         iPtr->assocData = (Tcl_HashTable *) NULL;  
         for (hPtr = Tcl_FirstHashEntry(hTablePtr, &search);  
                  hPtr != NULL;  
                  hPtr = Tcl_FirstHashEntry(hTablePtr, &search)) {  
             dPtr = (AssocData *) Tcl_GetHashValue(hPtr);  
             Tcl_DeleteHashEntry(hPtr);  
             if (dPtr->proc != NULL) {  
                 (*dPtr->proc)(dPtr->clientData, interp);  
             }  
             ckfree((char *) dPtr);  
         }  
         Tcl_DeleteHashTable(hTablePtr);  
         ckfree((char *) hTablePtr);  
     }  
   
     /*  
      * Finish deleting the global namespace.  
      */  
       
     Tcl_DeleteNamespace((Tcl_Namespace *) iPtr->globalNsPtr);  
   
     /*  
      * Free up the result *after* deleting variables, since variable  
      * deletion could have transferred ownership of the result string  
      * to Tcl.  
      */  
   
     Tcl_FreeResult(interp);  
     interp->result = NULL;  
     Tcl_DecrRefCount(iPtr->objResultPtr);  
     iPtr->objResultPtr = NULL;  
     if (iPtr->errorInfo != NULL) {  
         ckfree(iPtr->errorInfo);  
         iPtr->errorInfo = NULL;  
     }  
     if (iPtr->errorCode != NULL) {  
         ckfree(iPtr->errorCode);  
         iPtr->errorCode = NULL;  
     }  
     if (iPtr->appendResult != NULL) {  
         ckfree(iPtr->appendResult);  
         iPtr->appendResult = NULL;  
     }  
     TclFreePackageInfo(iPtr);  
     while (iPtr->tracePtr != NULL) {  
         Trace *nextPtr = iPtr->tracePtr->nextPtr;  
   
         ckfree((char *) iPtr->tracePtr);  
         iPtr->tracePtr = nextPtr;  
     }  
     if (iPtr->execEnvPtr != NULL) {  
         TclDeleteExecEnv(iPtr->execEnvPtr);  
     }  
     Tcl_DecrRefCount(iPtr->emptyObjPtr);  
     iPtr->emptyObjPtr = NULL;  
   
     resPtr = iPtr->resolverPtr;  
     while (resPtr) {  
         nextResPtr = resPtr->nextPtr;  
         ckfree(resPtr->name);  
         ckfree((char *) resPtr);  
         resPtr = nextResPtr;  
     }  
       
     /*  
      * Free up literal objects created for scripts compiled by the  
      * interpreter.  
      */  
   
     TclDeleteLiteralTable(interp, &(iPtr->literalTable));  
     ckfree((char *) iPtr);  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * Tcl_HideCommand --  
  *  
  *      Makes a command hidden so that it cannot be invoked from within  
  *      an interpreter, only from within an ancestor.  
  *  
  * Results:  
  *      A standard Tcl result; also leaves a message in the interp's result  
  *      if an error occurs.  
  *  
  * Side effects:  
  *      Removes a command from the command table and create an entry  
  *      into the hidden command table under the specified token name.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 int  
 Tcl_HideCommand(interp, cmdName, hiddenCmdToken)  
     Tcl_Interp *interp;         /* Interpreter in which to hide command. */  
     char *cmdName;              /* Name of command to hide. */  
     char *hiddenCmdToken;       /* Token name of the to-be-hidden command. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     Tcl_Command cmd;  
     Command *cmdPtr;  
     Tcl_HashTable *hiddenCmdTablePtr;  
     Tcl_HashEntry *hPtr;  
     int new;  
   
     if (iPtr->flags & DELETED) {  
   
         /*  
          * The interpreter is being deleted. Do not create any new  
          * structures, because it is not safe to modify the interpreter.  
          */  
           
         return TCL_ERROR;  
     }  
   
     /*  
      * Disallow hiding of commands that are currently in a namespace or  
      * renaming (as part of hiding) into a namespace.  
      *  
      * (because the current implementation with a single global table  
      *  and the needed uniqueness of names cause problems with namespaces)  
      *  
      * we don't need to check for "::" in cmdName because the real check is  
      * on the nsPtr below.  
      *  
      * hiddenCmdToken is just a string which is not interpreted in any way.  
      * It may contain :: but the string is not interpreted as a namespace  
      * qualifier command name. Thus, hiding foo::bar to foo::bar and then  
      * trying to expose or invoke ::foo::bar will NOT work; but if the  
      * application always uses the same strings it will get consistent  
      * behaviour.  
      *  
      * But as we currently limit ourselves to the global namespace only  
      * for the source, in order to avoid potential confusion,  
      * lets prevent "::" in the token too.  --dl  
      */  
   
     if (strstr(hiddenCmdToken, "::") != NULL) {  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                 "cannot use namespace qualifiers as hidden command",  
                 "token (rename)", (char *) NULL);  
         return TCL_ERROR;  
     }  
   
     /*  
      * Find the command to hide. An error is returned if cmdName can't  
      * be found. Look up the command only from the global namespace.  
      * Full path of the command must be given if using namespaces.  
      */  
   
     cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL,  
             /*flags*/ TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);  
     if (cmd == (Tcl_Command) NULL) {  
         return TCL_ERROR;  
     }  
     cmdPtr = (Command *) cmd;  
   
     /*  
      * Check that the command is really in global namespace  
      */  
   
     if ( cmdPtr->nsPtr != iPtr->globalNsPtr ) {  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                 "can only hide global namespace commands",  
                 " (use rename then hide)", (char *) NULL);  
         return TCL_ERROR;  
     }  
       
     /*  
      * Initialize the hidden command table if necessary.  
      */  
   
     hiddenCmdTablePtr = iPtr->hiddenCmdTablePtr;  
     if (hiddenCmdTablePtr == NULL) {  
         hiddenCmdTablePtr = (Tcl_HashTable *)  
                 ckalloc((unsigned) sizeof(Tcl_HashTable));  
         Tcl_InitHashTable(hiddenCmdTablePtr, TCL_STRING_KEYS);  
         iPtr->hiddenCmdTablePtr = hiddenCmdTablePtr;  
     }  
   
     /*  
      * It is an error to move an exposed command to a hidden command with  
      * hiddenCmdToken if a hidden command with the name hiddenCmdToken already  
      * exists.  
      */  
       
     hPtr = Tcl_CreateHashEntry(hiddenCmdTablePtr, hiddenCmdToken, &new);  
     if (!new) {  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                 "hidden command named \"", hiddenCmdToken, "\" already exists",  
                 (char *) NULL);  
         return TCL_ERROR;  
     }  
   
     /*  
      * Nb : This code is currently 'like' a rename to a specialy set apart  
      * name table. Changes here and in TclRenameCommand must  
      * be kept in synch untill the common parts are actually  
      * factorized out.  
      */  
   
     /*  
      * Remove the hash entry for the command from the interpreter command  
      * table. This is like deleting the command, so bump its command epoch;  
      * this invalidates any cached references that point to the command.  
      */  
   
     if (cmdPtr->hPtr != NULL) {  
         Tcl_DeleteHashEntry(cmdPtr->hPtr);  
         cmdPtr->hPtr = (Tcl_HashEntry *) NULL;  
         cmdPtr->cmdEpoch++;  
     }  
   
     /*  
      * Now link the hash table entry with the command structure.  
      * We ensured above that the nsPtr was right.  
      */  
       
     cmdPtr->hPtr = hPtr;  
     Tcl_SetHashValue(hPtr, (ClientData) cmdPtr);  
   
     /*  
      * If the command being hidden has a compile procedure, increment the  
      * interpreter's compileEpoch to invalidate its compiled code. This  
      * makes sure that we don't later try to execute old code compiled with  
      * command-specific (i.e., inline) bytecodes for the now-hidden  
      * command. This field is checked in Tcl_EvalObj and ObjInterpProc,  
      * and code whose compilation epoch doesn't match is recompiled.  
      */  
   
     if (cmdPtr->compileProc != NULL) {  
         iPtr->compileEpoch++;  
     }  
     return TCL_OK;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_ExposeCommand --  
  *  
  *      Makes a previously hidden command callable from inside the  
  *      interpreter instead of only by its ancestors.  
  *  
  * Results:  
  *      A standard Tcl result. If an error occurs, a message is left  
  *      in the interp's result.  
  *  
  * Side effects:  
  *      Moves commands from one hash table to another.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tcl_ExposeCommand(interp, hiddenCmdToken, cmdName)  
     Tcl_Interp *interp;         /* Interpreter in which to make command  
                                  * callable. */  
     char *hiddenCmdToken;       /* Name of hidden command. */  
     char *cmdName;              /* Name of to-be-exposed command. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     Command *cmdPtr;  
     Namespace *nsPtr;  
     Tcl_HashEntry *hPtr;  
     Tcl_HashTable *hiddenCmdTablePtr;  
     int new;  
   
     if (iPtr->flags & DELETED) {  
         /*  
          * The interpreter is being deleted. Do not create any new  
          * structures, because it is not safe to modify the interpreter.  
          */  
           
         return TCL_ERROR;  
     }  
   
     /*  
      * Check that we have a regular name for the command  
      * (that the user is not trying to do an expose and a rename  
      *  (to another namespace) at the same time)  
      */  
   
     if (strstr(cmdName, "::") != NULL) {  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                 "can not expose to a namespace ",  
                 "(use expose to toplevel, then rename)",  
                  (char *) NULL);  
         return TCL_ERROR;  
     }  
   
     /*  
      * Get the command from the hidden command table:  
      */  
   
     hPtr = NULL;  
     hiddenCmdTablePtr = iPtr->hiddenCmdTablePtr;  
     if (hiddenCmdTablePtr != NULL) {  
         hPtr = Tcl_FindHashEntry(hiddenCmdTablePtr, hiddenCmdToken);  
     }  
     if (hPtr == (Tcl_HashEntry *) NULL) {  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                 "unknown hidden command \"", hiddenCmdToken,  
                 "\"", (char *) NULL);  
         return TCL_ERROR;  
     }  
     cmdPtr = (Command *) Tcl_GetHashValue(hPtr);  
       
   
     /*  
      * Check that we have a true global namespace  
      * command (enforced by Tcl_HideCommand() but let's double  
      * check. (If it was not, we would not really know how to  
      * handle it).  
      */  
     if ( cmdPtr->nsPtr != iPtr->globalNsPtr ) {  
         /*  
          * This case is theoritically impossible,  
          * we might rather panic() than 'nicely' erroring out ?  
          */  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                 "trying to expose a non global command name space command",  
                 (char *) NULL);  
         return TCL_ERROR;  
     }  
       
     /* This is the global table */  
     nsPtr = cmdPtr->nsPtr;  
   
     /*  
      * It is an error to overwrite an existing exposed command as a result  
      * of exposing a previously hidden command.  
      */  
   
     hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, cmdName, &new);  
     if (!new) {  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                 "exposed command \"", cmdName,  
                 "\" already exists", (char *) NULL);  
         return TCL_ERROR;  
     }  
   
     /*  
      * Remove the hash entry for the command from the interpreter hidden  
      * command table.  
      */  
   
     if (cmdPtr->hPtr != NULL) {  
         Tcl_DeleteHashEntry(cmdPtr->hPtr);  
         cmdPtr->hPtr = NULL;  
     }  
   
     /*  
      * Now link the hash table entry with the command structure.  
      * This is like creating a new command, so deal with any shadowing  
      * of commands in the global namespace.  
      */  
       
     cmdPtr->hPtr = hPtr;  
   
     Tcl_SetHashValue(hPtr, (ClientData) cmdPtr);  
   
     /*  
      * Not needed as we are only in the global namespace  
      * (but would be needed again if we supported namespace command hiding)  
      *  
      * TclResetShadowedCmdRefs(interp, cmdPtr);  
      */  
   
   
     /*  
      * If the command being exposed has a compile procedure, increment  
      * interpreter's compileEpoch to invalidate its compiled code. This  
      * makes sure that we don't later try to execute old code compiled  
      * assuming the command is hidden. This field is checked in Tcl_EvalObj  
      * and ObjInterpProc, and code whose compilation epoch doesn't match is  
      * recompiled.  
      */  
   
     if (cmdPtr->compileProc != NULL) {  
         iPtr->compileEpoch++;  
     }  
     return TCL_OK;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_CreateCommand --  
  *  
  *      Define a new command in a command table.  
  *  
  * Results:  
  *      The return value is a token for the command, which can  
  *      be used in future calls to Tcl_GetCommandName.  
  *  
  * Side effects:  
  *      If a command named cmdName already exists for interp, it is deleted.  
  *      In the future, when cmdName is seen as the name of a command by  
  *      Tcl_Eval, proc will be called. To support the bytecode interpreter,  
  *      the command is created with a wrapper Tcl_ObjCmdProc  
  *      (TclInvokeStringCommand) that eventially calls proc. When the  
  *      command is deleted from the table, deleteProc will be called.  
  *      See the manual entry for details on the calling sequence.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tcl_Command  
 Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)  
     Tcl_Interp *interp;         /* Token for command interpreter returned by  
                                  * a previous call to Tcl_CreateInterp. */  
     char *cmdName;              /* Name of command. If it contains namespace  
                                  * qualifiers, the new command is put in the  
                                  * specified namespace; otherwise it is put  
                                  * in the global namespace. */  
     Tcl_CmdProc *proc;          /* Procedure to associate with cmdName. */  
     ClientData clientData;      /* Arbitrary value passed to string proc. */  
     Tcl_CmdDeleteProc *deleteProc;  
                                 /* If not NULL, gives a procedure to call  
                                  * when this command is deleted. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     ImportRef *oldRefPtr = NULL;  
     Namespace *nsPtr, *dummy1, *dummy2;  
     Command *cmdPtr, *refCmdPtr;  
     Tcl_HashEntry *hPtr;  
     char *tail;  
     int new;  
     ImportedCmdData *dataPtr;  
   
     if (iPtr->flags & DELETED) {  
         /*  
          * The interpreter is being deleted.  Don't create any new  
          * commands; it's not safe to muck with the interpreter anymore.  
          */  
   
         return (Tcl_Command) NULL;  
     }  
   
     /*  
      * Determine where the command should reside. If its name contains  
      * namespace qualifiers, we put it in the specified namespace;  
      * otherwise, we always put it in the global namespace.  
      */  
   
     if (strstr(cmdName, "::") != NULL) {  
        TclGetNamespaceForQualName(interp, cmdName, (Namespace *) NULL,  
            CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);  
        if ((nsPtr == NULL) || (tail == NULL)) {  
             return (Tcl_Command) NULL;  
         }  
     } else {  
         nsPtr = iPtr->globalNsPtr;  
         tail = cmdName;  
     }  
       
     hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new);  
     if (!new) {  
         /*  
          * Command already exists. Delete the old one.  
          * Be careful to preserve any existing import links so we can  
          * restore them down below.  That way, you can redefine a  
          * command and its import status will remain intact.  
          */  
   
         cmdPtr = (Command *) Tcl_GetHashValue(hPtr);  
         oldRefPtr = cmdPtr->importRefPtr;  
         cmdPtr->importRefPtr = NULL;  
   
         Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);  
         hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new);  
         if (!new) {  
             /*  
              * If the deletion callback recreated the command, just throw  
              * away the new command (if we try to delete it again, we  
              * could get stuck in an infinite loop).  
              */  
   
              ckfree((char*) Tcl_GetHashValue(hPtr));  
         }  
     }  
     cmdPtr = (Command *) ckalloc(sizeof(Command));  
     Tcl_SetHashValue(hPtr, cmdPtr);  
     cmdPtr->hPtr = hPtr;  
     cmdPtr->nsPtr = nsPtr;  
     cmdPtr->refCount = 1;  
     cmdPtr->cmdEpoch = 0;  
     cmdPtr->compileProc = (CompileProc *) NULL;  
     cmdPtr->objProc = TclInvokeStringCommand;  
     cmdPtr->objClientData = (ClientData) cmdPtr;  
     cmdPtr->proc = proc;  
     cmdPtr->clientData = clientData;  
     cmdPtr->deleteProc = deleteProc;  
     cmdPtr->deleteData = clientData;  
     cmdPtr->deleted = 0;  
     cmdPtr->importRefPtr = NULL;  
   
     /*  
      * Plug in any existing import references found above.  Be sure  
      * to update all of these references to point to the new command.  
      */  
   
     if (oldRefPtr != NULL) {  
         cmdPtr->importRefPtr = oldRefPtr;  
         while (oldRefPtr != NULL) {  
             refCmdPtr = oldRefPtr->importedCmdPtr;  
             dataPtr = (ImportedCmdData*)refCmdPtr->objClientData;  
             dataPtr->realCmdPtr = cmdPtr;  
             oldRefPtr = oldRefPtr->nextPtr;  
         }  
     }  
   
     /*  
      * We just created a command, so in its namespace and all of its parent  
      * namespaces, it may shadow global commands with the same name. If any  
      * shadowed commands are found, invalidate all cached command references  
      * in the affected namespaces.  
      */  
       
     TclResetShadowedCmdRefs(interp, cmdPtr);  
     return (Tcl_Command) cmdPtr;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_CreateObjCommand --  
  *  
  *      Define a new object-based command in a command table.  
  *  
  * Results:  
  *      The return value is a token for the command, which can  
  *      be used in future calls to Tcl_GetCommandName.  
  *  
  * Side effects:  
  *      If no command named "cmdName" already exists for interp, one is  
  *      created. Otherwise, if a command does exist, then if the  
  *      object-based Tcl_ObjCmdProc is TclInvokeStringCommand, we assume  
  *      Tcl_CreateCommand was called previously for the same command and  
  *      just set its Tcl_ObjCmdProc to the argument "proc"; otherwise, we  
  *      delete the old command.  
  *  
  *      In the future, during bytecode evaluation when "cmdName" is seen as  
  *      the name of a command by Tcl_EvalObj or Tcl_Eval, the object-based  
  *      Tcl_ObjCmdProc proc will be called. When the command is deleted from  
  *      the table, deleteProc will be called. See the manual entry for  
  *      details on the calling sequence.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tcl_Command  
 Tcl_CreateObjCommand(interp, cmdName, proc, clientData, deleteProc)  
     Tcl_Interp *interp;         /* Token for command interpreter (returned  
                                  * by previous call to Tcl_CreateInterp). */  
     char *cmdName;              /* Name of command. If it contains namespace  
                                  * qualifiers, the new command is put in the  
                                  * specified namespace; otherwise it is put  
                                  * in the global namespace. */  
     Tcl_ObjCmdProc *proc;       /* Object-based procedure to associate with  
                                  * name. */  
     ClientData clientData;      /* Arbitrary value to pass to object  
                                  * procedure. */  
     Tcl_CmdDeleteProc *deleteProc;  
                                 /* If not NULL, gives a procedure to call  
                                  * when this command is deleted. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     ImportRef *oldRefPtr = NULL;  
     Namespace *nsPtr, *dummy1, *dummy2;  
     Command *cmdPtr, *refCmdPtr;  
     Tcl_HashEntry *hPtr;  
     char *tail;  
     int new;  
     ImportedCmdData *dataPtr;  
   
     if (iPtr->flags & DELETED) {  
         /*  
          * The interpreter is being deleted.  Don't create any new  
          * commands;  it's not safe to muck with the interpreter anymore.  
          */  
   
         return (Tcl_Command) NULL;  
     }  
   
     /*  
      * Determine where the command should reside. If its name contains  
      * namespace qualifiers, we put it in the specified namespace;  
      * otherwise, we always put it in the global namespace.  
      */  
   
     if (strstr(cmdName, "::") != NULL) {  
        TclGetNamespaceForQualName(interp, cmdName, (Namespace *) NULL,  
            CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);  
        if ((nsPtr == NULL) || (tail == NULL)) {  
             return (Tcl_Command) NULL;  
         }  
     } else {  
         nsPtr = iPtr->globalNsPtr;  
         tail = cmdName;  
     }  
   
     hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new);  
     if (!new) {  
         cmdPtr = (Command *) Tcl_GetHashValue(hPtr);  
   
         /*  
          * Command already exists. If its object-based Tcl_ObjCmdProc is  
          * TclInvokeStringCommand, we just set its Tcl_ObjCmdProc to the  
          * argument "proc". Otherwise, we delete the old command.  
          */  
   
         if (cmdPtr->objProc == TclInvokeStringCommand) {  
             cmdPtr->objProc = proc;  
             cmdPtr->objClientData = clientData;  
             cmdPtr->deleteProc = deleteProc;  
             cmdPtr->deleteData = clientData;  
             return (Tcl_Command) cmdPtr;  
         }  
   
         /*  
          * Otherwise, we delete the old command.  Be careful to preserve  
          * any existing import links so we can restore them down below.  
          * That way, you can redefine a command and its import status  
          * will remain intact.  
          */  
   
         oldRefPtr = cmdPtr->importRefPtr;  
         cmdPtr->importRefPtr = NULL;  
   
         Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);  
         hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new);  
         if (!new) {  
             /*  
              * If the deletion callback recreated the command, just throw  
              * away the new command (if we try to delete it again, we  
              * could get stuck in an infinite loop).  
              */  
   
              ckfree((char *) Tcl_GetHashValue(hPtr));  
         }  
     }  
     cmdPtr = (Command *) ckalloc(sizeof(Command));  
     Tcl_SetHashValue(hPtr, cmdPtr);  
     cmdPtr->hPtr = hPtr;  
     cmdPtr->nsPtr = nsPtr;  
     cmdPtr->refCount = 1;  
     cmdPtr->cmdEpoch = 0;  
     cmdPtr->compileProc = (CompileProc *) NULL;  
     cmdPtr->objProc = proc;  
     cmdPtr->objClientData = clientData;  
     cmdPtr->proc = TclInvokeObjectCommand;  
     cmdPtr->clientData = (ClientData) cmdPtr;  
     cmdPtr->deleteProc = deleteProc;  
     cmdPtr->deleteData = clientData;  
     cmdPtr->deleted = 0;  
     cmdPtr->importRefPtr = NULL;  
   
     /*  
      * Plug in any existing import references found above.  Be sure  
      * to update all of these references to point to the new command.  
      */  
   
     if (oldRefPtr != NULL) {  
         cmdPtr->importRefPtr = oldRefPtr;  
         while (oldRefPtr != NULL) {  
             refCmdPtr = oldRefPtr->importedCmdPtr;  
             dataPtr = (ImportedCmdData*)refCmdPtr->objClientData;  
             dataPtr->realCmdPtr = cmdPtr;  
             oldRefPtr = oldRefPtr->nextPtr;  
         }  
     }  
       
     /*  
      * We just created a command, so in its namespace and all of its parent  
      * namespaces, it may shadow global commands with the same name. If any  
      * shadowed commands are found, invalidate all cached command references  
      * in the affected namespaces.  
      */  
       
     TclResetShadowedCmdRefs(interp, cmdPtr);  
     return (Tcl_Command) cmdPtr;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclInvokeStringCommand --  
  *  
  *      "Wrapper" Tcl_ObjCmdProc used to call an existing string-based  
  *      Tcl_CmdProc if no object-based procedure exists for a command. A  
  *      pointer to this procedure is stored as the Tcl_ObjCmdProc in a  
  *      Command structure. It simply turns around and calls the string  
  *      Tcl_CmdProc in the Command structure.  
  *  
  * Results:  
  *      A standard Tcl object result value.  
  *  
  * Side effects:  
  *      Besides those side effects of the called Tcl_CmdProc,  
  *      TclInvokeStringCommand allocates and frees storage.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclInvokeStringCommand(clientData, interp, objc, objv)  
     ClientData clientData;      /* Points to command's Command structure. */  
     Tcl_Interp *interp;         /* Current interpreter. */  
     register int objc;          /* Number of arguments. */  
     Tcl_Obj *CONST objv[];      /* Argument objects. */  
 {  
     register Command *cmdPtr = (Command *) clientData;  
     register int i;  
     int result;  
   
     /*  
      * This procedure generates an argv array for the string arguments. It  
      * starts out with stack-allocated space but uses dynamically-allocated  
      * storage if needed.  
      */  
   
 #define NUM_ARGS 20  
     char *(argStorage[NUM_ARGS]);  
     char **argv = argStorage;  
   
     /*  
      * Create the string argument array "argv". Make sure argv is large  
      * enough to hold the objc arguments plus 1 extra for the zero  
      * end-of-argv word.  
      */  
   
     if ((objc + 1) > NUM_ARGS) {  
         argv = (char **) ckalloc((unsigned)(objc + 1) * sizeof(char *));  
     }  
   
     for (i = 0;  i < objc;  i++) {  
         argv[i] = Tcl_GetString(objv[i]);  
     }  
     argv[objc] = 0;  
   
     /*  
      * Invoke the command's string-based Tcl_CmdProc.  
      */  
   
     result = (*cmdPtr->proc)(cmdPtr->clientData, interp, objc, argv);  
   
     /*  
      * Free the argv array if malloc'ed storage was used.  
      */  
   
     if (argv != argStorage) {  
         ckfree((char *) argv);  
     }  
     return result;  
 #undef NUM_ARGS  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclInvokeObjectCommand --  
  *  
  *      "Wrapper" Tcl_CmdProc used to call an existing object-based  
  *      Tcl_ObjCmdProc if no string-based procedure exists for a command.  
  *      A pointer to this procedure is stored as the Tcl_CmdProc in a  
  *      Command structure. It simply turns around and calls the object  
  *      Tcl_ObjCmdProc in the Command structure.  
  *  
  * Results:  
  *      A standard Tcl string result value.  
  *  
  * Side effects:  
  *      Besides those side effects of the called Tcl_CmdProc,  
  *      TclInvokeStringCommand allocates and frees storage.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclInvokeObjectCommand(clientData, interp, argc, argv)  
     ClientData clientData;      /* Points to command's Command structure. */  
     Tcl_Interp *interp;         /* Current interpreter. */  
     int argc;                   /* Number of arguments. */  
     register char **argv;       /* Argument strings. */  
 {  
     Command *cmdPtr = (Command *) clientData;  
     register Tcl_Obj *objPtr;  
     register int i;  
     int length, result;  
   
     /*  
      * This procedure generates an objv array for object arguments that hold  
      * the argv strings. It starts out with stack-allocated space but uses  
      * dynamically-allocated storage if needed.  
      */  
   
 #define NUM_ARGS 20  
     Tcl_Obj *(argStorage[NUM_ARGS]);  
     register Tcl_Obj **objv = argStorage;  
   
     /*  
      * Create the object argument array "objv". Make sure objv is large  
      * enough to hold the objc arguments plus 1 extra for the zero  
      * end-of-objv word.  
      */  
   
     if ((argc + 1) > NUM_ARGS) {  
         objv = (Tcl_Obj **)  
             ckalloc((unsigned)(argc + 1) * sizeof(Tcl_Obj *));  
     }  
   
     for (i = 0;  i < argc;  i++) {  
         length = strlen(argv[i]);  
         TclNewObj(objPtr);  
         TclInitStringRep(objPtr, argv[i], length);  
         Tcl_IncrRefCount(objPtr);  
         objv[i] = objPtr;  
     }  
     objv[argc] = 0;  
   
     /*  
      * Invoke the command's object-based Tcl_ObjCmdProc.  
      */  
   
     result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, argc, objv);  
   
     /*  
      * Move the interpreter's object result to the string result,  
      * then reset the object result.  
      */  
   
     Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),  
             TCL_VOLATILE);  
       
     /*  
      * Decrement the ref counts for the argument objects created above,  
      * then free the objv array if malloc'ed storage was used.  
      */  
   
     for (i = 0;  i < argc;  i++) {  
         objPtr = objv[i];  
         Tcl_DecrRefCount(objPtr);  
     }  
     if (objv != argStorage) {  
         ckfree((char *) objv);  
     }  
     return result;  
 #undef NUM_ARGS  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclRenameCommand --  
  *  
  *      Called to give an existing Tcl command a different name. Both the  
  *      old command name and the new command name can have "::" namespace  
  *      qualifiers. If the new command has a different namespace context,  
  *      the command will be moved to that namespace and will execute in  
  *      the context of that new namespace.  
  *  
  *      If the new command name is NULL or the null string, the command is  
  *      deleted.  
  *  
  * Results:  
  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.  
  *  
  * Side effects:  
  *      If anything goes wrong, an error message is returned in the  
  *      interpreter's result object.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclRenameCommand(interp, oldName, newName)  
     Tcl_Interp *interp;                 /* Current interpreter. */  
     char *oldName;                      /* Existing command name. */  
     char *newName;                      /* New command name. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     char *newTail;  
     Namespace *cmdNsPtr, *newNsPtr, *dummy1, *dummy2;  
     Tcl_Command cmd;  
     Command *cmdPtr;  
     Tcl_HashEntry *hPtr, *oldHPtr;  
     int new, result;  
   
     /*  
      * Find the existing command. An error is returned if cmdName can't  
      * be found.  
      */  
   
     cmd = Tcl_FindCommand(interp, oldName, (Tcl_Namespace *) NULL,  
         /*flags*/ 0);  
     cmdPtr = (Command *) cmd;  
     if (cmdPtr == NULL) {  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't ",  
                 ((newName == NULL)||(*newName == '\0'))? "delete":"rename",  
                 " \"", oldName, "\": command doesn't exist", (char *) NULL);  
         return TCL_ERROR;  
     }  
     cmdNsPtr = cmdPtr->nsPtr;  
   
     /*  
      * If the new command name is NULL or empty, delete the command. Do this  
      * with Tcl_DeleteCommandFromToken, since we already have the command.  
      */  
       
     if ((newName == NULL) || (*newName == '\0')) {  
         Tcl_DeleteCommandFromToken(interp, cmd);  
         return TCL_OK;  
     }  
   
     /*  
      * Make sure that the destination command does not already exist.  
      * The rename operation is like creating a command, so we should  
      * automatically create the containing namespaces just like  
      * Tcl_CreateCommand would.  
      */  
   
     TclGetNamespaceForQualName(interp, newName, (Namespace *) NULL,  
        CREATE_NS_IF_UNKNOWN, &newNsPtr, &dummy1, &dummy2, &newTail);  
   
     if ((newNsPtr == NULL) || (newTail == NULL)) {  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                  "can't rename to \"", newName, "\": bad command name",  
                  (char *) NULL);  
         return TCL_ERROR;  
     }  
     if (Tcl_FindHashEntry(&newNsPtr->cmdTable, newTail) != NULL) {  
         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                  "can't rename to \"", newName,  
                  "\": command already exists", (char *) NULL);  
         return TCL_ERROR;  
     }  
   
   
     /*  
      * Warning: any changes done in the code here are likely  
      * to be needed in Tcl_HideCommand() code too.  
      * (until the common parts are extracted out)     --dl  
      */  
   
     /*  
      * Put the command in the new namespace so we can check for an alias  
      * loop. Since we are adding a new command to a namespace, we must  
      * handle any shadowing of the global commands that this might create.  
      */  
       
     oldHPtr = cmdPtr->hPtr;  
     hPtr = Tcl_CreateHashEntry(&newNsPtr->cmdTable, newTail, &new);  
     Tcl_SetHashValue(hPtr, (ClientData) cmdPtr);  
     cmdPtr->hPtr = hPtr;  
     cmdPtr->nsPtr = newNsPtr;  
     TclResetShadowedCmdRefs(interp, cmdPtr);  
   
     /*  
      * Now check for an alias loop. If we detect one, put everything back  
      * the way it was and report the error.  
      */  
   
     result = TclPreventAliasLoop(interp, interp, (Tcl_Command) cmdPtr);  
     if (result != TCL_OK) {  
         Tcl_DeleteHashEntry(cmdPtr->hPtr);  
         cmdPtr->hPtr = oldHPtr;  
         cmdPtr->nsPtr = cmdNsPtr;  
         return result;  
     }  
   
     /*  
      * The new command name is okay, so remove the command from its  
      * current namespace. This is like deleting the command, so bump  
      * the cmdEpoch to invalidate any cached references to the command.  
      */  
       
     Tcl_DeleteHashEntry(oldHPtr);  
     cmdPtr->cmdEpoch++;  
   
     /*  
      * If the command being renamed has a compile procedure, increment the  
      * interpreter's compileEpoch to invalidate its compiled code. This  
      * makes sure that we don't later try to execute old code compiled for  
      * the now-renamed command.  
      */  
   
     if (cmdPtr->compileProc != NULL) {  
         iPtr->compileEpoch++;  
     }  
   
     return TCL_OK;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_SetCommandInfo --  
  *  
  *      Modifies various information about a Tcl command. Note that  
  *      this procedure will not change a command's namespace; use  
  *      Tcl_RenameCommand to do that. Also, the isNativeObjectProc  
  *      member of *infoPtr is ignored.  
  *  
  * Results:  
  *      If cmdName exists in interp, then the information at *infoPtr  
  *      is stored with the command in place of the current information  
  *      and 1 is returned. If the command doesn't exist then 0 is  
  *      returned.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tcl_SetCommandInfo(interp, cmdName, infoPtr)  
     Tcl_Interp *interp;                 /* Interpreter in which to look  
                                          * for command. */  
     char *cmdName;                      /* Name of desired command. */  
     Tcl_CmdInfo *infoPtr;               /* Where to find information  
                                          * to store in the command. */  
 {  
     Tcl_Command cmd;  
     Command *cmdPtr;  
   
     cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL,  
             /*flags*/ 0);  
     if (cmd == (Tcl_Command) NULL) {  
         return 0;  
     }  
   
     /*  
      * The isNativeObjectProc and nsPtr members of *infoPtr are ignored.  
      */  
       
     cmdPtr = (Command *) cmd;  
     cmdPtr->proc = infoPtr->proc;  
     cmdPtr->clientData = infoPtr->clientData;  
     if (infoPtr->objProc == (Tcl_ObjCmdProc *) NULL) {  
         cmdPtr->objProc = TclInvokeStringCommand;  
         cmdPtr->objClientData = (ClientData) cmdPtr;  
     } else {  
         cmdPtr->objProc = infoPtr->objProc;  
         cmdPtr->objClientData = infoPtr->objClientData;  
     }  
     cmdPtr->deleteProc = infoPtr->deleteProc;  
     cmdPtr->deleteData = infoPtr->deleteData;  
     return 1;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_GetCommandInfo --  
  *  
  *      Returns various information about a Tcl command.  
  *  
  * Results:  
  *      If cmdName exists in interp, then *infoPtr is modified to  
  *      hold information about cmdName and 1 is returned.  If the  
  *      command doesn't exist then 0 is returned and *infoPtr isn't  
  *      modified.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tcl_GetCommandInfo(interp, cmdName, infoPtr)  
     Tcl_Interp *interp;                 /* Interpreter in which to look  
                                          * for command. */  
     char *cmdName;                      /* Name of desired command. */  
     Tcl_CmdInfo *infoPtr;               /* Where to store information about  
                                          * command. */  
 {  
     Tcl_Command cmd;  
     Command *cmdPtr;  
   
     cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL,  
             /*flags*/ 0);  
     if (cmd == (Tcl_Command) NULL) {  
         return 0;  
     }  
   
     /*  
      * Set isNativeObjectProc 1 if objProc was registered by a call to  
      * Tcl_CreateObjCommand. Otherwise set it to 0.  
      */  
   
     cmdPtr = (Command *) cmd;  
     infoPtr->isNativeObjectProc =  
             (cmdPtr->objProc != TclInvokeStringCommand);  
     infoPtr->objProc = cmdPtr->objProc;  
     infoPtr->objClientData = cmdPtr->objClientData;  
     infoPtr->proc = cmdPtr->proc;  
     infoPtr->clientData = cmdPtr->clientData;  
     infoPtr->deleteProc = cmdPtr->deleteProc;  
     infoPtr->deleteData = cmdPtr->deleteData;  
     infoPtr->namespacePtr = (Tcl_Namespace *) cmdPtr->nsPtr;  
     return 1;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_GetCommandName --  
  *  
  *      Given a token returned by Tcl_CreateCommand, this procedure  
  *      returns the current name of the command (which may have changed  
  *      due to renaming).  
  *  
  * Results:  
  *      The return value is the name of the given command.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 char *  
 Tcl_GetCommandName(interp, command)  
     Tcl_Interp *interp;         /* Interpreter containing the command. */  
     Tcl_Command command;        /* Token for command returned by a previous  
                                  * call to Tcl_CreateCommand. The command  
                                  * must not have been deleted. */  
 {  
     Command *cmdPtr = (Command *) command;  
   
     if ((cmdPtr == NULL) || (cmdPtr->hPtr == NULL)) {  
   
         /*  
          * This should only happen if command was "created" after the  
          * interpreter began to be deleted, so there isn't really any  
          * command. Just return an empty string.  
          */  
   
         return "";  
     }  
     return Tcl_GetHashKey(cmdPtr->hPtr->tablePtr, cmdPtr->hPtr);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_GetCommandFullName --  
  *  
  *      Given a token returned by, e.g., Tcl_CreateCommand or  
  *      Tcl_FindCommand, this procedure appends to an object the command's  
  *      full name, qualified by a sequence of parent namespace names. The  
  *      command's fully-qualified name may have changed due to renaming.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The command's fully-qualified name is appended to the string  
  *      representation of objPtr.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tcl_GetCommandFullName(interp, command, objPtr)  
     Tcl_Interp *interp;         /* Interpreter containing the command. */  
     Tcl_Command command;        /* Token for command returned by a previous  
                                  * call to Tcl_CreateCommand. The command  
                                  * must not have been deleted. */  
     Tcl_Obj *objPtr;            /* Points to the object onto which the  
                                  * command's full name is appended. */  
   
 {  
     Interp *iPtr = (Interp *) interp;  
     register Command *cmdPtr = (Command *) command;  
     char *name;  
   
     /*  
      * Add the full name of the containing namespace, followed by the "::"  
      * separator, and the command name.  
      */  
   
     if (cmdPtr != NULL) {  
         if (cmdPtr->nsPtr != NULL) {  
             Tcl_AppendToObj(objPtr, cmdPtr->nsPtr->fullName, -1);  
             if (cmdPtr->nsPtr != iPtr->globalNsPtr) {  
                 Tcl_AppendToObj(objPtr, "::", 2);  
             }  
         }  
         if (cmdPtr->hPtr != NULL) {  
             name = Tcl_GetHashKey(cmdPtr->hPtr->tablePtr, cmdPtr->hPtr);  
             Tcl_AppendToObj(objPtr, name, -1);  
         }  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_DeleteCommand --  
  *  
  *      Remove the given command from the given interpreter.  
  *  
  * Results:  
  *      0 is returned if the command was deleted successfully.  
  *      -1 is returned if there didn't exist a command by that name.  
  *  
  * Side effects:  
  *      cmdName will no longer be recognized as a valid command for  
  *      interp.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tcl_DeleteCommand(interp, cmdName)  
     Tcl_Interp *interp;         /* Token for command interpreter (returned  
                                  * by a previous Tcl_CreateInterp call). */  
     char *cmdName;              /* Name of command to remove. */  
 {  
     Tcl_Command cmd;  
   
     /*  
      *  Find the desired command and delete it.  
      */  
   
     cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL,  
             /*flags*/ 0);  
     if (cmd == (Tcl_Command) NULL) {  
         return -1;  
     }  
     return Tcl_DeleteCommandFromToken(interp, cmd);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_DeleteCommandFromToken --  
  *  
  *      Removes the given command from the given interpreter. This procedure  
  *      resembles Tcl_DeleteCommand, but takes a Tcl_Command token instead  
  *      of a command name for efficiency.  
  *  
  * Results:  
  *      0 is returned if the command was deleted successfully.  
  *      -1 is returned if there didn't exist a command by that name.  
  *  
  * Side effects:  
  *      The command specified by "cmd" will no longer be recognized as a  
  *      valid command for "interp".  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tcl_DeleteCommandFromToken(interp, cmd)  
     Tcl_Interp *interp;         /* Token for command interpreter returned by  
                                  * a previous call to Tcl_CreateInterp. */  
     Tcl_Command cmd;            /* Token for command to delete. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     Command *cmdPtr = (Command *) cmd;  
     ImportRef *refPtr, *nextRefPtr;  
     Tcl_Command importCmd;  
   
     /*  
      * The code here is tricky.  We can't delete the hash table entry  
      * before invoking the deletion callback because there are cases  
      * where the deletion callback needs to invoke the command (e.g.  
      * object systems such as OTcl). However, this means that the  
      * callback could try to delete or rename the command. The deleted  
      * flag allows us to detect these cases and skip nested deletes.  
      */  
   
     if (cmdPtr->deleted) {  
         /*  
          * Another deletion is already in progress.  Remove the hash  
          * table entry now, but don't invoke a callback or free the  
          * command structure.  
          */  
   
         Tcl_DeleteHashEntry(cmdPtr->hPtr);  
         cmdPtr->hPtr = NULL;  
         return 0;  
     }  
   
     /*  
      * If the command being deleted has a compile procedure, increment the  
      * interpreter's compileEpoch to invalidate its compiled code. This  
      * makes sure that we don't later try to execute old code compiled with  
      * command-specific (i.e., inline) bytecodes for the now-deleted  
      * command. This field is checked in Tcl_EvalObj and ObjInterpProc, and  
      * code whose compilation epoch doesn't match is recompiled.  
      */  
   
     if (cmdPtr->compileProc != NULL) {  
         iPtr->compileEpoch++;  
     }  
   
     cmdPtr->deleted = 1;  
     if (cmdPtr->deleteProc != NULL) {  
         /*  
          * Delete the command's client data. If this was an imported command  
          * created when a command was imported into a namespace, this client  
          * data will be a pointer to a ImportedCmdData structure describing  
          * the "real" command that this imported command refers to.  
          */  
           
         /*  
          * If you are getting a crash during the call to deleteProc and  
          * cmdPtr->deleteProc is a pointer to the function free(), the  
          * most likely cause is that your extension allocated memory  
          * for the clientData argument to Tcl_CreateObjCommand() with  
          * the ckalloc() macro and you are now trying to deallocate  
          * this memory with free() instead of ckfree(). You should  
          * pass a pointer to your own method that calls ckfree().  
          */  
   
         (*cmdPtr->deleteProc)(cmdPtr->deleteData);  
     }  
   
     /*  
      * Bump the command epoch counter. This will invalidate all cached  
      * references that point to this command.  
      */  
       
     cmdPtr->cmdEpoch++;  
   
     /*  
      * If this command was imported into other namespaces, then imported  
      * commands were created that refer back to this command. Delete these  
      * imported commands now.  
      */  
   
     for (refPtr = cmdPtr->importRefPtr;  refPtr != NULL;  
             refPtr = nextRefPtr) {  
         nextRefPtr = refPtr->nextPtr;  
         importCmd = (Tcl_Command) refPtr->importedCmdPtr;  
         Tcl_DeleteCommandFromToken(interp, importCmd);  
     }  
   
     /*  
      * Don't use hPtr to delete the hash entry here, because it's  
      * possible that the deletion callback renamed the command.  
      * Instead, use cmdPtr->hptr, and make sure that no-one else  
      * has already deleted the hash entry.  
      */  
   
     if (cmdPtr->hPtr != NULL) {  
         Tcl_DeleteHashEntry(cmdPtr->hPtr);  
     }  
   
     /*  
      * Mark the Command structure as no longer valid. This allows  
      * TclExecuteByteCode to recognize when a Command has logically been  
      * deleted and a pointer to this Command structure cached in a CmdName  
      * object is invalid. TclExecuteByteCode will look up the command again  
      * in the interpreter's command hashtable.  
      */  
   
     cmdPtr->objProc = NULL;  
   
     /*  
      * Now free the Command structure, unless there is another reference to  
      * it from a CmdName Tcl object in some ByteCode code sequence. In that  
      * case, delay the cleanup until all references are either discarded  
      * (when a ByteCode is freed) or replaced by a new reference (when a  
      * cached CmdName Command reference is found to be invalid and  
      * TclExecuteByteCode looks up the command in the command hashtable).  
      */  
       
     TclCleanupCommand(cmdPtr);  
     return 0;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclCleanupCommand --  
  *  
  *      This procedure frees up a Command structure unless it is still  
  *      referenced from an interpreter's command hashtable or from a CmdName  
  *      Tcl object representing the name of a command in a ByteCode  
  *      instruction sequence.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Memory gets freed unless a reference to the Command structure still  
  *      exists. In that case the cleanup is delayed until the command is  
  *      deleted or when the last ByteCode referring to it is freed.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 TclCleanupCommand(cmdPtr)  
     register Command *cmdPtr;   /* Points to the Command structure to  
                                  * be freed. */  
 {  
     cmdPtr->refCount--;  
     if (cmdPtr->refCount <= 0) {  
         ckfree((char *) cmdPtr);  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_CreateMathFunc --  
  *  
  *      Creates a new math function for expressions in a given  
  *      interpreter.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The function defined by "name" is created or redefined. If the  
  *      function already exists then its definition is replaced; this  
  *      includes the builtin functions. Redefining a builtin function forces  
  *      all existing code to be invalidated since that code may be compiled  
  *      using an instruction specific to the replaced function. In addition,  
  *      redefioning a non-builtin function will force existing code to be  
  *      invalidated if the number of arguments has changed.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tcl_CreateMathFunc(interp, name, numArgs, argTypes, proc, clientData)  
     Tcl_Interp *interp;                 /* Interpreter in which function is  
                                          * to be available. */  
     char *name;                         /* Name of function (e.g. "sin"). */  
     int numArgs;                        /* Nnumber of arguments required by  
                                          * function. */  
     Tcl_ValueType *argTypes;            /* Array of types acceptable for  
                                          * each argument. */  
     Tcl_MathProc *proc;                 /* Procedure that implements the  
                                          * math function. */  
     ClientData clientData;              /* Additional value to pass to the  
                                          * function. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     Tcl_HashEntry *hPtr;  
     MathFunc *mathFuncPtr;  
     int new, i;  
   
     hPtr = Tcl_CreateHashEntry(&iPtr->mathFuncTable, name, &new);  
     if (new) {  
         Tcl_SetHashValue(hPtr, ckalloc(sizeof(MathFunc)));  
     }  
     mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);  
   
     if (!new) {  
         if (mathFuncPtr->builtinFuncIndex >= 0) {  
             /*  
              * We are redefining a builtin math function. Invalidate the  
              * interpreter's existing code by incrementing its  
              * compileEpoch member. This field is checked in Tcl_EvalObj  
              * and ObjInterpProc, and code whose compilation epoch doesn't  
              * match is recompiled. Newly compiled code will no longer  
              * treat the function as builtin.  
              */  
   
             iPtr->compileEpoch++;  
         } else {  
             /*  
              * A non-builtin function is being redefined. We must invalidate  
              * existing code if the number of arguments has changed. This  
              * is because existing code was compiled assuming that number.  
              */  
   
             if (numArgs != mathFuncPtr->numArgs) {  
                 iPtr->compileEpoch++;  
             }  
         }  
     }  
       
     mathFuncPtr->builtinFuncIndex = -1; /* can't be a builtin function */  
     if (numArgs > MAX_MATH_ARGS) {  
         numArgs = MAX_MATH_ARGS;  
     }  
     mathFuncPtr->numArgs = numArgs;  
     for (i = 0;  i < numArgs;  i++) {  
         mathFuncPtr->argTypes[i] = argTypes[i];  
     }  
     mathFuncPtr->proc = proc;  
     mathFuncPtr->clientData = clientData;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_EvalObjEx --  
  *  
  *      Execute Tcl commands stored in a Tcl object. These commands are  
  *      compiled into bytecodes if necessary, unless TCL_EVAL_DIRECT  
  *      is specified.  
  *  
  * Results:  
  *      The return value is one of the return codes defined in tcl.h  
  *      (such as TCL_OK), and the interpreter's result contains a value  
  *      to supplement the return code.  
  *  
  * Side effects:  
  *      The object is converted, if necessary, to a ByteCode object that  
  *      holds the bytecode instructions for the commands. Executing the  
  *      commands will almost certainly have side effects that depend  
  *      on those commands.  
  *  
  *      Just as in Tcl_Eval, interp->termOffset is set to the offset of the  
  *      last character executed in the objPtr's string.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tcl_EvalObjEx(interp, objPtr, flags)  
     Tcl_Interp *interp;                 /* Token for command interpreter  
                                          * (returned by a previous call to  
                                          * Tcl_CreateInterp). */  
     register Tcl_Obj *objPtr;           /* Pointer to object containing  
                                          * commands to execute. */  
     int flags;                          /* Collection of OR-ed bits that  
                                          * control the evaluation of the  
                                          * script.  Supported values are  
                                          * TCL_EVAL_GLOBAL and  
                                          * TCL_EVAL_DIRECT. */  
 {  
     register Interp *iPtr = (Interp *) interp;  
     int evalFlags;                      /* Interp->evalFlags value when the  
                                          * procedure was called. */  
     register ByteCode* codePtr;         /* Tcl Internal type of bytecode. */  
     int oldCount = iPtr->cmdCount;      /* Used to tell whether any commands  
                                          * at all were executed. */  
     int numSrcBytes;  
     int result;  
     CallFrame *savedVarFramePtr;        /* Saves old copy of iPtr->varFramePtr  
                                          * in case TCL_EVAL_GLOBAL was set. */  
     Namespace *namespacePtr;  
   
     Tcl_IncrRefCount(objPtr);  
   
     if ((iPtr->flags & USE_EVAL_DIRECT) || (flags & TCL_EVAL_DIRECT)) {  
         /*  
          * We're not supposed to use the compiler or byte-code interpreter.  
          * Let Tcl_EvalEx evaluate the command directly (and probably  
          * more slowly).  
          *  
          * Pure List Optimization (no string representation).  In this  
          * case, we can safely use Tcl_EvalObjv instead and get an  
          * appreciable improvement in execution speed.  This is because it  
          * allows us to avoid a setFromAny step that would just pack  
          * everything into a string and back out again.  
          *  
          * USE_EVAL_DIRECT is a special flag used for testing purpose only  
          * (ensure we go into the TCL_EVAL_DIRECT path, avoiding opt)  
          */  
         if (!(iPtr->flags & USE_EVAL_DIRECT) &&  
                 (objPtr->typePtr == &tclListType) && /* is a list... */  
                 (objPtr->bytes == NULL) /* ...without a string rep */) {  
             register List *listRepPtr =  
                 (List *) objPtr->internalRep.otherValuePtr;  
             result = Tcl_EvalObjv(interp, listRepPtr->elemCount,  
                     listRepPtr->elements, flags);  
         } else {  
             register char *p;  
             p = Tcl_GetStringFromObj(objPtr, &numSrcBytes);  
             result = Tcl_EvalEx(interp, p, numSrcBytes, flags);  
         }  
         Tcl_DecrRefCount(objPtr);  
         return result;  
     }  
   
     /*  
      * Prevent the object from being deleted as a side effect of evaling it.  
      */  
   
     savedVarFramePtr = iPtr->varFramePtr;  
     if (flags & TCL_EVAL_GLOBAL) {  
         iPtr->varFramePtr = NULL;  
     }  
   
     /*  
      * Reset both the interpreter's string and object results and clear out  
      * any error information. This makes sure that we return an empty  
      * result if there are no commands in the command string.  
      */  
   
     Tcl_ResetResult(interp);  
   
     /*  
      * Check depth of nested calls to Tcl_Eval:  if this gets too large,  
      * it's probably because of an infinite loop somewhere.  
      */  
   
     iPtr->numLevels++;  
     if (iPtr->numLevels > iPtr->maxNestingDepth) {  
         Tcl_AppendToObj(Tcl_GetObjResult(interp),  
                 "too many nested calls to Tcl_EvalObj (infinite loop?)", -1);  
         result = TCL_ERROR;  
         goto done;  
     }  
   
     /*  
      * On the Mac, we will never reach the default recursion limit before  
      * blowing the stack. So we need to do a check here.  
      */  
       
     if (TclpCheckStackSpace() == 0) {  
         /*NOTREACHED*/  
         Tcl_AppendToObj(Tcl_GetObjResult(interp),  
                 "too many nested calls to Tcl_EvalObj (infinite loop?)", -1);  
         result = TCL_ERROR;  
         goto done;  
     }  
   
     /*  
      * If the interpreter has been deleted, return an error.  
      */  
       
     if (iPtr->flags & DELETED) {  
         Tcl_ResetResult(interp);  
         Tcl_AppendToObj(Tcl_GetObjResult(interp),  
                 "attempt to call eval in deleted interpreter", -1);  
         Tcl_SetErrorCode(interp, "CORE", "IDELETE",  
                 "attempt to call eval in deleted interpreter",  
                 (char *) NULL);  
         result = TCL_ERROR;  
         goto done;  
     }  
   
     /*  
      * Get the ByteCode from the object. If it exists, make sure it hasn't  
      * been invalidated by, e.g., someone redefining a command with a  
      * compile procedure (this might make the compiled code wrong). If  
      * necessary, convert the object to be a ByteCode object and compile it.  
      * Also, if the code was compiled in/for a different interpreter,  
      * or for a different namespace, or for the same namespace but  
      * with different name resolution rules, we recompile it.  
      *  
      * Precompiled objects, however, are immutable and therefore  
      * they are not recompiled, even if the epoch has changed.  
      *  
      * To be pedantically correct, we should also check that the  
      * originating procPtr is the same as the current context procPtr  
      * (assuming one exists at all - none for global level).  This  
      * code is #def'ed out because [info body] was changed to never  
      * return a bytecode type object, which should obviate us from  
      * the extra checks here.  
      */  
   
     if (iPtr->varFramePtr != NULL) {  
         namespacePtr = iPtr->varFramePtr->nsPtr;  
     } else {  
         namespacePtr = iPtr->globalNsPtr;  
     }  
   
     if (objPtr->typePtr == &tclByteCodeType) {  
         codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;  
           
         if (((Interp *) *codePtr->interpHandle != iPtr)  
                 || (codePtr->compileEpoch != iPtr->compileEpoch)  
 #ifdef CHECK_PROC_ORIGINATION   /* [Bug: 3412 Pedantic] */  
                 || (codePtr->procPtr != NULL && !(iPtr->varFramePtr &&  
                         iPtr->varFramePtr->procPtr == codePtr->procPtr))  
 #endif  
                 || (codePtr->nsPtr != namespacePtr)  
                 || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) {  
             if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {  
                 if ((Interp *) *codePtr->interpHandle != iPtr) {  
                     panic("Tcl_EvalObj: compiled script jumped interps");  
                 }  
                 codePtr->compileEpoch = iPtr->compileEpoch;  
             } else {  
                 tclByteCodeType.freeIntRepProc(objPtr);  
             }  
         }  
     }  
     if (objPtr->typePtr != &tclByteCodeType) {  
         iPtr->errorLine = 1;  
         result = tclByteCodeType.setFromAnyProc(interp, objPtr);  
         if (result != TCL_OK) {  
             goto done;  
         }  
     } else {  
         codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;  
         if (((Interp *) *codePtr->interpHandle != iPtr)  
                 || (codePtr->compileEpoch != iPtr->compileEpoch)) {  
             (*tclByteCodeType.freeIntRepProc)(objPtr);  
             iPtr->errorLine = 1;  
             result = (*tclByteCodeType.setFromAnyProc)(interp, objPtr);  
             if (result != TCL_OK) {  
                 iPtr->numLevels--;  
                 return result;  
             }  
         }  
     }  
     codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;  
   
     /*  
      * Extract then reset the compilation flags in the interpreter.  
      * Resetting the flags must be done after any compilation.  
      */  
   
     evalFlags = iPtr->evalFlags;  
     iPtr->evalFlags = 0;  
   
     /*  
      * Execute the commands. If the code was compiled from an empty string,  
      * don't bother executing the code.  
      */  
   
     numSrcBytes = codePtr->numSrcBytes;  
     if ((numSrcBytes > 0) || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) {  
         /*  
          * Increment the code's ref count while it is being executed. If  
          * afterwards no references to it remain, free the code.  
          */  
           
         codePtr->refCount++;  
         result = TclExecuteByteCode(interp, codePtr);  
         codePtr->refCount--;  
         if (codePtr->refCount <= 0) {  
             TclCleanupByteCode(codePtr);  
         }  
     } else {  
         result = TCL_OK;  
     }  
   
     /*  
      * If no commands at all were executed, check for asynchronous  
      * handlers so that they at least get one change to execute.  
      * This is needed to handle event loops written in Tcl with  
      * empty bodies.  
      */  
   
     if ((oldCount == iPtr->cmdCount) && Tcl_AsyncReady()) {  
         result = Tcl_AsyncInvoke(interp, result);  
     }  
   
     /*  
      * Update the interpreter's evaluation level count. If we are again at  
      * the top level, process any unusual return code returned by the  
      * evaluated code.  
      */  
   
     if (iPtr->numLevels == 1) {  
         if (result == TCL_RETURN) {  
             result = TclUpdateReturnInfo(iPtr);  
         }  
         if ((result != TCL_OK) && (result != TCL_ERROR)  
                 && ((evalFlags & TCL_ALLOW_EXCEPTIONS) == 0)) {  
             ProcessUnexpectedResult(interp, result);  
             result = TCL_ERROR;  
         }  
     }  
   
     /*  
      * If an error occurred, record information about what was being  
      * executed when the error occurred.  
      */  
   
     if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {  
         RecordTracebackInfo(interp, objPtr, numSrcBytes);  
     }  
   
     /*  
      * Set the interpreter's termOffset member to the offset of the  
      * character just after the last one executed. We approximate the offset  
      * of the last character executed by using the number of characters  
      * compiled.  
      */  
   
     iPtr->termOffset = numSrcBytes;  
     iPtr->flags &= ~ERR_ALREADY_LOGGED;  
   
     done:  
     TclDecrRefCount(objPtr);  
     iPtr->varFramePtr = savedVarFramePtr;  
     iPtr->numLevels--;  
     return result;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * ProcessUnexpectedResult --  
  *  
  *      Procedure called by Tcl_EvalObj to set the interpreter's result  
  *      value to an appropriate error message when the code it evaluates  
  *      returns an unexpected result code (not TCL_OK and not TCL_ERROR) to  
  *      the topmost evaluation level.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The interpreter result is set to an error message appropriate to  
  *      the result code.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 ProcessUnexpectedResult(interp, returnCode)  
     Tcl_Interp *interp;         /* The interpreter in which the unexpected  
                                  * result code was returned. */  
     int returnCode;             /* The unexpected result code. */  
 {  
     Tcl_ResetResult(interp);  
     if (returnCode == TCL_BREAK) {  
         Tcl_AppendToObj(Tcl_GetObjResult(interp),  
                 "invoked \"break\" outside of a loop", -1);  
     } else if (returnCode == TCL_CONTINUE) {  
         Tcl_AppendToObj(Tcl_GetObjResult(interp),  
                 "invoked \"continue\" outside of a loop", -1);  
     } else {  
         char buf[30 + TCL_INTEGER_SPACE];  
   
         sprintf(buf, "command returned bad code: %d", returnCode);  
         Tcl_SetResult(interp, buf, TCL_VOLATILE);  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * RecordTracebackInfo --  
  *  
  *      Procedure called by Tcl_EvalObj to record information about what was  
  *      being executed when the error occurred.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Appends information about the script being evaluated to the  
  *      interpreter's "errorInfo" variable.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 RecordTracebackInfo(interp, objPtr, numSrcBytes)  
     Tcl_Interp *interp;         /* The interpreter in which the error  
                                  * occurred. */  
     Tcl_Obj *objPtr;            /* Points to object containing script whose  
                                  * evaluation resulted in an error. */  
     int numSrcBytes;            /* Number of bytes compiled in script. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     char buf[200];  
     char *ellipsis, *bytes;  
     int length;  
   
     /*  
      * Decide how much of the command to print in the error message  
      * (up to a certain number of bytes).  
      */  
       
     bytes = Tcl_GetStringFromObj(objPtr, &length);  
     length = TclMin(numSrcBytes, length);  
       
     ellipsis = "";  
     if (length > 150) {  
         length = 150;  
         ellipsis = " ...";  
     }  
       
     if (!(iPtr->flags & ERR_IN_PROGRESS)) {  
         sprintf(buf, "\n    while executing\n\"%.*s%s\"",  
                 length, bytes, ellipsis);  
     } else {  
         sprintf(buf, "\n    invoked from within\n\"%.*s%s\"",  
                 length, bytes, ellipsis);  
     }  
     Tcl_AddObjErrorInfo(interp, buf, -1);  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean --  
  *  
  *      Procedures to evaluate an expression and return its value in a  
  *      particular form.  
  *  
  * Results:  
  *      Each of the procedures below returns a standard Tcl result. If an  
  *      error occurs then an error message is left in the interp's result.  
  *      Otherwise the value of the expression, in the appropriate form,  
  *      is stored at *ptr. If the expression had a result that was  
  *      incompatible with the desired form then an error is returned.  
  *  
  * Side effects:  
  *      None.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 int  
 Tcl_ExprLong(interp, string, ptr)  
     Tcl_Interp *interp;         /* Context in which to evaluate the  
                                  * expression. */  
     char *string;               /* Expression to evaluate. */  
     long *ptr;                  /* Where to store result. */  
 {  
     register Tcl_Obj *exprPtr;  
     Tcl_Obj *resultPtr;  
     int length = strlen(string);  
     int result = TCL_OK;  
   
     if (length > 0) {  
         exprPtr = Tcl_NewStringObj(string, length);  
         Tcl_IncrRefCount(exprPtr);  
         result = Tcl_ExprObj(interp, exprPtr, &resultPtr);  
         if (result == TCL_OK) {  
             /*  
              * Store an integer based on the expression result.  
              */  
               
             if (resultPtr->typePtr == &tclIntType) {  
                 *ptr = resultPtr->internalRep.longValue;  
             } else if (resultPtr->typePtr == &tclDoubleType) {  
                 *ptr = (long) resultPtr->internalRep.doubleValue;  
             } else {  
                 Tcl_SetResult(interp,  
                         "expression didn't have numeric value", TCL_STATIC);  
                 result = TCL_ERROR;  
             }  
             Tcl_DecrRefCount(resultPtr);  /* discard the result object */  
         } else {  
             /*  
              * Move the interpreter's object result to the string result,  
              * then reset the object result.  
              */  
   
             Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),  
                     TCL_VOLATILE);  
         }  
         Tcl_DecrRefCount(exprPtr);  /* discard the expression object */  
     } else {  
         /*  
          * An empty string. Just set the result integer to 0.  
          */  
           
         *ptr = 0;  
     }  
     return result;  
 }  
   
 int  
 Tcl_ExprDouble(interp, string, ptr)  
     Tcl_Interp *interp;         /* Context in which to evaluate the  
                                  * expression. */  
     char *string;               /* Expression to evaluate. */  
     double *ptr;                /* Where to store result. */  
 {  
     register Tcl_Obj *exprPtr;  
     Tcl_Obj *resultPtr;  
     int length = strlen(string);  
     int result = TCL_OK;  
   
     if (length > 0) {  
         exprPtr = Tcl_NewStringObj(string, length);  
         Tcl_IncrRefCount(exprPtr);  
         result = Tcl_ExprObj(interp, exprPtr, &resultPtr);  
         if (result == TCL_OK) {  
             /*  
              * Store a double  based on the expression result.  
              */  
               
             if (resultPtr->typePtr == &tclIntType) {  
                 *ptr = (double) resultPtr->internalRep.longValue;  
             } else if (resultPtr->typePtr == &tclDoubleType) {  
                 *ptr = resultPtr->internalRep.doubleValue;  
             } else {  
                 Tcl_SetResult(interp,  
                         "expression didn't have numeric value", TCL_STATIC);  
                 result = TCL_ERROR;  
             }  
             Tcl_DecrRefCount(resultPtr);  /* discard the result object */  
         } else {  
             /*  
              * Move the interpreter's object result to the string result,  
              * then reset the object result.  
              */  
   
             Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),  
                     TCL_VOLATILE);  
         }  
         Tcl_DecrRefCount(exprPtr);  /* discard the expression object */  
     } else {  
         /*  
          * An empty string. Just set the result double to 0.0.  
          */  
           
         *ptr = 0.0;  
     }  
     return result;  
 }  
   
 int  
 Tcl_ExprBoolean(interp, string, ptr)  
     Tcl_Interp *interp;         /* Context in which to evaluate the  
                                  * expression. */  
     char *string;               /* Expression to evaluate. */  
     int *ptr;                   /* Where to store 0/1 result. */  
 {  
     register Tcl_Obj *exprPtr;  
     Tcl_Obj *resultPtr;  
     int length = strlen(string);  
     int result = TCL_OK;  
   
     if (length > 0) {  
         exprPtr = Tcl_NewStringObj(string, length);  
         Tcl_IncrRefCount(exprPtr);  
         result = Tcl_ExprObj(interp, exprPtr, &resultPtr);  
         if (result == TCL_OK) {  
             /*  
              * Store a boolean based on the expression result.  
              */  
               
             if (resultPtr->typePtr == &tclIntType) {  
                 *ptr = (resultPtr->internalRep.longValue != 0);  
             } else if (resultPtr->typePtr == &tclDoubleType) {  
                 *ptr = (resultPtr->internalRep.doubleValue != 0.0);  
             } else {  
                 result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr);  
             }  
             Tcl_DecrRefCount(resultPtr);  /* discard the result object */  
         }  
         if (result != TCL_OK) {  
             /*  
              * Move the interpreter's object result to the string result,  
              * then reset the object result.  
              */  
   
             Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),  
                     TCL_VOLATILE);  
         }  
         Tcl_DecrRefCount(exprPtr); /* discard the expression object */  
     } else {  
         /*  
          * An empty string. Just set the result boolean to 0 (false).  
          */  
           
         *ptr = 0;  
     }  
     return result;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj --  
  *  
  *      Procedures to evaluate an expression in an object and return its  
  *      value in a particular form.  
  *  
  * Results:  
  *      Each of the procedures below returns a standard Tcl result  
  *      object. If an error occurs then an error message is left in the  
  *      interpreter's result. Otherwise the value of the expression, in the  
  *      appropriate form, is stored at *ptr. If the expression had a result  
  *      that was incompatible with the desired form then an error is  
  *      returned.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 Tcl_ExprLongObj(interp, objPtr, ptr)  
     Tcl_Interp *interp;                 /* Context in which to evaluate the  
                                          * expression. */  
     register Tcl_Obj *objPtr;           /* Expression to evaluate. */  
     long *ptr;                          /* Where to store long result. */  
 {  
     Tcl_Obj *resultPtr;  
     int result;  
   
     result = Tcl_ExprObj(interp, objPtr, &resultPtr);  
     if (result == TCL_OK) {  
         if (resultPtr->typePtr == &tclIntType) {  
             *ptr = resultPtr->internalRep.longValue;  
         } else if (resultPtr->typePtr == &tclDoubleType) {  
             *ptr = (long) resultPtr->internalRep.doubleValue;  
         } else {  
             result = Tcl_GetLongFromObj(interp, resultPtr, ptr);  
             if (result != TCL_OK) {  
                 return result;  
             }  
         }  
         Tcl_DecrRefCount(resultPtr);  /* discard the result object */  
     }  
     return result;  
 }  
   
 int  
 Tcl_ExprDoubleObj(interp, objPtr, ptr)  
     Tcl_Interp *interp;                 /* Context in which to evaluate the  
                                          * expression. */  
     register Tcl_Obj *objPtr;           /* Expression to evaluate. */  
     double *ptr;                        /* Where to store double result. */  
 {  
     Tcl_Obj *resultPtr;  
     int result;  
   
     result = Tcl_ExprObj(interp, objPtr, &resultPtr);  
     if (result == TCL_OK) {  
         if (resultPtr->typePtr == &tclIntType) {  
             *ptr = (double) resultPtr->internalRep.longValue;  
         } else if (resultPtr->typePtr == &tclDoubleType) {  
             *ptr = resultPtr->internalRep.doubleValue;  
         } else {  
             result = Tcl_GetDoubleFromObj(interp, resultPtr, ptr);  
             if (result != TCL_OK) {  
                 return result;  
             }  
         }  
         Tcl_DecrRefCount(resultPtr);  /* discard the result object */  
     }  
     return result;  
 }  
   
 int  
 Tcl_ExprBooleanObj(interp, objPtr, ptr)  
     Tcl_Interp *interp;                 /* Context in which to evaluate the  
                                          * expression. */  
     register Tcl_Obj *objPtr;           /* Expression to evaluate. */  
     int *ptr;                           /* Where to store 0/1 result. */  
 {  
     Tcl_Obj *resultPtr;  
     int result;  
   
     result = Tcl_ExprObj(interp, objPtr, &resultPtr);  
     if (result == TCL_OK) {  
         if (resultPtr->typePtr == &tclIntType) {  
             *ptr = (resultPtr->internalRep.longValue != 0);  
         } else if (resultPtr->typePtr == &tclDoubleType) {  
             *ptr = (resultPtr->internalRep.doubleValue != 0.0);  
         } else {  
             result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr);  
         }  
         Tcl_DecrRefCount(resultPtr);  /* discard the result object */  
     }  
     return result;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclInvoke --  
  *  
  *      Invokes a Tcl command, given an argv/argc, from either the  
  *      exposed or the hidden sets of commands in the given interpreter.  
  *      NOTE: The command is invoked in the current stack frame of  
  *      the interpreter, thus it can modify local variables.  
  *  
  * Results:  
  *      A standard Tcl result.  
  *  
  * Side effects:  
  *      Whatever the command does.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclInvoke(interp, argc, argv, flags)  
     Tcl_Interp *interp;         /* Where to invoke the command. */  
     int argc;                   /* Count of args. */  
     register char **argv;       /* The arg strings; argv[0] is the name of  
                                  * the command to invoke. */  
     int flags;                  /* Combination of flags controlling the  
                                  * call: TCL_INVOKE_HIDDEN and  
                                  * TCL_INVOKE_NO_UNKNOWN. */  
 {  
     register Tcl_Obj *objPtr;  
     register int i;  
     int length, result;  
   
     /*  
      * This procedure generates an objv array for object arguments that hold  
      * the argv strings. It starts out with stack-allocated space but uses  
      * dynamically-allocated storage if needed.  
      */  
   
 #define NUM_ARGS 20  
     Tcl_Obj *(objStorage[NUM_ARGS]);  
     register Tcl_Obj **objv = objStorage;  
   
     /*  
      * Create the object argument array "objv". Make sure objv is large  
      * enough to hold the objc arguments plus 1 extra for the zero  
      * end-of-objv word.  
      */  
   
     if ((argc + 1) > NUM_ARGS) {  
         objv = (Tcl_Obj **)  
             ckalloc((unsigned)(argc + 1) * sizeof(Tcl_Obj *));  
     }  
   
     for (i = 0;  i < argc;  i++) {  
         length = strlen(argv[i]);  
         objv[i] = Tcl_NewStringObj(argv[i], length);  
         Tcl_IncrRefCount(objv[i]);  
     }  
     objv[argc] = 0;  
   
     /*  
      * Use TclObjInterpProc to actually invoke the command.  
      */  
   
     result = TclObjInvoke(interp, argc, objv, flags);  
   
     /*  
      * Move the interpreter's object result to the string result,  
      * then reset the object result.  
      */  
       
     Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),  
             TCL_VOLATILE);  
   
     /*  
      * Decrement the ref counts on the objv elements since we are done  
      * with them.  
      */  
   
     for (i = 0;  i < argc;  i++) {  
         objPtr = objv[i];  
         Tcl_DecrRefCount(objPtr);  
     }  
       
     /*  
      * Free the objv array if malloc'ed storage was used.  
      */  
   
     if (objv != objStorage) {  
         ckfree((char *) objv);  
     }  
     return result;  
 #undef NUM_ARGS  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclGlobalInvoke --  
  *  
  *      Invokes a Tcl command, given an argv/argc, from either the  
  *      exposed or hidden sets of commands in the given interpreter.  
  *      NOTE: The command is invoked in the global stack frame of  
  *      the interpreter, thus it cannot see any current state on  
  *      the stack for that interpreter.  
  *  
  * Results:  
  *      A standard Tcl result.  
  *  
  * Side effects:  
  *      Whatever the command does.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclGlobalInvoke(interp, argc, argv, flags)  
     Tcl_Interp *interp;         /* Where to invoke the command. */  
     int argc;                   /* Count of args. */  
     register char **argv;       /* The arg strings; argv[0] is the name of  
                                  * the command to invoke. */  
     int flags;                  /* Combination of flags controlling the  
                                  * call: TCL_INVOKE_HIDDEN and  
                                  * TCL_INVOKE_NO_UNKNOWN. */  
 {  
     register Interp *iPtr = (Interp *) interp;  
     int result;  
     CallFrame *savedVarFramePtr;  
   
     savedVarFramePtr = iPtr->varFramePtr;  
     iPtr->varFramePtr = NULL;  
     result = TclInvoke(interp, argc, argv, flags);  
     iPtr->varFramePtr = savedVarFramePtr;  
     return result;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclObjInvokeGlobal --  
  *  
  *      Object version: Invokes a Tcl command, given an objv/objc, from  
  *      either the exposed or hidden set of commands in the given  
  *      interpreter.  
  *      NOTE: The command is invoked in the global stack frame of the  
  *      interpreter, thus it cannot see any current state on the  
  *      stack of that interpreter.  
  *  
  * Results:  
  *      A standard Tcl result.  
  *  
  * Side effects:  
  *      Whatever the command does.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclObjInvokeGlobal(interp, objc, objv, flags)  
     Tcl_Interp *interp;         /* Interpreter in which command is to be  
                                  * invoked. */  
     int objc;                   /* Count of arguments. */  
     Tcl_Obj *CONST objv[];      /* Argument objects; objv[0] points to the  
                                  * name of the command to invoke. */  
     int flags;                  /* Combination of flags controlling the  
                                  * call: TCL_INVOKE_HIDDEN,  
                                  * TCL_INVOKE_NO_UNKNOWN, or  
                                  * TCL_INVOKE_NO_TRACEBACK. */  
 {  
     register Interp *iPtr = (Interp *) interp;  
     int result;  
     CallFrame *savedVarFramePtr;  
   
     savedVarFramePtr = iPtr->varFramePtr;  
     iPtr->varFramePtr = NULL;  
     result = TclObjInvoke(interp, objc, objv, flags);  
     iPtr->varFramePtr = savedVarFramePtr;  
     return result;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclObjInvoke --  
  *  
  *      Invokes a Tcl command, given an objv/objc, from either the  
  *      exposed or the hidden sets of commands in the given interpreter.  
  *  
  * Results:  
  *      A standard Tcl object result.  
  *  
  * Side effects:  
  *      Whatever the command does.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclObjInvoke(interp, objc, objv, flags)  
     Tcl_Interp *interp;         /* Interpreter in which command is to be  
                                  * invoked. */  
     int objc;                   /* Count of arguments. */  
     Tcl_Obj *CONST objv[];      /* Argument objects; objv[0] points to the  
                                  * name of the command to invoke. */  
     int flags;                  /* Combination of flags controlling the  
                                  * call: TCL_INVOKE_HIDDEN,  
                                  * TCL_INVOKE_NO_UNKNOWN, or  
                                  * TCL_INVOKE_NO_TRACEBACK. */  
 {  
     register Interp *iPtr = (Interp *) interp;  
     Tcl_HashTable *hTblPtr;     /* Table of hidden commands. */  
     char *cmdName;              /* Name of the command from objv[0]. */  
     register Tcl_HashEntry *hPtr;  
     Tcl_Command cmd;  
     Command *cmdPtr;  
     int localObjc;              /* Used to invoke "unknown" if the */  
     Tcl_Obj **localObjv = NULL; /* command is not found. */  
     register int i;  
     int length, result;  
     char *bytes;  
   
     if (interp == (Tcl_Interp *) NULL) {  
         return TCL_ERROR;  
     }  
   
     if ((objc < 1) || (objv == (Tcl_Obj **) NULL)) {  
         Tcl_AppendToObj(Tcl_GetObjResult(interp),  
                 "illegal argument vector", -1);  
         return TCL_ERROR;  
     }  
   
     cmdName = Tcl_GetString(objv[0]);  
     if (flags & TCL_INVOKE_HIDDEN) {  
         /*  
          * We never invoke "unknown" for hidden commands.  
          */  
           
         hPtr = NULL;  
         hTblPtr = ((Interp *) interp)->hiddenCmdTablePtr;  
         if (hTblPtr != NULL) {  
             hPtr = Tcl_FindHashEntry(hTblPtr, cmdName);  
         }  
         if (hPtr == NULL) {  
             Tcl_ResetResult(interp);  
             Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                      "invalid hidden command name \"", cmdName, "\"",  
                      (char *) NULL);  
             return TCL_ERROR;  
         }  
         cmdPtr = (Command *) Tcl_GetHashValue(hPtr);  
     } else {  
         cmdPtr = NULL;  
         cmd = Tcl_FindCommand(interp, cmdName,  
                 (Tcl_Namespace *) NULL, /*flags*/ TCL_GLOBAL_ONLY);  
         if (cmd != (Tcl_Command) NULL) {  
             cmdPtr = (Command *) cmd;  
         }  
         if (cmdPtr == NULL) {  
             if (!(flags & TCL_INVOKE_NO_UNKNOWN)) {  
                 cmd = Tcl_FindCommand(interp, "unknown",  
                         (Tcl_Namespace *) NULL, /*flags*/ TCL_GLOBAL_ONLY);  
                 if (cmd != (Tcl_Command) NULL) {  
                     cmdPtr = (Command *) cmd;  
                 }  
                 if (cmdPtr != NULL) {  
                     localObjc = (objc + 1);  
                     localObjv = (Tcl_Obj **)  
                         ckalloc((unsigned) (sizeof(Tcl_Obj *) * localObjc));  
                     localObjv[0] = Tcl_NewStringObj("unknown", -1);  
                     Tcl_IncrRefCount(localObjv[0]);  
                     for (i = 0;  i < objc;  i++) {  
                         localObjv[i+1] = objv[i];  
                     }  
                     objc = localObjc;  
                     objv = localObjv;  
                 }  
             }  
   
             /*  
              * Check again if we found the command. If not, "unknown" is  
              * not present and we cannot help, or the caller said not to  
              * call "unknown" (they specified TCL_INVOKE_NO_UNKNOWN).  
              */  
   
             if (cmdPtr == NULL) {  
                 Tcl_ResetResult(interp);  
                 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),  
                         "invalid command name \"",  cmdName, "\"",  
                          (char *) NULL);  
                 return TCL_ERROR;  
             }  
         }  
     }  
   
     /*  
      * Invoke the command procedure. First reset the interpreter's string  
      * and object results to their default empty values since they could  
      * have gotten changed by earlier invocations.  
      */  
   
     Tcl_ResetResult(interp);  
     iPtr->cmdCount++;  
     result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv);  
   
     /*  
      * If an error occurred, record information about what was being  
      * executed when the error occurred.  
      */  
   
     if ((result == TCL_ERROR)  
             && ((flags & TCL_INVOKE_NO_TRACEBACK) == 0)  
             && ((iPtr->flags & ERR_ALREADY_LOGGED) == 0)) {  
         Tcl_DString ds;  
           
         Tcl_DStringInit(&ds);  
         if (!(iPtr->flags & ERR_IN_PROGRESS)) {  
             Tcl_DStringAppend(&ds, "\n    while invoking\n\"", -1);  
         } else {  
             Tcl_DStringAppend(&ds, "\n    invoked from within\n\"", -1);  
         }  
         for (i = 0;  i < objc;  i++) {  
             bytes = Tcl_GetStringFromObj(objv[i], &length);  
             Tcl_DStringAppend(&ds, bytes, length);  
             if (i < (objc - 1)) {  
                 Tcl_DStringAppend(&ds, " ", -1);  
             } else if (Tcl_DStringLength(&ds) > 100) {  
                 Tcl_DStringSetLength(&ds, 100);  
                 Tcl_DStringAppend(&ds, "...", -1);  
                 break;  
             }  
         }  
           
         Tcl_DStringAppend(&ds, "\"", -1);  
         Tcl_AddObjErrorInfo(interp, Tcl_DStringValue(&ds), -1);  
         Tcl_DStringFree(&ds);  
         iPtr->flags &= ~ERR_ALREADY_LOGGED;  
     }  
   
     /*  
      * Free any locally allocated storage used to call "unknown".  
      */  
   
     if (localObjv != (Tcl_Obj **) NULL) {  
         Tcl_DecrRefCount(localObjv[0]);  
         ckfree((char *) localObjv);  
     }  
     return result;  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * Tcl_ExprString --  
  *  
  *      Evaluate an expression in a string and return its value in string  
  *      form.  
  *  
  * Results:  
  *      A standard Tcl result. If the result is TCL_OK, then the interp's  
  *      result is set to the string value of the expression. If the result  
  *      is TCL_ERROR, then the interp's result contains an error message.  
  *  
  * Side effects:  
  *      A Tcl object is allocated to hold a copy of the expression string.  
  *      This expression object is passed to Tcl_ExprObj and then  
  *      deallocated.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 int  
 Tcl_ExprString(interp, string)  
     Tcl_Interp *interp;         /* Context in which to evaluate the  
                                  * expression. */  
     char *string;               /* Expression to evaluate. */  
 {  
     register Tcl_Obj *exprPtr;  
     Tcl_Obj *resultPtr;  
     int length = strlen(string);  
     char buf[TCL_DOUBLE_SPACE];  
     int result = TCL_OK;  
   
     if (length > 0) {  
         TclNewObj(exprPtr);  
         TclInitStringRep(exprPtr, string, length);  
         Tcl_IncrRefCount(exprPtr);  
   
         result = Tcl_ExprObj(interp, exprPtr, &resultPtr);  
         if (result == TCL_OK) {  
             /*  
              * Set the interpreter's string result from the result object.  
              */  
               
             if (resultPtr->typePtr == &tclIntType) {  
                 sprintf(buf, "%ld", resultPtr->internalRep.longValue);  
                 Tcl_SetResult(interp, buf, TCL_VOLATILE);  
             } else if (resultPtr->typePtr == &tclDoubleType) {  
                 Tcl_PrintDouble((Tcl_Interp *) NULL,  
                         resultPtr->internalRep.doubleValue, buf);  
                 Tcl_SetResult(interp, buf, TCL_VOLATILE);  
             } else {  
                 /*  
                  * Set interpreter's string result from the result object.  
                  */  
               
                 Tcl_SetResult(interp, TclGetString(resultPtr),  
                         TCL_VOLATILE);  
             }  
             Tcl_DecrRefCount(resultPtr);  /* discard the result object */  
         } else {  
             /*  
              * Move the interpreter's object result to the string result,  
              * then reset the object result.  
              */  
               
             Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),  
                     TCL_VOLATILE);  
         }  
         Tcl_DecrRefCount(exprPtr); /* discard the expression object */  
     } else {  
         /*  
          * An empty string. Just set the interpreter's result to 0.  
          */  
           
         Tcl_SetResult(interp, "0", TCL_VOLATILE);  
     }  
     return result;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tcl_ExprObj --  
  *  
  *      Evaluate an expression in a Tcl_Obj.  
  *  
  * Results:  
  *      A standard Tcl object result. If the result is other than TCL_OK,  
  *      then the interpreter's result contains an error message. If the  
  *      result is TCL_OK, then a pointer to the expression's result value  
  *      object is stored in resultPtrPtr. In that case, the object's ref  
  *      count is incremented to reflect the reference returned to the  
  *      caller; the caller is then responsible for the resulting object  
  *      and must, for example, decrement the ref count when it is finished  
  *      with the object.  
  *  
  * Side effects:  
  *      Any side effects caused by subcommands in the expression, if any.  
  *      The interpreter result is not modified unless there is an error.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 Tcl_ExprObj(interp, objPtr, resultPtrPtr)  
     Tcl_Interp *interp;         /* Context in which to evaluate the  
                                  * expression. */  
     register Tcl_Obj *objPtr;   /* Points to Tcl object containing  
                                  * expression to evaluate. */  
     Tcl_Obj **resultPtrPtr;     /* Where the Tcl_Obj* that is the expression  
                                  * result is stored if no errors occur. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     CompileEnv compEnv;         /* Compilation environment structure  
                                  * allocated in frame. */  
     LiteralTable *localTablePtr = &(compEnv.localLitTable);  
     register ByteCode *codePtr = NULL;  
                                 /* Tcl Internal type of bytecode.  
                                  * Initialized to avoid compiler warning. */  
     AuxData *auxDataPtr;  
     LiteralEntry *entryPtr;  
     Tcl_Obj *saveObjPtr;  
     char *string;  
     int length, i, result;  
   
     /*  
      * First handle some common expressions specially.  
      */  
   
     string = Tcl_GetStringFromObj(objPtr, &length);  
     if (length == 1) {  
         if (*string == '0') {  
             *resultPtrPtr = Tcl_NewLongObj(0);  
             Tcl_IncrRefCount(*resultPtrPtr);  
             return TCL_OK;  
         } else if (*string == '1') {  
             *resultPtrPtr = Tcl_NewLongObj(1);  
             Tcl_IncrRefCount(*resultPtrPtr);  
             return TCL_OK;  
         }  
     } else if ((length == 2) && (*string == '!')) {  
         if (*(string+1) == '0') {  
             *resultPtrPtr = Tcl_NewLongObj(1);  
             Tcl_IncrRefCount(*resultPtrPtr);  
             return TCL_OK;  
         } else if (*(string+1) == '1') {  
             *resultPtrPtr = Tcl_NewLongObj(0);  
             Tcl_IncrRefCount(*resultPtrPtr);  
             return TCL_OK;  
         }  
     }  
   
     /*  
      * Get the ByteCode from the object. If it exists, make sure it hasn't  
      * been invalidated by, e.g., someone redefining a command with a  
      * compile procedure (this might make the compiled code wrong). If  
      * necessary, convert the object to be a ByteCode object and compile it.  
      * Also, if the code was compiled in/for a different interpreter, we  
      * recompile it.  
      *  
      * Precompiled expressions, however, are immutable and therefore  
      * they are not recompiled, even if the epoch has changed.  
      *  
      */  
   
     if (objPtr->typePtr == &tclByteCodeType) {  
         codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;  
         if (((Interp *) *codePtr->interpHandle != iPtr)  
                 || (codePtr->compileEpoch != iPtr->compileEpoch)) {  
             if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {  
                 if ((Interp *) *codePtr->interpHandle != iPtr) {  
                     panic("Tcl_ExprObj: compiled expression jumped interps");  
                 }  
                 codePtr->compileEpoch = iPtr->compileEpoch;  
             } else {  
                 (*tclByteCodeType.freeIntRepProc)(objPtr);  
                 objPtr->typePtr = (Tcl_ObjType *) NULL;  
             }  
         }  
     }  
     if (objPtr->typePtr != &tclByteCodeType) {  
         TclInitCompileEnv(interp, &compEnv, string, length);  
         result = TclCompileExpr(interp, string, length, &compEnv);  
   
         /*  
          * Free the compilation environment's literal table bucket array if  
          * it was dynamically allocated.  
          */  
   
         if (localTablePtr->buckets != localTablePtr->staticBuckets) {  
             ckfree((char *) localTablePtr->buckets);  
         }  
       
         if (result != TCL_OK) {  
             /*  
              * Compilation errors. Free storage allocated for compilation.  
              */  
   
 #ifdef TCL_COMPILE_DEBUG  
             TclVerifyLocalLiteralTable(&compEnv);  
 #endif /*TCL_COMPILE_DEBUG*/  
             entryPtr = compEnv.literalArrayPtr;  
             for (i = 0;  i < compEnv.literalArrayNext;  i++) {  
                 TclReleaseLiteral(interp, entryPtr->objPtr);  
                 entryPtr++;  
             }  
 #ifdef TCL_COMPILE_DEBUG  
             TclVerifyGlobalLiteralTable(iPtr);  
 #endif /*TCL_COMPILE_DEBUG*/  
       
             auxDataPtr = compEnv.auxDataArrayPtr;  
             for (i = 0;  i < compEnv.auxDataArrayNext;  i++) {  
                 if (auxDataPtr->type->freeProc != NULL) {  
                     auxDataPtr->type->freeProc(auxDataPtr->clientData);  
                 }  
                 auxDataPtr++;  
             }  
             TclFreeCompileEnv(&compEnv);  
             return result;  
         }  
   
         /*  
          * Successful compilation. If the expression yielded no  
          * instructions, push an zero object as the expression's result.  
          */  
               
         if (compEnv.codeNext == compEnv.codeStart) {  
             TclEmitPush(TclRegisterLiteral(&compEnv, "0", 1, /*onHeap*/ 0),  
                     &compEnv);  
         }  
               
         /*  
          * Add a "done" instruction as the last instruction and change the  
          * object into a ByteCode object. Ownership of the literal objects  
          * and aux data items is given to the ByteCode object.  
          */  
   
         compEnv.numSrcBytes = iPtr->termOffset;  
         TclEmitOpcode(INST_DONE, &compEnv);  
         TclInitByteCodeObj(objPtr, &compEnv);  
         TclFreeCompileEnv(&compEnv);  
         codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;  
 #ifdef TCL_COMPILE_DEBUG  
         if (tclTraceCompile == 2) {  
             TclPrintByteCodeObj(interp, objPtr);  
         }  
 #endif /* TCL_COMPILE_DEBUG */  
     }  
   
     /*  
      * Execute the expression after first saving the interpreter's result.  
      */  
       
     saveObjPtr = Tcl_GetObjResult(interp);  
     Tcl_IncrRefCount(saveObjPtr);  
     Tcl_ResetResult(interp);  
   
     /*  
      * Increment the code's ref count while it is being executed. If  
      * afterwards no references to it remain, free the code.  
      */  
       
     codePtr->refCount++;  
     result = TclExecuteByteCode(interp, codePtr);  
     codePtr->refCount--;  
     if (codePtr->refCount <= 0) {  
         TclCleanupByteCode(codePtr);  
         objPtr->typePtr = NULL;  
         objPtr->internalRep.otherValuePtr = NULL;  
     }  
       
     /*  
      * If the expression evaluated successfully, store a pointer to its  
      * value object in resultPtrPtr then restore the old interpreter result.  
      * We increment the object's ref count to reflect the reference that we  
      * are returning to the caller. We also decrement the ref count of the  
      * interpreter's result object after calling Tcl_SetResult since we  
      * next store into that field directly.  
      */  
       
     if (result == TCL_OK) {  
         *resultPtrPtr = iPtr->objResultPtr;  
         Tcl_IncrRefCount(iPtr->objResultPtr);  
           
         Tcl_SetObjResult(interp, saveObjPtr);  
     }  
     Tcl_DecrRefCount(saveObjPtr);  
     return result;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_CreateTrace --  
  *  
  *      Arrange for a procedure to be called to trace command execution.  
  *  
  * Results:  
  *      The return value is a token for the trace, which may be passed  
  *      to Tcl_DeleteTrace to eliminate the trace.  
  *  
  * Side effects:  
  *      From now on, proc will be called just before a command procedure  
  *      is called to execute a Tcl command.  Calls to proc will have the  
  *      following form:  
  *  
  *      void  
  *      proc(clientData, interp, level, command, cmdProc, cmdClientData,  
  *              argc, argv)  
  *          ClientData clientData;  
  *          Tcl_Interp *interp;  
  *          int level;  
  *          char *command;  
  *          int (*cmdProc)();  
  *          ClientData cmdClientData;  
  *          int argc;  
  *          char **argv;  
  *      {  
  *      }  
  *  
  *      The clientData and interp arguments to proc will be the same  
  *      as the corresponding arguments to this procedure.  Level gives  
  *      the nesting level of command interpretation for this interpreter  
  *      (0 corresponds to top level).  Command gives the ASCII text of  
  *      the raw command, cmdProc and cmdClientData give the procedure that  
  *      will be called to process the command and the ClientData value it  
  *      will receive, and argc and argv give the arguments to the  
  *      command, after any argument parsing and substitution.  Proc  
  *      does not return a value.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tcl_Trace  
 Tcl_CreateTrace(interp, level, proc, clientData)  
     Tcl_Interp *interp;         /* Interpreter in which to create trace. */  
     int level;                  /* Only call proc for commands at nesting  
                                  * level<=argument level (1=>top level). */  
     Tcl_CmdTraceProc *proc;     /* Procedure to call before executing each  
                                  * command. */  
     ClientData clientData;      /* Arbitrary value word to pass to proc. */  
 {  
     register Trace *tracePtr;  
     register Interp *iPtr = (Interp *) interp;  
   
     /*  
      * Invalidate existing compiled code for this interpreter and arrange  
      * (by setting the DONT_COMPILE_CMDS_INLINE flag) that when compiling  
      * new code, no commands will be compiled inline (i.e., into an inline  
      * sequence of instructions). We do this because commands that were  
      * compiled inline will never result in a command trace being called.  
      */  
   
     iPtr->compileEpoch++;  
     iPtr->flags |= DONT_COMPILE_CMDS_INLINE;  
   
     tracePtr = (Trace *) ckalloc(sizeof(Trace));  
     tracePtr->level = level;  
     tracePtr->proc = proc;  
     tracePtr->clientData = clientData;  
     tracePtr->nextPtr = iPtr->tracePtr;  
     iPtr->tracePtr = tracePtr;  
   
     return (Tcl_Trace) tracePtr;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_DeleteTrace --  
  *  
  *      Remove a trace.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      From now on there will be no more calls to the procedure given  
  *      in trace.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tcl_DeleteTrace(interp, trace)  
     Tcl_Interp *interp;         /* Interpreter that contains trace. */  
     Tcl_Trace trace;            /* Token for trace (returned previously by  
                                  * Tcl_CreateTrace). */  
 {  
     register Interp *iPtr = (Interp *) interp;  
     register Trace *tracePtr = (Trace *) trace;  
     register Trace *tracePtr2;  
   
     if (iPtr->tracePtr == tracePtr) {  
         iPtr->tracePtr = tracePtr->nextPtr;  
         ckfree((char *) tracePtr);  
     } else {  
         for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;  
                 tracePtr2 = tracePtr2->nextPtr) {  
             if (tracePtr2->nextPtr == tracePtr) {  
                 tracePtr2->nextPtr = tracePtr->nextPtr;  
                 ckfree((char *) tracePtr);  
                 break;  
             }  
         }  
     }  
   
     if (iPtr->tracePtr == NULL) {  
         /*  
          * When compiling new code, allow commands to be compiled inline.  
          */  
   
         iPtr->flags &= ~DONT_COMPILE_CMDS_INLINE;  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_AddErrorInfo --  
  *  
  *      Add information to the "errorInfo" variable that describes the  
  *      current error.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The contents of message are added to the "errorInfo" variable.  
  *      If Tcl_Eval has been called since the current value of errorInfo  
  *      was set, errorInfo is cleared before adding the new message.  
  *      If we are just starting to log an error, errorInfo is initialized  
  *      from the error message in the interpreter's result.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tcl_AddErrorInfo(interp, message)  
     Tcl_Interp *interp;         /* Interpreter to which error information  
                                  * pertains. */  
     CONST char *message;        /* Message to record. */  
 {  
     Tcl_AddObjErrorInfo(interp, message, -1);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_AddObjErrorInfo --  
  *  
  *      Add information to the "errorInfo" variable that describes the  
  *      current error. This routine differs from Tcl_AddErrorInfo by  
  *      taking a byte pointer and length.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      "length" bytes from "message" are added to the "errorInfo" variable.  
  *      If "length" is negative, use bytes up to the first NULL byte.  
  *      If Tcl_EvalObj has been called since the current value of errorInfo  
  *      was set, errorInfo is cleared before adding the new message.  
  *      If we are just starting to log an error, errorInfo is initialized  
  *      from the error message in the interpreter's result.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tcl_AddObjErrorInfo(interp, message, length)  
     Tcl_Interp *interp;         /* Interpreter to which error information  
                                  * pertains. */  
     CONST char *message;        /* Points to the first byte of an array of  
                                  * bytes of the message. */  
     int length;                 /* The number of bytes in the message.  
                                  * If < 0, then append all bytes up to a  
                                  * NULL byte. */  
 {  
     register Interp *iPtr = (Interp *) interp;  
     Tcl_Obj *messagePtr;  
       
     /*  
      * If we are just starting to log an error, errorInfo is initialized  
      * from the error message in the interpreter's result.  
      */  
   
     if (!(iPtr->flags & ERR_IN_PROGRESS)) { /* just starting to log error */  
         iPtr->flags |= ERR_IN_PROGRESS;  
   
         if (iPtr->result[0] == 0) {  
             (void) Tcl_SetVar2Ex(interp, "errorInfo", NULL, iPtr->objResultPtr,  
                     TCL_GLOBAL_ONLY);  
         } else {                /* use the string result */  
             Tcl_SetVar2(interp, "errorInfo", (char *) NULL, interp->result,  
                     TCL_GLOBAL_ONLY);  
         }  
   
         /*  
          * If the errorCode variable wasn't set by the code that generated  
          * the error, set it to "NONE".  
          */  
   
         if (!(iPtr->flags & ERROR_CODE_SET)) {  
             (void) Tcl_SetVar2(interp, "errorCode", (char *) NULL, "NONE",  
                     TCL_GLOBAL_ONLY);  
         }  
     }  
   
     /*  
      * Now append "message" to the end of errorInfo.  
      */  
   
     if (length != 0) {  
         messagePtr = Tcl_NewStringObj(message, length);  
         Tcl_IncrRefCount(messagePtr);  
         Tcl_SetVar2Ex(interp, "errorInfo", NULL, messagePtr,  
                 (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE));  
         Tcl_DecrRefCount(messagePtr); /* free msg object appended above */  
     }  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * Tcl_VarEvalVA --  
  *  
  *      Given a variable number of string arguments, concatenate them  
  *      all together and execute the result as a Tcl command.  
  *  
  * Results:  
  *      A standard Tcl return result.  An error message or other result may  
  *      be left in the interp's result.  
  *  
  * Side effects:  
  *      Depends on what was done by the command.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 int  
 Tcl_VarEvalVA (interp, argList)  
     Tcl_Interp *interp;         /* Interpreter in which to evaluate command. */  
     va_list argList;            /* Variable argument list. */  
 {  
     Tcl_DString buf;  
     char *string;  
     int result;  
   
     /*  
      * Copy the strings one after the other into a single larger  
      * string.  Use stack-allocated space for small commands, but if  
      * the command gets too large than call ckalloc to create the  
      * space.  
      */  
   
     Tcl_DStringInit(&buf);  
     while (1) {  
         string = va_arg(argList, char *);  
         if (string == NULL) {  
             break;  
         }  
         Tcl_DStringAppend(&buf, string, -1);  
     }  
   
     result = Tcl_Eval(interp, Tcl_DStringValue(&buf));  
     Tcl_DStringFree(&buf);  
     return result;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_VarEval --  
  *  
  *      Given a variable number of string arguments, concatenate them  
  *      all together and execute the result as a Tcl command.  
  *  
  * Results:  
  *      A standard Tcl return result.  An error message or other  
  *      result may be left in interp->result.  
  *  
  * Side effects:  
  *      Depends on what was done by the command.  
  *  
  *----------------------------------------------------------------------  
  */  
         /* VARARGS2 */ /* ARGSUSED */  
 int  
 Tcl_VarEval TCL_VARARGS_DEF(Tcl_Interp *,arg1)  
 {  
     Tcl_Interp *interp;  
     va_list argList;  
     int result;  
   
     interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList);  
     result = Tcl_VarEvalVA(interp, argList);  
     va_end(argList);  
   
     return result;  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * Tcl_GlobalEval --  
  *  
  *      Evaluate a command at global level in an interpreter.  
  *  
  * Results:  
  *      A standard Tcl result is returned, and the interp's result is  
  *      modified accordingly.  
  *  
  * Side effects:  
  *      The command string is executed in interp, and the execution  
  *      is carried out in the variable context of global level (no  
  *      procedures active), just as if an "uplevel #0" command were  
  *      being executed.  
  *  
  ---------------------------------------------------------------------------  
  */  
   
 int  
 Tcl_GlobalEval(interp, command)  
     Tcl_Interp *interp;         /* Interpreter in which to evaluate command. */  
     char *command;              /* Command to evaluate. */  
 {  
     register Interp *iPtr = (Interp *) interp;  
     int result;  
     CallFrame *savedVarFramePtr;  
   
     savedVarFramePtr = iPtr->varFramePtr;  
     iPtr->varFramePtr = NULL;  
     result = Tcl_Eval(interp, command);  
     iPtr->varFramePtr = savedVarFramePtr;  
     return result;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_SetRecursionLimit --  
  *  
  *      Set the maximum number of recursive calls that may be active  
  *      for an interpreter at once.  
  *  
  * Results:  
  *      The return value is the old limit on nesting for interp.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tcl_SetRecursionLimit(interp, depth)  
     Tcl_Interp *interp;                 /* Interpreter whose nesting limit  
                                          * is to be set. */  
     int depth;                          /* New value for maximimum depth. */  
 {  
     Interp *iPtr = (Interp *) interp;  
     int old;  
   
     old = iPtr->maxNestingDepth;  
     if (depth > 0) {  
         iPtr->maxNestingDepth = depth;  
     }  
     return old;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_AllowExceptions --  
  *  
  *      Sets a flag in an interpreter so that exceptions can occur  
  *      in the next call to Tcl_Eval without them being turned into  
  *      errors.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The TCL_ALLOW_EXCEPTIONS flag gets set in the interpreter's  
  *      evalFlags structure.  See the reference documentation for  
  *      more details.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tcl_AllowExceptions(interp)  
     Tcl_Interp *interp;         /* Interpreter in which to set flag. */  
 {  
     Interp *iPtr = (Interp *) interp;  
   
     iPtr->evalFlags |= TCL_ALLOW_EXCEPTIONS;  
 }  
   
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_GetVersion  
  *  
  *      Get the Tcl major, minor, and patchlevel version numbers and  
  *      the release type.  A patch is a release type TCL_FINAL_RELEASE  
  *      with a patchLevel > 0.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void Tcl_GetVersion(majorV, minorV, patchLevelV, type)  
     int *majorV;  
     int *minorV;  
     int *patchLevelV;  
     int *type;  
 {  
     if (majorV != NULL) {  
         *majorV = TCL_MAJOR_VERSION;  
     }  
     if (minorV != NULL) {  
         *minorV = TCL_MINOR_VERSION;  
     }  
     if (patchLevelV != NULL) {  
         *patchLevelV = TCL_RELEASE_SERIAL;  
     }  
     if (type != NULL) {  
         *type = TCL_RELEASE_LEVEL;  
     }  
 }  
   
   
 /* $History: tclbasic.c $  
  *  
  * *****************  Version 1  *****************  
  * User: Dtashley     Date: 1/02/01    Time: 1:34a  
  * Created in $/IjuScripter, IjuConsole/Source/Tcl Base  
  * Initial check-in.  
  */  
   
 /* End of TCLBASIC.C */  
1    /* $Header$ */
2    /*
3     * tclBasic.c --
4     *
5     *      Contains the basic facilities for TCL command interpretation,
6     *      including interpreter creation and deletion, command creation
7     *      and deletion, and command parsing and execution.
8     *
9     * Copyright (c) 1987-1994 The Regents of the University of California.
10     * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11     * Copyright (c) 1998-1999 by Scriptics Corporation.
12     *
13     * See the file "license.terms" for information on usage and redistribution
14     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15     *
16     * RCS: @(#) $Id: tclbasic.c,v 1.1.1.1 2001/06/13 04:33:43 dtashley Exp $
17     */
18    
19    #include "tclInt.h"
20    #include "tclCompile.h"
21    #ifndef TCL_GENERIC_ONLY
22    #   include "tclPort.h"
23    #endif
24    
25    /*
26     * Static procedures in this file:
27     */
28    
29    static void             DeleteInterpProc _ANSI_ARGS_((Tcl_Interp *interp));
30    static void             ProcessUnexpectedResult _ANSI_ARGS_((
31                                Tcl_Interp *interp, int returnCode));
32    static void             RecordTracebackInfo _ANSI_ARGS_((
33                                Tcl_Interp *interp, Tcl_Obj *objPtr,
34                                int numSrcBytes));
35    
36    extern TclStubs tclStubs;
37    
38    /*
39     * The following structure defines the commands in the Tcl core.
40     */
41    
42    typedef struct {
43        char *name;                 /* Name of object-based command. */
44        Tcl_CmdProc *proc;          /* String-based procedure for command. */
45        Tcl_ObjCmdProc *objProc;    /* Object-based procedure for command. */
46        CompileProc *compileProc;   /* Procedure called to compile command. */
47        int isSafe;                 /* If non-zero, command will be present
48                                     * in safe interpreter. Otherwise it will
49                                     * be hidden. */
50    } CmdInfo;
51    
52    /*
53     * The built-in commands, and the procedures that implement them:
54     */
55    
56    static CmdInfo builtInCmds[] = {
57        /*
58         * Commands in the generic core. Note that at least one of the proc or
59         * objProc members should be non-NULL. This avoids infinitely recursive
60         * calls between TclInvokeObjectCommand and TclInvokeStringCommand if a
61         * command name is computed at runtime and results in the name of a
62         * compiled command.
63         */
64    
65        {"append",          (Tcl_CmdProc *) NULL,   Tcl_AppendObjCmd,
66            (CompileProc *) NULL,           1},
67        {"array",           (Tcl_CmdProc *) NULL,   Tcl_ArrayObjCmd,
68            (CompileProc *) NULL,           1},
69        {"binary",          (Tcl_CmdProc *) NULL,   Tcl_BinaryObjCmd,
70            (CompileProc *) NULL,           1},
71        {"break",           (Tcl_CmdProc *) NULL,   Tcl_BreakObjCmd,
72            TclCompileBreakCmd,             1},
73        {"case",            (Tcl_CmdProc *) NULL,   Tcl_CaseObjCmd,
74            (CompileProc *) NULL,           1},
75        {"catch",           (Tcl_CmdProc *) NULL,   Tcl_CatchObjCmd,        
76            TclCompileCatchCmd,             1},
77        {"clock",           (Tcl_CmdProc *) NULL,   Tcl_ClockObjCmd,
78            (CompileProc *) NULL,           1},
79        {"concat",          (Tcl_CmdProc *) NULL,   Tcl_ConcatObjCmd,
80            (CompileProc *) NULL,           1},
81        {"continue",        (Tcl_CmdProc *) NULL,   Tcl_ContinueObjCmd,
82            TclCompileContinueCmd,          1},
83        {"encoding",        (Tcl_CmdProc *) NULL,   Tcl_EncodingObjCmd,
84            (CompileProc *) NULL,           0},
85        {"error",           (Tcl_CmdProc *) NULL,   Tcl_ErrorObjCmd,
86            (CompileProc *) NULL,           1},
87        {"eval",            (Tcl_CmdProc *) NULL,   Tcl_EvalObjCmd,
88            (CompileProc *) NULL,           1},
89        {"exit",            (Tcl_CmdProc *) NULL,   Tcl_ExitObjCmd,
90            (CompileProc *) NULL,           0},
91        {"expr",            (Tcl_CmdProc *) NULL,   Tcl_ExprObjCmd,
92            TclCompileExprCmd,              1},
93        {"fcopy",           (Tcl_CmdProc *) NULL,   Tcl_FcopyObjCmd,
94            (CompileProc *) NULL,           1},
95        {"fileevent",       (Tcl_CmdProc *) NULL,   Tcl_FileEventObjCmd,
96            (CompileProc *) NULL,           1},
97        {"for",             (Tcl_CmdProc *) NULL,   Tcl_ForObjCmd,
98            TclCompileForCmd,               1},
99        {"foreach",         (Tcl_CmdProc *) NULL,   Tcl_ForeachObjCmd,
100            TclCompileForeachCmd,           1},
101        {"format",          (Tcl_CmdProc *) NULL,   Tcl_FormatObjCmd,
102            (CompileProc *) NULL,           1},
103        {"global",          (Tcl_CmdProc *) NULL,   Tcl_GlobalObjCmd,
104            (CompileProc *) NULL,           1},
105        {"if",              (Tcl_CmdProc *) NULL,   Tcl_IfObjCmd,
106            TclCompileIfCmd,                1},
107        {"incr",            (Tcl_CmdProc *) NULL,   Tcl_IncrObjCmd,
108            TclCompileIncrCmd,              1},
109        {"info",            (Tcl_CmdProc *) NULL,   Tcl_InfoObjCmd,
110            (CompileProc *) NULL,           1},
111        {"join",            (Tcl_CmdProc *) NULL,   Tcl_JoinObjCmd,
112            (CompileProc *) NULL,           1},
113        {"lappend",         (Tcl_CmdProc *) NULL,   Tcl_LappendObjCmd,
114            (CompileProc *) NULL,           1},
115        {"lindex",          (Tcl_CmdProc *) NULL,   Tcl_LindexObjCmd,
116            (CompileProc *) NULL,           1},
117        {"linsert",         (Tcl_CmdProc *) NULL,   Tcl_LinsertObjCmd,
118            (CompileProc *) NULL,           1},
119        {"list",            (Tcl_CmdProc *) NULL,   Tcl_ListObjCmd,
120            (CompileProc *) NULL,           1},
121        {"llength",         (Tcl_CmdProc *) NULL,   Tcl_LlengthObjCmd,
122            (CompileProc *) NULL,           1},
123        {"load",            (Tcl_CmdProc *) NULL,   Tcl_LoadObjCmd,
124            (CompileProc *) NULL,           0},
125        {"lrange",          (Tcl_CmdProc *) NULL,   Tcl_LrangeObjCmd,
126            (CompileProc *) NULL,           1},
127        {"lreplace",        (Tcl_CmdProc *) NULL,   Tcl_LreplaceObjCmd,
128            (CompileProc *) NULL,           1},
129        {"lsearch",         (Tcl_CmdProc *) NULL,   Tcl_LsearchObjCmd,
130            (CompileProc *) NULL,           1},
131        {"lsort",           (Tcl_CmdProc *) NULL,   Tcl_LsortObjCmd,
132            (CompileProc *) NULL,           1},
133        {"namespace",       (Tcl_CmdProc *) NULL,   Tcl_NamespaceObjCmd,
134            (CompileProc *) NULL,           1},
135        {"package",         (Tcl_CmdProc *) NULL,   Tcl_PackageObjCmd,
136            (CompileProc *) NULL,           1},
137        {"proc",            (Tcl_CmdProc *) NULL,   Tcl_ProcObjCmd,
138            (CompileProc *) NULL,           1},
139        {"regexp",          (Tcl_CmdProc *) NULL,   Tcl_RegexpObjCmd,
140            (CompileProc *) NULL,           1},
141        {"regsub",          (Tcl_CmdProc *) NULL,   Tcl_RegsubObjCmd,
142            (CompileProc *) NULL,           1},
143        {"rename",          (Tcl_CmdProc *) NULL,   Tcl_RenameObjCmd,
144            (CompileProc *) NULL,           1},
145        {"return",          (Tcl_CmdProc *) NULL,   Tcl_ReturnObjCmd,      
146            (CompileProc *) NULL,           1},
147        {"scan",            (Tcl_CmdProc *) NULL,   Tcl_ScanObjCmd,
148            (CompileProc *) NULL,           1},
149        {"set",             (Tcl_CmdProc *) NULL,   Tcl_SetObjCmd,
150            TclCompileSetCmd,               1},
151        {"split",           (Tcl_CmdProc *) NULL,   Tcl_SplitObjCmd,
152            (CompileProc *) NULL,           1},
153        {"string",          (Tcl_CmdProc *) NULL,   Tcl_StringObjCmd,
154            (CompileProc *) NULL,           1},
155        {"subst",           (Tcl_CmdProc *) NULL,   Tcl_SubstObjCmd,
156            (CompileProc *) NULL,           1},
157        {"switch",          (Tcl_CmdProc *) NULL,   Tcl_SwitchObjCmd,      
158            (CompileProc *) NULL,           1},
159        {"trace",           (Tcl_CmdProc *) NULL,   Tcl_TraceObjCmd,
160            (CompileProc *) NULL,           1},
161        {"unset",           (Tcl_CmdProc *) NULL,   Tcl_UnsetObjCmd,        
162            (CompileProc *) NULL,           1},
163        {"uplevel",         (Tcl_CmdProc *) NULL,   Tcl_UplevelObjCmd,      
164            (CompileProc *) NULL,           1},
165        {"upvar",           (Tcl_CmdProc *) NULL,   Tcl_UpvarObjCmd,        
166            (CompileProc *) NULL,           1},
167        {"variable",        (Tcl_CmdProc *) NULL,   Tcl_VariableObjCmd,
168            (CompileProc *) NULL,           1},
169        {"while",           (Tcl_CmdProc *) NULL,   Tcl_WhileObjCmd,
170            TclCompileWhileCmd,             1},
171    
172        /*
173         * Commands in the UNIX core:
174         */
175    
176    #ifndef TCL_GENERIC_ONLY
177        {"after",           (Tcl_CmdProc *) NULL,   Tcl_AfterObjCmd,
178            (CompileProc *) NULL,           1},
179        {"cd",              (Tcl_CmdProc *) NULL,   Tcl_CdObjCmd,
180            (CompileProc *) NULL,           0},
181        {"close",           (Tcl_CmdProc *) NULL,   Tcl_CloseObjCmd,
182            (CompileProc *) NULL,           1},
183        {"eof",             (Tcl_CmdProc *) NULL,   Tcl_EofObjCmd,
184            (CompileProc *) NULL,           1},
185        {"fblocked",        (Tcl_CmdProc *) NULL,   Tcl_FblockedObjCmd,
186            (CompileProc *) NULL,           1},
187        {"fconfigure",      (Tcl_CmdProc *) NULL,   Tcl_FconfigureObjCmd,
188            (CompileProc *) NULL,           0},
189        {"file",            (Tcl_CmdProc *) NULL,   Tcl_FileObjCmd,
190            (CompileProc *) NULL,           0},
191        {"flush",           (Tcl_CmdProc *) NULL,   Tcl_FlushObjCmd,
192            (CompileProc *) NULL,           1},
193        {"gets",            (Tcl_CmdProc *) NULL,   Tcl_GetsObjCmd,
194            (CompileProc *) NULL,           1},
195        {"glob",            (Tcl_CmdProc *) NULL,   Tcl_GlobObjCmd,
196            (CompileProc *) NULL,           0},
197        {"open",            (Tcl_CmdProc *) NULL,   Tcl_OpenObjCmd,
198            (CompileProc *) NULL,           0},
199        {"pid",             (Tcl_CmdProc *) NULL,   Tcl_PidObjCmd,
200            (CompileProc *) NULL,           1},
201        {"puts",            (Tcl_CmdProc *) NULL,   Tcl_PutsObjCmd,
202            (CompileProc *) NULL,           1},
203        {"pwd",             (Tcl_CmdProc *) NULL,   Tcl_PwdObjCmd,
204            (CompileProc *) NULL,           0},
205        {"read",            (Tcl_CmdProc *) NULL,   Tcl_ReadObjCmd,
206            (CompileProc *) NULL,           1},
207        {"seek",            (Tcl_CmdProc *) NULL,   Tcl_SeekObjCmd,
208            (CompileProc *) NULL,           1},
209        {"socket",          (Tcl_CmdProc *) NULL,   Tcl_SocketObjCmd,
210            (CompileProc *) NULL,           0},
211        {"tell",            (Tcl_CmdProc *) NULL,   Tcl_TellObjCmd,
212            (CompileProc *) NULL,           1},
213        {"time",            (Tcl_CmdProc *) NULL,   Tcl_TimeObjCmd,
214            (CompileProc *) NULL,           1},
215        {"update",          (Tcl_CmdProc *) NULL,   Tcl_UpdateObjCmd,
216            (CompileProc *) NULL,           1},
217        {"vwait",           (Tcl_CmdProc *) NULL,   Tcl_VwaitObjCmd,
218            (CompileProc *) NULL,           1},
219        
220    #ifdef MAC_TCL
221        {"beep",            (Tcl_CmdProc *) NULL,   Tcl_BeepObjCmd,
222            (CompileProc *) NULL,           0},
223        {"echo",            Tcl_EchoCmd,            (Tcl_ObjCmdProc *) NULL,
224            (CompileProc *) NULL,           0},
225        {"ls",              (Tcl_CmdProc *) NULL,   Tcl_LsObjCmd,
226            (CompileProc *) NULL,           0},
227        {"resource",        (Tcl_CmdProc *) NULL,   Tcl_ResourceObjCmd,
228            (CompileProc *) NULL,           1},
229        {"source",          (Tcl_CmdProc *) NULL,   Tcl_MacSourceObjCmd,
230            (CompileProc *) NULL,           0},
231    #else
232        {"exec",            (Tcl_CmdProc *) NULL,   Tcl_ExecObjCmd,
233            (CompileProc *) NULL,           0},
234        {"source",          (Tcl_CmdProc *) NULL,   Tcl_SourceObjCmd,
235            (CompileProc *) NULL,           0},
236    #endif /* MAC_TCL */
237        
238    #endif /* TCL_GENERIC_ONLY */
239        {NULL,              (Tcl_CmdProc *) NULL,   (Tcl_ObjCmdProc *) NULL,
240            (CompileProc *) NULL,           0}
241    };
242    
243    
244    /*
245     *----------------------------------------------------------------------
246     *
247     * Tcl_CreateInterp --
248     *
249     *      Create a new TCL command interpreter.
250     *
251     * Results:
252     *      The return value is a token for the interpreter, which may be
253     *      used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
254     *      Tcl_DeleteInterp.
255     *
256     * Side effects:
257     *      The command interpreter is initialized with an empty variable
258     *      table and the built-in commands.
259     *
260     *----------------------------------------------------------------------
261     */
262    
263    Tcl_Interp *
264    Tcl_CreateInterp()
265    {
266        Interp *iPtr;
267        Tcl_Interp *interp;
268        Command *cmdPtr;
269        BuiltinFunc *builtinFuncPtr;
270        MathFunc *mathFuncPtr;
271        Tcl_HashEntry *hPtr;
272        CmdInfo *cmdInfoPtr;
273        int i;
274        union {
275            char c[sizeof(short)];
276            short s;
277        } order;
278    #ifdef TCL_COMPILE_STATS
279        ByteCodeStats *statsPtr;
280    #endif /* TCL_COMPILE_STATS */
281    
282        TclInitSubsystems(NULL);
283    
284        /*
285         * Panic if someone updated the CallFrame structure without
286         * also updating the Tcl_CallFrame structure (or vice versa).
287         */  
288    
289        if (sizeof(Tcl_CallFrame) != sizeof(CallFrame)) {
290            /*NOTREACHED*/
291            panic("Tcl_CallFrame and CallFrame are not the same size");
292        }
293    
294        /*
295         * Initialize support for namespaces and create the global namespace
296         * (whose name is ""; an alias is "::"). This also initializes the
297         * Tcl object type table and other object management code.
298         */
299    
300        iPtr = (Interp *) ckalloc(sizeof(Interp));
301        interp = (Tcl_Interp *) iPtr;
302    
303        iPtr->result                = iPtr->resultSpace;
304        iPtr->freeProc              = NULL;
305        iPtr->errorLine             = 0;
306        iPtr->objResultPtr          = Tcl_NewObj();
307        Tcl_IncrRefCount(iPtr->objResultPtr);
308        iPtr->handle                = TclHandleCreate(iPtr);
309        iPtr->globalNsPtr           = NULL;
310        iPtr->hiddenCmdTablePtr     = NULL;
311        iPtr->interpInfo            = NULL;
312        Tcl_InitHashTable(&iPtr->mathFuncTable, TCL_STRING_KEYS);
313    
314        iPtr->numLevels = 0;
315        iPtr->maxNestingDepth = 1000;
316        iPtr->framePtr = NULL;
317        iPtr->varFramePtr = NULL;
318        iPtr->activeTracePtr = NULL;
319        iPtr->returnCode = TCL_OK;
320        iPtr->errorInfo = NULL;
321        iPtr->errorCode = NULL;
322    
323        iPtr->appendResult = NULL;
324        iPtr->appendAvl = 0;
325        iPtr->appendUsed = 0;
326    
327        Tcl_InitHashTable(&iPtr->packageTable, TCL_STRING_KEYS);
328        iPtr->packageUnknown = NULL;
329        iPtr->cmdCount = 0;
330        iPtr->termOffset = 0;
331        TclInitLiteralTable(&(iPtr->literalTable));
332        iPtr->compileEpoch = 0;
333        iPtr->compiledProcPtr = NULL;
334        iPtr->resolverPtr = NULL;
335        iPtr->evalFlags = 0;
336        iPtr->scriptFile = NULL;
337        iPtr->flags = 0;
338        iPtr->tracePtr = NULL;
339        iPtr->assocData = (Tcl_HashTable *) NULL;
340        iPtr->execEnvPtr = NULL;          /* set after namespaces initialized */
341        iPtr->emptyObjPtr = Tcl_NewObj(); /* another empty object */
342        Tcl_IncrRefCount(iPtr->emptyObjPtr);
343        iPtr->resultSpace[0] = 0;
344    
345        iPtr->globalNsPtr = NULL;   /* force creation of global ns below */
346        iPtr->globalNsPtr = (Namespace *) Tcl_CreateNamespace(interp, "",
347                (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL);
348        if (iPtr->globalNsPtr == NULL) {
349            panic("Tcl_CreateInterp: can't create global namespace");
350        }
351    
352        /*
353         * Initialize support for code compilation and execution. We call
354         * TclCreateExecEnv after initializing namespaces since it tries to
355         * reference a Tcl variable (it links to the Tcl "tcl_traceExec"
356         * variable).
357         */
358    
359        iPtr->execEnvPtr = TclCreateExecEnv(interp);
360    
361        /*
362         * Initialize the compilation and execution statistics kept for this
363         * interpreter.
364         */
365    
366    #ifdef TCL_COMPILE_STATS
367        statsPtr = &(iPtr->stats);
368        statsPtr->numExecutions = 0;
369        statsPtr->numCompilations = 0;
370        statsPtr->numByteCodesFreed = 0;
371        (VOID *) memset(statsPtr->instructionCount, 0,
372                sizeof(statsPtr->instructionCount));
373    
374        statsPtr->totalSrcBytes = 0.0;
375        statsPtr->totalByteCodeBytes = 0.0;
376        statsPtr->currentSrcBytes = 0.0;
377        statsPtr->currentByteCodeBytes = 0.0;
378        (VOID *) memset(statsPtr->srcCount, 0, sizeof(statsPtr->srcCount));
379        (VOID *) memset(statsPtr->byteCodeCount, 0,
380                sizeof(statsPtr->byteCodeCount));
381        (VOID *) memset(statsPtr->lifetimeCount, 0,
382                sizeof(statsPtr->lifetimeCount));
383        
384        statsPtr->currentInstBytes   = 0.0;
385        statsPtr->currentLitBytes    = 0.0;
386        statsPtr->currentExceptBytes = 0.0;
387        statsPtr->currentAuxBytes    = 0.0;
388        statsPtr->currentCmdMapBytes = 0.0;
389        
390        statsPtr->numLiteralsCreated    = 0;
391        statsPtr->totalLitStringBytes   = 0.0;
392        statsPtr->currentLitStringBytes = 0.0;
393        (VOID *) memset(statsPtr->literalCount, 0,
394                sizeof(statsPtr->literalCount));
395    #endif /* TCL_COMPILE_STATS */    
396    
397        /*
398         * Initialise the stub table pointer.
399         */
400    
401        iPtr->stubTable = &tclStubs;
402    
403        
404        /*
405         * Create the core commands. Do it here, rather than calling
406         * Tcl_CreateCommand, because it's faster (there's no need to check for
407         * a pre-existing command by the same name). If a command has a
408         * Tcl_CmdProc but no Tcl_ObjCmdProc, set the Tcl_ObjCmdProc to
409         * TclInvokeStringCommand. This is an object-based wrapper procedure
410         * that extracts strings, calls the string procedure, and creates an
411         * object for the result. Similarly, if a command has a Tcl_ObjCmdProc
412         * but no Tcl_CmdProc, set the Tcl_CmdProc to TclInvokeObjectCommand.
413         */
414    
415        for (cmdInfoPtr = builtInCmds;  cmdInfoPtr->name != NULL;
416                cmdInfoPtr++) {
417            int new;
418            Tcl_HashEntry *hPtr;
419    
420            if ((cmdInfoPtr->proc == (Tcl_CmdProc *) NULL)
421                    && (cmdInfoPtr->objProc == (Tcl_ObjCmdProc *) NULL)
422                    && (cmdInfoPtr->compileProc == (CompileProc *) NULL)) {
423                panic("Tcl_CreateInterp: builtin command with NULL string and object command procs and a NULL compile proc\n");
424            }
425            
426            hPtr = Tcl_CreateHashEntry(&iPtr->globalNsPtr->cmdTable,
427                    cmdInfoPtr->name, &new);
428            if (new) {
429                cmdPtr = (Command *) ckalloc(sizeof(Command));
430                cmdPtr->hPtr = hPtr;
431                cmdPtr->nsPtr = iPtr->globalNsPtr;
432                cmdPtr->refCount = 1;
433                cmdPtr->cmdEpoch = 0;
434                cmdPtr->compileProc = cmdInfoPtr->compileProc;
435                if (cmdInfoPtr->proc == (Tcl_CmdProc *) NULL) {
436                    cmdPtr->proc = TclInvokeObjectCommand;
437                    cmdPtr->clientData = (ClientData) cmdPtr;
438                } else {
439                    cmdPtr->proc = cmdInfoPtr->proc;
440                    cmdPtr->clientData = (ClientData) NULL;
441                }
442                if (cmdInfoPtr->objProc == (Tcl_ObjCmdProc *) NULL) {
443                    cmdPtr->objProc = TclInvokeStringCommand;
444                    cmdPtr->objClientData = (ClientData) cmdPtr;
445                } else {
446                    cmdPtr->objProc = cmdInfoPtr->objProc;
447                    cmdPtr->objClientData = (ClientData) NULL;
448                }
449                cmdPtr->deleteProc = NULL;
450                cmdPtr->deleteData = (ClientData) NULL;
451                cmdPtr->deleted = 0;
452                cmdPtr->importRefPtr = NULL;
453                Tcl_SetHashValue(hPtr, cmdPtr);
454            }
455        }
456    
457        /*
458         * Register the builtin math functions.
459         */
460    
461        i = 0;
462        for (builtinFuncPtr = builtinFuncTable;  builtinFuncPtr->name != NULL;
463                builtinFuncPtr++) {
464            Tcl_CreateMathFunc((Tcl_Interp *) iPtr, builtinFuncPtr->name,
465                    builtinFuncPtr->numArgs, builtinFuncPtr->argTypes,
466                    (Tcl_MathProc *) NULL, (ClientData) 0);
467            hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable,
468                    builtinFuncPtr->name);
469            if (hPtr == NULL) {
470                panic("Tcl_CreateInterp: Tcl_CreateMathFunc incorrectly registered '%s'", builtinFuncPtr->name);
471                return NULL;
472            }
473            mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
474            mathFuncPtr->builtinFuncIndex = i;
475            i++;
476        }
477        iPtr->flags |= EXPR_INITIALIZED;
478    
479        /*
480         * Do Multiple/Safe Interps Tcl init stuff
481         */
482    
483        TclInterpInit(interp);
484    
485        /*
486         * We used to create the "errorInfo" and "errorCode" global vars at this
487         * point because so much of the Tcl implementation assumes they already
488         * exist. This is not quite enough, however, since they can be unset
489         * at any time.
490         *
491         * There are 2 choices:
492         *    + Check every place where a GetVar of those is used
493         *      and the NULL result is not checked (like in tclLoad.c)
494         *    + Make SetVar,... NULL friendly
495         * We choose the second option because :
496         *    + It is easy and low cost to check for NULL pointer before
497         *      calling strlen()
498         *    + It can be helpfull to other people using those API
499         *    + Passing a NULL value to those closest 'meaning' is empty string
500         *      (specially with the new objects where 0 bytes strings are ok)
501         * So the following init is commented out:              -- dl
502         *
503         * (void) Tcl_SetVar2((Tcl_Interp *)iPtr, "errorInfo", (char *) NULL,
504         *       "", TCL_GLOBAL_ONLY);
505         * (void) Tcl_SetVar2((Tcl_Interp *)iPtr, "errorCode", (char *) NULL,
506         *       "NONE", TCL_GLOBAL_ONLY);
507         */
508    
509    #ifndef TCL_GENERIC_ONLY
510        TclSetupEnv(interp);
511    #endif
512    
513        /*
514         * Compute the byte order of this machine.
515         */
516    
517        order.s = 1;
518        Tcl_SetVar2(interp, "tcl_platform", "byteOrder",
519                ((order.c[0] == 1) ? "littleEndian" : "bigEndian"),
520                TCL_GLOBAL_ONLY);
521    
522        /*
523         * Set up other variables such as tcl_version and tcl_library
524         */
525    
526        Tcl_SetVar(interp, "tcl_patchLevel", TCL_PATCH_LEVEL, TCL_GLOBAL_ONLY);
527        Tcl_SetVar(interp, "tcl_version", TCL_VERSION, TCL_GLOBAL_ONLY);
528        Tcl_TraceVar2(interp, "tcl_precision", (char *) NULL,
529                TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
530                TclPrecTraceProc, (ClientData) NULL);
531        TclpSetVariables(interp);
532    
533    #ifdef TCL_THREADS
534        /*
535         * The existence of the "threaded" element of the tcl_platform array indicates
536         * that this particular Tcl shell has been compiled with threads turned on.
537         * Using "info exists tcl_platform(threaded)" a Tcl script can introspect on the
538         * interpreter level of thread safety.
539         */
540    
541    
542        Tcl_SetVar2(interp, "tcl_platform", "threaded", "1",
543                TCL_GLOBAL_ONLY);
544    #endif
545    
546        /*
547         * Register Tcl's version number.
548         */
549    
550        Tcl_PkgProvideEx(interp, "Tcl", TCL_VERSION, (ClientData) &tclStubs);
551        
552    #ifdef Tcl_InitStubs
553    #undef Tcl_InitStubs
554    #endif
555        Tcl_InitStubs(interp, TCL_VERSION, 1);
556    
557        return interp;
558    }
559    
560    /*
561     *----------------------------------------------------------------------
562     *
563     * TclHideUnsafeCommands --
564     *
565     *      Hides base commands that are not marked as safe from this
566     *      interpreter.
567     *
568     * Results:
569     *      TCL_OK if it succeeds, TCL_ERROR else.
570     *
571     * Side effects:
572     *      Hides functionality in an interpreter.
573     *
574     *----------------------------------------------------------------------
575     */
576    
577    int
578    TclHideUnsafeCommands(interp)
579        Tcl_Interp *interp;         /* Hide commands in this interpreter. */
580    {
581        register CmdInfo *cmdInfoPtr;
582    
583        if (interp == (Tcl_Interp *) NULL) {
584            return TCL_ERROR;
585        }
586        for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
587            if (!cmdInfoPtr->isSafe) {
588                Tcl_HideCommand(interp, cmdInfoPtr->name, cmdInfoPtr->name);
589            }
590        }
591        return TCL_OK;
592    }
593    
594    /*
595     *--------------------------------------------------------------
596     *
597     * Tcl_CallWhenDeleted --
598     *
599     *      Arrange for a procedure to be called before a given
600     *      interpreter is deleted. The procedure is called as soon
601     *      as Tcl_DeleteInterp is called; if Tcl_CallWhenDeleted is
602     *      called on an interpreter that has already been deleted,
603     *      the procedure will be called when the last Tcl_Release is
604     *      done on the interpreter.
605     *
606     * Results:
607     *      None.
608     *
609     * Side effects:
610     *      When Tcl_DeleteInterp is invoked to delete interp,
611     *      proc will be invoked.  See the manual entry for
612     *      details.
613     *
614     *--------------------------------------------------------------
615     */
616    
617    void
618    Tcl_CallWhenDeleted(interp, proc, clientData)
619        Tcl_Interp *interp;         /* Interpreter to watch. */
620        Tcl_InterpDeleteProc *proc; /* Procedure to call when interpreter
621                                     * is about to be deleted. */
622        ClientData clientData;      /* One-word value to pass to proc. */
623    {
624        Interp *iPtr = (Interp *) interp;
625        static int assocDataCounter = 0;
626    #ifdef TCL_THREADS
627        static Tcl_Mutex assocMutex;
628    #endif
629        int new;
630        char buffer[32 + TCL_INTEGER_SPACE];
631        AssocData *dPtr = (AssocData *) ckalloc(sizeof(AssocData));
632        Tcl_HashEntry *hPtr;
633    
634        Tcl_MutexLock(&assocMutex);
635        sprintf(buffer, "Assoc Data Key #%d", assocDataCounter);
636        assocDataCounter++;
637        Tcl_MutexUnlock(&assocMutex);
638    
639        if (iPtr->assocData == (Tcl_HashTable *) NULL) {
640            iPtr->assocData = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
641            Tcl_InitHashTable(iPtr->assocData, TCL_STRING_KEYS);
642        }
643        hPtr = Tcl_CreateHashEntry(iPtr->assocData, buffer, &new);
644        dPtr->proc = proc;
645        dPtr->clientData = clientData;
646        Tcl_SetHashValue(hPtr, dPtr);
647    }
648    
649    /*
650     *--------------------------------------------------------------
651     *
652     * Tcl_DontCallWhenDeleted --
653     *
654     *      Cancel the arrangement for a procedure to be called when
655     *      a given interpreter is deleted.
656     *
657     * Results:
658     *      None.
659     *
660     * Side effects:
661     *      If proc and clientData were previously registered as a
662     *      callback via Tcl_CallWhenDeleted, they are unregistered.
663     *      If they weren't previously registered then nothing
664     *      happens.
665     *
666     *--------------------------------------------------------------
667     */
668    
669    void
670    Tcl_DontCallWhenDeleted(interp, proc, clientData)
671        Tcl_Interp *interp;         /* Interpreter to watch. */
672        Tcl_InterpDeleteProc *proc; /* Procedure to call when interpreter
673                                     * is about to be deleted. */
674        ClientData clientData;      /* One-word value to pass to proc. */
675    {
676        Interp *iPtr = (Interp *) interp;
677        Tcl_HashTable *hTablePtr;
678        Tcl_HashSearch hSearch;
679        Tcl_HashEntry *hPtr;
680        AssocData *dPtr;
681    
682        hTablePtr = iPtr->assocData;
683        if (hTablePtr == (Tcl_HashTable *) NULL) {
684            return;
685        }
686        for (hPtr = Tcl_FirstHashEntry(hTablePtr, &hSearch); hPtr != NULL;
687                hPtr = Tcl_NextHashEntry(&hSearch)) {
688            dPtr = (AssocData *) Tcl_GetHashValue(hPtr);
689            if ((dPtr->proc == proc) && (dPtr->clientData == clientData)) {
690                ckfree((char *) dPtr);
691                Tcl_DeleteHashEntry(hPtr);
692                return;
693            }
694        }
695    }
696    
697    /*
698     *----------------------------------------------------------------------
699     *
700     * Tcl_SetAssocData --
701     *
702     *      Creates a named association between user-specified data, a delete
703     *      function and this interpreter. If the association already exists
704     *      the data is overwritten with the new data. The delete function will
705     *      be invoked when the interpreter is deleted.
706     *
707     * Results:
708     *      None.
709     *
710     * Side effects:
711     *      Sets the associated data, creates the association if needed.
712     *
713     *----------------------------------------------------------------------
714     */
715    
716    void
717    Tcl_SetAssocData(interp, name, proc, clientData)
718        Tcl_Interp *interp;         /* Interpreter to associate with. */
719        char *name;                 /* Name for association. */
720        Tcl_InterpDeleteProc *proc; /* Proc to call when interpreter is
721                                     * about to be deleted. */
722        ClientData clientData;      /* One-word value to pass to proc. */
723    {
724        Interp *iPtr = (Interp *) interp;
725        AssocData *dPtr;
726        Tcl_HashEntry *hPtr;
727        int new;
728    
729        if (iPtr->assocData == (Tcl_HashTable *) NULL) {
730            iPtr->assocData = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
731            Tcl_InitHashTable(iPtr->assocData, TCL_STRING_KEYS);
732        }
733        hPtr = Tcl_CreateHashEntry(iPtr->assocData, name, &new);
734        if (new == 0) {
735            dPtr = (AssocData *) Tcl_GetHashValue(hPtr);
736        } else {
737            dPtr = (AssocData *) ckalloc(sizeof(AssocData));
738        }
739        dPtr->proc = proc;
740        dPtr->clientData = clientData;
741    
742        Tcl_SetHashValue(hPtr, dPtr);
743    }
744    
745    /*
746     *----------------------------------------------------------------------
747     *
748     * Tcl_DeleteAssocData --
749     *
750     *      Deletes a named association of user-specified data with
751     *      the specified interpreter.
752     *
753     * Results:
754     *      None.
755     *
756     * Side effects:
757     *      Deletes the association.
758     *
759     *----------------------------------------------------------------------
760     */
761    
762    void
763    Tcl_DeleteAssocData(interp, name)
764        Tcl_Interp *interp;                 /* Interpreter to associate with. */
765        char *name;                         /* Name of association. */
766    {
767        Interp *iPtr = (Interp *) interp;
768        AssocData *dPtr;
769        Tcl_HashEntry *hPtr;
770    
771        if (iPtr->assocData == (Tcl_HashTable *) NULL) {
772            return;
773        }
774        hPtr = Tcl_FindHashEntry(iPtr->assocData, name);
775        if (hPtr == (Tcl_HashEntry *) NULL) {
776            return;
777        }
778        dPtr = (AssocData *) Tcl_GetHashValue(hPtr);
779        if (dPtr->proc != NULL) {
780            (dPtr->proc) (dPtr->clientData, interp);
781        }
782        ckfree((char *) dPtr);
783        Tcl_DeleteHashEntry(hPtr);
784    }
785    
786    /*
787     *----------------------------------------------------------------------
788     *
789     * Tcl_GetAssocData --
790     *
791     *      Returns the client data associated with this name in the
792     *      specified interpreter.
793     *
794     * Results:
795     *      The client data in the AssocData record denoted by the named
796     *      association, or NULL.
797     *
798     * Side effects:
799     *      None.
800     *
801     *----------------------------------------------------------------------
802     */
803    
804    ClientData
805    Tcl_GetAssocData(interp, name, procPtr)
806        Tcl_Interp *interp;                 /* Interpreter associated with. */
807        char *name;                         /* Name of association. */
808        Tcl_InterpDeleteProc **procPtr;     /* Pointer to place to store address
809                                             * of current deletion callback. */
810    {
811        Interp *iPtr = (Interp *) interp;
812        AssocData *dPtr;
813        Tcl_HashEntry *hPtr;
814    
815        if (iPtr->assocData == (Tcl_HashTable *) NULL) {
816            return (ClientData) NULL;
817        }
818        hPtr = Tcl_FindHashEntry(iPtr->assocData, name);
819        if (hPtr == (Tcl_HashEntry *) NULL) {
820            return (ClientData) NULL;
821        }
822        dPtr = (AssocData *) Tcl_GetHashValue(hPtr);
823        if (procPtr != (Tcl_InterpDeleteProc **) NULL) {
824            *procPtr = dPtr->proc;
825        }
826        return dPtr->clientData;
827    }
828    
829    /*
830     *----------------------------------------------------------------------
831     *
832     * Tcl_InterpDeleted --
833     *
834     *      Returns nonzero if the interpreter has been deleted with a call
835     *      to Tcl_DeleteInterp.
836     *
837     * Results:
838     *      Nonzero if the interpreter is deleted, zero otherwise.
839     *
840     * Side effects:
841     *      None.
842     *
843     *----------------------------------------------------------------------
844     */
845    
846    int
847    Tcl_InterpDeleted(interp)
848        Tcl_Interp *interp;
849    {
850        return (((Interp *) interp)->flags & DELETED) ? 1 : 0;
851    }
852    
853    /*
854     *----------------------------------------------------------------------
855     *
856     * Tcl_DeleteInterp --
857     *
858     *      Ensures that the interpreter will be deleted eventually. If there
859     *      are no Tcl_Preserve calls in effect for this interpreter, it is
860     *      deleted immediately, otherwise the interpreter is deleted when
861     *      the last Tcl_Preserve is matched by a call to Tcl_Release. In either
862     *      case, the procedure runs the currently registered deletion callbacks.
863     *
864     * Results:
865     *      None.
866     *
867     * Side effects:
868     *      The interpreter is marked as deleted. The caller may still use it
869     *      safely if there are calls to Tcl_Preserve in effect for the
870     *      interpreter, but further calls to Tcl_Eval etc in this interpreter
871     *      will fail.
872     *
873     *----------------------------------------------------------------------
874     */
875    
876    void
877    Tcl_DeleteInterp(interp)
878        Tcl_Interp *interp;         /* Token for command interpreter (returned
879                                     * by a previous call to Tcl_CreateInterp). */
880    {
881        Interp *iPtr = (Interp *) interp;
882    
883        /*
884         * If the interpreter has already been marked deleted, just punt.
885         */
886    
887        if (iPtr->flags & DELETED) {
888            return;
889        }
890        
891        /*
892         * Mark the interpreter as deleted. No further evals will be allowed.
893         */
894    
895        iPtr->flags |= DELETED;
896    
897        /*
898         * Ensure that the interpreter is eventually deleted.
899         */
900    
901        Tcl_EventuallyFree((ClientData) interp,
902                (Tcl_FreeProc *) DeleteInterpProc);
903    }
904    
905    /*
906     *----------------------------------------------------------------------
907     *
908     * DeleteInterpProc --
909     *
910     *      Helper procedure to delete an interpreter. This procedure is
911     *      called when the last call to Tcl_Preserve on this interpreter
912     *      is matched by a call to Tcl_Release. The procedure cleans up
913     *      all resources used in the interpreter and calls all currently
914     *      registered interpreter deletion callbacks.
915     *
916     * Results:
917     *      None.
918     *
919     * Side effects:
920     *      Whatever the interpreter deletion callbacks do. Frees resources
921     *      used by the interpreter.
922     *
923     *----------------------------------------------------------------------
924     */
925    
926    static void
927    DeleteInterpProc(interp)
928        Tcl_Interp *interp;                 /* Interpreter to delete. */
929    {
930        Interp *iPtr = (Interp *) interp;
931        Tcl_HashEntry *hPtr;
932        Tcl_HashSearch search;
933        Tcl_HashTable *hTablePtr;
934        ResolverScheme *resPtr, *nextResPtr;
935    
936        /*
937         * Punt if there is an error in the Tcl_Release/Tcl_Preserve matchup.
938         */
939        
940        if (iPtr->numLevels > 0) {
941            panic("DeleteInterpProc called with active evals");
942        }
943    
944        /*
945         * The interpreter should already be marked deleted; otherwise how
946         * did we get here?
947         */
948    
949        if (!(iPtr->flags & DELETED)) {
950            panic("DeleteInterpProc called on interpreter not marked deleted");
951        }
952    
953        TclHandleFree(iPtr->handle);
954    
955        /*
956         * Dismantle everything in the global namespace except for the
957         * "errorInfo" and "errorCode" variables. These remain until the
958         * namespace is actually destroyed, in case any errors occur.
959         *  
960         * Dismantle the namespace here, before we clear the assocData. If any
961         * background errors occur here, they will be deleted below.
962         */
963        
964        TclTeardownNamespace(iPtr->globalNsPtr);
965    
966        /*
967         * Delete all the hidden commands.
968         */
969        
970        hTablePtr = iPtr->hiddenCmdTablePtr;
971        if (hTablePtr != NULL) {
972            /*
973             * Non-pernicious deletion.  The deletion callbacks will not be
974             * allowed to create any new hidden or non-hidden commands.
975             * Tcl_DeleteCommandFromToken() will remove the entry from the
976             * hiddenCmdTablePtr.
977             */
978            
979            hPtr = Tcl_FirstHashEntry(hTablePtr, &search);
980            for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
981                Tcl_DeleteCommandFromToken(interp,
982                        (Tcl_Command) Tcl_GetHashValue(hPtr));
983            }
984            Tcl_DeleteHashTable(hTablePtr);
985            ckfree((char *) hTablePtr);
986        }
987        /*
988         * Tear down the math function table.
989         */
990    
991        for (hPtr = Tcl_FirstHashEntry(&iPtr->mathFuncTable, &search);
992                 hPtr != NULL;
993                 hPtr = Tcl_NextHashEntry(&search)) {
994            ckfree((char *) Tcl_GetHashValue(hPtr));
995        }
996        Tcl_DeleteHashTable(&iPtr->mathFuncTable);
997    
998        /*
999         * Invoke deletion callbacks; note that a callback can create new
1000         * callbacks, so we iterate.
1001         */
1002    
1003        while (iPtr->assocData != (Tcl_HashTable *) NULL) {
1004            AssocData *dPtr;
1005            
1006            hTablePtr = iPtr->assocData;
1007            iPtr->assocData = (Tcl_HashTable *) NULL;
1008            for (hPtr = Tcl_FirstHashEntry(hTablePtr, &search);
1009                     hPtr != NULL;
1010                     hPtr = Tcl_FirstHashEntry(hTablePtr, &search)) {
1011                dPtr = (AssocData *) Tcl_GetHashValue(hPtr);
1012                Tcl_DeleteHashEntry(hPtr);
1013                if (dPtr->proc != NULL) {
1014                    (*dPtr->proc)(dPtr->clientData, interp);
1015                }
1016                ckfree((char *) dPtr);
1017            }
1018            Tcl_DeleteHashTable(hTablePtr);
1019            ckfree((char *) hTablePtr);
1020        }
1021    
1022        /*
1023         * Finish deleting the global namespace.
1024         */
1025        
1026        Tcl_DeleteNamespace((Tcl_Namespace *) iPtr->globalNsPtr);
1027    
1028        /*
1029         * Free up the result *after* deleting variables, since variable
1030         * deletion could have transferred ownership of the result string
1031         * to Tcl.
1032         */
1033    
1034        Tcl_FreeResult(interp);
1035        interp->result = NULL;
1036        Tcl_DecrRefCount(iPtr->objResultPtr);
1037        iPtr->objResultPtr = NULL;
1038        if (iPtr->errorInfo != NULL) {
1039            ckfree(iPtr->errorInfo);
1040            iPtr->errorInfo = NULL;
1041        }
1042        if (iPtr->errorCode != NULL) {
1043            ckfree(iPtr->errorCode);
1044            iPtr->errorCode = NULL;
1045        }
1046        if (iPtr->appendResult != NULL) {
1047            ckfree(iPtr->appendResult);
1048            iPtr->appendResult = NULL;
1049        }
1050        TclFreePackageInfo(iPtr);
1051        while (iPtr->tracePtr != NULL) {
1052            Trace *nextPtr = iPtr->tracePtr->nextPtr;
1053    
1054            ckfree((char *) iPtr->tracePtr);
1055            iPtr->tracePtr = nextPtr;
1056        }
1057        if (iPtr->execEnvPtr != NULL) {
1058            TclDeleteExecEnv(iPtr->execEnvPtr);
1059        }
1060        Tcl_DecrRefCount(iPtr->emptyObjPtr);
1061        iPtr->emptyObjPtr = NULL;
1062    
1063        resPtr = iPtr->resolverPtr;
1064        while (resPtr) {
1065            nextResPtr = resPtr->nextPtr;
1066            ckfree(resPtr->name);
1067            ckfree((char *) resPtr);
1068            resPtr = nextResPtr;
1069        }
1070        
1071        /*
1072         * Free up literal objects created for scripts compiled by the
1073         * interpreter.
1074         */
1075    
1076        TclDeleteLiteralTable(interp, &(iPtr->literalTable));
1077        ckfree((char *) iPtr);
1078    }
1079    
1080    /*
1081     *---------------------------------------------------------------------------
1082     *
1083     * Tcl_HideCommand --
1084     *
1085     *      Makes a command hidden so that it cannot be invoked from within
1086     *      an interpreter, only from within an ancestor.
1087     *
1088     * Results:
1089     *      A standard Tcl result; also leaves a message in the interp's result
1090     *      if an error occurs.
1091     *
1092     * Side effects:
1093     *      Removes a command from the command table and create an entry
1094     *      into the hidden command table under the specified token name.
1095     *
1096     *---------------------------------------------------------------------------
1097     */
1098    
1099    int
1100    Tcl_HideCommand(interp, cmdName, hiddenCmdToken)
1101        Tcl_Interp *interp;         /* Interpreter in which to hide command. */
1102        char *cmdName;              /* Name of command to hide. */
1103        char *hiddenCmdToken;       /* Token name of the to-be-hidden command. */
1104    {
1105        Interp *iPtr = (Interp *) interp;
1106        Tcl_Command cmd;
1107        Command *cmdPtr;
1108        Tcl_HashTable *hiddenCmdTablePtr;
1109        Tcl_HashEntry *hPtr;
1110        int new;
1111    
1112        if (iPtr->flags & DELETED) {
1113    
1114            /*
1115             * The interpreter is being deleted. Do not create any new
1116             * structures, because it is not safe to modify the interpreter.
1117             */
1118            
1119            return TCL_ERROR;
1120        }
1121    
1122        /*
1123         * Disallow hiding of commands that are currently in a namespace or
1124         * renaming (as part of hiding) into a namespace.
1125         *
1126         * (because the current implementation with a single global table
1127         *  and the needed uniqueness of names cause problems with namespaces)
1128         *
1129         * we don't need to check for "::" in cmdName because the real check is
1130         * on the nsPtr below.
1131         *
1132         * hiddenCmdToken is just a string which is not interpreted in any way.
1133         * It may contain :: but the string is not interpreted as a namespace
1134         * qualifier command name. Thus, hiding foo::bar to foo::bar and then
1135         * trying to expose or invoke ::foo::bar will NOT work; but if the
1136         * application always uses the same strings it will get consistent
1137         * behaviour.
1138         *
1139         * But as we currently limit ourselves to the global namespace only
1140         * for the source, in order to avoid potential confusion,
1141         * lets prevent "::" in the token too.  --dl
1142         */
1143    
1144        if (strstr(hiddenCmdToken, "::") != NULL) {
1145            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1146                    "cannot use namespace qualifiers as hidden command",
1147                    "token (rename)", (char *) NULL);
1148            return TCL_ERROR;
1149        }
1150    
1151        /*
1152         * Find the command to hide. An error is returned if cmdName can't
1153         * be found. Look up the command only from the global namespace.
1154         * Full path of the command must be given if using namespaces.
1155         */
1156    
1157        cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL,
1158                /*flags*/ TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1159        if (cmd == (Tcl_Command) NULL) {
1160            return TCL_ERROR;
1161        }
1162        cmdPtr = (Command *) cmd;
1163    
1164        /*
1165         * Check that the command is really in global namespace
1166         */
1167    
1168        if ( cmdPtr->nsPtr != iPtr->globalNsPtr ) {
1169            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1170                    "can only hide global namespace commands",
1171                    " (use rename then hide)", (char *) NULL);
1172            return TCL_ERROR;
1173        }
1174        
1175        /*
1176         * Initialize the hidden command table if necessary.
1177         */
1178    
1179        hiddenCmdTablePtr = iPtr->hiddenCmdTablePtr;
1180        if (hiddenCmdTablePtr == NULL) {
1181            hiddenCmdTablePtr = (Tcl_HashTable *)
1182                    ckalloc((unsigned) sizeof(Tcl_HashTable));
1183            Tcl_InitHashTable(hiddenCmdTablePtr, TCL_STRING_KEYS);
1184            iPtr->hiddenCmdTablePtr = hiddenCmdTablePtr;
1185        }
1186    
1187        /*
1188         * It is an error to move an exposed command to a hidden command with
1189         * hiddenCmdToken if a hidden command with the name hiddenCmdToken already
1190         * exists.
1191         */
1192        
1193        hPtr = Tcl_CreateHashEntry(hiddenCmdTablePtr, hiddenCmdToken, &new);
1194        if (!new) {
1195            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1196                    "hidden command named \"", hiddenCmdToken, "\" already exists",
1197                    (char *) NULL);
1198            return TCL_ERROR;
1199        }
1200    
1201        /*
1202         * Nb : This code is currently 'like' a rename to a specialy set apart
1203         * name table. Changes here and in TclRenameCommand must
1204         * be kept in synch untill the common parts are actually
1205         * factorized out.
1206         */
1207    
1208        /*
1209         * Remove the hash entry for the command from the interpreter command
1210         * table. This is like deleting the command, so bump its command epoch;
1211         * this invalidates any cached references that point to the command.
1212         */
1213    
1214        if (cmdPtr->hPtr != NULL) {
1215            Tcl_DeleteHashEntry(cmdPtr->hPtr);
1216            cmdPtr->hPtr = (Tcl_HashEntry *) NULL;
1217            cmdPtr->cmdEpoch++;
1218        }
1219    
1220        /*
1221         * Now link the hash table entry with the command structure.
1222         * We ensured above that the nsPtr was right.
1223         */
1224        
1225        cmdPtr->hPtr = hPtr;
1226        Tcl_SetHashValue(hPtr, (ClientData) cmdPtr);
1227    
1228        /*
1229         * If the command being hidden has a compile procedure, increment the
1230         * interpreter's compileEpoch to invalidate its compiled code. This
1231         * makes sure that we don't later try to execute old code compiled with
1232         * command-specific (i.e., inline) bytecodes for the now-hidden
1233         * command. This field is checked in Tcl_EvalObj and ObjInterpProc,
1234         * and code whose compilation epoch doesn't match is recompiled.
1235         */
1236    
1237        if (cmdPtr->compileProc != NULL) {
1238            iPtr->compileEpoch++;
1239        }
1240        return TCL_OK;
1241    }
1242    
1243    /*
1244     *----------------------------------------------------------------------
1245     *
1246     * Tcl_ExposeCommand --
1247     *
1248     *      Makes a previously hidden command callable from inside the
1249     *      interpreter instead of only by its ancestors.
1250     *
1251     * Results:
1252     *      A standard Tcl result. If an error occurs, a message is left
1253     *      in the interp's result.
1254     *
1255     * Side effects:
1256     *      Moves commands from one hash table to another.
1257     *
1258     *----------------------------------------------------------------------
1259     */
1260    
1261    int
1262    Tcl_ExposeCommand(interp, hiddenCmdToken, cmdName)
1263        Tcl_Interp *interp;         /* Interpreter in which to make command
1264                                     * callable. */
1265        char *hiddenCmdToken;       /* Name of hidden command. */
1266        char *cmdName;              /* Name of to-be-exposed command. */
1267    {
1268        Interp *iPtr = (Interp *) interp;
1269        Command *cmdPtr;
1270        Namespace *nsPtr;
1271        Tcl_HashEntry *hPtr;
1272        Tcl_HashTable *hiddenCmdTablePtr;
1273        int new;
1274    
1275        if (iPtr->flags & DELETED) {
1276            /*
1277             * The interpreter is being deleted. Do not create any new
1278             * structures, because it is not safe to modify the interpreter.
1279             */
1280            
1281            return TCL_ERROR;
1282        }
1283    
1284        /*
1285         * Check that we have a regular name for the command
1286         * (that the user is not trying to do an expose and a rename
1287         *  (to another namespace) at the same time)
1288         */
1289    
1290        if (strstr(cmdName, "::") != NULL) {
1291            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1292                    "can not expose to a namespace ",
1293                    "(use expose to toplevel, then rename)",
1294                     (char *) NULL);
1295            return TCL_ERROR;
1296        }
1297    
1298        /*
1299         * Get the command from the hidden command table:
1300         */
1301    
1302        hPtr = NULL;
1303        hiddenCmdTablePtr = iPtr->hiddenCmdTablePtr;
1304        if (hiddenCmdTablePtr != NULL) {
1305            hPtr = Tcl_FindHashEntry(hiddenCmdTablePtr, hiddenCmdToken);
1306        }
1307        if (hPtr == (Tcl_HashEntry *) NULL) {
1308            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1309                    "unknown hidden command \"", hiddenCmdToken,
1310                    "\"", (char *) NULL);
1311            return TCL_ERROR;
1312        }
1313        cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
1314        
1315    
1316        /*
1317         * Check that we have a true global namespace
1318         * command (enforced by Tcl_HideCommand() but let's double
1319         * check. (If it was not, we would not really know how to
1320         * handle it).
1321         */
1322        if ( cmdPtr->nsPtr != iPtr->globalNsPtr ) {
1323            /*
1324             * This case is theoritically impossible,
1325             * we might rather panic() than 'nicely' erroring out ?
1326             */
1327            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1328                    "trying to expose a non global command name space command",
1329                    (char *) NULL);
1330            return TCL_ERROR;
1331        }
1332        
1333        /* This is the global table */
1334        nsPtr = cmdPtr->nsPtr;
1335    
1336        /*
1337         * It is an error to overwrite an existing exposed command as a result
1338         * of exposing a previously hidden command.
1339         */
1340    
1341        hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, cmdName, &new);
1342        if (!new) {
1343            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1344                    "exposed command \"", cmdName,
1345                    "\" already exists", (char *) NULL);
1346            return TCL_ERROR;
1347        }
1348    
1349        /*
1350         * Remove the hash entry for the command from the interpreter hidden
1351         * command table.
1352         */
1353    
1354        if (cmdPtr->hPtr != NULL) {
1355            Tcl_DeleteHashEntry(cmdPtr->hPtr);
1356            cmdPtr->hPtr = NULL;
1357        }
1358    
1359        /*
1360         * Now link the hash table entry with the command structure.
1361         * This is like creating a new command, so deal with any shadowing
1362         * of commands in the global namespace.
1363         */
1364        
1365        cmdPtr->hPtr = hPtr;
1366    
1367        Tcl_SetHashValue(hPtr, (ClientData) cmdPtr);
1368    
1369        /*
1370         * Not needed as we are only in the global namespace
1371         * (but would be needed again if we supported namespace command hiding)
1372         *
1373         * TclResetShadowedCmdRefs(interp, cmdPtr);
1374         */
1375    
1376    
1377        /*
1378         * If the command being exposed has a compile procedure, increment
1379         * interpreter's compileEpoch to invalidate its compiled code. This
1380         * makes sure that we don't later try to execute old code compiled
1381         * assuming the command is hidden. This field is checked in Tcl_EvalObj
1382         * and ObjInterpProc, and code whose compilation epoch doesn't match is
1383         * recompiled.
1384         */
1385    
1386        if (cmdPtr->compileProc != NULL) {
1387            iPtr->compileEpoch++;
1388        }
1389        return TCL_OK;
1390    }
1391    
1392    /*
1393     *----------------------------------------------------------------------
1394     *
1395     * Tcl_CreateCommand --
1396     *
1397     *      Define a new command in a command table.
1398     *
1399     * Results:
1400     *      The return value is a token for the command, which can
1401     *      be used in future calls to Tcl_GetCommandName.
1402     *
1403     * Side effects:
1404     *      If a command named cmdName already exists for interp, it is deleted.
1405     *      In the future, when cmdName is seen as the name of a command by
1406     *      Tcl_Eval, proc will be called. To support the bytecode interpreter,
1407     *      the command is created with a wrapper Tcl_ObjCmdProc
1408     *      (TclInvokeStringCommand) that eventially calls proc. When the
1409     *      command is deleted from the table, deleteProc will be called.
1410     *      See the manual entry for details on the calling sequence.
1411     *
1412     *----------------------------------------------------------------------
1413     */
1414    
1415    Tcl_Command
1416    Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
1417        Tcl_Interp *interp;         /* Token for command interpreter returned by
1418                                     * a previous call to Tcl_CreateInterp. */
1419        char *cmdName;              /* Name of command. If it contains namespace
1420                                     * qualifiers, the new command is put in the
1421                                     * specified namespace; otherwise it is put
1422                                     * in the global namespace. */
1423        Tcl_CmdProc *proc;          /* Procedure to associate with cmdName. */
1424        ClientData clientData;      /* Arbitrary value passed to string proc. */
1425        Tcl_CmdDeleteProc *deleteProc;
1426                                    /* If not NULL, gives a procedure to call
1427                                     * when this command is deleted. */
1428    {
1429        Interp *iPtr = (Interp *) interp;
1430        ImportRef *oldRefPtr = NULL;
1431        Namespace *nsPtr, *dummy1, *dummy2;
1432        Command *cmdPtr, *refCmdPtr;
1433        Tcl_HashEntry *hPtr;
1434        char *tail;
1435        int new;
1436        ImportedCmdData *dataPtr;
1437    
1438        if (iPtr->flags & DELETED) {
1439            /*
1440             * The interpreter is being deleted.  Don't create any new
1441             * commands; it's not safe to muck with the interpreter anymore.
1442             */
1443    
1444            return (Tcl_Command) NULL;
1445        }
1446    
1447        /*
1448         * Determine where the command should reside. If its name contains
1449         * namespace qualifiers, we put it in the specified namespace;
1450         * otherwise, we always put it in the global namespace.
1451         */
1452    
1453        if (strstr(cmdName, "::") != NULL) {
1454           TclGetNamespaceForQualName(interp, cmdName, (Namespace *) NULL,
1455               CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);
1456           if ((nsPtr == NULL) || (tail == NULL)) {
1457                return (Tcl_Command) NULL;
1458            }
1459        } else {
1460            nsPtr = iPtr->globalNsPtr;
1461            tail = cmdName;
1462        }
1463        
1464        hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new);
1465        if (!new) {
1466            /*
1467             * Command already exists. Delete the old one.
1468             * Be careful to preserve any existing import links so we can
1469             * restore them down below.  That way, you can redefine a
1470             * command and its import status will remain intact.
1471             */
1472    
1473            cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
1474            oldRefPtr = cmdPtr->importRefPtr;
1475            cmdPtr->importRefPtr = NULL;
1476    
1477            Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
1478            hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new);
1479            if (!new) {
1480                /*
1481                 * If the deletion callback recreated the command, just throw
1482                 * away the new command (if we try to delete it again, we
1483                 * could get stuck in an infinite loop).
1484                 */
1485    
1486                 ckfree((char*) Tcl_GetHashValue(hPtr));
1487            }
1488        }
1489        cmdPtr = (Command *) ckalloc(sizeof(Command));
1490        Tcl_SetHashValue(hPtr, cmdPtr);
1491        cmdPtr->hPtr = hPtr;
1492        cmdPtr->nsPtr = nsPtr;
1493        cmdPtr->refCount = 1;
1494        cmdPtr->cmdEpoch = 0;
1495        cmdPtr->compileProc = (CompileProc *) NULL;
1496        cmdPtr->objProc = TclInvokeStringCommand;
1497        cmdPtr->objClientData = (ClientData) cmdPtr;
1498        cmdPtr->proc = proc;
1499        cmdPtr->clientData = clientData;
1500        cmdPtr->deleteProc = deleteProc;
1501        cmdPtr->deleteData = clientData;
1502        cmdPtr->deleted = 0;
1503        cmdPtr->importRefPtr = NULL;
1504    
1505        /*
1506         * Plug in any existing import references found above.  Be sure
1507         * to update all of these references to point to the new command.
1508         */
1509    
1510        if (oldRefPtr != NULL) {
1511            cmdPtr->importRefPtr = oldRefPtr;
1512            while (oldRefPtr != NULL) {
1513                refCmdPtr = oldRefPtr->importedCmdPtr;
1514                dataPtr = (ImportedCmdData*)refCmdPtr->objClientData;
1515                dataPtr->realCmdPtr = cmdPtr;
1516                oldRefPtr = oldRefPtr->nextPtr;
1517            }
1518        }
1519    
1520        /*
1521         * We just created a command, so in its namespace and all of its parent
1522         * namespaces, it may shadow global commands with the same name. If any
1523         * shadowed commands are found, invalidate all cached command references
1524         * in the affected namespaces.
1525         */
1526        
1527        TclResetShadowedCmdRefs(interp, cmdPtr);
1528        return (Tcl_Command) cmdPtr;
1529    }
1530    
1531    /*
1532     *----------------------------------------------------------------------
1533     *
1534     * Tcl_CreateObjCommand --
1535     *
1536     *      Define a new object-based command in a command table.
1537     *
1538     * Results:
1539     *      The return value is a token for the command, which can
1540     *      be used in future calls to Tcl_GetCommandName.
1541     *
1542     * Side effects:
1543     *      If no command named "cmdName" already exists for interp, one is
1544     *      created. Otherwise, if a command does exist, then if the
1545     *      object-based Tcl_ObjCmdProc is TclInvokeStringCommand, we assume
1546     *      Tcl_CreateCommand was called previously for the same command and
1547     *      just set its Tcl_ObjCmdProc to the argument "proc"; otherwise, we
1548     *      delete the old command.
1549     *
1550     *      In the future, during bytecode evaluation when "cmdName" is seen as
1551     *      the name of a command by Tcl_EvalObj or Tcl_Eval, the object-based
1552     *      Tcl_ObjCmdProc proc will be called. When the command is deleted from
1553     *      the table, deleteProc will be called. See the manual entry for
1554     *      details on the calling sequence.
1555     *
1556     *----------------------------------------------------------------------
1557     */
1558    
1559    Tcl_Command
1560    Tcl_CreateObjCommand(interp, cmdName, proc, clientData, deleteProc)
1561        Tcl_Interp *interp;         /* Token for command interpreter (returned
1562                                     * by previous call to Tcl_CreateInterp). */
1563        char *cmdName;              /* Name of command. If it contains namespace
1564                                     * qualifiers, the new command is put in the
1565                                     * specified namespace; otherwise it is put
1566                                     * in the global namespace. */
1567        Tcl_ObjCmdProc *proc;       /* Object-based procedure to associate with
1568                                     * name. */
1569        ClientData clientData;      /* Arbitrary value to pass to object
1570                                     * procedure. */
1571        Tcl_CmdDeleteProc *deleteProc;
1572                                    /* If not NULL, gives a procedure to call
1573                                     * when this command is deleted. */
1574    {
1575        Interp *iPtr = (Interp *) interp;
1576        ImportRef *oldRefPtr = NULL;
1577        Namespace *nsPtr, *dummy1, *dummy2;
1578        Command *cmdPtr, *refCmdPtr;
1579        Tcl_HashEntry *hPtr;
1580        char *tail;
1581        int new;
1582        ImportedCmdData *dataPtr;
1583    
1584        if (iPtr->flags & DELETED) {
1585            /*
1586             * The interpreter is being deleted.  Don't create any new
1587             * commands;  it's not safe to muck with the interpreter anymore.
1588             */
1589    
1590            return (Tcl_Command) NULL;
1591        }
1592    
1593        /*
1594         * Determine where the command should reside. If its name contains
1595         * namespace qualifiers, we put it in the specified namespace;
1596         * otherwise, we always put it in the global namespace.
1597         */
1598    
1599        if (strstr(cmdName, "::") != NULL) {
1600           TclGetNamespaceForQualName(interp, cmdName, (Namespace *) NULL,
1601               CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);
1602           if ((nsPtr == NULL) || (tail == NULL)) {
1603                return (Tcl_Command) NULL;
1604            }
1605        } else {
1606            nsPtr = iPtr->globalNsPtr;
1607            tail = cmdName;
1608        }
1609    
1610        hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new);
1611        if (!new) {
1612            cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
1613    
1614            /*
1615             * Command already exists. If its object-based Tcl_ObjCmdProc is
1616             * TclInvokeStringCommand, we just set its Tcl_ObjCmdProc to the
1617             * argument "proc". Otherwise, we delete the old command.
1618             */
1619    
1620            if (cmdPtr->objProc == TclInvokeStringCommand) {
1621                cmdPtr->objProc = proc;
1622                cmdPtr->objClientData = clientData;
1623                cmdPtr->deleteProc = deleteProc;
1624                cmdPtr->deleteData = clientData;
1625                return (Tcl_Command) cmdPtr;
1626            }
1627    
1628            /*
1629             * Otherwise, we delete the old command.  Be careful to preserve
1630             * any existing import links so we can restore them down below.
1631             * That way, you can redefine a command and its import status
1632             * will remain intact.
1633             */
1634    
1635            oldRefPtr = cmdPtr->importRefPtr;
1636            cmdPtr->importRefPtr = NULL;
1637    
1638            Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
1639            hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new);
1640            if (!new) {
1641                /*
1642                 * If the deletion callback recreated the command, just throw
1643                 * away the new command (if we try to delete it again, we
1644                 * could get stuck in an infinite loop).
1645                 */
1646    
1647                 ckfree((char *) Tcl_GetHashValue(hPtr));
1648            }
1649        }
1650        cmdPtr = (Command *) ckalloc(sizeof(Command));
1651        Tcl_SetHashValue(hPtr, cmdPtr);
1652        cmdPtr->hPtr = hPtr;
1653        cmdPtr->nsPtr = nsPtr;
1654        cmdPtr->refCount = 1;
1655        cmdPtr->cmdEpoch = 0;
1656        cmdPtr->compileProc = (CompileProc *) NULL;
1657        cmdPtr->objProc = proc;
1658        cmdPtr->objClientData = clientData;
1659        cmdPtr->proc = TclInvokeObjectCommand;
1660        cmdPtr->clientData = (ClientData) cmdPtr;
1661        cmdPtr->deleteProc = deleteProc;
1662        cmdPtr->deleteData = clientData;
1663        cmdPtr->deleted = 0;
1664        cmdPtr->importRefPtr = NULL;
1665    
1666        /*
1667         * Plug in any existing import references found above.  Be sure
1668         * to update all of these references to point to the new command.
1669         */
1670    
1671        if (oldRefPtr != NULL) {
1672            cmdPtr->importRefPtr = oldRefPtr;
1673            while (oldRefPtr != NULL) {
1674                refCmdPtr = oldRefPtr->importedCmdPtr;
1675                dataPtr = (ImportedCmdData*)refCmdPtr->objClientData;
1676                dataPtr->realCmdPtr = cmdPtr;
1677                oldRefPtr = oldRefPtr->nextPtr;
1678            }
1679        }
1680        
1681        /*
1682         * We just created a command, so in its namespace and all of its parent
1683         * namespaces, it may shadow global commands with the same name. If any
1684         * shadowed commands are found, invalidate all cached command references
1685         * in the affected namespaces.
1686         */
1687        
1688        TclResetShadowedCmdRefs(interp, cmdPtr);
1689        return (Tcl_Command) cmdPtr;
1690    }
1691    
1692    /*
1693     *----------------------------------------------------------------------
1694     *
1695     * TclInvokeStringCommand --
1696     *
1697     *      "Wrapper" Tcl_ObjCmdProc used to call an existing string-based
1698     *      Tcl_CmdProc if no object-based procedure exists for a command. A
1699     *      pointer to this procedure is stored as the Tcl_ObjCmdProc in a
1700     *      Command structure. It simply turns around and calls the string
1701     *      Tcl_CmdProc in the Command structure.
1702     *
1703     * Results:
1704     *      A standard Tcl object result value.
1705     *
1706     * Side effects:
1707     *      Besides those side effects of the called Tcl_CmdProc,
1708     *      TclInvokeStringCommand allocates and frees storage.
1709     *
1710     *----------------------------------------------------------------------
1711     */
1712    
1713    int
1714    TclInvokeStringCommand(clientData, interp, objc, objv)
1715        ClientData clientData;      /* Points to command's Command structure. */
1716        Tcl_Interp *interp;         /* Current interpreter. */
1717        register int objc;          /* Number of arguments. */
1718        Tcl_Obj *CONST objv[];      /* Argument objects. */
1719    {
1720        register Command *cmdPtr = (Command *) clientData;
1721        register int i;
1722        int result;
1723    
1724        /*
1725         * This procedure generates an argv array for the string arguments. It
1726         * starts out with stack-allocated space but uses dynamically-allocated
1727         * storage if needed.
1728         */
1729    
1730    #define NUM_ARGS 20
1731        char *(argStorage[NUM_ARGS]);
1732        char **argv = argStorage;
1733    
1734        /*
1735         * Create the string argument array "argv". Make sure argv is large
1736         * enough to hold the objc arguments plus 1 extra for the zero
1737         * end-of-argv word.
1738         */
1739    
1740        if ((objc + 1) > NUM_ARGS) {
1741            argv = (char **) ckalloc((unsigned)(objc + 1) * sizeof(char *));
1742        }
1743    
1744        for (i = 0;  i < objc;  i++) {
1745            argv[i] = Tcl_GetString(objv[i]);
1746        }
1747        argv[objc] = 0;
1748    
1749        /*
1750         * Invoke the command's string-based Tcl_CmdProc.
1751         */
1752    
1753        result = (*cmdPtr->proc)(cmdPtr->clientData, interp, objc, argv);
1754    
1755        /*
1756         * Free the argv array if malloc'ed storage was used.
1757         */
1758    
1759        if (argv != argStorage) {
1760            ckfree((char *) argv);
1761        }
1762        return result;
1763    #undef NUM_ARGS
1764    }
1765    
1766    /*
1767     *----------------------------------------------------------------------
1768     *
1769     * TclInvokeObjectCommand --
1770     *
1771     *      "Wrapper" Tcl_CmdProc used to call an existing object-based
1772     *      Tcl_ObjCmdProc if no string-based procedure exists for a command.
1773     *      A pointer to this procedure is stored as the Tcl_CmdProc in a
1774     *      Command structure. It simply turns around and calls the object
1775     *      Tcl_ObjCmdProc in the Command structure.
1776     *
1777     * Results:
1778     *      A standard Tcl string result value.
1779     *
1780     * Side effects:
1781     *      Besides those side effects of the called Tcl_CmdProc,
1782     *      TclInvokeStringCommand allocates and frees storage.
1783     *
1784     *----------------------------------------------------------------------
1785     */
1786    
1787    int
1788    TclInvokeObjectCommand(clientData, interp, argc, argv)
1789        ClientData clientData;      /* Points to command's Command structure. */
1790        Tcl_Interp *interp;         /* Current interpreter. */
1791        int argc;                   /* Number of arguments. */
1792        register char **argv;       /* Argument strings. */
1793    {
1794        Command *cmdPtr = (Command *) clientData;
1795        register Tcl_Obj *objPtr;
1796        register int i;
1797        int length, result;
1798    
1799        /*
1800         * This procedure generates an objv array for object arguments that hold
1801         * the argv strings. It starts out with stack-allocated space but uses
1802         * dynamically-allocated storage if needed.
1803         */
1804    
1805    #define NUM_ARGS 20
1806        Tcl_Obj *(argStorage[NUM_ARGS]);
1807        register Tcl_Obj **objv = argStorage;
1808    
1809        /*
1810         * Create the object argument array "objv". Make sure objv is large
1811         * enough to hold the objc arguments plus 1 extra for the zero
1812         * end-of-objv word.
1813         */
1814    
1815        if ((argc + 1) > NUM_ARGS) {
1816            objv = (Tcl_Obj **)
1817                ckalloc((unsigned)(argc + 1) * sizeof(Tcl_Obj *));
1818        }
1819    
1820        for (i = 0;  i < argc;  i++) {
1821            length = strlen(argv[i]);
1822            TclNewObj(objPtr);
1823            TclInitStringRep(objPtr, argv[i], length);
1824            Tcl_IncrRefCount(objPtr);
1825            objv[i] = objPtr;
1826        }
1827        objv[argc] = 0;
1828    
1829        /*
1830         * Invoke the command's object-based Tcl_ObjCmdProc.
1831         */
1832    
1833        result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, argc, objv);
1834    
1835        /*
1836         * Move the interpreter's object result to the string result,
1837         * then reset the object result.
1838         */
1839    
1840        Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),
1841                TCL_VOLATILE);
1842        
1843        /*
1844         * Decrement the ref counts for the argument objects created above,
1845         * then free the objv array if malloc'ed storage was used.
1846         */
1847    
1848        for (i = 0;  i < argc;  i++) {
1849            objPtr = objv[i];
1850            Tcl_DecrRefCount(objPtr);
1851        }
1852        if (objv != argStorage) {
1853            ckfree((char *) objv);
1854        }
1855        return result;
1856    #undef NUM_ARGS
1857    }
1858    
1859    /*
1860     *----------------------------------------------------------------------
1861     *
1862     * TclRenameCommand --
1863     *
1864     *      Called to give an existing Tcl command a different name. Both the
1865     *      old command name and the new command name can have "::" namespace
1866     *      qualifiers. If the new command has a different namespace context,
1867     *      the command will be moved to that namespace and will execute in
1868     *      the context of that new namespace.
1869     *
1870     *      If the new command name is NULL or the null string, the command is
1871     *      deleted.
1872     *
1873     * Results:
1874     *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
1875     *
1876     * Side effects:
1877     *      If anything goes wrong, an error message is returned in the
1878     *      interpreter's result object.
1879     *
1880     *----------------------------------------------------------------------
1881     */
1882    
1883    int
1884    TclRenameCommand(interp, oldName, newName)
1885        Tcl_Interp *interp;                 /* Current interpreter. */
1886        char *oldName;                      /* Existing command name. */
1887        char *newName;                      /* New command name. */
1888    {
1889        Interp *iPtr = (Interp *) interp;
1890        char *newTail;
1891        Namespace *cmdNsPtr, *newNsPtr, *dummy1, *dummy2;
1892        Tcl_Command cmd;
1893        Command *cmdPtr;
1894        Tcl_HashEntry *hPtr, *oldHPtr;
1895        int new, result;
1896    
1897        /*
1898         * Find the existing command. An error is returned if cmdName can't
1899         * be found.
1900         */
1901    
1902        cmd = Tcl_FindCommand(interp, oldName, (Tcl_Namespace *) NULL,
1903            /*flags*/ 0);
1904        cmdPtr = (Command *) cmd;
1905        if (cmdPtr == NULL) {
1906            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't ",
1907                    ((newName == NULL)||(*newName == '\0'))? "delete":"rename",
1908                    " \"", oldName, "\": command doesn't exist", (char *) NULL);
1909            return TCL_ERROR;
1910        }
1911        cmdNsPtr = cmdPtr->nsPtr;
1912    
1913        /*
1914         * If the new command name is NULL or empty, delete the command. Do this
1915         * with Tcl_DeleteCommandFromToken, since we already have the command.
1916         */
1917        
1918        if ((newName == NULL) || (*newName == '\0')) {
1919            Tcl_DeleteCommandFromToken(interp, cmd);
1920            return TCL_OK;
1921        }
1922    
1923        /*
1924         * Make sure that the destination command does not already exist.
1925         * The rename operation is like creating a command, so we should
1926         * automatically create the containing namespaces just like
1927         * Tcl_CreateCommand would.
1928         */
1929    
1930        TclGetNamespaceForQualName(interp, newName, (Namespace *) NULL,
1931           CREATE_NS_IF_UNKNOWN, &newNsPtr, &dummy1, &dummy2, &newTail);
1932    
1933        if ((newNsPtr == NULL) || (newTail == NULL)) {
1934            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1935                     "can't rename to \"", newName, "\": bad command name",
1936                     (char *) NULL);
1937            return TCL_ERROR;
1938        }
1939        if (Tcl_FindHashEntry(&newNsPtr->cmdTable, newTail) != NULL) {
1940            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1941                     "can't rename to \"", newName,
1942                     "\": command already exists", (char *) NULL);
1943            return TCL_ERROR;
1944        }
1945    
1946    
1947        /*
1948         * Warning: any changes done in the code here are likely
1949         * to be needed in Tcl_HideCommand() code too.
1950         * (until the common parts are extracted out)     --dl
1951         */
1952    
1953        /*
1954         * Put the command in the new namespace so we can check for an alias
1955         * loop. Since we are adding a new command to a namespace, we must
1956         * handle any shadowing of the global commands that this might create.
1957         */
1958        
1959        oldHPtr = cmdPtr->hPtr;
1960        hPtr = Tcl_CreateHashEntry(&newNsPtr->cmdTable, newTail, &new);
1961        Tcl_SetHashValue(hPtr, (ClientData) cmdPtr);
1962        cmdPtr->hPtr = hPtr;
1963        cmdPtr->nsPtr = newNsPtr;
1964        TclResetShadowedCmdRefs(interp, cmdPtr);
1965    
1966        /*
1967         * Now check for an alias loop. If we detect one, put everything back
1968         * the way it was and report the error.
1969         */
1970    
1971        result = TclPreventAliasLoop(interp, interp, (Tcl_Command) cmdPtr);
1972        if (result != TCL_OK) {
1973            Tcl_DeleteHashEntry(cmdPtr->hPtr);
1974            cmdPtr->hPtr = oldHPtr;
1975            cmdPtr->nsPtr = cmdNsPtr;
1976            return result;
1977        }
1978    
1979        /*
1980         * The new command name is okay, so remove the command from its
1981         * current namespace. This is like deleting the command, so bump
1982         * the cmdEpoch to invalidate any cached references to the command.
1983         */
1984        
1985        Tcl_DeleteHashEntry(oldHPtr);
1986        cmdPtr->cmdEpoch++;
1987    
1988        /*
1989         * If the command being renamed has a compile procedure, increment the
1990         * interpreter's compileEpoch to invalidate its compiled code. This
1991         * makes sure that we don't later try to execute old code compiled for
1992         * the now-renamed command.
1993         */
1994    
1995        if (cmdPtr->compileProc != NULL) {
1996            iPtr->compileEpoch++;
1997        }
1998    
1999        return TCL_OK;
2000    }
2001    
2002    /*
2003     *----------------------------------------------------------------------
2004     *
2005     * Tcl_SetCommandInfo --
2006     *
2007     *      Modifies various information about a Tcl command. Note that
2008     *      this procedure will not change a command's namespace; use
2009     *      Tcl_RenameCommand to do that. Also, the isNativeObjectProc
2010     *      member of *infoPtr is ignored.
2011     *
2012     * Results:
2013     *      If cmdName exists in interp, then the information at *infoPtr
2014     *      is stored with the command in place of the current information
2015     *      and 1 is returned. If the command doesn't exist then 0 is
2016     *      returned.
2017     *
2018     * Side effects:
2019     *      None.
2020     *
2021     *----------------------------------------------------------------------
2022     */
2023    
2024    int
2025    Tcl_SetCommandInfo(interp, cmdName, infoPtr)
2026        Tcl_Interp *interp;                 /* Interpreter in which to look
2027                                             * for command. */
2028        char *cmdName;                      /* Name of desired command. */
2029        Tcl_CmdInfo *infoPtr;               /* Where to find information
2030                                             * to store in the command. */
2031    {
2032        Tcl_Command cmd;
2033        Command *cmdPtr;
2034    
2035        cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL,
2036                /*flags*/ 0);
2037        if (cmd == (Tcl_Command) NULL) {
2038            return 0;
2039        }
2040    
2041        /*
2042         * The isNativeObjectProc and nsPtr members of *infoPtr are ignored.
2043         */
2044        
2045        cmdPtr = (Command *) cmd;
2046        cmdPtr->proc = infoPtr->proc;
2047        cmdPtr->clientData = infoPtr->clientData;
2048        if (infoPtr->objProc == (Tcl_ObjCmdProc *) NULL) {
2049            cmdPtr->objProc = TclInvokeStringCommand;
2050            cmdPtr->objClientData = (ClientData) cmdPtr;
2051        } else {
2052            cmdPtr->objProc = infoPtr->objProc;
2053            cmdPtr->objClientData = infoPtr->objClientData;
2054        }
2055        cmdPtr->deleteProc = infoPtr->deleteProc;
2056        cmdPtr->deleteData = infoPtr->deleteData;
2057        return 1;
2058    }
2059    
2060    /*
2061     *----------------------------------------------------------------------
2062     *
2063     * Tcl_GetCommandInfo --
2064     *
2065     *      Returns various information about a Tcl command.
2066     *
2067     * Results:
2068     *      If cmdName exists in interp, then *infoPtr is modified to
2069     *      hold information about cmdName and 1 is returned.  If the
2070     *      command doesn't exist then 0 is returned and *infoPtr isn't
2071     *      modified.
2072     *
2073     * Side effects:
2074     *      None.
2075     *
2076     *----------------------------------------------------------------------
2077     */
2078    
2079    int
2080    Tcl_GetCommandInfo(interp, cmdName, infoPtr)
2081        Tcl_Interp *interp;                 /* Interpreter in which to look
2082                                             * for command. */
2083        char *cmdName;                      /* Name of desired command. */
2084        Tcl_CmdInfo *infoPtr;               /* Where to store information about
2085                                             * command. */
2086    {
2087        Tcl_Command cmd;
2088        Command *cmdPtr;
2089    
2090        cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL,
2091                /*flags*/ 0);
2092        if (cmd == (Tcl_Command) NULL) {
2093            return 0;
2094        }
2095    
2096        /*
2097         * Set isNativeObjectProc 1 if objProc was registered by a call to
2098         * Tcl_CreateObjCommand. Otherwise set it to 0.
2099         */
2100    
2101        cmdPtr = (Command *) cmd;
2102        infoPtr->isNativeObjectProc =
2103                (cmdPtr->objProc != TclInvokeStringCommand);
2104        infoPtr->objProc = cmdPtr->objProc;
2105        infoPtr->objClientData = cmdPtr->objClientData;
2106        infoPtr->proc = cmdPtr->proc;
2107        infoPtr->clientData = cmdPtr->clientData;
2108        infoPtr->deleteProc = cmdPtr->deleteProc;
2109        infoPtr->deleteData = cmdPtr->deleteData;
2110        infoPtr->namespacePtr = (Tcl_Namespace *) cmdPtr->nsPtr;
2111        return 1;
2112    }
2113    
2114    /*
2115     *----------------------------------------------------------------------
2116     *
2117     * Tcl_GetCommandName --
2118     *
2119     *      Given a token returned by Tcl_CreateCommand, this procedure
2120     *      returns the current name of the command (which may have changed
2121     *      due to renaming).
2122     *
2123     * Results:
2124     *      The return value is the name of the given command.
2125     *
2126     * Side effects:
2127     *      None.
2128     *
2129     *----------------------------------------------------------------------
2130     */
2131    
2132    char *
2133    Tcl_GetCommandName(interp, command)
2134        Tcl_Interp *interp;         /* Interpreter containing the command. */
2135        Tcl_Command command;        /* Token for command returned by a previous
2136                                     * call to Tcl_CreateCommand. The command
2137                                     * must not have been deleted. */
2138    {
2139        Command *cmdPtr = (Command *) command;
2140    
2141        if ((cmdPtr == NULL) || (cmdPtr->hPtr == NULL)) {
2142    
2143            /*
2144             * This should only happen if command was "created" after the
2145             * interpreter began to be deleted, so there isn't really any
2146             * command. Just return an empty string.
2147             */
2148    
2149            return "";
2150        }
2151        return Tcl_GetHashKey(cmdPtr->hPtr->tablePtr, cmdPtr->hPtr);
2152    }
2153    
2154    /*
2155     *----------------------------------------------------------------------
2156     *
2157     * Tcl_GetCommandFullName --
2158     *
2159     *      Given a token returned by, e.g., Tcl_CreateCommand or
2160     *      Tcl_FindCommand, this procedure appends to an object the command's
2161     *      full name, qualified by a sequence of parent namespace names. The
2162     *      command's fully-qualified name may have changed due to renaming.
2163     *
2164     * Results:
2165     *      None.
2166     *
2167     * Side effects:
2168     *      The command's fully-qualified name is appended to the string
2169     *      representation of objPtr.
2170     *
2171     *----------------------------------------------------------------------
2172     */
2173    
2174    void
2175    Tcl_GetCommandFullName(interp, command, objPtr)
2176        Tcl_Interp *interp;         /* Interpreter containing the command. */
2177        Tcl_Command command;        /* Token for command returned by a previous
2178                                     * call to Tcl_CreateCommand. The command
2179                                     * must not have been deleted. */
2180        Tcl_Obj *objPtr;            /* Points to the object onto which the
2181                                     * command's full name is appended. */
2182    
2183    {
2184        Interp *iPtr = (Interp *) interp;
2185        register Command *cmdPtr = (Command *) command;
2186        char *name;
2187    
2188        /*
2189         * Add the full name of the containing namespace, followed by the "::"
2190         * separator, and the command name.
2191         */
2192    
2193        if (cmdPtr != NULL) {
2194            if (cmdPtr->nsPtr != NULL) {
2195                Tcl_AppendToObj(objPtr, cmdPtr->nsPtr->fullName, -1);
2196                if (cmdPtr->nsPtr != iPtr->globalNsPtr) {
2197                    Tcl_AppendToObj(objPtr, "::", 2);
2198                }
2199            }
2200            if (cmdPtr->hPtr != NULL) {
2201                name = Tcl_GetHashKey(cmdPtr->hPtr->tablePtr, cmdPtr->hPtr);
2202                Tcl_AppendToObj(objPtr, name, -1);
2203            }
2204        }
2205    }
2206    
2207    /*
2208     *----------------------------------------------------------------------
2209     *
2210     * Tcl_DeleteCommand --
2211     *
2212     *      Remove the given command from the given interpreter.
2213     *
2214     * Results:
2215     *      0 is returned if the command was deleted successfully.
2216     *      -1 is returned if there didn't exist a command by that name.
2217     *
2218     * Side effects:
2219     *      cmdName will no longer be recognized as a valid command for
2220     *      interp.
2221     *
2222     *----------------------------------------------------------------------
2223     */
2224    
2225    int
2226    Tcl_DeleteCommand(interp, cmdName)
2227        Tcl_Interp *interp;         /* Token for command interpreter (returned
2228                                     * by a previous Tcl_CreateInterp call). */
2229        char *cmdName;              /* Name of command to remove. */
2230    {
2231        Tcl_Command cmd;
2232    
2233        /*
2234         *  Find the desired command and delete it.
2235         */
2236    
2237        cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL,
2238                /*flags*/ 0);
2239        if (cmd == (Tcl_Command) NULL) {
2240            return -1;
2241        }
2242        return Tcl_DeleteCommandFromToken(interp, cmd);
2243    }
2244    
2245    /*
2246     *----------------------------------------------------------------------
2247     *
2248     * Tcl_DeleteCommandFromToken --
2249     *
2250     *      Removes the given command from the given interpreter. This procedure
2251     *      resembles Tcl_DeleteCommand, but takes a Tcl_Command token instead
2252     *      of a command name for efficiency.
2253     *
2254     * Results:
2255     *      0 is returned if the command was deleted successfully.
2256     *      -1 is returned if there didn't exist a command by that name.
2257     *
2258     * Side effects:
2259     *      The command specified by "cmd" will no longer be recognized as a
2260     *      valid command for "interp".
2261     *
2262     *----------------------------------------------------------------------
2263     */
2264    
2265    int
2266    Tcl_DeleteCommandFromToken(interp, cmd)
2267        Tcl_Interp *interp;         /* Token for command interpreter returned by
2268                                     * a previous call to Tcl_CreateInterp. */
2269        Tcl_Command cmd;            /* Token for command to delete. */
2270    {
2271        Interp *iPtr = (Interp *) interp;
2272        Command *cmdPtr = (Command *) cmd;
2273        ImportRef *refPtr, *nextRefPtr;
2274        Tcl_Command importCmd;
2275    
2276        /*
2277         * The code here is tricky.  We can't delete the hash table entry
2278         * before invoking the deletion callback because there are cases
2279         * where the deletion callback needs to invoke the command (e.g.
2280         * object systems such as OTcl). However, this means that the
2281         * callback could try to delete or rename the command. The deleted
2282         * flag allows us to detect these cases and skip nested deletes.
2283         */
2284    
2285        if (cmdPtr->deleted) {
2286            /*
2287             * Another deletion is already in progress.  Remove the hash
2288             * table entry now, but don't invoke a callback or free the
2289             * command structure.
2290             */
2291    
2292            Tcl_DeleteHashEntry(cmdPtr->hPtr);
2293            cmdPtr->hPtr = NULL;
2294            return 0;
2295        }
2296    
2297        /*
2298         * If the command being deleted has a compile procedure, increment the
2299         * interpreter's compileEpoch to invalidate its compiled code. This
2300         * makes sure that we don't later try to execute old code compiled with
2301         * command-specific (i.e., inline) bytecodes for the now-deleted
2302         * command. This field is checked in Tcl_EvalObj and ObjInterpProc, and
2303         * code whose compilation epoch doesn't match is recompiled.
2304         */
2305    
2306        if (cmdPtr->compileProc != NULL) {
2307            iPtr->compileEpoch++;
2308        }
2309    
2310        cmdPtr->deleted = 1;
2311        if (cmdPtr->deleteProc != NULL) {
2312            /*
2313             * Delete the command's client data. If this was an imported command
2314             * created when a command was imported into a namespace, this client
2315             * data will be a pointer to a ImportedCmdData structure describing
2316             * the "real" command that this imported command refers to.
2317             */
2318            
2319            /*
2320             * If you are getting a crash during the call to deleteProc and
2321             * cmdPtr->deleteProc is a pointer to the function free(), the
2322             * most likely cause is that your extension allocated memory
2323             * for the clientData argument to Tcl_CreateObjCommand() with
2324             * the ckalloc() macro and you are now trying to deallocate
2325             * this memory with free() instead of ckfree(). You should
2326             * pass a pointer to your own method that calls ckfree().
2327             */
2328    
2329            (*cmdPtr->deleteProc)(cmdPtr->deleteData);
2330        }
2331    
2332        /*
2333         * Bump the command epoch counter. This will invalidate all cached
2334         * references that point to this command.
2335         */
2336        
2337        cmdPtr->cmdEpoch++;
2338    
2339        /*
2340         * If this command was imported into other namespaces, then imported
2341         * commands were created that refer back to this command. Delete these
2342         * imported commands now.
2343         */
2344    
2345        for (refPtr = cmdPtr->importRefPtr;  refPtr != NULL;
2346                refPtr = nextRefPtr) {
2347            nextRefPtr = refPtr->nextPtr;
2348            importCmd = (Tcl_Command) refPtr->importedCmdPtr;
2349            Tcl_DeleteCommandFromToken(interp, importCmd);
2350        }
2351    
2352        /*
2353         * Don't use hPtr to delete the hash entry here, because it's
2354         * possible that the deletion callback renamed the command.
2355         * Instead, use cmdPtr->hptr, and make sure that no-one else
2356         * has already deleted the hash entry.
2357         */
2358    
2359        if (cmdPtr->hPtr != NULL) {
2360            Tcl_DeleteHashEntry(cmdPtr->hPtr);
2361        }
2362    
2363        /*
2364         * Mark the Command structure as no longer valid. This allows
2365         * TclExecuteByteCode to recognize when a Command has logically been
2366         * deleted and a pointer to this Command structure cached in a CmdName
2367         * object is invalid. TclExecuteByteCode will look up the command again
2368         * in the interpreter's command hashtable.
2369         */
2370    
2371        cmdPtr->objProc = NULL;
2372    
2373        /*
2374         * Now free the Command structure, unless there is another reference to
2375         * it from a CmdName Tcl object in some ByteCode code sequence. In that
2376         * case, delay the cleanup until all references are either discarded
2377         * (when a ByteCode is freed) or replaced by a new reference (when a
2378         * cached CmdName Command reference is found to be invalid and
2379         * TclExecuteByteCode looks up the command in the command hashtable).
2380         */
2381        
2382        TclCleanupCommand(cmdPtr);
2383        return 0;
2384    }
2385    
2386    /*
2387     *----------------------------------------------------------------------
2388     *
2389     * TclCleanupCommand --
2390     *
2391     *      This procedure frees up a Command structure unless it is still
2392     *      referenced from an interpreter's command hashtable or from a CmdName
2393     *      Tcl object representing the name of a command in a ByteCode
2394     *      instruction sequence.
2395     *
2396     * Results:
2397     *      None.
2398     *
2399     * Side effects:
2400     *      Memory gets freed unless a reference to the Command structure still
2401     *      exists. In that case the cleanup is delayed until the command is
2402     *      deleted or when the last ByteCode referring to it is freed.
2403     *
2404     *----------------------------------------------------------------------
2405     */
2406    
2407    void
2408    TclCleanupCommand(cmdPtr)
2409        register Command *cmdPtr;   /* Points to the Command structure to
2410                                     * be freed. */
2411    {
2412        cmdPtr->refCount--;
2413        if (cmdPtr->refCount <= 0) {
2414            ckfree((char *) cmdPtr);
2415        }
2416    }
2417    
2418    /*
2419     *----------------------------------------------------------------------
2420     *
2421     * Tcl_CreateMathFunc --
2422     *
2423     *      Creates a new math function for expressions in a given
2424     *      interpreter.
2425     *
2426     * Results:
2427     *      None.
2428     *
2429     * Side effects:
2430     *      The function defined by "name" is created or redefined. If the
2431     *      function already exists then its definition is replaced; this
2432     *      includes the builtin functions. Redefining a builtin function forces
2433     *      all existing code to be invalidated since that code may be compiled
2434     *      using an instruction specific to the replaced function. In addition,
2435     *      redefioning a non-builtin function will force existing code to be
2436     *      invalidated if the number of arguments has changed.
2437     *
2438     *----------------------------------------------------------------------
2439     */
2440    
2441    void
2442    Tcl_CreateMathFunc(interp, name, numArgs, argTypes, proc, clientData)
2443        Tcl_Interp *interp;                 /* Interpreter in which function is
2444                                             * to be available. */
2445        char *name;                         /* Name of function (e.g. "sin"). */
2446        int numArgs;                        /* Nnumber of arguments required by
2447                                             * function. */
2448        Tcl_ValueType *argTypes;            /* Array of types acceptable for
2449                                             * each argument. */
2450        Tcl_MathProc *proc;                 /* Procedure that implements the
2451                                             * math function. */
2452        ClientData clientData;              /* Additional value to pass to the
2453                                             * function. */
2454    {
2455        Interp *iPtr = (Interp *) interp;
2456        Tcl_HashEntry *hPtr;
2457        MathFunc *mathFuncPtr;
2458        int new, i;
2459    
2460        hPtr = Tcl_CreateHashEntry(&iPtr->mathFuncTable, name, &new);
2461        if (new) {
2462            Tcl_SetHashValue(hPtr, ckalloc(sizeof(MathFunc)));
2463        }
2464        mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
2465    
2466        if (!new) {
2467            if (mathFuncPtr->builtinFuncIndex >= 0) {
2468                /*
2469                 * We are redefining a builtin math function. Invalidate the
2470                 * interpreter's existing code by incrementing its
2471                 * compileEpoch member. This field is checked in Tcl_EvalObj
2472                 * and ObjInterpProc, and code whose compilation epoch doesn't
2473                 * match is recompiled. Newly compiled code will no longer
2474                 * treat the function as builtin.
2475                 */
2476    
2477                iPtr->compileEpoch++;
2478            } else {
2479                /*
2480                 * A non-builtin function is being redefined. We must invalidate
2481                 * existing code if the number of arguments has changed. This
2482                 * is because existing code was compiled assuming that number.
2483                 */
2484    
2485                if (numArgs != mathFuncPtr->numArgs) {
2486                    iPtr->compileEpoch++;
2487                }
2488            }
2489        }
2490        
2491        mathFuncPtr->builtinFuncIndex = -1; /* can't be a builtin function */
2492        if (numArgs > MAX_MATH_ARGS) {
2493            numArgs = MAX_MATH_ARGS;
2494        }
2495        mathFuncPtr->numArgs = numArgs;
2496        for (i = 0;  i < numArgs;  i++) {
2497            mathFuncPtr->argTypes[i] = argTypes[i];
2498        }
2499        mathFuncPtr->proc = proc;
2500        mathFuncPtr->clientData = clientData;
2501    }
2502    
2503    /*
2504     *----------------------------------------------------------------------
2505     *
2506     * Tcl_EvalObjEx --
2507     *
2508     *      Execute Tcl commands stored in a Tcl object. These commands are
2509     *      compiled into bytecodes if necessary, unless TCL_EVAL_DIRECT
2510     *      is specified.
2511     *
2512     * Results:
2513     *      The return value is one of the return codes defined in tcl.h
2514     *      (such as TCL_OK), and the interpreter's result contains a value
2515     *      to supplement the return code.
2516     *
2517     * Side effects:
2518     *      The object is converted, if necessary, to a ByteCode object that
2519     *      holds the bytecode instructions for the commands. Executing the
2520     *      commands will almost certainly have side effects that depend
2521     *      on those commands.
2522     *
2523     *      Just as in Tcl_Eval, interp->termOffset is set to the offset of the
2524     *      last character executed in the objPtr's string.
2525     *
2526     *----------------------------------------------------------------------
2527     */
2528    
2529    int
2530    Tcl_EvalObjEx(interp, objPtr, flags)
2531        Tcl_Interp *interp;                 /* Token for command interpreter
2532                                             * (returned by a previous call to
2533                                             * Tcl_CreateInterp). */
2534        register Tcl_Obj *objPtr;           /* Pointer to object containing
2535                                             * commands to execute. */
2536        int flags;                          /* Collection of OR-ed bits that
2537                                             * control the evaluation of the
2538                                             * script.  Supported values are
2539                                             * TCL_EVAL_GLOBAL and
2540                                             * TCL_EVAL_DIRECT. */
2541    {
2542        register Interp *iPtr = (Interp *) interp;
2543        int evalFlags;                      /* Interp->evalFlags value when the
2544                                             * procedure was called. */
2545        register ByteCode* codePtr;         /* Tcl Internal type of bytecode. */
2546        int oldCount = iPtr->cmdCount;      /* Used to tell whether any commands
2547                                             * at all were executed. */
2548        int numSrcBytes;
2549        int result;
2550        CallFrame *savedVarFramePtr;        /* Saves old copy of iPtr->varFramePtr
2551                                             * in case TCL_EVAL_GLOBAL was set. */
2552        Namespace *namespacePtr;
2553    
2554        Tcl_IncrRefCount(objPtr);
2555    
2556        if ((iPtr->flags & USE_EVAL_DIRECT) || (flags & TCL_EVAL_DIRECT)) {
2557            /*
2558             * We're not supposed to use the compiler or byte-code interpreter.
2559             * Let Tcl_EvalEx evaluate the command directly (and probably
2560             * more slowly).
2561             *
2562             * Pure List Optimization (no string representation).  In this
2563             * case, we can safely use Tcl_EvalObjv instead and get an
2564             * appreciable improvement in execution speed.  This is because it
2565             * allows us to avoid a setFromAny step that would just pack
2566             * everything into a string and back out again.
2567             *
2568             * USE_EVAL_DIRECT is a special flag used for testing purpose only
2569             * (ensure we go into the TCL_EVAL_DIRECT path, avoiding opt)
2570             */
2571            if (!(iPtr->flags & USE_EVAL_DIRECT) &&
2572                    (objPtr->typePtr == &tclListType) && /* is a list... */
2573                    (objPtr->bytes == NULL) /* ...without a string rep */) {
2574                register List *listRepPtr =
2575                    (List *) objPtr->internalRep.otherValuePtr;
2576                result = Tcl_EvalObjv(interp, listRepPtr->elemCount,
2577                        listRepPtr->elements, flags);
2578            } else {
2579                register char *p;
2580                p = Tcl_GetStringFromObj(objPtr, &numSrcBytes);
2581                result = Tcl_EvalEx(interp, p, numSrcBytes, flags);
2582            }
2583            Tcl_DecrRefCount(objPtr);
2584            return result;
2585        }
2586    
2587        /*
2588         * Prevent the object from being deleted as a side effect of evaling it.
2589         */
2590    
2591        savedVarFramePtr = iPtr->varFramePtr;
2592        if (flags & TCL_EVAL_GLOBAL) {
2593            iPtr->varFramePtr = NULL;
2594        }
2595    
2596        /*
2597         * Reset both the interpreter's string and object results and clear out
2598         * any error information. This makes sure that we return an empty
2599         * result if there are no commands in the command string.
2600         */
2601    
2602        Tcl_ResetResult(interp);
2603    
2604        /*
2605         * Check depth of nested calls to Tcl_Eval:  if this gets too large,
2606         * it's probably because of an infinite loop somewhere.
2607         */
2608    
2609        iPtr->numLevels++;
2610        if (iPtr->numLevels > iPtr->maxNestingDepth) {
2611            Tcl_AppendToObj(Tcl_GetObjResult(interp),
2612                    "too many nested calls to Tcl_EvalObj (infinite loop?)", -1);
2613            result = TCL_ERROR;
2614            goto done;
2615        }
2616    
2617        /*
2618         * On the Mac, we will never reach the default recursion limit before
2619         * blowing the stack. So we need to do a check here.
2620         */
2621        
2622        if (TclpCheckStackSpace() == 0) {
2623            /*NOTREACHED*/
2624            Tcl_AppendToObj(Tcl_GetObjResult(interp),
2625                    "too many nested calls to Tcl_EvalObj (infinite loop?)", -1);
2626            result = TCL_ERROR;
2627            goto done;
2628        }
2629    
2630        /*
2631         * If the interpreter has been deleted, return an error.
2632         */
2633        
2634        if (iPtr->flags & DELETED) {
2635            Tcl_ResetResult(interp);
2636            Tcl_AppendToObj(Tcl_GetObjResult(interp),
2637                    "attempt to call eval in deleted interpreter", -1);
2638            Tcl_SetErrorCode(interp, "CORE", "IDELETE",
2639                    "attempt to call eval in deleted interpreter",
2640                    (char *) NULL);
2641            result = TCL_ERROR;
2642            goto done;
2643        }
2644    
2645        /*
2646         * Get the ByteCode from the object. If it exists, make sure it hasn't
2647         * been invalidated by, e.g., someone redefining a command with a
2648         * compile procedure (this might make the compiled code wrong). If
2649         * necessary, convert the object to be a ByteCode object and compile it.
2650         * Also, if the code was compiled in/for a different interpreter,
2651         * or for a different namespace, or for the same namespace but
2652         * with different name resolution rules, we recompile it.
2653         *
2654         * Precompiled objects, however, are immutable and therefore
2655         * they are not recompiled, even if the epoch has changed.
2656         *
2657         * To be pedantically correct, we should also check that the
2658         * originating procPtr is the same as the current context procPtr
2659         * (assuming one exists at all - none for global level).  This
2660         * code is #def'ed out because [info body] was changed to never
2661         * return a bytecode type object, which should obviate us from
2662         * the extra checks here.
2663         */
2664    
2665        if (iPtr->varFramePtr != NULL) {
2666            namespacePtr = iPtr->varFramePtr->nsPtr;
2667        } else {
2668            namespacePtr = iPtr->globalNsPtr;
2669        }
2670    
2671        if (objPtr->typePtr == &tclByteCodeType) {
2672            codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
2673            
2674            if (((Interp *) *codePtr->interpHandle != iPtr)
2675                    || (codePtr->compileEpoch != iPtr->compileEpoch)
2676    #ifdef CHECK_PROC_ORIGINATION   /* [Bug: 3412 Pedantic] */
2677                    || (codePtr->procPtr != NULL && !(iPtr->varFramePtr &&
2678                            iPtr->varFramePtr->procPtr == codePtr->procPtr))
2679    #endif
2680                    || (codePtr->nsPtr != namespacePtr)
2681                    || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) {
2682                if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
2683                    if ((Interp *) *codePtr->interpHandle != iPtr) {
2684                        panic("Tcl_EvalObj: compiled script jumped interps");
2685                    }
2686                    codePtr->compileEpoch = iPtr->compileEpoch;
2687                } else {
2688                    tclByteCodeType.freeIntRepProc(objPtr);
2689                }
2690            }
2691        }
2692        if (objPtr->typePtr != &tclByteCodeType) {
2693            iPtr->errorLine = 1;
2694            result = tclByteCodeType.setFromAnyProc(interp, objPtr);
2695            if (result != TCL_OK) {
2696                goto done;
2697            }
2698        } else {
2699            codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
2700            if (((Interp *) *codePtr->interpHandle != iPtr)
2701                    || (codePtr->compileEpoch != iPtr->compileEpoch)) {
2702                (*tclByteCodeType.freeIntRepProc)(objPtr);
2703                iPtr->errorLine = 1;
2704                result = (*tclByteCodeType.setFromAnyProc)(interp, objPtr);
2705                if (result != TCL_OK) {
2706                    iPtr->numLevels--;
2707                    return result;
2708                }
2709            }
2710        }
2711        codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
2712    
2713        /*
2714         * Extract then reset the compilation flags in the interpreter.
2715         * Resetting the flags must be done after any compilation.
2716         */
2717    
2718        evalFlags = iPtr->evalFlags;
2719        iPtr->evalFlags = 0;
2720    
2721        /*
2722         * Execute the commands. If the code was compiled from an empty string,
2723         * don't bother executing the code.
2724         */
2725    
2726        numSrcBytes = codePtr->numSrcBytes;
2727        if ((numSrcBytes > 0) || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) {
2728            /*
2729             * Increment the code's ref count while it is being executed. If
2730             * afterwards no references to it remain, free the code.
2731             */
2732            
2733            codePtr->refCount++;
2734            result = TclExecuteByteCode(interp, codePtr);
2735            codePtr->refCount--;
2736            if (codePtr->refCount <= 0) {
2737                TclCleanupByteCode(codePtr);
2738            }
2739        } else {
2740            result = TCL_OK;
2741        }
2742    
2743        /*
2744         * If no commands at all were executed, check for asynchronous
2745         * handlers so that they at least get one change to execute.
2746         * This is needed to handle event loops written in Tcl with
2747         * empty bodies.
2748         */
2749    
2750        if ((oldCount == iPtr->cmdCount) && Tcl_AsyncReady()) {
2751            result = Tcl_AsyncInvoke(interp, result);
2752        }
2753    
2754        /*
2755         * Update the interpreter's evaluation level count. If we are again at
2756         * the top level, process any unusual return code returned by the
2757         * evaluated code.
2758         */
2759    
2760        if (iPtr->numLevels == 1) {
2761            if (result == TCL_RETURN) {
2762                result = TclUpdateReturnInfo(iPtr);
2763            }
2764            if ((result != TCL_OK) && (result != TCL_ERROR)
2765                    && ((evalFlags & TCL_ALLOW_EXCEPTIONS) == 0)) {
2766                ProcessUnexpectedResult(interp, result);
2767                result = TCL_ERROR;
2768            }
2769        }
2770    
2771        /*
2772         * If an error occurred, record information about what was being
2773         * executed when the error occurred.
2774         */
2775    
2776        if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
2777            RecordTracebackInfo(interp, objPtr, numSrcBytes);
2778        }
2779    
2780        /*
2781         * Set the interpreter's termOffset member to the offset of the
2782         * character just after the last one executed. We approximate the offset
2783         * of the last character executed by using the number of characters
2784         * compiled.
2785         */
2786    
2787        iPtr->termOffset = numSrcBytes;
2788        iPtr->flags &= ~ERR_ALREADY_LOGGED;
2789    
2790        done:
2791        TclDecrRefCount(objPtr);
2792        iPtr->varFramePtr = savedVarFramePtr;
2793        iPtr->numLevels--;
2794        return result;
2795    }
2796    
2797    /*
2798     *----------------------------------------------------------------------
2799     *
2800     * ProcessUnexpectedResult --
2801     *
2802     *      Procedure called by Tcl_EvalObj to set the interpreter's result
2803     *      value to an appropriate error message when the code it evaluates
2804     *      returns an unexpected result code (not TCL_OK and not TCL_ERROR) to
2805     *      the topmost evaluation level.
2806     *
2807     * Results:
2808     *      None.
2809     *
2810     * Side effects:
2811     *      The interpreter result is set to an error message appropriate to
2812     *      the result code.
2813     *
2814     *----------------------------------------------------------------------
2815     */
2816    
2817    static void
2818    ProcessUnexpectedResult(interp, returnCode)
2819        Tcl_Interp *interp;         /* The interpreter in which the unexpected
2820                                     * result code was returned. */
2821        int returnCode;             /* The unexpected result code. */
2822    {
2823        Tcl_ResetResult(interp);
2824        if (returnCode == TCL_BREAK) {
2825            Tcl_AppendToObj(Tcl_GetObjResult(interp),
2826                    "invoked \"break\" outside of a loop", -1);
2827        } else if (returnCode == TCL_CONTINUE) {
2828            Tcl_AppendToObj(Tcl_GetObjResult(interp),
2829                    "invoked \"continue\" outside of a loop", -1);
2830        } else {
2831            char buf[30 + TCL_INTEGER_SPACE];
2832    
2833            sprintf(buf, "command returned bad code: %d", returnCode);
2834            Tcl_SetResult(interp, buf, TCL_VOLATILE);
2835        }
2836    }
2837    
2838    /*
2839     *----------------------------------------------------------------------
2840     *
2841     * RecordTracebackInfo --
2842     *
2843     *      Procedure called by Tcl_EvalObj to record information about what was
2844     *      being executed when the error occurred.
2845     *
2846     * Results:
2847     *      None.
2848     *
2849     * Side effects:
2850     *      Appends information about the script being evaluated to the
2851     *      interpreter's "errorInfo" variable.
2852     *
2853     *----------------------------------------------------------------------
2854     */
2855    
2856    static void
2857    RecordTracebackInfo(interp, objPtr, numSrcBytes)
2858        Tcl_Interp *interp;         /* The interpreter in which the error
2859                                     * occurred. */
2860        Tcl_Obj *objPtr;            /* Points to object containing script whose
2861                                     * evaluation resulted in an error. */
2862        int numSrcBytes;            /* Number of bytes compiled in script. */
2863    {
2864        Interp *iPtr = (Interp *) interp;
2865        char buf[200];
2866        char *ellipsis, *bytes;
2867        int length;
2868    
2869        /*
2870         * Decide how much of the command to print in the error message
2871         * (up to a certain number of bytes).
2872         */
2873        
2874        bytes = Tcl_GetStringFromObj(objPtr, &length);
2875        length = TclMin(numSrcBytes, length);
2876        
2877        ellipsis = "";
2878        if (length > 150) {
2879            length = 150;
2880            ellipsis = " ...";
2881        }
2882        
2883        if (!(iPtr->flags & ERR_IN_PROGRESS)) {
2884            sprintf(buf, "\n    while executing\n\"%.*s%s\"",
2885                    length, bytes, ellipsis);
2886        } else {
2887            sprintf(buf, "\n    invoked from within\n\"%.*s%s\"",
2888                    length, bytes, ellipsis);
2889        }
2890        Tcl_AddObjErrorInfo(interp, buf, -1);
2891    }
2892    
2893    /*
2894     *---------------------------------------------------------------------------
2895     *
2896     * Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean --
2897     *
2898     *      Procedures to evaluate an expression and return its value in a
2899     *      particular form.
2900     *
2901     * Results:
2902     *      Each of the procedures below returns a standard Tcl result. If an
2903     *      error occurs then an error message is left in the interp's result.
2904     *      Otherwise the value of the expression, in the appropriate form,
2905     *      is stored at *ptr. If the expression had a result that was
2906     *      incompatible with the desired form then an error is returned.
2907     *
2908     * Side effects:
2909     *      None.
2910     *
2911     *---------------------------------------------------------------------------
2912     */
2913    
2914    int
2915    Tcl_ExprLong(interp, string, ptr)
2916        Tcl_Interp *interp;         /* Context in which to evaluate the
2917                                     * expression. */
2918        char *string;               /* Expression to evaluate. */
2919        long *ptr;                  /* Where to store result. */
2920    {
2921        register Tcl_Obj *exprPtr;
2922        Tcl_Obj *resultPtr;
2923        int length = strlen(string);
2924        int result = TCL_OK;
2925    
2926        if (length > 0) {
2927            exprPtr = Tcl_NewStringObj(string, length);
2928            Tcl_IncrRefCount(exprPtr);
2929            result = Tcl_ExprObj(interp, exprPtr, &resultPtr);
2930            if (result == TCL_OK) {
2931                /*
2932                 * Store an integer based on the expression result.
2933                 */
2934                
2935                if (resultPtr->typePtr == &tclIntType) {
2936                    *ptr = resultPtr->internalRep.longValue;
2937                } else if (resultPtr->typePtr == &tclDoubleType) {
2938                    *ptr = (long) resultPtr->internalRep.doubleValue;
2939                } else {
2940                    Tcl_SetResult(interp,
2941                            "expression didn't have numeric value", TCL_STATIC);
2942                    result = TCL_ERROR;
2943                }
2944                Tcl_DecrRefCount(resultPtr);  /* discard the result object */
2945            } else {
2946                /*
2947                 * Move the interpreter's object result to the string result,
2948                 * then reset the object result.
2949                 */
2950    
2951                Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),
2952                        TCL_VOLATILE);
2953            }
2954            Tcl_DecrRefCount(exprPtr);  /* discard the expression object */
2955        } else {
2956            /*
2957             * An empty string. Just set the result integer to 0.
2958             */
2959            
2960            *ptr = 0;
2961        }
2962        return result;
2963    }
2964    
2965    int
2966    Tcl_ExprDouble(interp, string, ptr)
2967        Tcl_Interp *interp;         /* Context in which to evaluate the
2968                                     * expression. */
2969        char *string;               /* Expression to evaluate. */
2970        double *ptr;                /* Where to store result. */
2971    {
2972        register Tcl_Obj *exprPtr;
2973        Tcl_Obj *resultPtr;
2974        int length = strlen(string);
2975        int result = TCL_OK;
2976    
2977        if (length > 0) {
2978            exprPtr = Tcl_NewStringObj(string, length);
2979            Tcl_IncrRefCount(exprPtr);
2980            result = Tcl_ExprObj(interp, exprPtr, &resultPtr);
2981            if (result == TCL_OK) {
2982                /*
2983                 * Store a double  based on the expression result.
2984                 */
2985                
2986                if (resultPtr->typePtr == &tclIntType) {
2987                    *ptr = (double) resultPtr->internalRep.longValue;
2988                } else if (resultPtr->typePtr == &tclDoubleType) {
2989                    *ptr = resultPtr->internalRep.doubleValue;
2990                } else {
2991                    Tcl_SetResult(interp,
2992                            "expression didn't have numeric value", TCL_STATIC);
2993                    result = TCL_ERROR;
2994                }
2995                Tcl_DecrRefCount(resultPtr);  /* discard the result object */
2996            } else {
2997                /*
2998                 * Move the interpreter's object result to the string result,
2999                 * then reset the object result.
3000                 */
3001    
3002                Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),
3003                        TCL_VOLATILE);
3004            }
3005            Tcl_DecrRefCount(exprPtr);  /* discard the expression object */
3006        } else {
3007            /*
3008             * An empty string. Just set the result double to 0.0.
3009             */
3010            
3011            *ptr = 0.0;
3012        }
3013        return result;
3014    }
3015    
3016    int
3017    Tcl_ExprBoolean(interp, string, ptr)
3018        Tcl_Interp *interp;         /* Context in which to evaluate the
3019                                     * expression. */
3020        char *string;               /* Expression to evaluate. */
3021        int *ptr;                   /* Where to store 0/1 result. */
3022    {
3023        register Tcl_Obj *exprPtr;
3024        Tcl_Obj *resultPtr;
3025        int length = strlen(string);
3026        int result = TCL_OK;
3027    
3028        if (length > 0) {
3029            exprPtr = Tcl_NewStringObj(string, length);
3030            Tcl_IncrRefCount(exprPtr);
3031            result = Tcl_ExprObj(interp, exprPtr, &resultPtr);
3032            if (result == TCL_OK) {
3033                /*
3034                 * Store a boolean based on the expression result.
3035                 */
3036                
3037                if (resultPtr->typePtr == &tclIntType) {
3038                    *ptr = (resultPtr->internalRep.longValue != 0);
3039                } else if (resultPtr->typePtr == &tclDoubleType) {
3040                    *ptr = (resultPtr->internalRep.doubleValue != 0.0);
3041                } else {
3042                    result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr);
3043                }
3044                Tcl_DecrRefCount(resultPtr);  /* discard the result object */
3045            }
3046            if (result != TCL_OK) {
3047                /*
3048                 * Move the interpreter's object result to the string result,
3049                 * then reset the object result.
3050                 */
3051    
3052                Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),
3053                        TCL_VOLATILE);
3054            }
3055            Tcl_DecrRefCount(exprPtr); /* discard the expression object */
3056        } else {
3057            /*
3058             * An empty string. Just set the result boolean to 0 (false).
3059             */
3060            
3061            *ptr = 0;
3062        }
3063        return result;
3064    }
3065    
3066    /*
3067     *--------------------------------------------------------------
3068     *
3069     * Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj --
3070     *
3071     *      Procedures to evaluate an expression in an object and return its
3072     *      value in a particular form.
3073     *
3074     * Results:
3075     *      Each of the procedures below returns a standard Tcl result
3076     *      object. If an error occurs then an error message is left in the
3077     *      interpreter's result. Otherwise the value of the expression, in the
3078     *      appropriate form, is stored at *ptr. If the expression had a result
3079     *      that was incompatible with the desired form then an error is
3080     *      returned.
3081     *
3082     * Side effects:
3083     *      None.
3084     *
3085     *--------------------------------------------------------------
3086     */
3087    
3088    int
3089    Tcl_ExprLongObj(interp, objPtr, ptr)
3090        Tcl_Interp *interp;                 /* Context in which to evaluate the
3091                                             * expression. */
3092        register Tcl_Obj *objPtr;           /* Expression to evaluate. */
3093        long *ptr;                          /* Where to store long result. */
3094    {
3095        Tcl_Obj *resultPtr;
3096        int result;
3097    
3098        result = Tcl_ExprObj(interp, objPtr, &resultPtr);
3099        if (result == TCL_OK) {
3100            if (resultPtr->typePtr == &tclIntType) {
3101                *ptr = resultPtr->internalRep.longValue;
3102            } else if (resultPtr->typePtr == &tclDoubleType) {
3103                *ptr = (long) resultPtr->internalRep.doubleValue;
3104            } else {
3105                result = Tcl_GetLongFromObj(interp, resultPtr, ptr);
3106                if (result != TCL_OK) {
3107                    return result;
3108                }
3109            }
3110            Tcl_DecrRefCount(resultPtr);  /* discard the result object */
3111        }
3112        return result;
3113    }
3114    
3115    int
3116    Tcl_ExprDoubleObj(interp, objPtr, ptr)
3117        Tcl_Interp *interp;                 /* Context in which to evaluate the
3118                                             * expression. */
3119        register Tcl_Obj *objPtr;           /* Expression to evaluate. */
3120        double *ptr;                        /* Where to store double result. */
3121    {
3122        Tcl_Obj *resultPtr;
3123        int result;
3124    
3125        result = Tcl_ExprObj(interp, objPtr, &resultPtr);
3126        if (result == TCL_OK) {
3127            if (resultPtr->typePtr == &tclIntType) {
3128                *ptr = (double) resultPtr->internalRep.longValue;
3129            } else if (resultPtr->typePtr == &tclDoubleType) {
3130                *ptr = resultPtr->internalRep.doubleValue;
3131            } else {
3132                result = Tcl_GetDoubleFromObj(interp, resultPtr, ptr);
3133                if (result != TCL_OK) {
3134                    return result;
3135                }
3136            }
3137            Tcl_DecrRefCount(resultPtr);  /* discard the result object */
3138        }
3139        return result;
3140    }
3141    
3142    int
3143    Tcl_ExprBooleanObj(interp, objPtr, ptr)
3144        Tcl_Interp *interp;                 /* Context in which to evaluate the
3145                                             * expression. */
3146        register Tcl_Obj *objPtr;           /* Expression to evaluate. */
3147        int *ptr;                           /* Where to store 0/1 result. */
3148    {
3149        Tcl_Obj *resultPtr;
3150        int result;
3151    
3152        result = Tcl_ExprObj(interp, objPtr, &resultPtr);
3153        if (result == TCL_OK) {
3154            if (resultPtr->typePtr == &tclIntType) {
3155                *ptr = (resultPtr->internalRep.longValue != 0);
3156            } else if (resultPtr->typePtr == &tclDoubleType) {
3157                *ptr = (resultPtr->internalRep.doubleValue != 0.0);
3158            } else {
3159                result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr);
3160            }
3161            Tcl_DecrRefCount(resultPtr);  /* discard the result object */
3162        }
3163        return result;
3164    }
3165    
3166    /*
3167     *----------------------------------------------------------------------
3168     *
3169     * TclInvoke --
3170     *
3171     *      Invokes a Tcl command, given an argv/argc, from either the
3172     *      exposed or the hidden sets of commands in the given interpreter.
3173     *      NOTE: The command is invoked in the current stack frame of
3174     *      the interpreter, thus it can modify local variables.
3175     *
3176     * Results:
3177     *      A standard Tcl result.
3178     *
3179     * Side effects:
3180     *      Whatever the command does.
3181     *
3182     *----------------------------------------------------------------------
3183     */
3184    
3185    int
3186    TclInvoke(interp, argc, argv, flags)
3187        Tcl_Interp *interp;         /* Where to invoke the command. */
3188        int argc;                   /* Count of args. */
3189        register char **argv;       /* The arg strings; argv[0] is the name of
3190                                     * the command to invoke. */
3191        int flags;                  /* Combination of flags controlling the
3192                                     * call: TCL_INVOKE_HIDDEN and
3193                                     * TCL_INVOKE_NO_UNKNOWN. */
3194    {
3195        register Tcl_Obj *objPtr;
3196        register int i;
3197        int length, result;
3198    
3199        /*
3200         * This procedure generates an objv array for object arguments that hold
3201         * the argv strings. It starts out with stack-allocated space but uses
3202         * dynamically-allocated storage if needed.
3203         */
3204    
3205    #define NUM_ARGS 20
3206        Tcl_Obj *(objStorage[NUM_ARGS]);
3207        register Tcl_Obj **objv = objStorage;
3208    
3209        /*
3210         * Create the object argument array "objv". Make sure objv is large
3211         * enough to hold the objc arguments plus 1 extra for the zero
3212         * end-of-objv word.
3213         */
3214    
3215        if ((argc + 1) > NUM_ARGS) {
3216            objv = (Tcl_Obj **)
3217                ckalloc((unsigned)(argc + 1) * sizeof(Tcl_Obj *));
3218        }
3219    
3220        for (i = 0;  i < argc;  i++) {
3221            length = strlen(argv[i]);
3222            objv[i] = Tcl_NewStringObj(argv[i], length);
3223            Tcl_IncrRefCount(objv[i]);
3224        }
3225        objv[argc] = 0;
3226    
3227        /*
3228         * Use TclObjInterpProc to actually invoke the command.
3229         */
3230    
3231        result = TclObjInvoke(interp, argc, objv, flags);
3232    
3233        /*
3234         * Move the interpreter's object result to the string result,
3235         * then reset the object result.
3236         */
3237        
3238        Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),
3239                TCL_VOLATILE);
3240    
3241        /*
3242         * Decrement the ref counts on the objv elements since we are done
3243         * with them.
3244         */
3245    
3246        for (i = 0;  i < argc;  i++) {
3247            objPtr = objv[i];
3248            Tcl_DecrRefCount(objPtr);
3249        }
3250        
3251        /*
3252         * Free the objv array if malloc'ed storage was used.
3253         */
3254    
3255        if (objv != objStorage) {
3256            ckfree((char *) objv);
3257        }
3258        return result;
3259    #undef NUM_ARGS
3260    }
3261    
3262    /*
3263     *----------------------------------------------------------------------
3264     *
3265     * TclGlobalInvoke --
3266     *
3267     *      Invokes a Tcl command, given an argv/argc, from either the
3268     *      exposed or hidden sets of commands in the given interpreter.
3269     *      NOTE: The command is invoked in the global stack frame of
3270     *      the interpreter, thus it cannot see any current state on
3271     *      the stack for that interpreter.
3272     *
3273     * Results:
3274     *      A standard Tcl result.
3275     *
3276     * Side effects:
3277     *      Whatever the command does.
3278     *
3279     *----------------------------------------------------------------------
3280     */
3281    
3282    int
3283    TclGlobalInvoke(interp, argc, argv, flags)
3284        Tcl_Interp *interp;         /* Where to invoke the command. */
3285        int argc;                   /* Count of args. */
3286        register char **argv;       /* The arg strings; argv[0] is the name of
3287                                     * the command to invoke. */
3288        int flags;                  /* Combination of flags controlling the
3289                                     * call: TCL_INVOKE_HIDDEN and
3290                                     * TCL_INVOKE_NO_UNKNOWN. */
3291    {
3292        register Interp *iPtr = (Interp *) interp;
3293        int result;
3294        CallFrame *savedVarFramePtr;
3295    
3296        savedVarFramePtr = iPtr->varFramePtr;
3297        iPtr->varFramePtr = NULL;
3298        result = TclInvoke(interp, argc, argv, flags);
3299        iPtr->varFramePtr = savedVarFramePtr;
3300        return result;
3301    }
3302    
3303    /*
3304     *----------------------------------------------------------------------
3305     *
3306     * TclObjInvokeGlobal --
3307     *
3308     *      Object version: Invokes a Tcl command, given an objv/objc, from
3309     *      either the exposed or hidden set of commands in the given
3310     *      interpreter.
3311     *      NOTE: The command is invoked in the global stack frame of the
3312     *      interpreter, thus it cannot see any current state on the
3313     *      stack of that interpreter.
3314     *
3315     * Results:
3316     *      A standard Tcl result.
3317     *
3318     * Side effects:
3319     *      Whatever the command does.
3320     *
3321     *----------------------------------------------------------------------
3322     */
3323    
3324    int
3325    TclObjInvokeGlobal(interp, objc, objv, flags)
3326        Tcl_Interp *interp;         /* Interpreter in which command is to be
3327                                     * invoked. */
3328        int objc;                   /* Count of arguments. */
3329        Tcl_Obj *CONST objv[];      /* Argument objects; objv[0] points to the
3330                                     * name of the command to invoke. */
3331        int flags;                  /* Combination of flags controlling the
3332                                     * call: TCL_INVOKE_HIDDEN,
3333                                     * TCL_INVOKE_NO_UNKNOWN, or
3334                                     * TCL_INVOKE_NO_TRACEBACK. */
3335    {
3336        register Interp *iPtr = (Interp *) interp;
3337        int result;
3338        CallFrame *savedVarFramePtr;
3339    
3340        savedVarFramePtr = iPtr->varFramePtr;
3341        iPtr->varFramePtr = NULL;
3342        result = TclObjInvoke(interp, objc, objv, flags);
3343        iPtr->varFramePtr = savedVarFramePtr;
3344        return result;
3345    }
3346    
3347    /*
3348     *----------------------------------------------------------------------
3349     *
3350     * TclObjInvoke --
3351     *
3352     *      Invokes a Tcl command, given an objv/objc, from either the
3353     *      exposed or the hidden sets of commands in the given interpreter.
3354     *
3355     * Results:
3356     *      A standard Tcl object result.
3357     *
3358     * Side effects:
3359     *      Whatever the command does.
3360     *
3361     *----------------------------------------------------------------------
3362     */
3363    
3364    int
3365    TclObjInvoke(interp, objc, objv, flags)
3366        Tcl_Interp *interp;         /* Interpreter in which command is to be
3367                                     * invoked. */
3368        int objc;                   /* Count of arguments. */
3369        Tcl_Obj *CONST objv[];      /* Argument objects; objv[0] points to the
3370                                     * name of the command to invoke. */
3371        int flags;                  /* Combination of flags controlling the
3372                                     * call: TCL_INVOKE_HIDDEN,
3373                                     * TCL_INVOKE_NO_UNKNOWN, or
3374                                     * TCL_INVOKE_NO_TRACEBACK. */
3375    {
3376        register Interp *iPtr = (Interp *) interp;
3377        Tcl_HashTable *hTblPtr;     /* Table of hidden commands. */
3378        char *cmdName;              /* Name of the command from objv[0]. */
3379        register Tcl_HashEntry *hPtr;
3380        Tcl_Command cmd;
3381        Command *cmdPtr;
3382        int localObjc;              /* Used to invoke "unknown" if the */
3383        Tcl_Obj **localObjv = NULL; /* command is not found. */
3384        register int i;
3385        int length, result;
3386        char *bytes;
3387    
3388        if (interp == (Tcl_Interp *) NULL) {
3389            return TCL_ERROR;
3390        }
3391    
3392        if ((objc < 1) || (objv == (Tcl_Obj **) NULL)) {
3393            Tcl_AppendToObj(Tcl_GetObjResult(interp),
3394                    "illegal argument vector", -1);
3395            return TCL_ERROR;
3396        }
3397    
3398        cmdName = Tcl_GetString(objv[0]);
3399        if (flags & TCL_INVOKE_HIDDEN) {
3400            /*
3401             * We never invoke "unknown" for hidden commands.
3402             */
3403            
3404            hPtr = NULL;
3405            hTblPtr = ((Interp *) interp)->hiddenCmdTablePtr;
3406            if (hTblPtr != NULL) {
3407                hPtr = Tcl_FindHashEntry(hTblPtr, cmdName);
3408            }
3409            if (hPtr == NULL) {
3410                Tcl_ResetResult(interp);
3411                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
3412                         "invalid hidden command name \"", cmdName, "\"",
3413                         (char *) NULL);
3414                return TCL_ERROR;
3415            }
3416            cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
3417        } else {
3418            cmdPtr = NULL;
3419            cmd = Tcl_FindCommand(interp, cmdName,
3420                    (Tcl_Namespace *) NULL, /*flags*/ TCL_GLOBAL_ONLY);
3421            if (cmd != (Tcl_Command) NULL) {
3422                cmdPtr = (Command *) cmd;
3423            }
3424            if (cmdPtr == NULL) {
3425                if (!(flags & TCL_INVOKE_NO_UNKNOWN)) {
3426                    cmd = Tcl_FindCommand(interp, "unknown",
3427                            (Tcl_Namespace *) NULL, /*flags*/ TCL_GLOBAL_ONLY);
3428                    if (cmd != (Tcl_Command) NULL) {
3429                        cmdPtr = (Command *) cmd;
3430                    }
3431                    if (cmdPtr != NULL) {
3432                        localObjc = (objc + 1);
3433                        localObjv = (Tcl_Obj **)
3434                            ckalloc((unsigned) (sizeof(Tcl_Obj *) * localObjc));
3435                        localObjv[0] = Tcl_NewStringObj("unknown", -1);
3436                        Tcl_IncrRefCount(localObjv[0]);
3437                        for (i = 0;  i < objc;  i++) {
3438                            localObjv[i+1] = objv[i];
3439                        }
3440                        objc = localObjc;
3441                        objv = localObjv;
3442                    }
3443                }
3444    
3445                /*
3446                 * Check again if we found the command. If not, "unknown" is
3447                 * not present and we cannot help, or the caller said not to
3448                 * call "unknown" (they specified TCL_INVOKE_NO_UNKNOWN).
3449                 */
3450    
3451                if (cmdPtr == NULL) {
3452                    Tcl_ResetResult(interp);
3453                    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
3454                            "invalid command name \"",  cmdName, "\"",
3455                             (char *) NULL);
3456                    return TCL_ERROR;
3457                }
3458            }
3459        }
3460    
3461        /*
3462         * Invoke the command procedure. First reset the interpreter's string
3463         * and object results to their default empty values since they could
3464         * have gotten changed by earlier invocations.
3465         */
3466    
3467        Tcl_ResetResult(interp);
3468        iPtr->cmdCount++;
3469        result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv);
3470    
3471        /*
3472         * If an error occurred, record information about what was being
3473         * executed when the error occurred.
3474         */
3475    
3476        if ((result == TCL_ERROR)
3477                && ((flags & TCL_INVOKE_NO_TRACEBACK) == 0)
3478                && ((iPtr->flags & ERR_ALREADY_LOGGED) == 0)) {
3479            Tcl_DString ds;
3480            
3481            Tcl_DStringInit(&ds);
3482            if (!(iPtr->flags & ERR_IN_PROGRESS)) {
3483                Tcl_DStringAppend(&ds, "\n    while invoking\n\"", -1);
3484            } else {
3485                Tcl_DStringAppend(&ds, "\n    invoked from within\n\"", -1);
3486            }
3487            for (i = 0;  i < objc;  i++) {
3488                bytes = Tcl_GetStringFromObj(objv[i], &length);
3489                Tcl_DStringAppend(&ds, bytes, length);
3490                if (i < (objc - 1)) {
3491                    Tcl_DStringAppend(&ds, " ", -1);
3492                } else if (Tcl_DStringLength(&ds) > 100) {
3493                    Tcl_DStringSetLength(&ds, 100);
3494                    Tcl_DStringAppend(&ds, "...", -1);
3495                    break;
3496                }
3497            }
3498            
3499            Tcl_DStringAppend(&ds, "\"", -1);
3500            Tcl_AddObjErrorInfo(interp, Tcl_DStringValue(&ds), -1);
3501            Tcl_DStringFree(&ds);
3502            iPtr->flags &= ~ERR_ALREADY_LOGGED;
3503        }
3504    
3505        /*
3506         * Free any locally allocated storage used to call "unknown".
3507         */
3508    
3509        if (localObjv != (Tcl_Obj **) NULL) {
3510            Tcl_DecrRefCount(localObjv[0]);
3511            ckfree((char *) localObjv);
3512        }
3513        return result;
3514    }
3515    
3516    /*
3517     *---------------------------------------------------------------------------
3518     *
3519     * Tcl_ExprString --
3520     *
3521     *      Evaluate an expression in a string and return its value in string
3522     *      form.
3523     *
3524     * Results:
3525     *      A standard Tcl result. If the result is TCL_OK, then the interp's
3526     *      result is set to the string value of the expression. If the result
3527     *      is TCL_ERROR, then the interp's result contains an error message.
3528     *
3529     * Side effects:
3530     *      A Tcl object is allocated to hold a copy of the expression string.
3531     *      This expression object is passed to Tcl_ExprObj and then
3532     *      deallocated.
3533     *
3534     *---------------------------------------------------------------------------
3535     */
3536    
3537    int
3538    Tcl_ExprString(interp, string)
3539        Tcl_Interp *interp;         /* Context in which to evaluate the
3540                                     * expression. */
3541        char *string;               /* Expression to evaluate. */
3542    {
3543        register Tcl_Obj *exprPtr;
3544        Tcl_Obj *resultPtr;
3545        int length = strlen(string);
3546        char buf[TCL_DOUBLE_SPACE];
3547        int result = TCL_OK;
3548    
3549        if (length > 0) {
3550            TclNewObj(exprPtr);
3551            TclInitStringRep(exprPtr, string, length);
3552            Tcl_IncrRefCount(exprPtr);
3553    
3554            result = Tcl_ExprObj(interp, exprPtr, &resultPtr);
3555            if (result == TCL_OK) {
3556                /*
3557                 * Set the interpreter's string result from the result object.
3558                 */
3559                
3560                if (resultPtr->typePtr == &tclIntType) {
3561                    sprintf(buf, "%ld", resultPtr->internalRep.longValue);
3562                    Tcl_SetResult(interp, buf, TCL_VOLATILE);
3563                } else if (resultPtr->typePtr == &tclDoubleType) {
3564                    Tcl_PrintDouble((Tcl_Interp *) NULL,
3565                            resultPtr->internalRep.doubleValue, buf);
3566                    Tcl_SetResult(interp, buf, TCL_VOLATILE);
3567                } else {
3568                    /*
3569                     * Set interpreter's string result from the result object.
3570                     */
3571                
3572                    Tcl_SetResult(interp, TclGetString(resultPtr),
3573                            TCL_VOLATILE);
3574                }
3575                Tcl_DecrRefCount(resultPtr);  /* discard the result object */
3576            } else {
3577                /*
3578                 * Move the interpreter's object result to the string result,
3579                 * then reset the object result.
3580                 */
3581                
3582                Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),
3583                        TCL_VOLATILE);
3584            }
3585            Tcl_DecrRefCount(exprPtr); /* discard the expression object */
3586        } else {
3587            /*
3588             * An empty string. Just set the interpreter's result to 0.
3589             */
3590            
3591            Tcl_SetResult(interp, "0", TCL_VOLATILE);
3592        }
3593        return result;
3594    }
3595    
3596    /*
3597     *--------------------------------------------------------------
3598     *
3599     * Tcl_ExprObj --
3600     *
3601     *      Evaluate an expression in a Tcl_Obj.
3602     *
3603     * Results:
3604     *      A standard Tcl object result. If the result is other than TCL_OK,
3605     *      then the interpreter's result contains an error message. If the
3606     *      result is TCL_OK, then a pointer to the expression's result value
3607     *      object is stored in resultPtrPtr. In that case, the object's ref
3608     *      count is incremented to reflect the reference returned to the
3609     *      caller; the caller is then responsible for the resulting object
3610     *      and must, for example, decrement the ref count when it is finished
3611     *      with the object.
3612     *
3613     * Side effects:
3614     *      Any side effects caused by subcommands in the expression, if any.
3615     *      The interpreter result is not modified unless there is an error.
3616     *
3617     *--------------------------------------------------------------
3618     */
3619    
3620    int
3621    Tcl_ExprObj(interp, objPtr, resultPtrPtr)
3622        Tcl_Interp *interp;         /* Context in which to evaluate the
3623                                     * expression. */
3624        register Tcl_Obj *objPtr;   /* Points to Tcl object containing
3625                                     * expression to evaluate. */
3626        Tcl_Obj **resultPtrPtr;     /* Where the Tcl_Obj* that is the expression
3627                                     * result is stored if no errors occur. */
3628    {
3629        Interp *iPtr = (Interp *) interp;
3630        CompileEnv compEnv;         /* Compilation environment structure
3631                                     * allocated in frame. */
3632        LiteralTable *localTablePtr = &(compEnv.localLitTable);
3633        register ByteCode *codePtr = NULL;
3634                                    /* Tcl Internal type of bytecode.
3635                                     * Initialized to avoid compiler warning. */
3636        AuxData *auxDataPtr;
3637        LiteralEntry *entryPtr;
3638        Tcl_Obj *saveObjPtr;
3639        char *string;
3640        int length, i, result;
3641    
3642        /*
3643         * First handle some common expressions specially.
3644         */
3645    
3646        string = Tcl_GetStringFromObj(objPtr, &length);
3647        if (length == 1) {
3648            if (*string == '0') {
3649                *resultPtrPtr = Tcl_NewLongObj(0);
3650                Tcl_IncrRefCount(*resultPtrPtr);
3651                return TCL_OK;
3652            } else if (*string == '1') {
3653                *resultPtrPtr = Tcl_NewLongObj(1);
3654                Tcl_IncrRefCount(*resultPtrPtr);
3655                return TCL_OK;
3656            }
3657        } else if ((length == 2) && (*string == '!')) {
3658            if (*(string+1) == '0') {
3659                *resultPtrPtr = Tcl_NewLongObj(1);
3660                Tcl_IncrRefCount(*resultPtrPtr);
3661                return TCL_OK;
3662            } else if (*(string+1) == '1') {
3663                *resultPtrPtr = Tcl_NewLongObj(0);
3664                Tcl_IncrRefCount(*resultPtrPtr);
3665                return TCL_OK;
3666            }
3667        }
3668    
3669        /*
3670         * Get the ByteCode from the object. If it exists, make sure it hasn't
3671         * been invalidated by, e.g., someone redefining a command with a
3672         * compile procedure (this might make the compiled code wrong). If
3673         * necessary, convert the object to be a ByteCode object and compile it.
3674         * Also, if the code was compiled in/for a different interpreter, we
3675         * recompile it.
3676         *
3677         * Precompiled expressions, however, are immutable and therefore
3678         * they are not recompiled, even if the epoch has changed.
3679         *
3680         */
3681    
3682        if (objPtr->typePtr == &tclByteCodeType) {
3683            codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
3684            if (((Interp *) *codePtr->interpHandle != iPtr)
3685                    || (codePtr->compileEpoch != iPtr->compileEpoch)) {
3686                if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
3687                    if ((Interp *) *codePtr->interpHandle != iPtr) {
3688                        panic("Tcl_ExprObj: compiled expression jumped interps");
3689                    }
3690                    codePtr->compileEpoch = iPtr->compileEpoch;
3691                } else {
3692                    (*tclByteCodeType.freeIntRepProc)(objPtr);
3693                    objPtr->typePtr = (Tcl_ObjType *) NULL;
3694                }
3695            }
3696        }
3697        if (objPtr->typePtr != &tclByteCodeType) {
3698            TclInitCompileEnv(interp, &compEnv, string, length);
3699            result = TclCompileExpr(interp, string, length, &compEnv);
3700    
3701            /*
3702             * Free the compilation environment's literal table bucket array if
3703             * it was dynamically allocated.
3704             */
3705    
3706            if (localTablePtr->buckets != localTablePtr->staticBuckets) {
3707                ckfree((char *) localTablePtr->buckets);
3708            }
3709        
3710            if (result != TCL_OK) {
3711                /*
3712                 * Compilation errors. Free storage allocated for compilation.
3713                 */
3714    
3715    #ifdef TCL_COMPILE_DEBUG
3716                TclVerifyLocalLiteralTable(&compEnv);
3717    #endif /*TCL_COMPILE_DEBUG*/
3718                entryPtr = compEnv.literalArrayPtr;
3719                for (i = 0;  i < compEnv.literalArrayNext;  i++) {
3720                    TclReleaseLiteral(interp, entryPtr->objPtr);
3721                    entryPtr++;
3722                }
3723    #ifdef TCL_COMPILE_DEBUG
3724                TclVerifyGlobalLiteralTable(iPtr);
3725    #endif /*TCL_COMPILE_DEBUG*/
3726        
3727                auxDataPtr = compEnv.auxDataArrayPtr;
3728                for (i = 0;  i < compEnv.auxDataArrayNext;  i++) {
3729                    if (auxDataPtr->type->freeProc != NULL) {
3730                        auxDataPtr->type->freeProc(auxDataPtr->clientData);
3731                    }
3732                    auxDataPtr++;
3733                }
3734                TclFreeCompileEnv(&compEnv);
3735                return result;
3736            }
3737    
3738            /*
3739             * Successful compilation. If the expression yielded no
3740             * instructions, push an zero object as the expression's result.
3741             */
3742                
3743            if (compEnv.codeNext == compEnv.codeStart) {
3744                TclEmitPush(TclRegisterLiteral(&compEnv, "0", 1, /*onHeap*/ 0),
3745                        &compEnv);
3746            }
3747                
3748            /*
3749             * Add a "done" instruction as the last instruction and change the
3750             * object into a ByteCode object. Ownership of the literal objects
3751             * and aux data items is given to the ByteCode object.
3752             */
3753    
3754            compEnv.numSrcBytes = iPtr->termOffset;
3755            TclEmitOpcode(INST_DONE, &compEnv);
3756            TclInitByteCodeObj(objPtr, &compEnv);
3757            TclFreeCompileEnv(&compEnv);
3758            codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
3759    #ifdef TCL_COMPILE_DEBUG
3760            if (tclTraceCompile == 2) {
3761                TclPrintByteCodeObj(interp, objPtr);
3762            }
3763    #endif /* TCL_COMPILE_DEBUG */
3764        }
3765    
3766        /*
3767         * Execute the expression after first saving the interpreter's result.
3768         */
3769        
3770        saveObjPtr = Tcl_GetObjResult(interp);
3771        Tcl_IncrRefCount(saveObjPtr);
3772        Tcl_ResetResult(interp);
3773    
3774        /*
3775         * Increment the code's ref count while it is being executed. If
3776         * afterwards no references to it remain, free the code.
3777         */
3778        
3779        codePtr->refCount++;
3780        result = TclExecuteByteCode(interp, codePtr);
3781        codePtr->refCount--;
3782        if (codePtr->refCount <= 0) {
3783            TclCleanupByteCode(codePtr);
3784            objPtr->typePtr = NULL;
3785            objPtr->internalRep.otherValuePtr = NULL;
3786        }
3787        
3788        /*
3789         * If the expression evaluated successfully, store a pointer to its
3790         * value object in resultPtrPtr then restore the old interpreter result.
3791         * We increment the object's ref count to reflect the reference that we
3792         * are returning to the caller. We also decrement the ref count of the
3793         * interpreter's result object after calling Tcl_SetResult since we
3794         * next store into that field directly.
3795         */
3796        
3797        if (result == TCL_OK) {
3798            *resultPtrPtr = iPtr->objResultPtr;
3799            Tcl_IncrRefCount(iPtr->objResultPtr);
3800            
3801            Tcl_SetObjResult(interp, saveObjPtr);
3802        }
3803        Tcl_DecrRefCount(saveObjPtr);
3804        return result;
3805    }
3806    
3807    /*
3808     *----------------------------------------------------------------------
3809     *
3810     * Tcl_CreateTrace --
3811     *
3812     *      Arrange for a procedure to be called to trace command execution.
3813     *
3814     * Results:
3815     *      The return value is a token for the trace, which may be passed
3816     *      to Tcl_DeleteTrace to eliminate the trace.
3817     *
3818     * Side effects:
3819     *      From now on, proc will be called just before a command procedure
3820     *      is called to execute a Tcl command.  Calls to proc will have the
3821     *      following form:
3822     *
3823     *      void
3824     *      proc(clientData, interp, level, command, cmdProc, cmdClientData,
3825     *              argc, argv)
3826     *          ClientData clientData;
3827     *          Tcl_Interp *interp;
3828     *          int level;
3829     *          char *command;
3830     *          int (*cmdProc)();
3831     *          ClientData cmdClientData;
3832     *          int argc;
3833     *          char **argv;
3834     *      {
3835     *      }
3836     *
3837     *      The clientData and interp arguments to proc will be the same
3838     *      as the corresponding arguments to this procedure.  Level gives
3839     *      the nesting level of command interpretation for this interpreter
3840     *      (0 corresponds to top level).  Command gives the ASCII text of
3841     *      the raw command, cmdProc and cmdClientData give the procedure that
3842     *      will be called to process the command and the ClientData value it
3843     *      will receive, and argc and argv give the arguments to the
3844     *      command, after any argument parsing and substitution.  Proc
3845     *      does not return a value.
3846     *
3847     *----------------------------------------------------------------------
3848     */
3849    
3850    Tcl_Trace
3851    Tcl_CreateTrace(interp, level, proc, clientData)
3852        Tcl_Interp *interp;         /* Interpreter in which to create trace. */
3853        int level;                  /* Only call proc for commands at nesting
3854                                     * level<=argument level (1=>top level). */
3855        Tcl_CmdTraceProc *proc;     /* Procedure to call before executing each
3856                                     * command. */
3857        ClientData clientData;      /* Arbitrary value word to pass to proc. */
3858    {
3859        register Trace *tracePtr;
3860        register Interp *iPtr = (Interp *) interp;
3861    
3862        /*
3863         * Invalidate existing compiled code for this interpreter and arrange
3864         * (by setting the DONT_COMPILE_CMDS_INLINE flag) that when compiling
3865         * new code, no commands will be compiled inline (i.e., into an inline
3866         * sequence of instructions). We do this because commands that were
3867         * compiled inline will never result in a command trace being called.
3868         */
3869    
3870        iPtr->compileEpoch++;
3871        iPtr->flags |= DONT_COMPILE_CMDS_INLINE;
3872    
3873        tracePtr = (Trace *) ckalloc(sizeof(Trace));
3874        tracePtr->level = level;
3875        tracePtr->proc = proc;
3876        tracePtr->clientData = clientData;
3877        tracePtr->nextPtr = iPtr->tracePtr;
3878        iPtr->tracePtr = tracePtr;
3879    
3880        return (Tcl_Trace) tracePtr;
3881    }
3882    
3883    /*
3884     *----------------------------------------------------------------------
3885     *
3886     * Tcl_DeleteTrace --
3887     *
3888     *      Remove a trace.
3889     *
3890     * Results:
3891     *      None.
3892     *
3893     * Side effects:
3894     *      From now on there will be no more calls to the procedure given
3895     *      in trace.
3896     *
3897     *----------------------------------------------------------------------
3898     */
3899    
3900    void
3901    Tcl_DeleteTrace(interp, trace)
3902        Tcl_Interp *interp;         /* Interpreter that contains trace. */
3903        Tcl_Trace trace;            /* Token for trace (returned previously by
3904                                     * Tcl_CreateTrace). */
3905    {
3906        register Interp *iPtr = (Interp *) interp;
3907        register Trace *tracePtr = (Trace *) trace;
3908        register Trace *tracePtr2;
3909    
3910        if (iPtr->tracePtr == tracePtr) {
3911            iPtr->tracePtr = tracePtr->nextPtr;
3912            ckfree((char *) tracePtr);
3913        } else {
3914            for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
3915                    tracePtr2 = tracePtr2->nextPtr) {
3916                if (tracePtr2->nextPtr == tracePtr) {
3917                    tracePtr2->nextPtr = tracePtr->nextPtr;
3918                    ckfree((char *) tracePtr);
3919                    break;
3920                }
3921            }
3922        }
3923    
3924        if (iPtr->tracePtr == NULL) {
3925            /*
3926             * When compiling new code, allow commands to be compiled inline.
3927             */
3928    
3929            iPtr->flags &= ~DONT_COMPILE_CMDS_INLINE;
3930        }
3931    }
3932    
3933    /*
3934     *----------------------------------------------------------------------
3935     *
3936     * Tcl_AddErrorInfo --
3937     *
3938     *      Add information to the "errorInfo" variable that describes the
3939     *      current error.
3940     *
3941     * Results:
3942     *      None.
3943     *
3944     * Side effects:
3945     *      The contents of message are added to the "errorInfo" variable.
3946     *      If Tcl_Eval has been called since the current value of errorInfo
3947     *      was set, errorInfo is cleared before adding the new message.
3948     *      If we are just starting to log an error, errorInfo is initialized
3949     *      from the error message in the interpreter's result.
3950     *
3951     *----------------------------------------------------------------------
3952     */
3953    
3954    void
3955    Tcl_AddErrorInfo(interp, message)
3956        Tcl_Interp *interp;         /* Interpreter to which error information
3957                                     * pertains. */
3958        CONST char *message;        /* Message to record. */
3959    {
3960        Tcl_AddObjErrorInfo(interp, message, -1);
3961    }
3962    
3963    /*
3964     *----------------------------------------------------------------------
3965     *
3966     * Tcl_AddObjErrorInfo --
3967     *
3968     *      Add information to the "errorInfo" variable that describes the
3969     *      current error. This routine differs from Tcl_AddErrorInfo by
3970     *      taking a byte pointer and length.
3971     *
3972     * Results:
3973     *      None.
3974     *
3975     * Side effects:
3976     *      "length" bytes from "message" are added to the "errorInfo" variable.
3977     *      If "length" is negative, use bytes up to the first NULL byte.
3978     *      If Tcl_EvalObj has been called since the current value of errorInfo
3979     *      was set, errorInfo is cleared before adding the new message.
3980     *      If we are just starting to log an error, errorInfo is initialized
3981     *      from the error message in the interpreter's result.
3982     *
3983     *----------------------------------------------------------------------
3984     */
3985    
3986    void
3987    Tcl_AddObjErrorInfo(interp, message, length)
3988        Tcl_Interp *interp;         /* Interpreter to which error information
3989                                     * pertains. */
3990        CONST char *message;        /* Points to the first byte of an array of
3991                                     * bytes of the message. */
3992        int length;                 /* The number of bytes in the message.
3993                                     * If < 0, then append all bytes up to a
3994                                     * NULL byte. */
3995    {
3996        register Interp *iPtr = (Interp *) interp;
3997        Tcl_Obj *messagePtr;
3998        
3999        /*
4000         * If we are just starting to log an error, errorInfo is initialized
4001         * from the error message in the interpreter's result.
4002         */
4003    
4004        if (!(iPtr->flags & ERR_IN_PROGRESS)) { /* just starting to log error */
4005            iPtr->flags |= ERR_IN_PROGRESS;
4006    
4007            if (iPtr->result[0] == 0) {
4008                (void) Tcl_SetVar2Ex(interp, "errorInfo", NULL, iPtr->objResultPtr,
4009                        TCL_GLOBAL_ONLY);
4010            } else {                /* use the string result */
4011                Tcl_SetVar2(interp, "errorInfo", (char *) NULL, interp->result,
4012                        TCL_GLOBAL_ONLY);
4013            }
4014    
4015            /*
4016             * If the errorCode variable wasn't set by the code that generated
4017             * the error, set it to "NONE".
4018             */
4019    
4020            if (!(iPtr->flags & ERROR_CODE_SET)) {
4021                (void) Tcl_SetVar2(interp, "errorCode", (char *) NULL, "NONE",
4022                        TCL_GLOBAL_ONLY);
4023            }
4024        }
4025    
4026        /*
4027         * Now append "message" to the end of errorInfo.
4028         */
4029    
4030        if (length != 0) {
4031            messagePtr = Tcl_NewStringObj(message, length);
4032            Tcl_IncrRefCount(messagePtr);
4033            Tcl_SetVar2Ex(interp, "errorInfo", NULL, messagePtr,
4034                    (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE));
4035            Tcl_DecrRefCount(messagePtr); /* free msg object appended above */
4036        }
4037    }
4038    
4039    /*
4040     *---------------------------------------------------------------------------
4041     *
4042     * Tcl_VarEvalVA --
4043     *
4044     *      Given a variable number of string arguments, concatenate them
4045     *      all together and execute the result as a Tcl command.
4046     *
4047     * Results:
4048     *      A standard Tcl return result.  An error message or other result may
4049     *      be left in the interp's result.
4050     *
4051     * Side effects:
4052     *      Depends on what was done by the command.
4053     *
4054     *---------------------------------------------------------------------------
4055     */
4056    
4057    int
4058    Tcl_VarEvalVA (interp, argList)
4059        Tcl_Interp *interp;         /* Interpreter in which to evaluate command. */
4060        va_list argList;            /* Variable argument list. */
4061    {
4062        Tcl_DString buf;
4063        char *string;
4064        int result;
4065    
4066        /*
4067         * Copy the strings one after the other into a single larger
4068         * string.  Use stack-allocated space for small commands, but if
4069         * the command gets too large than call ckalloc to create the
4070         * space.
4071         */
4072    
4073        Tcl_DStringInit(&buf);
4074        while (1) {
4075            string = va_arg(argList, char *);
4076            if (string == NULL) {
4077                break;
4078            }
4079            Tcl_DStringAppend(&buf, string, -1);
4080        }
4081    
4082        result = Tcl_Eval(interp, Tcl_DStringValue(&buf));
4083        Tcl_DStringFree(&buf);
4084        return result;
4085    }
4086    
4087    /*
4088     *----------------------------------------------------------------------
4089     *
4090     * Tcl_VarEval --
4091     *
4092     *      Given a variable number of string arguments, concatenate them
4093     *      all together and execute the result as a Tcl command.
4094     *
4095     * Results:
4096     *      A standard Tcl return result.  An error message or other
4097     *      result may be left in interp->result.
4098     *
4099     * Side effects:
4100     *      Depends on what was done by the command.
4101     *
4102     *----------------------------------------------------------------------
4103     */
4104            /* VARARGS2 */ /* ARGSUSED */
4105    int
4106    Tcl_VarEval TCL_VARARGS_DEF(Tcl_Interp *,arg1)
4107    {
4108        Tcl_Interp *interp;
4109        va_list argList;
4110        int result;
4111    
4112        interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
4113        result = Tcl_VarEvalVA(interp, argList);
4114        va_end(argList);
4115    
4116        return result;
4117    }
4118    
4119    /*
4120     *---------------------------------------------------------------------------
4121     *
4122     * Tcl_GlobalEval --
4123     *
4124     *      Evaluate a command at global level in an interpreter.
4125     *
4126     * Results:
4127     *      A standard Tcl result is returned, and the interp's result is
4128     *      modified accordingly.
4129     *
4130     * Side effects:
4131     *      The command string is executed in interp, and the execution
4132     *      is carried out in the variable context of global level (no
4133     *      procedures active), just as if an "uplevel #0" command were
4134     *      being executed.
4135     *
4136     ---------------------------------------------------------------------------
4137     */
4138    
4139    int
4140    Tcl_GlobalEval(interp, command)
4141        Tcl_Interp *interp;         /* Interpreter in which to evaluate command. */
4142        char *command;              /* Command to evaluate. */
4143    {
4144        register Interp *iPtr = (Interp *) interp;
4145        int result;
4146        CallFrame *savedVarFramePtr;
4147    
4148        savedVarFramePtr = iPtr->varFramePtr;
4149        iPtr->varFramePtr = NULL;
4150        result = Tcl_Eval(interp, command);
4151        iPtr->varFramePtr = savedVarFramePtr;
4152        return result;
4153    }
4154    
4155    /*
4156     *----------------------------------------------------------------------
4157     *
4158     * Tcl_SetRecursionLimit --
4159     *
4160     *      Set the maximum number of recursive calls that may be active
4161     *      for an interpreter at once.
4162     *
4163     * Results:
4164     *      The return value is the old limit on nesting for interp.
4165     *
4166     * Side effects:
4167     *      None.
4168     *
4169     *----------------------------------------------------------------------
4170     */
4171    
4172    int
4173    Tcl_SetRecursionLimit(interp, depth)
4174        Tcl_Interp *interp;                 /* Interpreter whose nesting limit
4175                                             * is to be set. */
4176        int depth;                          /* New value for maximimum depth. */
4177    {
4178        Interp *iPtr = (Interp *) interp;
4179        int old;
4180    
4181        old = iPtr->maxNestingDepth;
4182        if (depth > 0) {
4183            iPtr->maxNestingDepth = depth;
4184        }
4185        return old;
4186    }
4187    
4188    /*
4189     *----------------------------------------------------------------------
4190     *
4191     * Tcl_AllowExceptions --
4192     *
4193     *      Sets a flag in an interpreter so that exceptions can occur
4194     *      in the next call to Tcl_Eval without them being turned into
4195     *      errors.
4196     *
4197     * Results:
4198     *      None.
4199     *
4200     * Side effects:
4201     *      The TCL_ALLOW_EXCEPTIONS flag gets set in the interpreter's
4202     *      evalFlags structure.  See the reference documentation for
4203     *      more details.
4204     *
4205     *----------------------------------------------------------------------
4206     */
4207    
4208    void
4209    Tcl_AllowExceptions(interp)
4210        Tcl_Interp *interp;         /* Interpreter in which to set flag. */
4211    {
4212        Interp *iPtr = (Interp *) interp;
4213    
4214        iPtr->evalFlags |= TCL_ALLOW_EXCEPTIONS;
4215    }
4216    
4217    
4218    /*
4219     *----------------------------------------------------------------------
4220     *
4221     * Tcl_GetVersion
4222     *
4223     *      Get the Tcl major, minor, and patchlevel version numbers and
4224     *      the release type.  A patch is a release type TCL_FINAL_RELEASE
4225     *      with a patchLevel > 0.
4226     *
4227     * Results:
4228     *      None.
4229     *
4230     * Side effects:
4231     *      None.
4232     *
4233     *----------------------------------------------------------------------
4234     */
4235    
4236    void Tcl_GetVersion(majorV, minorV, patchLevelV, type)
4237        int *majorV;
4238        int *minorV;
4239        int *patchLevelV;
4240        int *type;
4241    {
4242        if (majorV != NULL) {
4243            *majorV = TCL_MAJOR_VERSION;
4244        }
4245        if (minorV != NULL) {
4246            *minorV = TCL_MINOR_VERSION;
4247        }
4248        if (patchLevelV != NULL) {
4249            *patchLevelV = TCL_RELEASE_SERIAL;
4250        }
4251        if (type != NULL) {
4252            *type = TCL_RELEASE_LEVEL;
4253        }
4254    }
4255    
4256    /* End of tclbasic.c */

Legend:
Removed from v.42  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25