📄 tclbasic.c
字号:
/* * 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 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tclBasic.c 1.12 98/08/10 17:21:31 */#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 HiddenCmdsDeleteProc _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp));/* * 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_BreakCmd, (Tcl_ObjCmdProc *) NULL, 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_ContinueCmd, (Tcl_ObjCmdProc *) NULL, TclCompileContinueCmd, 1}, {"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_FileEventCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 1}, {"for", Tcl_ForCmd, (Tcl_ObjCmdProc *) NULL, 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_IfCmd, (Tcl_ObjCmdProc *) NULL, TclCompileIfCmd, 1}, {"incr", Tcl_IncrCmd, (Tcl_ObjCmdProc *) NULL, TclCompileIncrCmd, 1}, {"info", (Tcl_CmdProc *) NULL, Tcl_InfoObjCmd, (CompileProc *) NULL, 1}, {"interp", (Tcl_CmdProc *) NULL, Tcl_InterpObjCmd, (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_LoadCmd, (Tcl_ObjCmdProc *) NULL, (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_PackageCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 1}, {"proc", (Tcl_CmdProc *) NULL, Tcl_ProcObjCmd, (CompileProc *) NULL, 1}, {"regexp", Tcl_RegexpCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 1}, {"regsub", Tcl_RegsubCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 1}, {"rename", (Tcl_CmdProc *) NULL, Tcl_RenameObjCmd, (CompileProc *) NULL, 1}, {"return", (Tcl_CmdProc *) NULL, Tcl_ReturnObjCmd, (CompileProc *) NULL, 1}, {"scan", Tcl_ScanCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 1}, {"set", Tcl_SetCmd, (Tcl_ObjCmdProc *) NULL, TclCompileSetCmd, 1}, {"split", (Tcl_CmdProc *) NULL, Tcl_SplitObjCmd, (CompileProc *) NULL, 1}, {"string", (Tcl_CmdProc *) NULL, Tcl_StringObjCmd, (CompileProc *) NULL, 1}, {"subst", Tcl_SubstCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 1}, {"switch", (Tcl_CmdProc *) NULL, Tcl_SwitchObjCmd, (CompileProc *) NULL, 1}, {"trace", Tcl_TraceCmd, (Tcl_ObjCmdProc *) NULL, (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_WhileCmd, (Tcl_ObjCmdProc *) NULL, 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_FconfigureCmd, (Tcl_ObjCmdProc *) NULL, (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_GlobCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 0}, {"open", Tcl_OpenCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 0}, {"pid", (Tcl_CmdProc *) NULL, Tcl_PidObjCmd, (CompileProc *) NULL, 1}, {"puts", (Tcl_CmdProc *) NULL, Tcl_PutsObjCmd, (CompileProc *) NULL, 1}, {"pwd", Tcl_PwdCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 0}, {"read", (Tcl_CmdProc *) NULL, Tcl_ReadObjCmd, (CompileProc *) NULL, 1}, {"seek", Tcl_SeekCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 1}, {"socket", Tcl_SocketCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 0}, {"tell", Tcl_TellCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 1}, {"time", (Tcl_CmdProc *) NULL, Tcl_TimeObjCmd, (CompileProc *) NULL, 1}, {"update", Tcl_UpdateCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 1}, {"vwait", Tcl_VwaitCmd, (Tcl_ObjCmdProc *) NULL, (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_LsCmd, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 0}, {"resource", (Tcl_CmdProc *) NULL, Tcl_ResourceObjCmd, (CompileProc *) NULL, 1}, {"source", (Tcl_CmdProc *) NULL, Tcl_MacSourceObjCmd, (CompileProc *) NULL, 0},#else {"exec", Tcl_ExecCmd, (Tcl_ObjCmdProc *) NULL, (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(){ register Interp *iPtr; register Command *cmdPtr; register CmdInfo *cmdInfoPtr; union { char c[sizeof(short)]; short s; } order; int i; /* * 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. */ TclInitNamespaces(); iPtr = (Interp *) ckalloc(sizeof(Interp)); iPtr->result = iPtr->resultSpace; iPtr->freeProc = 0; iPtr->objResultPtr = Tcl_NewObj(); /* an empty object */ Tcl_IncrRefCount(iPtr->objResultPtr); iPtr->errorLine = 0; 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; for (i = 0; i < NUM_REGEXPS; i++) { iPtr->patterns[i] = NULL; iPtr->patLengths[i] = -1; iPtr->regexps[i] = NULL; } Tcl_InitHashTable(&iPtr->packageTable, TCL_STRING_KEYS); iPtr->packageUnknown = NULL; iPtr->cmdCount = 0; iPtr->termOffset = 0; 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( (Tcl_Interp *) iPtr, "", (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL); if (iPtr->globalNsPtr == NULL) { panic("Tcl_CreateInterp: can't create global namespace"); } /* * Initialize support for code compilation. Do this after initializing * namespaces since TclCreateExecEnv will try to reference a Tcl * variable (it links to the Tcl "tcl_traceExec" variable). */ iPtr->execEnvPtr = TclCreateExecEnv((Tcl_Interp *) iPtr); /* * 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); } } /* * Initialize/Create "errorInfo" and "errorCode" global vars * (because some part of the C code assume they exists * and we can get a seg fault otherwise (in multiple * interps loading of extensions for instance) --dl) */ /* * We can't assume that because we initialize * the variables here, they won't be unset later. * so we had 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 choosed 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 */ /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -