tclbasic.c

来自「tcl是工具命令语言」· C语言 代码 · 共 2,069 行 · 第 1/5 页

C
2,069
字号
ClientDataTcl_GetAssocData(interp, name, procPtr)    Tcl_Interp *interp;			/* Interpreter associated with. */    CONST 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. * *---------------------------------------------------------------------- */intTcl_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. * *---------------------------------------------------------------------- */voidTcl_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 voidDeleteInterpProc(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) {	Tcl_DeleteTrace((Tcl_Interp*) iPtr, (Tcl_Trace) iPtr->tracePtr);    }    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. * *--------------------------------------------------------------------------- */intTcl_HideCommand(interp, cmdName, hiddenCmdToken)    Tcl_Interp *interp;		/* Interpreter in which to hide command. */    CONST char *cmdName;	/* Name of command to hide. */    CONST 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++;    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?