tclresult.c

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

C
1,053
字号
    }     /*     * If we had to allocate a buffer from the heap,      * free it now.     */     if (args != static_list) {     	ckfree((void *)args);    }#undef STATIC_LIST_SIZE}/* *---------------------------------------------------------------------- * * Tcl_AppendResult -- * *	Append a variable number of strings onto the interpreter's string *	result. * * Results: *	None. * * Side effects: *	The result of the interpreter given by the first argument is *	extended by the strings given by the second and following arguments *	(up to a terminating NULL argument). * *	If the string result is empty, the object result is moved to the *	string result, then the object result is reset. * *---------------------------------------------------------------------- */voidTcl_AppendResult TCL_VARARGS_DEF(Tcl_Interp *,arg1){    Tcl_Interp *interp;    va_list argList;    interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList);    Tcl_AppendResultVA(interp, argList);    va_end(argList);}/* *---------------------------------------------------------------------- * * Tcl_AppendElement -- * *	Convert a string to a valid Tcl list element and append it to the *	result (which is ostensibly a list). * * Results: *	None. * * Side effects: *	The result in the interpreter given by the first argument is *	extended with a list element converted from string. A separator *	space is added before the converted list element unless the current *	result is empty, contains the single character "{", or ends in " {". * *	If the string result is empty, the object result is moved to the *	string result, then the object result is reset. * *---------------------------------------------------------------------- */voidTcl_AppendElement(interp, string)    Tcl_Interp *interp;		/* Interpreter whose result is to be				 * extended. */    CONST char *string;		/* String to convert to list element and				 * add to result. */{    Interp *iPtr = (Interp *) interp;    char *dst;    int size;    int flags;    /*     * If the string result is empty, move the object result to the     * string result, then reset the object result.     */    if (*(iPtr->result) == 0) {	Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),	        TCL_VOLATILE);    }    /*     * See how much space is needed, and grow the append buffer if     * needed to accommodate the list element.     */    size = Tcl_ScanElement(string, &flags) + 1;    if ((iPtr->result != iPtr->appendResult)	    || (iPtr->appendResult[iPtr->appendUsed] != 0)	    || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {       SetupAppendBuffer(iPtr, size+iPtr->appendUsed);    }    /*     * Convert the string into a list element and copy it to the     * buffer that's forming, with a space separator if needed.     */    dst = iPtr->appendResult + iPtr->appendUsed;    if (TclNeedSpace(iPtr->appendResult, dst)) {	iPtr->appendUsed++;	*dst = ' ';	dst++;    }    iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);}/* *---------------------------------------------------------------------- * * SetupAppendBuffer -- * *	This procedure makes sure that there is an append buffer properly *	initialized, if necessary, from the interpreter's result, and *	that it has at least enough room to accommodate newSpace new *	bytes of information. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */static voidSetupAppendBuffer(iPtr, newSpace)    Interp *iPtr;		/* Interpreter whose result is being set up. */    int newSpace;		/* Make sure that at least this many bytes				 * of new information may be added. */{    int totalSpace;    /*     * Make the append buffer larger, if that's necessary, then copy the     * result into the append buffer and make the append buffer the official     * Tcl result.     */    if (iPtr->result != iPtr->appendResult) {	/*	 * If an oversized buffer was used recently, then free it up	 * so we go back to a smaller buffer.  This avoids tying up	 * memory forever after a large operation.	 */	if (iPtr->appendAvl > 500) {	    ckfree(iPtr->appendResult);	    iPtr->appendResult = NULL;	    iPtr->appendAvl = 0;	}	iPtr->appendUsed = strlen(iPtr->result);    } else if (iPtr->result[iPtr->appendUsed] != 0) {	/*	 * Most likely someone has modified a result created by	 * Tcl_AppendResult et al. so that it has a different size.	 * Just recompute the size.	 */	iPtr->appendUsed = strlen(iPtr->result);    }        totalSpace = newSpace + iPtr->appendUsed;    if (totalSpace >= iPtr->appendAvl) {	char *new;	if (totalSpace < 100) {	    totalSpace = 200;	} else {	    totalSpace *= 2;	}	new = (char *) ckalloc((unsigned) totalSpace);	strcpy(new, iPtr->result);	if (iPtr->appendResult != NULL) {	    ckfree(iPtr->appendResult);	}	iPtr->appendResult = new;	iPtr->appendAvl = totalSpace;    } else if (iPtr->result != iPtr->appendResult) {	strcpy(iPtr->appendResult, iPtr->result);    }        Tcl_FreeResult((Tcl_Interp *) iPtr);    iPtr->result = iPtr->appendResult;}/* *---------------------------------------------------------------------- * * Tcl_FreeResult -- * *	This procedure frees up the memory associated with an interpreter's *	string result. It also resets the interpreter's result object. *	Tcl_FreeResult is most commonly used when a procedure is about to *	replace one result value with another. * * Results: *	None. * * Side effects: *	Frees the memory associated with interp's string result and sets *	interp->freeProc to zero, but does not change interp->result or *	clear error state. Resets interp's result object to an unshared *	empty object. * *---------------------------------------------------------------------- */voidTcl_FreeResult(interp)    register Tcl_Interp *interp; /* Interpreter for which to free result. */{    register Interp *iPtr = (Interp *) interp;        if (iPtr->freeProc != NULL) {	if ((iPtr->freeProc == TCL_DYNAMIC)	        || (iPtr->freeProc == (Tcl_FreeProc *) free)) {	    ckfree(iPtr->result);	} else {	    (*iPtr->freeProc)(iPtr->result);	}	iPtr->freeProc = 0;    }        ResetObjResult(iPtr);}/* *---------------------------------------------------------------------- * * Tcl_ResetResult -- * *	This procedure resets both the interpreter's string and object *	results. * * Results: *	None. * * Side effects: *	It resets the result object to an unshared empty object. It *	then restores the interpreter's string result area to its default *	initialized state, freeing up any memory that may have been *	allocated. It also clears any error information for the interpreter. * *---------------------------------------------------------------------- */voidTcl_ResetResult(interp)    register Tcl_Interp *interp; /* Interpreter for which to clear result. */{    register Interp *iPtr = (Interp *) interp;    ResetObjResult(iPtr);    if (iPtr->freeProc != NULL) {	if ((iPtr->freeProc == TCL_DYNAMIC)	        || (iPtr->freeProc == (Tcl_FreeProc *) free)) {	    ckfree(iPtr->result);	} else {	    (*iPtr->freeProc)(iPtr->result);	}	iPtr->freeProc = 0;    }    iPtr->result = iPtr->resultSpace;    iPtr->resultSpace[0] = 0;    iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);}/* *---------------------------------------------------------------------- * * ResetObjResult -- * *	Procedure used to reset an interpreter's Tcl result object. * * Results: *	None. * * Side effects: *	Resets the interpreter's result object to an unshared empty string *	object with ref count one. It does not clear any error information *	in the interpreter. * *---------------------------------------------------------------------- */static voidResetObjResult(iPtr)    register Interp *iPtr;	/* Points to the interpreter whose result				 * object should be reset. */{    register Tcl_Obj *objResultPtr = iPtr->objResultPtr;    if (Tcl_IsShared(objResultPtr)) {	TclDecrRefCount(objResultPtr);	TclNewObj(objResultPtr);	Tcl_IncrRefCount(objResultPtr);	iPtr->objResultPtr = objResultPtr;    } else {	if ((objResultPtr->bytes != NULL)	        && (objResultPtr->bytes != tclEmptyStringRep)) {	    ckfree((char *) objResultPtr->bytes);	}	objResultPtr->bytes  = tclEmptyStringRep;	objResultPtr->length = 0;	if ((objResultPtr->typePtr != NULL)	        && (objResultPtr->typePtr->freeIntRepProc != NULL)) {	    objResultPtr->typePtr->freeIntRepProc(objResultPtr);	}	objResultPtr->typePtr = (Tcl_ObjType *) NULL;    }}/* *---------------------------------------------------------------------- * * Tcl_SetErrorCodeVA -- * *	This procedure is called to record machine-readable information *	about an error that is about to be returned. * * Results: *	None. * * Side effects: *	The errorCode global variable is modified to hold all of the *	arguments to this procedure, in a list form with each argument *	becoming one element of the list.  A flag is set internally *	to remember that errorCode has been set, so the variable doesn't *	get set automatically when the error is returned. * *---------------------------------------------------------------------- */voidTcl_SetErrorCodeVA (interp, argList)    Tcl_Interp *interp;		/* Interpreter in which to access the errorCode				 * variable. */    va_list argList;		/* Variable argument list. */{    char *string;    int flags;    Interp *iPtr = (Interp *) interp;    /*     * Scan through the arguments one at a time, appending them to     * $errorCode as list elements.     */    flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;    while (1) {	string = va_arg(argList, char *);	if (string == NULL) {	    break;	}	(void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",		(char *) NULL, string, flags);	flags |= TCL_APPEND_VALUE;    }    iPtr->flags |= ERROR_CODE_SET;}/* *---------------------------------------------------------------------- * * Tcl_SetErrorCode -- * *	This procedure is called to record machine-readable information *	about an error that is about to be returned. * * Results: *	None. * * Side effects: *	The errorCode global variable is modified to hold all of the *	arguments to this procedure, in a list form with each argument *	becoming one element of the list.  A flag is set internally *	to remember that errorCode has been set, so the variable doesn't *	get set automatically when the error is returned. * *---------------------------------------------------------------------- */	/* VARARGS2 */voidTcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1){    Tcl_Interp *interp;    va_list argList;    /*     * Scan through the arguments one at a time, appending them to     * $errorCode as list elements.     */    interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList);    Tcl_SetErrorCodeVA(interp, argList);    va_end(argList);}/* *---------------------------------------------------------------------- * * Tcl_SetObjErrorCode -- * *	This procedure is called to record machine-readable information *	about an error that is about to be returned. The caller should *	build a list object up and pass it to this routine. * * Results: *	None. * * Side effects: *	The errorCode global variable is modified to be the new value. *	A flag is set internally to remember that errorCode has been *	set, so the variable doesn't get set automatically when the *	error is returned. * *---------------------------------------------------------------------- */voidTcl_SetObjErrorCode(interp, errorObjPtr)    Tcl_Interp *interp;    Tcl_Obj *errorObjPtr;{    Interp *iPtr;        iPtr = (Interp *) interp;    Tcl_SetVar2Ex(interp, "errorCode", NULL, errorObjPtr, TCL_GLOBAL_ONLY);    iPtr->flags |= ERROR_CODE_SET;}/* *------------------------------------------------------------------------- * * TclTransferResult -- * *	Copy the result (and error information) from one interp to  *	another.  Used when one interp has caused another interp to  *	evaluate a script and then wants to transfer the results back *	to itself. * *	This routine copies the string reps of the result and error  *	information.  It does not simply increment the refcounts of the *	result and error information objects themselves. *	It is not legal to exchange objects between interps, because an *	object may be kept alive by one interp, but have an internal rep  *	that is only valid while some other interp is alive.   * * Results: *	The target interp's result is set to a copy of the source interp's *	result.  The source's error information "$errorInfo" may be *	appended to the target's error information and the source's error *	code "$errorCode" may be stored in the target's error code. * * Side effects: *	None. * *------------------------------------------------------------------------- */	voidTclTransferResult(sourceInterp, result, targetInterp)    Tcl_Interp *sourceInterp;	/* Interp whose result and error information				 * should be moved to the target interp.  				 * After moving result, this interp's result 				 * is reset. */    int result;			/* TCL_OK if just the result should be copied, 				 * TCL_ERROR if both the result and error 				 * information should be copied. */    Tcl_Interp *targetInterp;	/* Interp where result and error information 				 * should be stored.  If source and target				 * are the same, nothing is done. */{    Interp *iPtr;    Tcl_Obj *objPtr;    if (sourceInterp == targetInterp) {	return;    }    if (result == TCL_ERROR) {	/*	 * An error occurred, so transfer error information from the source	 * interpreter to the target interpreter.  Setting the flags tells	 * the target interp that it has inherited a partial traceback	 * chain, not just a simple error message.	 */	iPtr = (Interp *) sourceInterp;        if ((iPtr->flags & ERR_ALREADY_LOGGED) == 0) {            Tcl_AddErrorInfo(sourceInterp, "");        }        iPtr->flags &= ~(ERR_ALREADY_LOGGED);                Tcl_ResetResult(targetInterp);        	objPtr = Tcl_GetVar2Ex(sourceInterp, "errorInfo", NULL,		TCL_GLOBAL_ONLY);	Tcl_SetVar2Ex(targetInterp, "errorInfo", NULL, objPtr,		TCL_GLOBAL_ONLY);	objPtr = Tcl_GetVar2Ex(sourceInterp, "errorCode", NULL,		TCL_GLOBAL_ONLY);	Tcl_SetVar2Ex(targetInterp, "errorCode", NULL, objPtr,		TCL_GLOBAL_ONLY);	((Interp *) targetInterp)->flags |= (ERR_IN_PROGRESS | ERROR_CODE_SET);    }    ((Interp *) targetInterp)->returnCode = ((Interp *) sourceInterp)->returnCode;    Tcl_SetObjResult(targetInterp, Tcl_GetObjResult(sourceInterp));    Tcl_ResetResult(sourceInterp);}

⌨️ 快捷键说明

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