tclbasic.c
来自「tcl是工具命令语言」· C语言 代码 · 共 2,069 行 · 第 1/5 页
C
2,069 行
*/ 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->flags = 0; cmdPtr->importRefPtr = NULL; cmdPtr->tracePtr = 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. * *---------------------------------------------------------------------- */intTclInvokeStringCommand(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 CONST char *(argStorage[NUM_ARGS]); CONST 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 = (CONST 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. * *---------------------------------------------------------------------- */intTclInvokeObjectCommand(clientData, interp, argc, argv) ClientData clientData; /* Points to command's Command structure. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ register CONST 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. * *---------------------------------------------------------------------- */intTclRenameCommand(interp, oldName, newName) Tcl_Interp *interp; /* Current interpreter. */ char *oldName; /* Existing command name. */ char *newName; /* New command name. */{ Interp *iPtr = (Interp *) interp; CONST char *newTail; Namespace *cmdNsPtr, *newNsPtr, *dummy1, *dummy2; Tcl_Command cmd; Command *cmdPtr; Tcl_HashEntry *hPtr, *oldHPtr; int new, result; Tcl_Obj* oldFullName; Tcl_DString newFullName; /* * 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; oldFullName = Tcl_NewObj(); Tcl_IncrRefCount( oldFullName ); Tcl_GetCommandFullName( interp, cmd, oldFullName ); /* * 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); result = TCL_OK; goto done; } /* * 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); result = TCL_ERROR; goto done; } if (Tcl_FindHashEntry(&newNsPtr->cmdTable, newTail) != NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't rename to \"", newName, "\": command already exists", (char *) NULL); result = TCL_ERROR; goto done; } /* * 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; goto done; } /* * Script for rename traces can delete the command "oldName". * Therefore increment the reference count for cmdPtr so that * it's Command structure is freed only towards the end of this * function by calling TclCleanupCommand. * * The trace procedure needs to get a fully qualified name for * old and new commands [Tcl bug #651271], or else there's no way * for the trace procedure to get the namespace from which the old * command is being renamed! */ Tcl_DStringInit( &newFullName ); Tcl_DStringAppend( &newFullName, newNsPtr->fullName, -1 ); if ( newNsPtr != iPtr->globalNsPtr ) { Tcl_DStringAppend( &newFullName, "::", 2 ); } Tcl_DStringAppend( &newFullName, newTail, -1 ); cmdPtr->refCount++; CallCommandTraces( iPtr, cmdPtr, Tcl_GetString( oldFullName ), Tcl_DStringValue( &newFullName ), TCL_TRACE_RENAME); Tcl_DStringFree( &newFullName ); /* * 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++; } /* * Now free the Command structure, if the "oldName" command has * been deleted by invocation of rename traces. */ TclCleanupCommand(cmdPtr); result = TCL_OK; done: TclDecrRefCount( oldFullName ); return result;}/* *----------------------------------------------------------------------
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?