tclvar.c

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

C
1,908
字号
		if (flags & TCL_LEAVE_ERR_MSG) {		    part1 = TclGetString(part1Ptr);		    VarErrMsg(interp, part1, part2, msg, needArray);		}		return NULL;	    }	    part2 = (char *) part1Ptr->internalRep.twoPtrValue.ptr2;	    part1Ptr = (Tcl_Obj *) part1Ptr->internalRep.twoPtrValue.ptr1;	    typePtr = part1Ptr->typePtr;	}	parsed = 1;    }    part1 = Tcl_GetStringFromObj(part1Ptr, &len1);        nsPtr = ((varFramePtr == NULL)? iPtr->globalNsPtr : varFramePtr->nsPtr);    if (nsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) {	goto doParse;    }        if (typePtr == &tclLocalVarNameType) {	Proc *procPtr = (Proc *) part1Ptr->internalRep.twoPtrValue.ptr1;	int localIndex = (int) part1Ptr->internalRep.twoPtrValue.ptr2;	int useLocal;	useLocal = ((varFramePtr != NULL) && varFramePtr->isProcCallFrame	        && !(flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)));	if (useLocal && (procPtr == varFramePtr->procPtr)) {	    /*	     * part1Ptr points to an indexed local variable of the	     * correct procedure: use the cached value.	     */	    	    varPtr = &(varFramePtr->compiledLocals[localIndex]);	    goto donePart1;	}	goto doneParsing;    } else if (typePtr == &tclNsVarNameType) {	Namespace *cachedNsPtr;	int useGlobal, useReference;	varPtr = (Var *) part1Ptr->internalRep.twoPtrValue.ptr2;	cachedNsPtr = (Namespace *) part1Ptr->internalRep.twoPtrValue.ptr1;	useGlobal = (cachedNsPtr == iPtr->globalNsPtr) 	    && ((flags & TCL_GLOBAL_ONLY) 		|| ((*part1 == ':') && (*(part1+1) == ':'))		|| (varFramePtr == NULL) 		|| (!varFramePtr->isProcCallFrame 		    && (nsPtr == iPtr->globalNsPtr)));	useReference = useGlobal || ((cachedNsPtr == nsPtr) 	        && ((flags & TCL_NAMESPACE_ONLY) 		    || (varFramePtr && !varFramePtr->isProcCallFrame 			&& !(flags & TCL_GLOBAL_ONLY)			/* careful: an undefined ns variable could			 * be hiding a valid global reference. */			&& !(varPtr->flags & VAR_UNDEFINED))));	if (useReference && (varPtr->hPtr != NULL)) {	    /*	     * A straight global or namespace reference, use it. It isn't 	     * so simple to deal with 'implicit' namespace references, i.e., 	     * those where the reference could be to either a namespace 	     * or a global variable. Those we lookup again.	     *	     * If (varPtr->hPtr == NULL), this might be a reference to a	     * variable in a deleted namespace, kept alive by e.g. part1Ptr.	     * We could conceivably be so unlucky that a new namespace was	     * created at the same address as the deleted one, so to be 	     * safe we test for a valid hPtr.	     */	    goto donePart1;	}	goto doneParsing;    }    doParse:    if (!parsed && (*(part1 + len1 - 1) == ')')) {	/*	 * part1Ptr is possibly an unparsed array element.	 */	register int i;	char *newPart2;	len2 = -1;	for (i = 0; i < len1; i++) {	    if (*(part1 + i) == '(') {		if (part2 != NULL) {		    if (flags & TCL_LEAVE_ERR_MSG) {			VarErrMsg(interp, part1, part2, msg, needArray);		    }		}					/*		 * part1Ptr points to an array element; first copy 		 * the element name to a new string part2.		 */		part2 = part1 + i + 1;		len2 = len1 - i - 2;		len1 = i;		newPart2 = ckalloc((unsigned int) (len2+1));		memcpy(newPart2, part2, (unsigned int) len2);		*(newPart2+len2) = '\0';		part2 = newPart2;		/*		 * Free the internal rep of the original part1Ptr, now		 * renamed objPtr, and set it to tclParsedVarNameType.		 */		objPtr = part1Ptr;		if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {		    typePtr->freeIntRepProc(objPtr);		}		objPtr->typePtr = &tclParsedVarNameType;		/*		 * Define a new string object to hold the new part1Ptr, i.e., 		 * the array name. Set the internal rep of objPtr, reset		 * typePtr and part1 to contain the references to the		 * array name.		 */		part1Ptr = Tcl_NewStringObj(part1, len1);		Tcl_IncrRefCount(part1Ptr);		objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) part1Ptr;		objPtr->internalRep.twoPtrValue.ptr2 = (VOID *) part2;				typePtr = part1Ptr->typePtr;		part1 = TclGetString(part1Ptr);		break;	    }	}    }        doneParsing:    /*     * part1Ptr is not an array element; look it up, and convert      * it to one of the cached types if possible.     */    if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {	typePtr->freeIntRepProc(part1Ptr);	part1Ptr->typePtr = NULL;    }    varPtr = TclLookupSimpleVar(interp, part1, flags,             createPart1, &errMsg, &index);    if (varPtr == NULL) {	if ((errMsg != NULL) && (flags & TCL_LEAVE_ERR_MSG)) {	    VarErrMsg(interp, part1, part2, msg, errMsg);	}	return NULL;    }    /*     * Cache the newly found variable if possible.     */    if (index >= 0) {        /*	 * An indexed local variable.	 */	Proc *procPtr = ((Interp *) interp)->varFramePtr->procPtr;	part1Ptr->typePtr = &tclLocalVarNameType;	procPtr->refCount++;	part1Ptr->internalRep.twoPtrValue.ptr1 = (VOID *) procPtr;	part1Ptr->internalRep.twoPtrValue.ptr2 = (VOID *) index;    } else if (index > -3) {	Namespace *nsPtr;    	nsPtr = ((index == -1)? iPtr->globalNsPtr : varFramePtr->nsPtr);	varPtr->refCount++;	part1Ptr->typePtr = &tclNsVarNameType;	part1Ptr->internalRep.twoPtrValue.ptr1 = (VOID *) nsPtr;	part1Ptr->internalRep.twoPtrValue.ptr2 = (VOID *) varPtr;    } else {	/*	 * At least mark part1Ptr as already parsed.	 */	part1Ptr->typePtr = &tclParsedVarNameType;	part1Ptr->internalRep.twoPtrValue.ptr1 = NULL;	part1Ptr->internalRep.twoPtrValue.ptr2 = NULL;    }        donePart1:#if 0    if (varPtr == NULL) {	if (flags & TCL_LEAVE_ERR_MSG) {	    part1 = TclGetString(part1Ptr);	    VarErrMsg(interp, part1, part2, msg, 		    "Cached variable reference is NULL.");	}	return NULL;    }#endif    while (TclIsVarLink(varPtr)) {	varPtr = varPtr->value.linkPtr;    }    if (part2 != NULL) {	/*	 * Array element sought: look it up.	 */	part1 = TclGetString(part1Ptr);	*arrayPtrPtr = varPtr;	varPtr = TclLookupArrayElement(interp, part1, part2,                 flags, msg, createPart1, createPart2, varPtr);    }    return varPtr;}/* *---------------------------------------------------------------------- * * TclLookupSimpleVar -- * *	This procedure is used by to locate a simple variable (i.e., not *      an array element) given its name. * * Results: *	The return value is a pointer to the variable structure indicated by *	varName, or NULL if the variable couldn't be found. If the variable  *      can't be found and create is 1, a new as-yet-undefined (VAR_UNDEFINED)  *      variable structure is created, entered into a hash table, and returned. * *      If the current CallFrame corresponds to a proc and the variable found is *      one of the compiledLocals, its index is placed in *indexPtr. Otherwise, *      *indexPtr will be set to (according to the needs of TclObjLookupVar): *               -1 a global reference *               -2 a reference to a namespace variable *               -3 a non-cachable reference, i.e., one of: *                    . non-indexed local var *                    . a reference of unknown origin; *                    . resolution by a namespace or interp resolver * *	If the variable isn't found and creation wasn't specified, or some *	other error occurs, NULL is returned and the corresponding error *	message is left in *errMsgPtr.  * *	Note: it's possible for the variable returned to be VAR_UNDEFINED *	even if create is 1 (this only causes the hash table entry to be *	created).  For example, the variable might be a global that has been *	unset but is still referenced by a procedure, or a variable that has *	been unset but it only being kept in existence (if VAR_UNDEFINED) by *	a trace. * * Side effects: *	A new hashtable entry may be created if create is 1. * *---------------------------------------------------------------------- */Var *TclLookupSimpleVar(interp, varName, flags, create, errMsgPtr, indexPtr)    Tcl_Interp *interp;		/* Interpreter to use for lookup. */    CONST char *varName;        /* This is a simple variable name that could				 * representa scalar or an array. */    int flags;		        /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,				 * and TCL_LEAVE_ERR_MSG bits matter. */    CONST int create;		/* If 1, create hash table entry for varname,				 * if it doesn't already exist. If 0, return 				 * error if it doesn't exist. */    CONST char **errMsgPtr;    int *indexPtr;{        Interp *iPtr = (Interp *) interp;    CallFrame *varFramePtr = iPtr->varFramePtr;				/* Points to the procedure call frame whose				 * variables are currently in use. Same as				 * the current procedure's frame, if any,				 * unless an "uplevel" is executing. */    Tcl_HashTable *tablePtr;	/* Points to the hashtable, if any, in which				 * to look up the variable. */    Tcl_Var var;                /* Used to search for global names. */    Var *varPtr;		/* Points to the Var structure returned for				 * the variable. */    Namespace *varNsPtr, *cxtNsPtr, *dummy1Ptr, *dummy2Ptr;    ResolverScheme *resPtr;    Tcl_HashEntry *hPtr;    int new, i, result;    varPtr = NULL;    varNsPtr = NULL;		/* set non-NULL if a nonlocal variable */    *indexPtr = -3;    /*     * If this namespace has a variable resolver, then give it first     * crack at the variable resolution.  It may return a Tcl_Var     * value, it may signal to continue onward, or it may signal     * an error.     */    if ((flags & TCL_GLOBAL_ONLY) || iPtr->varFramePtr == NULL) {        cxtNsPtr = iPtr->globalNsPtr;    } else {        cxtNsPtr = iPtr->varFramePtr->nsPtr;    }    if (cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) {        resPtr = iPtr->resolverPtr;        if (cxtNsPtr->varResProc) {            result = (*cxtNsPtr->varResProc)(interp, varName,		    (Tcl_Namespace *) cxtNsPtr, flags, &var);        } else {            result = TCL_CONTINUE;        }        while (result == TCL_CONTINUE && resPtr) {            if (resPtr->varResProc) {                result = (*resPtr->varResProc)(interp, varName,			(Tcl_Namespace *) cxtNsPtr, flags, &var);            }            resPtr = resPtr->nextPtr;        }        if (result == TCL_OK) {            varPtr = (Var *) var;	    return varPtr;        } else if (result != TCL_CONTINUE) {	    return NULL;        }    }    /*     * Look up varName. Look it up as either a namespace variable or as a     * local variable in a procedure call frame (varFramePtr).     * Interpret varName as a namespace variable if:     *    1) so requested by a TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY flag,     *    2) there is no active frame (we're at the global :: scope),     *    3) the active frame was pushed to define the namespace context     *       for a "namespace eval" or "namespace inscope" command,     *    4) the name has namespace qualifiers ("::"s).     * Otherwise, if varName is a local variable, search first in the     * frame's array of compiler-allocated local variables, then in its     * hashtable for runtime-created local variables.     *     * If create and the variable isn't found, create the variable and,     * if necessary, create varFramePtr's local var hashtable.     */    if (((flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) != 0)	    || (varFramePtr == NULL)	    || !varFramePtr->isProcCallFrame	    || (strstr(varName, "::") != NULL)) {	CONST char *tail;	int lookGlobal;		lookGlobal = (flags & TCL_GLOBAL_ONLY) 	    || (cxtNsPtr == iPtr->globalNsPtr)	    || ((*varName == ':') && (*(varName+1) == ':'));	if (lookGlobal) {	    *indexPtr = -1;	    flags = (flags | TCL_GLOBAL_ONLY) & ~TCL_NAMESPACE_ONLY;	} else if (flags & TCL_NAMESPACE_ONLY) {	    *indexPtr = -2;	}	/*	 * Don't pass TCL_LEAVE_ERR_MSG, we may yet create the variable,	 * or otherwise generate our own error!	 */	var = Tcl_FindNamespaceVar(interp, varName, (Tcl_Namespace *) cxtNsPtr,		flags & ~TCL_LEAVE_ERR_MSG);	if (var != (Tcl_Var) NULL) {            varPtr = (Var *) var;        }	if (varPtr == NULL) {	    if (create) {   /* var wasn't found so create it  */		TclGetNamespaceForQualName(interp, varName, cxtNsPtr,			flags, &varNsPtr, &dummy1Ptr, &dummy2Ptr, &tail);		if (varNsPtr == NULL) {		    *errMsgPtr = badNamespace;		    return NULL;		}		if (tail == NULL) {		    *errMsgPtr = missingName;		    return NULL;		}

⌨️ 快捷键说明

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