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 + -
显示快捷键?