diff options
-rw-r--r-- | ChangeLog | 34 | ||||
-rw-r--r-- | generic/tclBasic.c | 106 | ||||
-rw-r--r-- | generic/tclCmdAH.c | 14 | ||||
-rw-r--r-- | generic/tclCmdMZ.c | 5 | ||||
-rw-r--r-- | generic/tclEvent.c | 189 | ||||
-rw-r--r-- | generic/tclExecute.c | 19 | ||||
-rw-r--r-- | generic/tclIOUtil.c | 12 | ||||
-rw-r--r-- | generic/tclInt.h | 13 | ||||
-rw-r--r-- | generic/tclInterp.c | 8 | ||||
-rw-r--r-- | generic/tclMain.c | 5 | ||||
-rw-r--r-- | generic/tclNamesp.c | 154 | ||||
-rw-r--r-- | generic/tclProc.c | 11 | ||||
-rw-r--r-- | generic/tclResult.c | 58 | ||||
-rw-r--r-- | generic/tclTrace.c | 26 |
14 files changed, 372 insertions, 282 deletions
@@ -1,3 +1,35 @@ +2004-10-15 Don Porter <dgp@users.sourceforge.net> + + * generic/tclBasic.c (Tcl_CreateInterp,Tcl_DeleteInterp, + TclEvalObjvInternal,Tcl_LogCommandInfo,TclAddObjErrorInfo): + * generic/tclCmdAH.c (Tcl_CatchObjCmd): + * generic/tclEvent.c (BgError,ErrAssocData,Tcl_BackgroundError, + HandleBgErrors,BgErrorDeleteProc): + * generic/tclExecute.c (TclCreateExecEnv,TclDeleteExecEnv): + * generic/tclIOUtil.c (comments only): + * generic/tclInt.h (ExecEnv,Interp, ERR_IN_PROGRESS): + * generic/tclInterp.c ([tclInit]): + * generic/tclMain.c (comments only): + * generic/tclNamesp.c + (Tcl_CreateNamespace,Tcl_DeleteNamespace,TclTeardownNamespace): + * generic/tclProc.c (TclUpdateReturnInfo): + * generic/tclResult.c + (Tcl_ResetResult,TclTransferResult): + * generic/tclTrace.c (CallVarTraces): + Reworked management of the "errorInfo" data of an interp. + That information is now primarily stored in a new private + (Tcl_Obj *) field of the Interp struct, rather than using a + global variable ::errorInfo as the primary storage. The + ERR_IN_PROGRESS flag bit value is no longer required to manage + the value in its new location, and is removed. Variable traces + are established to support compatibility for any code expecting + the ::errorInfo variable to hold the information. + + ***POTENTIAL INCOMPATIBILITY*** + Code that sets traces on the ::errorInfo variable may notice a + difference in timing of the firing of those traces. Code that + uses the value ERR_IN_PROGRESS. + 2004-10-14 Donal K. Fellows <donal.k.fellows@man.ac.uk> TIP#217 IMPLEMENTATION @@ -165,7 +197,7 @@ the ::errorCode variable to hold the information. ***POTENTIAL INCOMPATIBILITY*** - Code that sets traces on the ::errorCode value may notice a + Code that sets traces on the ::errorCode variable may notice a difference in timing of the firing of those traces. * generic/tclNamesp.c (Tcl_PopCallFrame): Removed Bug 1038021 diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 5e410d4..8891f52 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclBasic.c,v 1.125 2004/10/06 00:24:16 dgp Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.126 2004/10/15 04:01:27 dgp Exp $ */ #include "tclInt.h" @@ -241,7 +241,12 @@ Tcl_CreateInterp() Tcl_IncrRefCount(iPtr->defaultReturnOpts); iPtr->returnOpts = iPtr->defaultReturnOpts; Tcl_IncrRefCount(iPtr->returnOpts); + iPtr->errorInfo = NULL; + iPtr->eiVar = Tcl_NewStringObj("errorInfo", -1); + Tcl_IncrRefCount(iPtr->eiVar); iPtr->errorCode = NULL; + iPtr->ecVar = Tcl_NewStringObj("errorCode", -1); + Tcl_IncrRefCount(iPtr->ecVar); iPtr->appendResult = NULL; iPtr->appendAvl = 0; @@ -894,10 +899,6 @@ DeleteInterpProc(interp) TclLimitRemoveAllHandlers(interp); /* - * 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. * @@ -982,10 +983,16 @@ DeleteInterpProc(interp) interp->result = NULL; Tcl_DecrRefCount(iPtr->objResultPtr); iPtr->objResultPtr = NULL; + Tcl_DecrRefCount(iPtr->ecVar); if (iPtr->errorCode) { Tcl_DecrRefCount(iPtr->errorCode); iPtr->errorCode = NULL; } + Tcl_DecrRefCount(iPtr->eiVar); + if (iPtr->errorInfo) { + Tcl_DecrRefCount(iPtr->errorInfo); + iPtr->errorInfo = NULL; + } Tcl_DecrRefCount(iPtr->returnOpts); Tcl_DecrRefCount(iPtr->defaultReturnOpts); Tcl_DecrRefCount(iPtr->returnCodeKey); @@ -3057,10 +3064,13 @@ TclEvalObjvInternal(interp, objc, objv, command, length, flags) * Call 'leave' command traces */ if (!(cmdPtr->flags & CMD_IS_DELETED)) { - int saveErrFlags = iPtr->flags - & (ERR_IN_PROGRESS | ERR_ALREADY_LOGGED); + int saveErrFlags = iPtr->flags & ERR_ALREADY_LOGGED; Tcl_Obj *saveOptions = iPtr->returnOpts; + Tcl_Obj *saveErrInfo = iPtr->errorInfo; Tcl_Obj *saveErrCode = iPtr->errorCode; + if (saveErrInfo) { + Tcl_IncrRefCount(saveErrInfo); + } if (saveErrCode) { Tcl_IncrRefCount(saveErrCode); } @@ -3082,8 +3092,17 @@ TclEvalObjvInternal(interp, objc, objv, command, length, flags) Tcl_DecrRefCount(iPtr->errorCode); } iPtr->errorCode = saveErrCode; - } else if (saveErrCode) { - Tcl_DecrRefCount(saveErrCode); + if (iPtr->errorInfo) { + Tcl_DecrRefCount(iPtr->errorInfo); + } + iPtr->errorInfo = saveErrInfo; + } else { + if (saveErrCode) { + Tcl_DecrRefCount(saveErrCode); + } + if (saveErrInfo) { + Tcl_DecrRefCount(saveErrInfo); + } } Tcl_DecrRefCount(saveOptions); } @@ -3227,7 +3246,7 @@ Tcl_EvalObjv(interp, objc, objv, flags) * Tcl_LogCommandInfo -- * * This procedure is invoked after an error occurs in an interpreter. - * It adds information to the "errorInfo" variable to describe the + * It adds information to iPtr->errorInfo field to describe the * command that was being executed when the error occurred. * * Results: @@ -3235,10 +3254,7 @@ Tcl_EvalObjv(interp, objc, objv, flags) * * Side effects: * Information about the command is added to errorInfo and the - * line number stored internally in the interpreter is set. If this - * is the first call to this procedure or Tcl_AddObjErrorInfo since - * an error occurred, then old information in errorInfo is - * deleted. + * line number stored internally in the interpreter is set. * *---------------------------------------------------------------------- */ @@ -3277,7 +3293,7 @@ Tcl_LogCommandInfo(interp, script, command, length) } } - if (!(iPtr->flags & ERR_IN_PROGRESS)) { + if (iPtr->errorInfo == NULL) { message = Tcl_NewStringObj("\n while executing\n\"", -1); } else { message = Tcl_NewStringObj("\n invoked from within\n\"", -1); @@ -3602,12 +3618,7 @@ Tcl_EvalEx(interp, script, numBytes, flags) return TCL_OK; error: - /* - * Generate various pieces of error information, such as the line - * number where the error occurred and information to add to the - * errorInfo variable. Then free resources that had been allocated - * to the command. - */ + /* Generate and log various pieces of error information. */ if ((code == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) { commandLength = parse.commandSize; @@ -3625,6 +3636,8 @@ Tcl_EvalEx(interp, script, numBytes, flags) } iPtr->flags &= ~ERR_ALREADY_LOGGED; + /* Then free resources that had been allocated to the command. */ + for (i = 0; i < objectsUsed; i++) { Tcl_DecrRefCount(objv[i]); } @@ -4359,16 +4372,14 @@ Tcl_ExprString(interp, string) * * TclAppendObjToErrorInfo -- * - * Add a Tcl_Obj value to the "errorInfo" variable that describes the + * Add a Tcl_Obj value to the errorInfo field that describes the * current error. * * Results: * None. * * Side effects: - * The value of the Tcl_obj is added to the "errorInfo" variable. - * If Tcl_Eval has been called since the current value of errorInfo - * was set, errorInfo is cleared before adding the new message. + * The value of the Tcl_obj is appended to the errorInfo field. * If we are just starting to log an error, errorInfo is initialized * from the error message in the interpreter's result. * @@ -4391,16 +4402,14 @@ TclAppendObjToErrorInfo(interp, objPtr) * * Tcl_AddErrorInfo -- * - * Add information to the "errorInfo" variable that describes the + * Add information to the errorInfo field that describes the * current error. * * Results: * None. * * Side effects: - * The contents of message are added to the "errorInfo" variable. - * If Tcl_Eval has been called since the current value of errorInfo - * was set, errorInfo is cleared before adding the new message. + * The contents of message are appended to the errorInfo field. * If we are just starting to log an error, errorInfo is initialized * from the error message in the interpreter's result. * @@ -4421,7 +4430,7 @@ Tcl_AddErrorInfo(interp, message) * * Tcl_AddObjErrorInfo -- * - * Add information to the "errorInfo" variable that describes the + * Add information to the errorInfo field that describes the * current error. This routine differs from Tcl_AddErrorInfo by * taking a byte pointer and length. * @@ -4429,10 +4438,8 @@ Tcl_AddErrorInfo(interp, message) * None. * * Side effects: - * "length" bytes from "message" are added to the "errorInfo" variable. + * "length" bytes from "message" are appended to the errorInfo field. * If "length" is negative, use bytes up to the first NULL byte. - * If Tcl_EvalObj has been called since the current value of errorInfo - * was set, errorInfo is cleared before adding the new message. * If we are just starting to log an error, errorInfo is initialized * from the error message in the interpreter's result. * @@ -4457,16 +4464,20 @@ Tcl_AddObjErrorInfo(interp, message, length) * from the error message in the interpreter's result. */ - if (!(iPtr->flags & ERR_IN_PROGRESS)) { /* just starting to log error */ - iPtr->flags |= ERR_IN_PROGRESS; - - if (iPtr->result[0] == 0) { - Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorInfo, NULL, - iPtr->objResultPtr, TCL_GLOBAL_ONLY); - } else { /* use the string result */ - Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorInfo, NULL, - Tcl_NewStringObj(interp->result, -1), TCL_GLOBAL_ONLY); + if (iPtr->errorInfo == NULL) { /* just starting to log error */ + if (iPtr->result[0] != 0) { + /* + * The interp's string result is set, apparently by some + * extension making a deprecated direct write to it. + * That extension may expect interp->result to continue + * to be set, so we'll take special pains to avoid clearing + * it, until we drop support for interp->result completely. + */ + iPtr->errorInfo = Tcl_NewStringObj(interp->result, -1); + } else { + iPtr->errorInfo = iPtr->objResultPtr; } + Tcl_IncrRefCount(iPtr->errorInfo); } /* @@ -4474,11 +4485,12 @@ Tcl_AddObjErrorInfo(interp, message, length) */ if (length != 0) { - messagePtr = Tcl_NewStringObj(message, length); - Tcl_IncrRefCount(messagePtr); - Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorInfo, NULL, - messagePtr, (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE)); - Tcl_DecrRefCount(messagePtr); /* free msg object appended above */ + if (Tcl_IsShared(iPtr->errorInfo)) { + Tcl_DecrRefCount(iPtr->errorInfo); + iPtr->errorInfo = Tcl_DuplicateObj(iPtr->errorInfo); + Tcl_IncrRefCount(iPtr->errorInfo); + } + Tcl_AppendToObj(iPtr->errorInfo, message, length); } } diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 05bf91a..960b039 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdAH.c,v 1.53 2004/10/06 09:07:12 dkf Exp $ + * RCS: @(#) $Id: tclCmdAH.c,v 1.54 2004/10/15 04:01:28 dgp Exp $ */ #include "tclInt.h" @@ -280,17 +280,19 @@ Tcl_CatchObjCmd(dummy, interp, objc, objv) iPtr->returnLevelKey, Tcl_NewIntObj(0)); } - if (iPtr->flags & ERR_IN_PROGRESS) { + if (result == TCL_ERROR) { + /* + * When result was an error, fill in any missing values + * for -errorinfo, -errorcode, and -errorline + */ + value = NULL; Tcl_DictObjGet(NULL, options, iPtr->returnErrorinfoKey, &value); if (NULL == value) { Tcl_DictObjPut(NULL, options, iPtr->returnErrorinfoKey, - Tcl_ObjGetVar2(interp, iPtr->execEnvPtr->errorInfo, - NULL, TCL_GLOBAL_ONLY)); + iPtr->errorInfo); } - } - if (result == TCL_ERROR) { value = NULL; Tcl_DictObjGet(NULL, options, iPtr->returnErrorcodeKey, &value); if (NULL == value) { diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index 2c8b8a7..a408db6 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -15,7 +15,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdMZ.c,v 1.111 2004/10/06 09:44:11 dkf Exp $ + * RCS: @(#) $Id: tclCmdMZ.c,v 1.112 2004/10/15 04:01:28 dgp Exp $ */ #include "tclInt.h" @@ -880,8 +880,7 @@ Tcl_ReturnObjCmd(dummy, interp, objc, objv) * Returns the return code the [return] command should return. * * Side effects: - * When the return code is TCL_ERROR, the values of ::errorInfo - * and ::errorCode may be updated. + * None. * *---------------------------------------------------------------------- */ diff --git a/generic/tclEvent.c b/generic/tclEvent.c index 5a38ad7..5ef1533 100644 --- a/generic/tclEvent.c +++ b/generic/tclEvent.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclEvent.c,v 1.47 2004/10/05 18:14:27 dgp Exp $ + * RCS: @(#) $Id: tclEvent.c,v 1.48 2004/10/15 04:01:29 dgp Exp $ */ #include "tclInt.h" @@ -25,16 +25,10 @@ */ typedef struct BgError { - Tcl_Interp *interp; /* Interpreter in which error occurred. NULL - * means this error report has been cancelled - * (a previous report generated a break). */ - char *errorMsg; /* Copy of the error message (the interp's - * result when the error occurred). - * Malloc-ed. */ - char *errorInfo; /* Value of the errorInfo variable - * (malloc-ed). */ - Tcl_Obj *errorCode; /* Value of the errorCode variable - * (malloc-ed). */ + Tcl_Obj *errorMsg; /* Copy of the error message (the interp's + * result when the error occurred). */ + Tcl_Obj *errorInfo; /* Value of the errorInfo variable */ + Tcl_Obj *errorCode; /* Value of the errorCode variable */ struct BgError *nextPtr; /* Next in list of all pending error * reports for this interpreter, or NULL * for end of list. */ @@ -47,6 +41,7 @@ typedef struct BgError { */ typedef struct ErrAssocData { + Tcl_Interp *interp; /* Interpreter in which error occurred. */ BgError *firstBgPtr; /* First in list of all background errors * waiting to be processed for this * interpreter (NULL if none). */ @@ -160,11 +155,13 @@ Tcl_BackgroundError(interp) * occurred. */ { BgError *errPtr; - CONST char *errResult, *varValue; ErrAssocData *assocPtr; - int length; Interp *iPtr = (Interp *) interp; + errPtr = (BgError *) ckalloc(sizeof(BgError)); + errPtr->errorMsg = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errPtr->errorMsg); + /* * The Tcl_AddErrorInfo call below (with an empty string) ensures that * errorInfo gets properly set. It's needed in cases where the error @@ -174,19 +171,8 @@ Tcl_BackgroundError(interp) */ Tcl_AddErrorInfo(interp, ""); - - errResult = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &length); - - errPtr = (BgError *) ckalloc(sizeof(BgError)); - errPtr->interp = interp; - errPtr->errorMsg = (char *) ckalloc((unsigned) (length + 1)); - memcpy(errPtr->errorMsg, errResult, (size_t) (length + 1)); - varValue = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); - if (varValue == NULL) { - varValue = errPtr->errorMsg; - } - errPtr->errorInfo = (char *) ckalloc((unsigned) (strlen(varValue) + 1)); - strcpy(errPtr->errorInfo, varValue); + errPtr->errorInfo = iPtr->errorInfo; + Tcl_IncrRefCount(errPtr->errorInfo); if (iPtr->errorCode) { errPtr->errorCode = iPtr->errorCode; @@ -209,6 +195,7 @@ Tcl_BackgroundError(interp) */ assocPtr = (ErrAssocData *) ckalloc(sizeof(ErrAssocData)); + assocPtr->interp = interp; assocPtr->firstBgPtr = NULL; assocPtr->lastBgPtr = NULL; Tcl_SetAssocData(interp, "tclBgError", BgErrorDeleteProc, @@ -245,43 +232,50 @@ static void HandleBgErrors(clientData) ClientData clientData; /* Pointer to ErrAssocData structure. */ { - Tcl_Interp *interp; - int code; - BgError *errPtr; ErrAssocData *assocPtr = (ErrAssocData *) clientData; - Tcl_Channel errChannel; + Tcl_Interp *interp = assocPtr->interp; + BgError *errPtr; Tcl_Obj *objv[2]; + /* + * Not bothering to save/restore the interp state. Assume that + * any code that has interp state it needs to keep will make + * its own Tcl_SaveResult call before calling something like + * Tcl_DoOneEvent() that could lead us here. + */ + objv[0] = Tcl_NewStringObj("bgerror", -1); Tcl_IncrRefCount(objv[0]); - objv[1] = NULL; Tcl_Preserve((ClientData) assocPtr); + Tcl_Preserve((ClientData) interp); while (assocPtr->firstBgPtr != NULL) { - interp = assocPtr->firstBgPtr->interp; - if (interp == NULL) { - goto doneWithInterp; - } + int code; + Interp *iPtr = (Interp *)interp; + errPtr = assocPtr->firstBgPtr; /* * Restore important state variables to what they were at * the time the error occurred. + * + * Need to set the variables, not the interp fields, because + * Tcl_EvalObjv() calls Tcl_ResetResult() which would destroy + * anything we write to the interp fields. */ - Tcl_SetVar(interp, "errorInfo", assocPtr->firstBgPtr->errorInfo, - TCL_GLOBAL_ONLY); - Tcl_SetVar2Ex(interp, "errorCode", NULL, - assocPtr->firstBgPtr->errorCode, TCL_GLOBAL_ONLY); + Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, + errPtr->errorInfo, TCL_GLOBAL_ONLY); + Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL, + errPtr->errorCode, TCL_GLOBAL_ONLY); /* * Create and invoke the bgerror command. */ - objv[1] = Tcl_NewStringObj(assocPtr->firstBgPtr->errorMsg, -1); + objv[1] = errPtr->errorMsg; Tcl_IncrRefCount(objv[1]); Tcl_AllowExceptions(interp); - Tcl_Preserve((ClientData) interp); code = Tcl_EvalObjv(interp, 2, objv, TCL_EVAL_GLOBAL); if (code == TCL_ERROR) { @@ -302,49 +296,37 @@ HandleBgErrors(clientData) Tcl_SaveResult(interp, &save); TclObjInvoke(interp, 2, objv, TCL_INVOKE_HIDDEN); Tcl_RestoreResult(interp, &save); + } else { - goto doneWithInterp; - } - - /* - * We have to get the error output channel at the latest possible - * time, because the eval (above) might have changed the channel. - */ + /* + * We have to get the error output channel at the latest + * possible time, because the eval (above) might have + * changed the channel. + */ - errChannel = Tcl_GetStdChannel(TCL_STDERR); - if (errChannel != (Tcl_Channel) NULL) { - char *string; - int len; - - string = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &len); - if (Tcl_FindCommand(interp, "bgerror", NULL, TCL_GLOBAL_ONLY) == NULL) { - Tcl_WriteChars(errChannel, assocPtr->firstBgPtr->errorInfo, -1); - Tcl_WriteChars(errChannel, "\n", -1); - } else { - Tcl_WriteChars(errChannel, - "bgerror failed to handle background error.\n", - -1); - Tcl_WriteChars(errChannel, " Original error: ", -1); - Tcl_WriteChars(errChannel, assocPtr->firstBgPtr->errorMsg, - -1); - Tcl_WriteChars(errChannel, "\n", -1); - Tcl_WriteChars(errChannel, " Error in bgerror: ", -1); - Tcl_WriteChars(errChannel, string, len); - Tcl_WriteChars(errChannel, "\n", -1); - } - Tcl_Flush(errChannel); - } - } else if (code == TCL_BREAK) { - - /* - * Break means cancel any remaining error reports for this - * interpreter. - */ - - for (errPtr = assocPtr->firstBgPtr; errPtr != NULL; - errPtr = errPtr->nextPtr) { - if (errPtr->interp == interp) { - errPtr->interp = NULL; + Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR); + if (errChannel != (Tcl_Channel) NULL) { + Tcl_Obj *resultPtr = Tcl_GetObjResult(interp); + + Tcl_IncrRefCount(resultPtr); + if (Tcl_FindCommand(interp, "bgerror", + NULL, TCL_GLOBAL_ONLY) == NULL) { + Tcl_WriteObj(errChannel, errPtr->errorInfo); + Tcl_WriteChars(errChannel, "\n", -1); + } else { + Tcl_WriteChars(errChannel, + "bgerror failed to handle background error.\n", + -1); + Tcl_WriteChars(errChannel, " Original error: ", -1); + Tcl_WriteObj(errChannel, errPtr->errorMsg); + Tcl_WriteChars(errChannel, "\n", -1); + Tcl_WriteChars(errChannel, + " Error in bgerror: ", -1); + Tcl_WriteObj(errChannel, resultPtr); + Tcl_WriteChars(errChannel, "\n", -1); + } + Tcl_DecrRefCount(resultPtr); + Tcl_Flush(errChannel); } } } @@ -353,28 +335,37 @@ HandleBgErrors(clientData) * Discard the command and the information about the error report. */ -doneWithInterp: - if (objv[1]) { - Tcl_DecrRefCount(objv[1]); - objv[1] = NULL; - } + Tcl_DecrRefCount(objv[1]); + Tcl_DecrRefCount(errPtr->errorMsg); + Tcl_DecrRefCount(errPtr->errorInfo); + Tcl_DecrRefCount(errPtr->errorCode); + assocPtr->firstBgPtr = errPtr->nextPtr; + ckfree((char *) errPtr); - if (assocPtr->firstBgPtr) { - ckfree(assocPtr->firstBgPtr->errorMsg); - ckfree(assocPtr->firstBgPtr->errorInfo); - Tcl_DecrRefCount(assocPtr->firstBgPtr->errorCode); - errPtr = assocPtr->firstBgPtr->nextPtr; - ckfree((char *) assocPtr->firstBgPtr); - assocPtr->firstBgPtr = errPtr; + if (code == TCL_BREAK) { + /* + * Break means cancel any remaining error reports for this + * interpreter. + */ + break; } - if (interp != NULL) { - Tcl_Release((ClientData) interp); - } } + + /* Cleanup any error reports we didn't do (due to a TCL_BREAK) */ + while (assocPtr->firstBgPtr != NULL) { + errPtr = assocPtr->firstBgPtr; + assocPtr->firstBgPtr = errPtr->nextPtr; + Tcl_DecrRefCount(errPtr->errorMsg); + Tcl_DecrRefCount(errPtr->errorInfo); + Tcl_DecrRefCount(errPtr->errorCode); + ckfree((char *) errPtr); + } + assocPtr->lastBgPtr = NULL; Tcl_DecrRefCount(objv[0]); + Tcl_Release((ClientData) interp); Tcl_Release((ClientData) assocPtr); } @@ -409,8 +400,8 @@ BgErrorDeleteProc(clientData, interp) while (assocPtr->firstBgPtr != NULL) { errPtr = assocPtr->firstBgPtr; assocPtr->firstBgPtr = errPtr->nextPtr; - ckfree(errPtr->errorMsg); - ckfree(errPtr->errorInfo); + Tcl_DecrRefCount(errPtr->errorMsg); + Tcl_DecrRefCount(errPtr->errorInfo); Tcl_DecrRefCount(errPtr->errorCode); ckfree((char *) errPtr); } diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 60b9344..b59389b 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclExecute.c,v 1.156 2004/10/08 15:39:53 dkf Exp $ + * RCS: @(#) $Id: tclExecute.c,v 1.157 2004/10/15 04:01:29 dgp Exp $ */ #ifdef STDC_HEADERS @@ -527,12 +527,6 @@ TclCreateExecEnv(interp) eePtr->tosPtr = stackPtr - 1; eePtr->endPtr = stackPtr + (TCL_STACK_INITIAL_SIZE - 2); - eePtr->errorInfo = Tcl_NewStringObj("::errorInfo", -1); - Tcl_IncrRefCount(eePtr->errorInfo); - - eePtr->errorCode = Tcl_NewStringObj("::errorCode", -1); - Tcl_IncrRefCount(eePtr->errorCode); - Tcl_MutexLock(&execMutex); if (!execInitialized) { TclInitAuxDataTypeTable(); @@ -571,8 +565,6 @@ TclDeleteExecEnv(eePtr) } else { Tcl_Panic("ERROR: freeing an execEnv whose stack is still in use.\n"); } - TclDecrRefCount(eePtr->errorInfo); - TclDecrRefCount(eePtr->errorCode); ckfree((char *) eePtr); } @@ -5142,15 +5134,16 @@ ValidatePcAndStackTop(codePtr, pc, stackTop, stackLowerBound, checkStack) * * IllegalExprOperandType -- * - * Used by TclExecuteByteCode to add an error message to errorInfo - * when an illegal operand type is detected by an expression - * instruction. The argument opndPtr holds the operand object in error. + * Used by TclExecuteByteCode to append an error message to + * the interp result when an illegal operand type is detected by an + * expression instruction. The argument opndPtr holds the operand + * object in error. * * Results: * None. * * Side effects: - * An error message is appended to errorInfo. + * An error message is appended to the interp result. * *---------------------------------------------------------------------- */ diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index 0f31689..befc9c7 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -17,7 +17,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIOUtil.c,v 1.111 2004/10/07 14:50:22 vincentdarley Exp $ + * RCS: @(#) $Id: tclIOUtil.c,v 1.112 2004/10/15 04:01:31 dgp Exp $ */ #include "tclInt.h" @@ -1783,23 +1783,23 @@ Tcl_SetErrno(err) * * This procedure is typically called after UNIX kernel calls * return errors. It stores machine-readable information about - * the error in $errorCode returns an information string for - * the caller's use. + * the error in errorCode field of interp and returns an + * information string for the caller's use. * * Results: * The return value is a human-readable string describing the * error. * * Side effects: - * The global variable $errorCode is reset. + * The errorCode field of the interp is set. * *---------------------------------------------------------------------- */ CONST char * Tcl_PosixError(interp) - Tcl_Interp *interp; /* Interpreter whose $errorCode variable - * is to be changed. */ + Tcl_Interp *interp; /* Interpreter whose errorCode field + * is to be set. */ { CONST char *id, *msg; diff --git a/generic/tclInt.h b/generic/tclInt.h index c97e727..f513b19 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.180 2004/10/05 18:14:27 dgp Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.181 2004/10/15 04:01:31 dgp Exp $ */ #ifndef _TCLINT @@ -888,8 +888,6 @@ typedef struct ExecEnv { Tcl_Obj **tosPtr; /* Points to current top of stack; * (stackPtr-1) when the stack is empty. */ Tcl_Obj **endPtr; /* Points to last usable item in stack. */ - Tcl_Obj *errorInfo; - Tcl_Obj *errorCode; } ExecEnv; /* @@ -1332,7 +1330,10 @@ typedef struct Interp { Tcl_Obj *returnLevelKey; /* holds "-level" */ Tcl_Obj *returnOptionsKey; /* holds "-options" */ + Tcl_Obj *errorInfo; /* errorInfo value (now as a Tcl_Obj) */ + Tcl_Obj *eiVar; /* cached ref to ::errorInfo variable */ Tcl_Obj *errorCode; /* errorCode value (now as a Tcl_Obj) */ + Tcl_Obj *ecVar; /* cached ref to ::errorInfo variable */ /* * Resource limiting framework support (TIP#143). @@ -1395,11 +1396,8 @@ typedef struct Interp { * don't process any more commands for it, and destroy * the structure as soon as all nested invocations of * Tcl_Eval are done. - * ERR_IN_PROGRESS: Non-zero means an error unwind is already in - * progress. Zero means a command proc has been - * invoked since last error occured. * ERR_ALREADY_LOGGED: Non-zero means information has already been logged - * in $errorInfo for the current Tcl_Eval instance, + * in iPtr->errorInfo for the current Tcl_Eval instance, * so Tcl_Eval needn't log it (used to implement the * "error message log" command). * DONT_COMPILE_CMDS_INLINE: Non-zero means that the bytecode compiler @@ -1418,7 +1416,6 @@ typedef struct Interp { */ #define DELETED 1 -#define ERR_IN_PROGRESS 2 #define ERR_ALREADY_LOGGED 4 #define DONT_COMPILE_CMDS_INLINE 0x20 #define RAND_SEED_INITIALIZED 0x40 diff --git a/generic/tclInterp.c b/generic/tclInterp.c index 5ba48ab..51ce8fd 100644 --- a/generic/tclInterp.c +++ b/generic/tclInterp.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInterp.c,v 1.46 2004/10/06 14:59:02 dgp Exp $ + * RCS: @(#) $Id: tclInterp.c,v 1.47 2004/10/15 04:01:32 dgp Exp $ */ #include "tclInt.h" @@ -59,7 +59,7 @@ static char initScript[] = "if {[info proc tclInit]==\"\"} {\n\ proc tclInit {} {\n\ - global tcl_libPath tcl_library errorInfo\n\ + global tcl_libPath tcl_library\n\ global env tclDefaultLibrary\n\ rename tclInit {}\n\ set errors {}\n\ @@ -84,10 +84,10 @@ static char initScript[] = "if {[info proc tclInit]==\"\"} {\n\ set tcl_library $i\n\ set tclfile [file join $i init.tcl]\n\ if {[file exists $tclfile]} {\n\ - if {![catch {uplevel #0 [list source $tclfile]} msg]} {\n\ + if {![catch {uplevel #0 [list source $tclfile]} msg opt]} {\n\ return\n\ } else {\n\ - append errors \"$tclfile: $msg\n$errorInfo\n\"\n\ + append errors \"$tclfile: $msg\n$opt(-errorinfo)\n\"\n\ }\n\ }\n\ }\n\ diff --git a/generic/tclMain.c b/generic/tclMain.c index 1e736fe..238b485 100644 --- a/generic/tclMain.c +++ b/generic/tclMain.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMain.c,v 1.27 2004/06/11 21:30:08 dgp Exp $ + * RCS: @(#) $Id: tclMain.c,v 1.28 2004/10/15 04:01:32 dgp Exp $ */ #include "tclInt.h" @@ -438,7 +438,8 @@ Tcl_Main(argc, argv, appInitProc) /* * The following statement guarantees that the errorInfo - * variable is set properly. + * variable is set properly when the error has to do with + * the opening or reading of the file. */ Tcl_AddErrorInfo(interp, ""); diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 4c7a420..6b606f0 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -21,7 +21,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclNamesp.c,v 1.61 2004/10/06 15:59:24 dgp Exp $ + * RCS: @(#) $Id: tclNamesp.c,v 1.62 2004/10/15 04:01:32 dgp Exp $ */ #include "tclInt.h" @@ -175,9 +175,15 @@ static void DupNsNameInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr, static char * ErrorCodeRead _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, CONST char *name1, CONST char *name2, int flags)); +static char * ErrorInfoRead _ANSI_ARGS_(( ClientData clientData, + Tcl_Interp *interp, CONST char *name1, + CONST char *name2, int flags)); static char * EstablishErrorCodeTraces _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, CONST char *name1, CONST char *name2, int flags)); +static char * EstablishErrorInfoTraces _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + CONST char *name1, CONST char *name2, int flags)); static void FreeNsNameInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr)); static int GetNamespaceFromObj _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *objPtr, @@ -525,7 +531,7 @@ Tcl_PopCallFrame(interp) * EstablishErrorCodeTraces -- * * Creates traces on the ::errorCode variable to keep its value - * consistent with the expectation of legacy code. + * consistent with the expectations of legacy code. * * Results: * None. @@ -535,6 +541,7 @@ Tcl_PopCallFrame(interp) * *---------------------------------------------------------------------- */ + static char * EstablishErrorCodeTraces(clientData, interp, name1, name2, flags) ClientData clientData; @@ -549,6 +556,23 @@ EstablishErrorCodeTraces(clientData, interp, name1, name2, flags) EstablishErrorCodeTraces, (ClientData) NULL); return NULL; } + +/* + *---------------------------------------------------------------------- + * + * ErrorCodeRead -- + * + * Called when the ::errorCode variable is read. Copies the + * current value of the interp's errorCode field into ::errorCode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ static char * ErrorCodeRead(clientData, interp, name1, name2, flags) @@ -562,8 +586,72 @@ ErrorCodeRead(clientData, interp, name1, name2, flags) if (flags & TCL_INTERP_DESTROYED) return NULL; if (iPtr->errorCode == NULL) return NULL; - Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorCode, NULL, - iPtr->errorCode, TCL_GLOBAL_ONLY); + Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL, iPtr->errorCode, TCL_GLOBAL_ONLY); + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * EstablishErrorInfoTraces -- + * + * Creates traces on the ::errorInfo variable to keep its value + * consistent with the expectations of legacy code. + * + * Results: + * None. + * + * Side effects: + * Read and unset traces are established on ::errorInfo. + * + *---------------------------------------------------------------------- + */ + +static char * +EstablishErrorInfoTraces(clientData, interp, name1, name2, flags) + ClientData clientData; + Tcl_Interp *interp; + CONST char *name1; + CONST char *name2; + int flags; +{ + Tcl_TraceVar(interp, "errorInfo", TCL_GLOBAL_ONLY | TCL_TRACE_READS, + ErrorInfoRead, (ClientData) NULL); + Tcl_TraceVar(interp, "errorInfo", TCL_GLOBAL_ONLY | TCL_TRACE_UNSETS, + EstablishErrorInfoTraces, (ClientData) NULL); + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * ErrorInfoRead -- + * + * Called when the ::errorInfo variable is read. Copies the + * current value of the interp's errorInfo field into ::errorInfo. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static char * +ErrorInfoRead(clientData, interp, name1, name2, flags) + ClientData clientData; + Tcl_Interp *interp; + CONST char *name1; + CONST char *name2; + int flags; +{ + Interp *iPtr = (Interp *)interp; + + if (flags & TCL_INTERP_DESTROYED) return NULL; + if (iPtr->errorInfo == NULL) return NULL; + Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, iPtr->errorInfo, TCL_GLOBAL_ONLY); return NULL; } @@ -705,9 +793,10 @@ Tcl_CreateNamespace(interp, name, clientData, deleteProc) } else { /* * In the global namespace create traces to maintain the - * ::errorCode variable. + * ::errorInfo and ::errorCode variables. */ iPtr->globalNsPtr = nsPtr; + EstablishErrorInfoTraces(NULL, interp, NULL, NULL, 0); EstablishErrorCodeTraces(NULL, interp, NULL, NULL, 0); } @@ -829,11 +918,11 @@ Tcl_DeleteNamespace(namespacePtr) TclTeardownNamespace(nsPtr); if ((nsPtr != globalNsPtr) || (iPtr->flags & DELETED)) { - /* + /* * If this is the global namespace, then it may have residual - * "errorInfo" and "errorCode" variables for errors that - * occurred while it was being torn down. Try to clear the - * variable list one last time. + * "errorInfo" and "errorCode" variables for errors that + * occurred while it was being torn down. Try to clear the + * variable list one last time. */ TclDeleteVars((Interp *) nsPtr->interp, &nsPtr->varTable); @@ -852,7 +941,8 @@ Tcl_DeleteNamespace(namespacePtr) nsPtr->flags |= NS_DEAD; } } else { - /* Restore the ::errorCode traces */ + /* Restore the ::errorInfo and ::errorCode traces */ + EstablishErrorInfoTraces(NULL, nsPtr->interp, NULL, NULL, 0); EstablishErrorCodeTraces(NULL, nsPtr->interp, NULL, NULL, 0); } } @@ -868,9 +958,7 @@ Tcl_DeleteNamespace(namespacePtr) * commands, variables, and child namespaces. * * This is kept separate from Tcl_DeleteNamespace so that the global - * namespace can be handled specially. Global variables like - * "errorInfo" and "errorCode" need to remain intact while other - * namespaces and commands are torn down, in case any errors occur. + * namespace can be handled specially. * * Results: * None. @@ -878,8 +966,6 @@ Tcl_DeleteNamespace(namespacePtr) * Side effects: * Removes this namespace from its parent's child namespace hashtable. * Deletes all commands, variables and namespaces in this namespace. - * If this is the global namespace, the "errorInfo" and "errorCode" - * variables are left alone and deleted later. * *---------------------------------------------------------------------- */ @@ -894,47 +980,17 @@ TclTeardownNamespace(nsPtr) Tcl_HashSearch search; Tcl_Namespace *childNsPtr; Tcl_Command cmd; - Namespace *globalNsPtr = - (Namespace *) Tcl_GetGlobalNamespace((Tcl_Interp *) iPtr); int i; /* * Start by destroying the namespace's variable table, * since variables might trigger traces. + * Variable table should be cleared but not freed! + * TclDeleteVars frees it, so we reinitialize it afterwards. */ - if (nsPtr == globalNsPtr) { - /* - * This is the global namespace. Tearing it down will destroy the - * ::errorInfo variable. We save and restore it - * in case there are any errors in progress, so the error details - * it contains will not be lost. See test namespace-8.5 - */ - - Tcl_Obj *errorInfo = Tcl_GetVar2Ex(nsPtr->interp, "errorInfo", - NULL, TCL_GLOBAL_ONLY); - - if (errorInfo) { - Tcl_IncrRefCount(errorInfo); - } - - TclDeleteVars(iPtr, &nsPtr->varTable); - Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS); - - if (errorInfo) { - Tcl_SetVar2Ex(nsPtr->interp, "errorInfo", NULL, - errorInfo, TCL_GLOBAL_ONLY); - Tcl_DecrRefCount(errorInfo); - } - } else { - /* - * Variable table should be cleared but not freed! TclDeleteVars - * frees it, so we reinitialize it afterwards. - */ - - TclDeleteVars(iPtr, &nsPtr->varTable); - Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS); - } + TclDeleteVars(iPtr, &nsPtr->varTable); + Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS); /* * Remove the namespace from its parent's child hashtable. diff --git a/generic/tclProc.c b/generic/tclProc.c index 833e6d7..1be2e09 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclProc.c,v 1.59 2004/10/06 10:11:05 dkf Exp $ + * RCS: @(#) $Id: tclProc.c,v 1.60 2004/10/15 04:01:33 dgp Exp $ */ #include "tclInt.h" @@ -1295,7 +1295,7 @@ TclProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description, procName) * Side effects: * If the result returned is TCL_ERROR, traceback information about * the procedure just executed is appended to the interpreter's - * "errorInfo" variable. + * errorInfo field. * *---------------------------------------------------------------------- */ @@ -1439,7 +1439,7 @@ TclProcCleanupProc(procPtr) * the procedure, instead of TCL_RETURN. * * Side effects: - * The errorInfo and errorCode variables may get modified. + * The errorInfo and errorCode fields may get set. * *---------------------------------------------------------------------- */ @@ -1481,9 +1481,8 @@ TclUpdateReturnInfo(iPtr) Tcl_DictObjGet(NULL, iPtr->returnOpts, iPtr->returnErrorinfoKey, &valuePtr); if (valuePtr != NULL) { - Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorInfo, - NULL, valuePtr, TCL_GLOBAL_ONLY); - iPtr->flags |= ERR_IN_PROGRESS; + iPtr->errorInfo = valuePtr; + Tcl_IncrRefCount(iPtr->errorInfo); } } return code; diff --git a/generic/tclResult.c b/generic/tclResult.c index 9870501..9fd0bfc 100644 --- a/generic/tclResult.c +++ b/generic/tclResult.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclResult.c,v 1.14 2004/10/06 15:59:25 dgp Exp $ + * RCS: @(#) $Id: tclResult.c,v 1.15 2004/10/15 04:01:33 dgp Exp $ */ #include "tclInt.h" @@ -732,12 +732,20 @@ Tcl_ResetResult(interp) iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; if (iPtr->errorCode) { - Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorCode, NULL, + /* Legacy support */ + Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL, iPtr->errorCode, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(iPtr->errorCode); iPtr->errorCode = NULL; } - iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS); + if (iPtr->errorInfo) { + /* Legacy support*/ + Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, + iPtr->errorInfo, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(iPtr->errorInfo); + iPtr->errorInfo = NULL; + } + iPtr->flags &= ~ERR_ALREADY_LOGGED; } /* @@ -794,26 +802,23 @@ ResetObjResult(iPtr) * None. * * Side effects: - * The errorCode global variable is modified to hold all of the + * The errorCode field of the interp 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. + * becoming one element of the list. * *---------------------------------------------------------------------- */ void Tcl_SetErrorCodeVA (interp, argList) - Tcl_Interp *interp; /* Interpreter in which to access the errorCode - * variable. */ + Tcl_Interp *interp; /* Interpreter in which to set errorCode */ va_list argList; /* Variable argument list. */ { Tcl_Obj *errorObj = Tcl_NewObj(); /* * Scan through the arguments one at a time, appending them to - * $errorCode as list elements. + * the errorCode field as list elements. */ while (1) { @@ -838,11 +843,9 @@ Tcl_SetErrorCodeVA (interp, argList) * None. * * Side effects: - * The errorCode global variable is modified to hold all of the + * The errorCode field of the interp 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. + * becoming one element of the list. * *---------------------------------------------------------------------- */ @@ -855,7 +858,7 @@ Tcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1) /* * Scan through the arguments one at a time, appending them to - * $errorCode as list elements. + * the errorCode field as list elements. */ interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList); @@ -876,10 +879,7 @@ Tcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1) * 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. + * The errorCode field of the interp is set to the new value. * *---------------------------------------------------------------------- */ @@ -917,9 +917,9 @@ Tcl_SetObjErrorCode(interp, errorObjPtr) * * 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. + * result. The source's errorInfo field may be transferred to the + * target's errorInfo field, and the source's errorCode field may be + * transferred to the target's errorCode field. * * Side effects: * None. @@ -963,17 +963,13 @@ TclTransferResult(sourceInterp, result, targetInterp) Tcl_ResetResult(targetInterp); - objPtr = Tcl_GetVar2Ex(sourceInterp, "errorInfo", NULL, - TCL_GLOBAL_ONLY); - if (objPtr) { - Tcl_SetVar2Ex(targetInterp, "errorInfo", NULL, objPtr, - TCL_GLOBAL_ONLY); - ((Interp *) targetInterp)->flags |= ERR_IN_PROGRESS; + if (iPtr->errorInfo) { + ((Interp *) targetInterp)->errorInfo = iPtr->errorInfo; + Tcl_IncrRefCount(((Interp *) targetInterp)->errorInfo); } - objPtr = ((Interp *) sourceInterp)->errorCode; - if (objPtr) { - Tcl_SetObjErrorCode(targetInterp, objPtr); + if (iPtr->errorCode) { + Tcl_SetObjErrorCode(targetInterp, iPtr->errorCode); } } diff --git a/generic/tclTrace.c b/generic/tclTrace.c index 2b0f10f..b2067b3 100644 --- a/generic/tclTrace.c +++ b/generic/tclTrace.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclTrace.c,v 1.15 2004/10/06 15:59:25 dgp Exp $ + * RCS: @(#) $Id: tclTrace.c,v 1.16 2004/10/15 04:01:33 dgp Exp $ */ #include "tclInt.h" @@ -2413,8 +2413,8 @@ TclVarTraceExists(interp, varName) * Returns TCL_OK to indicate normal operation. Returns TCL_ERROR * if invocation of a trace procedure indicated an error. When * TCL_ERROR is returned and leaveErrMsg is true, then the - * ::errorInfo variable of iPtr has information about the error - * appended to it. + * errorInfo field of iPtr has information about the error + * placed in it. * * Side effects: * Almost anything can happen, depending on trace; this procedure @@ -2450,10 +2450,13 @@ TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, flags, leaveErrMsg) int copiedName; int code = TCL_OK; int disposeFlags = 0; - int saveErrFlags = iPtr->flags - & (ERR_IN_PROGRESS | ERR_ALREADY_LOGGED); + int saveErrFlags = iPtr->flags & ERR_ALREADY_LOGGED; + Tcl_Obj *saveErrInfo = iPtr->errorInfo; Tcl_Obj *saveErrCode = iPtr->errorCode; + if (saveErrInfo) { + Tcl_IncrRefCount(saveErrInfo); + } if (saveErrCode) { Tcl_IncrRefCount(saveErrCode); } @@ -2581,12 +2584,21 @@ TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, flags, leaveErrMsg) done: if (code == TCL_OK) { iPtr->flags |= saveErrFlags; + if (iPtr->errorInfo) { + Tcl_DecrRefCount(iPtr->errorInfo); + } + iPtr->errorInfo = saveErrInfo; if (iPtr->errorCode) { Tcl_DecrRefCount(iPtr->errorCode); } iPtr->errorCode = saveErrCode; - } else if (saveErrCode) { - Tcl_DecrRefCount(saveErrCode); + } else { + if (saveErrInfo) { + Tcl_DecrRefCount(saveErrInfo); + } + if (saveErrCode) { + Tcl_DecrRefCount(saveErrCode); + } } if (code == TCL_ERROR) { if (leaveErrMsg) { |