diff options
Diffstat (limited to 'generic/tclResult.c')
| -rw-r--r-- | generic/tclResult.c | 338 | 
1 files changed, 242 insertions, 96 deletions
| diff --git a/generic/tclResult.c b/generic/tclResult.c index c461387..2f2563a 100644 --- a/generic/tclResult.c +++ b/generic/tclResult.c @@ -7,8 +7,6 @@   *   * 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.47.2.1 2010/03/24 15:31:48 dgp Exp $   */  #include "tclInt.h" @@ -19,7 +17,7 @@  enum returnKeys {      KEY_CODE,	KEY_ERRORCODE,	KEY_ERRORINFO,	KEY_ERRORLINE, -    KEY_LEVEL,	KEY_OPTIONS,	KEY_LAST +    KEY_LEVEL,	KEY_OPTIONS,	KEY_ERRORSTACK,	KEY_LAST  };  /* @@ -46,6 +44,8 @@ typedef struct InterpState {      Tcl_Obj *errorCode;      Tcl_Obj *returnOpts;      Tcl_Obj *objResult; +    Tcl_Obj *errorStack; +    int resetErrorStack;  } InterpState;  /* @@ -74,14 +74,16 @@ Tcl_SaveInterpState(      Tcl_Interp *interp,		/* Interpreter's state to be saved */      int status)			/* status code for current operation */  { -    Interp *iPtr = (Interp *)interp; -    InterpState *statePtr = (InterpState *)ckalloc(sizeof(InterpState)); +    Interp *iPtr = (Interp *) interp; +    InterpState *statePtr = ckalloc(sizeof(InterpState));      statePtr->status = status;      statePtr->flags = iPtr->flags & ERR_ALREADY_LOGGED;      statePtr->returnLevel = iPtr->returnLevel;      statePtr->returnCode = iPtr->returnCode;      statePtr->errorInfo = iPtr->errorInfo; +    statePtr->errorStack = iPtr->errorStack; +    statePtr->resetErrorStack = iPtr->resetErrorStack;      if (statePtr->errorInfo) {  	Tcl_IncrRefCount(statePtr->errorInfo);      } @@ -93,6 +95,9 @@ Tcl_SaveInterpState(      if (statePtr->returnOpts) {  	Tcl_IncrRefCount(statePtr->returnOpts);      } +    if (statePtr->errorStack) { +	Tcl_IncrRefCount(statePtr->errorStack); +    }      statePtr->objResult = Tcl_GetObjResult(interp);      Tcl_IncrRefCount(statePtr->objResult);      return (Tcl_InterpState) statePtr; @@ -121,8 +126,8 @@ Tcl_RestoreInterpState(      Tcl_Interp *interp,		/* Interpreter's state to be restored. */      Tcl_InterpState state)	/* Saved interpreter state. */  { -    Interp *iPtr = (Interp *)interp; -    InterpState *statePtr = (InterpState *)state; +    Interp *iPtr = (Interp *) interp; +    InterpState *statePtr = (InterpState *) state;      int status = statePtr->status;      iPtr->flags &= ~ERR_ALREADY_LOGGED; @@ -130,6 +135,7 @@ Tcl_RestoreInterpState(      iPtr->returnLevel = statePtr->returnLevel;      iPtr->returnCode = statePtr->returnCode; +    iPtr->resetErrorStack = statePtr->resetErrorStack;      if (iPtr->errorInfo) {  	Tcl_DecrRefCount(iPtr->errorInfo);      } @@ -144,6 +150,13 @@ Tcl_RestoreInterpState(      if (iPtr->errorCode) {  	Tcl_IncrRefCount(iPtr->errorCode);      } +    if (iPtr->errorStack) { +	Tcl_DecrRefCount(iPtr->errorStack); +    } +    iPtr->errorStack = statePtr->errorStack; +    if (iPtr->errorStack) { +	Tcl_IncrRefCount(iPtr->errorStack); +    }      if (iPtr->returnOpts) {  	Tcl_DecrRefCount(iPtr->returnOpts);      } @@ -177,7 +190,7 @@ void  Tcl_DiscardInterpState(      Tcl_InterpState state)	/* saved interpreter state */  { -    InterpState *statePtr = (InterpState *)state; +    InterpState *statePtr = (InterpState *) state;      if (statePtr->errorInfo) {  	Tcl_DecrRefCount(statePtr->errorInfo); @@ -188,8 +201,11 @@ Tcl_DiscardInterpState(      if (statePtr->returnOpts) {  	Tcl_DecrRefCount(statePtr->returnOpts);      } +    if (statePtr->errorStack) { +	Tcl_DecrRefCount(statePtr->errorStack); +    }      Tcl_DecrRefCount(statePtr->objResult); -    ckfree((char *) statePtr); +    ckfree(statePtr);  }  /* @@ -214,6 +230,7 @@ Tcl_DiscardInterpState(   *----------------------------------------------------------------------   */ +#undef Tcl_SaveResult  void  Tcl_SaveResult(      Tcl_Interp *interp,		/* Interpreter to save. */ @@ -288,6 +305,7 @@ Tcl_SaveResult(   *----------------------------------------------------------------------   */ +#undef Tcl_RestoreResult  void  Tcl_RestoreResult(      Tcl_Interp *interp,		/* Interpreter being restored. */ @@ -315,7 +333,7 @@ Tcl_RestoreResult(  	 */  	if (iPtr->appendResult != NULL) { -	    ckfree((char *) iPtr->appendResult); +	    ckfree(iPtr->appendResult);  	}  	iPtr->appendResult = statePtr->appendResult; @@ -356,6 +374,7 @@ Tcl_RestoreResult(   *----------------------------------------------------------------------   */ +#undef Tcl_DiscardResult  void  Tcl_DiscardResult(      Tcl_SavedResult *statePtr)	/* State returned by Tcl_SaveResult. */ @@ -364,12 +383,10 @@ Tcl_DiscardResult(      if (statePtr->result == statePtr->appendResult) {  	ckfree(statePtr->appendResult); +    } else if (statePtr->freeProc == TCL_DYNAMIC) { +        ckfree(statePtr->result);      } else if (statePtr->freeProc) { -	if (statePtr->freeProc == TCL_DYNAMIC) { -	    ckfree(statePtr->result); -	} else { -	    (*statePtr->freeProc)(statePtr->result); -	} +        statePtr->freeProc(statePtr->result);      }  } @@ -401,7 +418,6 @@ Tcl_SetResult(  				 * a Tcl_FreeProc such as free. */  {      Interp *iPtr = (Interp *) interp; -    int length;      register Tcl_FreeProc *oldFreeProc = iPtr->freeProc;      char *oldResult = iPtr->result; @@ -410,17 +426,18 @@ Tcl_SetResult(  	iPtr->result = iPtr->resultSpace;  	iPtr->freeProc = 0;      } else if (freeProc == TCL_VOLATILE) { -	length = strlen(result); +	int length = strlen(result); +  	if (length > TCL_RESULT_SIZE) { -	    iPtr->result = (char *) ckalloc((unsigned) length+1); +	    iPtr->result = ckalloc(length + 1);  	    iPtr->freeProc = TCL_DYNAMIC;  	} else {  	    iPtr->result = iPtr->resultSpace;  	    iPtr->freeProc = 0;  	} -	strcpy(iPtr->result, result); +	memcpy(iPtr->result, result, (unsigned) length+1);      } else { -	iPtr->result = result; +	iPtr->result = (char *) result;  	iPtr->freeProc = freeProc;      } @@ -434,7 +451,7 @@ Tcl_SetResult(  	if (oldFreeProc == TCL_DYNAMIC) {  	    ckfree(oldResult);  	} else { -	    (*oldFreeProc)(oldResult); +	    oldFreeProc(oldResult);  	}      } @@ -462,7 +479,7 @@ Tcl_SetResult(   *----------------------------------------------------------------------   */ -CONST char * +const char *  Tcl_GetStringResult(      register Tcl_Interp *interp)/* Interpreter whose result to return. */  { @@ -471,11 +488,13 @@ Tcl_GetStringResult(       * result, then reset the object result.       */ -    if (*(interp->result) == 0) { +    Interp *iPtr = (Interp *) interp; + +    if (*(iPtr->result) == 0) {  	Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),  		TCL_VOLATILE);      } -    return interp->result; +    return iPtr->result;  }  /* @@ -525,7 +544,7 @@ Tcl_SetObjResult(  	if (iPtr->freeProc == TCL_DYNAMIC) {  	    ckfree(iPtr->result);  	} else { -	    (*iPtr->freeProc)(iPtr->result); +	    iPtr->freeProc(iPtr->result);  	}  	iPtr->freeProc = 0;      } @@ -567,7 +586,7 @@ Tcl_GetObjResult(       * result, then reset the string result.       */ -    if (*(iPtr->result) != 0) { +    if (iPtr->result[0] != 0) {  	ResetObjResult(iPtr);  	objResultPtr = iPtr->objResultPtr; @@ -578,12 +597,12 @@ Tcl_GetObjResult(  	    if (iPtr->freeProc == TCL_DYNAMIC) {  		ckfree(iPtr->result);  	    } else { -		(*iPtr->freeProc)(iPtr->result); +		iPtr->freeProc(iPtr->result);  	    }  	    iPtr->freeProc = 0;  	}  	iPtr->result = iPtr->resultSpace; -	iPtr->resultSpace[0] = 0; +	iPtr->result[0] = 0;      }      return iPtr->objResultPtr;  } @@ -630,14 +649,14 @@ Tcl_AppendResultVA(       * calls to Tcl_GetStringResult() itself. [Patch 1041072 discussion]       */ -#ifdef USE_DIRECT_INTERP_RESULT_ACCESS +#ifdef USE_INTERP_RESULT      /*       * Ensure that the interp->result is legal so old Tcl 7.* code still       * works. There's still embarrasingly much of it about...       */      (void) Tcl_GetStringResult(interp); -#endif /* USE_DIRECT_INTERP_RESULT_ACCESS */ +#endif /* USE_INTERP_RESULT */  }  /* @@ -699,7 +718,7 @@ void  Tcl_AppendElement(      Tcl_Interp *interp,		/* Interpreter whose result is to be  				 * extended. */ -    CONST char *element)	/* String to convert to list element and add +    const char *element)	/* String to convert to list element and add  				 * to result. */  {      Interp *iPtr = (Interp *) interp; @@ -813,7 +832,7 @@ SetupAppendBuffer(  	} else {  	    totalSpace *= 2;  	} -	new = (char *) ckalloc((unsigned) totalSpace); +	new = ckalloc(totalSpace);  	strcpy(new, iPtr->result);  	if (iPtr->appendResult != NULL) {  	    ckfree(iPtr->appendResult); @@ -860,7 +879,7 @@ Tcl_FreeResult(  	if (iPtr->freeProc == TCL_DYNAMIC) {  	    ckfree(iPtr->result);  	} else { -	    (*iPtr->freeProc)(iPtr->result); +	    iPtr->freeProc(iPtr->result);  	}  	iPtr->freeProc = 0;      } @@ -898,7 +917,7 @@ Tcl_ResetResult(  	if (iPtr->freeProc == TCL_DYNAMIC) {  	    ckfree(iPtr->result);  	} else { -	    (*iPtr->freeProc)(iPtr->result); +	    iPtr->freeProc(iPtr->result);  	}  	iPtr->freeProc = 0;      } @@ -922,6 +941,7 @@ Tcl_ResetResult(  	Tcl_DecrRefCount(iPtr->errorInfo);  	iPtr->errorInfo = NULL;      } +    iPtr->resetErrorStack = 1;      iPtr->returnLevel = 1;      iPtr->returnCode = TCL_OK;      if (iPtr->returnOpts) { @@ -961,14 +981,15 @@ ResetObjResult(  	TclNewObj(objResultPtr);  	Tcl_IncrRefCount(objResultPtr);  	iPtr->objResultPtr = objResultPtr; -    } else if (objResultPtr->bytes != tclEmptyStringRep) { -	if (objResultPtr->bytes != NULL) { -	    ckfree((char *) objResultPtr->bytes); +    } else { +	if (objResultPtr->bytes != tclEmptyStringRep) { +	    if (objResultPtr->bytes) { +		ckfree(objResultPtr->bytes); +	    } +	    objResultPtr->bytes = tclEmptyStringRep; +	    objResultPtr->length = 0;  	} -	objResultPtr->bytes = tclEmptyStringRep; -	objResultPtr->length = 0;  	TclFreeIntRep(objResultPtr); -	objResultPtr->typePtr = NULL;      }  } @@ -1005,6 +1026,7 @@ Tcl_SetErrorCodeVA(      while (1) {  	char *elem = va_arg(argList, char *); +  	if (elem == NULL) {  	    break;  	} @@ -1083,6 +1105,43 @@ Tcl_SetObjErrorCode(  /*   *----------------------------------------------------------------------   * + * Tcl_GetErrorLine -- + * + *      Returns the line number associated with the current error. + * + *---------------------------------------------------------------------- + */ + +#undef Tcl_GetErrorLine +int +Tcl_GetErrorLine( +    Tcl_Interp *interp) +{ +    return ((Interp *) interp)->errorLine; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SetErrorLine -- + * + *      Sets the line number associated with the current error. + * + *---------------------------------------------------------------------- + */ + +#undef Tcl_SetErrorLine +void +Tcl_SetErrorLine( +    Tcl_Interp *interp, +    int value) +{ +    ((Interp *) interp)->errorLine = value; +} + +/* + *---------------------------------------------------------------------- + *   * GetKeys --   *   *	Returns a Tcl_Obj * array of the standard keys used in the return @@ -1095,8 +1154,8 @@ Tcl_SetObjErrorCode(   *	A Tcl_Obj * array.   *   * Side effects: - * 	First time called in a thread, creates the keys (allocating memory) - * 	and arranges for their cleanup at thread exit. + *	First time called in a thread, creates the keys (allocating memory) + *	and arranges for their cleanup at thread exit.   *   *----------------------------------------------------------------------   */ @@ -1119,6 +1178,7 @@ GetKeys(void)  	TclNewLiteralStringObj(keys[KEY_ERRORCODE], "-errorcode");  	TclNewLiteralStringObj(keys[KEY_ERRORINFO], "-errorinfo");  	TclNewLiteralStringObj(keys[KEY_ERRORLINE], "-errorline"); +	TclNewLiteralStringObj(keys[KEY_ERRORSTACK],"-errorstack");  	TclNewLiteralStringObj(keys[KEY_LEVEL],	    "-level");  	TclNewLiteralStringObj(keys[KEY_OPTIONS],   "-options"); @@ -1130,7 +1190,7 @@ GetKeys(void)  	 * ... and arrange for their clenaup.  	 */ -	Tcl_CreateThreadExitHandler(ReleaseKeys, (ClientData) keys); +	Tcl_CreateThreadExitHandler(ReleaseKeys, keys);      }      return keys;  } @@ -1147,7 +1207,7 @@ GetKeys(void)   *	None.   *   * Side effects: - * 	Frees memory. + *	Frees memory.   *   *----------------------------------------------------------------------   */ @@ -1156,7 +1216,7 @@ static void  ReleaseKeys(      ClientData clientData)  { -    Tcl_Obj **keys = (Tcl_Obj **)clientData; +    Tcl_Obj **keys = clientData;      int i;      for (i = KEY_CODE; i < KEY_LAST; i++) { @@ -1180,7 +1240,7 @@ ReleaseKeys(   *	Returns the return code the [return] command should return.   *   * Side effects: - * 	None. + *	None.   *   *----------------------------------------------------------------------   */ @@ -1213,7 +1273,8 @@ TclProcessReturn(  	    Tcl_DecrRefCount(iPtr->errorInfo);  	    iPtr->errorInfo = NULL;  	} -	Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORINFO], &valuePtr); +	Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORINFO], +                &valuePtr);  	if (valuePtr != NULL) {  	    int infoLen; @@ -1224,14 +1285,50 @@ TclProcessReturn(  		iPtr->flags |= ERR_ALREADY_LOGGED;  	    }  	} -	Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORCODE], &valuePtr); +	Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORSTACK], +                &valuePtr); +	if (valuePtr != NULL) { +            int len, valueObjc; +            Tcl_Obj **valueObjv; + +            if (Tcl_IsShared(iPtr->errorStack)) { +                Tcl_Obj *newObj; +                 +                newObj = Tcl_DuplicateObj(iPtr->errorStack); +                Tcl_DecrRefCount(iPtr->errorStack); +                Tcl_IncrRefCount(newObj); +                iPtr->errorStack = newObj; +            } + +            /* +             * List extraction done after duplication to avoid moving the rug +             * if someone does [return -errorstack [info errorstack]] +             */ + +            if (Tcl_ListObjGetElements(interp, valuePtr, &valueObjc, +                    &valueObjv) == TCL_ERROR) { +                return TCL_ERROR; +            } +            iPtr->resetErrorStack = 0; +            Tcl_ListObjLength(interp, iPtr->errorStack, &len); + +            /* +             * Reset while keeping the list intrep as much as possible. +             */ + +            Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, valueObjc, +                    valueObjv); + 	} +	Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORCODE], +                &valuePtr);  	if (valuePtr != NULL) {  	    Tcl_SetObjErrorCode(interp, valuePtr);  	} else {  	    Tcl_SetErrorCode(interp, "NONE", NULL);  	} -	Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORLINE], &valuePtr); +	Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORLINE], +                &valuePtr);  	if (valuePtr != NULL) {  	    TclGetIntFromObj(NULL, valuePtr, &iPtr->errorLine);  	} @@ -1255,12 +1352,12 @@ TclProcessReturn(   *	Parses, checks, and stores the options to the [return] command.   *   * Results: - *	Returns TCL_ERROR is any of the option values are invalid. Otherwise, + *	Returns TCL_ERROR if any of the option values are invalid. Otherwise,   *	returns TCL_OK, and writes the returnOpts, code, and level values to   *	the pointers provided.   *   * Side effects: - * 	None. + *	None.   *   *----------------------------------------------------------------------   */ @@ -1269,16 +1366,16 @@ int  TclMergeReturnOptions(      Tcl_Interp *interp,		/* Current interpreter. */      int objc,			/* Number of arguments. */ -    Tcl_Obj *CONST objv[],	/* Argument objects. */ +    Tcl_Obj *const objv[],	/* Argument objects. */      Tcl_Obj **optionsPtrPtr,	/* If not NULL, points to space for a (Tcl_Obj  				 * *) where the pointer to the merged return -				 * options dictionary should be written */ +				 * options dictionary should be written. */      int *codePtr,		/* If not NULL, points to space where the -				 * -code value should be written */ +				 * -code value should be written. */      int *levelPtr)		/* If not NULL, points to space where the -				 * -level value should be written */ +				 * -level value should be written. */  { -    int code=TCL_OK; +    int code = TCL_OK;      int level = 1;      Tcl_Obj *valuePtr;      Tcl_Obj *returnOpts = Tcl_NewObj(); @@ -1286,12 +1383,12 @@ TclMergeReturnOptions(      for (;  objc > 1;  objv += 2, objc -= 2) {  	int optLen; -	CONST char *opt = TclGetStringFromObj(objv[0], &optLen); +	const char *opt = TclGetStringFromObj(objv[0], &optLen);  	int compareLen; -	CONST char *compare = +	const char *compare =  		TclGetStringFromObj(keys[KEY_OPTIONS], &compareLen); -	if ((optLen == compareLen) && (strcmp(opt, compare) == 0)) { +	if ((optLen == compareLen) && (memcmp(opt, compare, optLen) == 0)) {  	    Tcl_DictSearch search;  	    int done = 0;  	    Tcl_Obj *keyPtr; @@ -1304,10 +1401,11 @@ TclMergeReturnOptions(  		 * Value is not a legal dictionary.  		 */ -		Tcl_ResetResult(interp); -		Tcl_AppendResult(interp, "bad ", compare, -			" value: expected dictionary but got \"", -			TclGetString(objv[1]), "\"", NULL); +		Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                        "bad %s value: expected dictionary but got \"%s\"", +                        compare, TclGetString(objv[1]))); +		Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_OPTIONS", +			NULL);  		goto error;  	    } @@ -1333,27 +1431,11 @@ TclMergeReturnOptions(       */      Tcl_DictObjGet(NULL, returnOpts, keys[KEY_CODE], &valuePtr); -    if ((valuePtr != NULL) -	    && (TCL_ERROR == TclGetIntFromObj(NULL, valuePtr, &code))) { -	static CONST char *returnCodes[] = { -	    "ok", "error", "return", "break", "continue", NULL -	}; - -	if (TCL_ERROR == Tcl_GetIndexFromObj(NULL, valuePtr, returnCodes, -		NULL, TCL_EXACT, &code)) { -	    /* -	     * Value is not a legal return code. -	     */ - -	    Tcl_ResetResult(interp); -	    Tcl_AppendResult(interp, "bad completion code \"", -		    TclGetString(valuePtr), -		    "\": must be ok, error, return, break, " -		    "continue, or an integer", NULL); +    if (valuePtr != NULL) { +	if (TclGetCompletionCodeFromObj(interp, valuePtr, +                &code) == TCL_ERROR) {  	    goto error;  	} -    } -    if (valuePtr != NULL) {  	Tcl_DictObjRemove(NULL, returnOpts, keys[KEY_CODE]);      } @@ -1369,10 +1451,10 @@ TclMergeReturnOptions(  	     * Value is not a legal level.  	     */ -	    Tcl_ResetResult(interp); -	    Tcl_AppendResult(interp, "bad -level value: " -		    "expected non-negative integer but got \"", -		    TclGetString(valuePtr), "\"", NULL); +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                    "bad -level value: expected non-negative integer but got" +                    " \"%s\"", TclGetString(valuePtr))); +	    Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_LEVEL", NULL);  	    goto error;  	}  	Tcl_DictObjRemove(NULL, returnOpts, keys[KEY_LEVEL]); @@ -1390,15 +1472,51 @@ TclMergeReturnOptions(  	    /*  	     * Value is not a list, which is illegal for -errorcode.  	     */ -	    Tcl_ResetResult(interp); -	    Tcl_AppendResult(interp, "bad -errorcode value: " -			     "expected a list but got \"", -			     TclGetString(valuePtr), "\"", NULL); + +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                    "bad -errorcode value: expected a list but got \"%s\"", +                    TclGetString(valuePtr))); +	    Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_ERRORCODE", +		    NULL);  	    goto error;  	}      }      /* +     * Check for bogus -errorstack value. +     */ + +    Tcl_DictObjGet(NULL, returnOpts, keys[KEY_ERRORSTACK], &valuePtr); +    if (valuePtr != NULL) { +	int length; + +	if (TCL_ERROR == Tcl_ListObjLength(NULL, valuePtr, &length )) { +	    /* +	     * Value is not a list, which is illegal for -errorstack. +	     */ + +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                    "bad -errorstack value: expected a list but got \"%s\"", +                    TclGetString(valuePtr))); +	    Tcl_SetErrorCode(interp, "TCL", "RESULT", "NONLIST_ERRORSTACK", +                    NULL); +	    goto error; +	} +        if (length % 2) { +            /* +             * Errorstack must always be an even-sized list +             */ + +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                    "forbidden odd-sized list for -errorstack: \"%s\"", +		    TclGetString(valuePtr))); +	    Tcl_SetErrorCode(interp, "TCL", "RESULT", +                    "ODDSIZEDLIST_ERRORSTACK", NULL); +	    goto error; +        } +    } + +    /*       * Convert [return -code return -level X] to [return -code ok -level X+1]       */ @@ -1474,7 +1592,8 @@ Tcl_GetReturnOptions(      }      if (result == TCL_ERROR) { -	Tcl_AddObjErrorInfo(interp, "", -1); +	Tcl_AddErrorInfo(interp, ""); +        Tcl_DictObjPut(NULL, options, keys[KEY_ERRORSTACK], iPtr->errorStack);      }      if (iPtr->errorCode) {  	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORCODE], iPtr->errorCode); @@ -1490,6 +1609,31 @@ Tcl_GetReturnOptions(  /*   *-------------------------------------------------------------------------   * + * TclNoErrorStack -- + * + *	Removes the -errorstack entry from an options dict to avoid reference + *	cycles. + * + * Results: + *	The (unshared) argument options dict, modified in -place. + * + *------------------------------------------------------------------------- + */ + +Tcl_Obj * +TclNoErrorStack( +    Tcl_Interp *interp, +    Tcl_Obj *options) +{ +    Tcl_Obj **keys = GetKeys(); +     +    Tcl_DictObjRemove(interp, options, keys[KEY_ERRORSTACK]); +    return options; +} + +/* + *------------------------------------------------------------------------- + *   * Tcl_SetReturnOptions --   *   *	Accepts an interp and a dictionary of return options, and sets the @@ -1518,9 +1662,9 @@ Tcl_SetReturnOptions(      Tcl_IncrRefCount(options);      if (TCL_ERROR == TclListObjGetElements(interp, options, &objc, &objv)  	    || (objc % 2)) { -	Tcl_ResetResult(interp); -	Tcl_AppendResult(interp, "expected dict but got \"", -		TclGetString(options), "\"", NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "expected dict but got \"%s\"", TclGetString(options))); +	Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_OPTIONS", NULL);  	code = TCL_ERROR;      } else if (TCL_ERROR == TclMergeReturnOptions(interp, objc, objv,  	    &mergedOpts, &code, &level)) { @@ -1536,7 +1680,7 @@ Tcl_SetReturnOptions(  /*   *-------------------------------------------------------------------------   * - * TclTransferResult -- + * Tcl_TransferResult --   *   *	Copy the result (and error information) from one interp to another.   *	Used when one interp has caused another interp to evaluate a script @@ -1562,7 +1706,7 @@ Tcl_SetReturnOptions(   */  void -TclTransferResult( +Tcl_TransferResult(      Tcl_Interp *sourceInterp,	/* Interp whose result and error information  				 * should be moved to the target interp.  				 * After moving result, this interp's result @@ -1605,5 +1749,7 @@ TclTransferResult(   * mode: c   * c-basic-offset: 4   * fill-column: 78 + * tab-width: 8 + * indent-tabs-mode: nil   * End:   */ | 
