Tcl Source Code

Artifact [86fbc55009]
Login

Artifact 86fbc55009852ce78a60f2617115b6f1547641a4:

Attachment "531640.patch" to ticket [531640ffff] added by dgp 2003-04-11 00:28:39.
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.78
diff -u -r1.78 tclBasic.c
--- generic/tclBasic.c	5 Apr 2003 01:41:22 -0000	1.78
+++ generic/tclBasic.c	10 Apr 2003 17:07:29 -0000
@@ -337,9 +337,27 @@
     iPtr->framePtr = NULL;
     iPtr->varFramePtr = NULL;
     iPtr->activeVarTracePtr = NULL;
-    iPtr->returnCode = TCL_OK;
-    iPtr->errorInfo = NULL;
-    iPtr->errorCode = NULL;
+
+    iPtr->returnCodeKey = Tcl_NewStringObj("-code",-1);
+    Tcl_IncrRefCount(iPtr->returnCodeKey);
+    iPtr->returnErrorcodeKey = Tcl_NewStringObj("-errorcode",-1);
+    Tcl_IncrRefCount(iPtr->returnErrorcodeKey);
+    iPtr->returnErrorinfoKey = Tcl_NewStringObj("-errorinfo",-1);
+    Tcl_IncrRefCount(iPtr->returnErrorinfoKey);
+    iPtr->returnErrorlineKey = Tcl_NewStringObj("-errorline",-1);
+    Tcl_IncrRefCount(iPtr->returnErrorlineKey);
+    iPtr->returnLevelKey = Tcl_NewStringObj("-level",-1);
+    Tcl_IncrRefCount(iPtr->returnLevelKey);
+    iPtr->returnOptionsKey = Tcl_NewStringObj("-options",-1);
+    Tcl_IncrRefCount(iPtr->returnOptionsKey);
+    iPtr->defaultReturnOpts = Tcl_NewDictObj();
+    Tcl_DictObjPut(NULL, iPtr->defaultReturnOpts,
+	    iPtr->returnCodeKey, Tcl_NewIntObj(TCL_OK));
+    Tcl_DictObjPut(NULL, iPtr->defaultReturnOpts,
+	    iPtr->returnLevelKey, Tcl_NewIntObj(1));
+    Tcl_IncrRefCount(iPtr->defaultReturnOpts);
+    iPtr->returnOpts = iPtr->defaultReturnOpts;
+    Tcl_IncrRefCount(iPtr->returnOpts);
 
     iPtr->appendResult = NULL;
     iPtr->appendAvl = 0;
@@ -1062,14 +1080,14 @@
     interp->result = NULL;
     Tcl_DecrRefCount(iPtr->objResultPtr);
     iPtr->objResultPtr = NULL;
-    if (iPtr->errorInfo != NULL) {
-	ckfree(iPtr->errorInfo);
-        iPtr->errorInfo = NULL;
-    }
-    if (iPtr->errorCode != NULL) {
-	ckfree(iPtr->errorCode);
-        iPtr->errorCode = NULL;
-    }
+    Tcl_DecrRefCount(iPtr->returnOpts);
+    Tcl_DecrRefCount(iPtr->defaultReturnOpts);
+    Tcl_DecrRefCount(iPtr->returnCodeKey);
+    Tcl_DecrRefCount(iPtr->returnErrorcodeKey);
+    Tcl_DecrRefCount(iPtr->returnErrorinfoKey);
+    Tcl_DecrRefCount(iPtr->returnErrorlineKey);
+    Tcl_DecrRefCount(iPtr->returnLevelKey);
+    Tcl_DecrRefCount(iPtr->returnOptionsKey);
     if (iPtr->appendResult != NULL) {
 	ckfree(iPtr->appendResult);
         iPtr->appendResult = NULL;
Index: generic/tclCmdAH.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdAH.c,v
retrieving revision 1.30
diff -u -r1.30 tclCmdAH.c
--- generic/tclCmdAH.c	8 Apr 2003 22:55:09 -0000	1.30
+++ generic/tclCmdAH.c	10 Apr 2003 17:07:29 -0000
@@ -234,10 +234,11 @@
     Tcl_Obj *CONST objv[];	/* Argument objects. */
 {
     Tcl_Obj *varNamePtr = NULL;
+    Tcl_Obj *optionVarNamePtr = NULL;
     int result;
 
-    if ((objc != 2) && (objc != 3)) {
-	Tcl_WrongNumArgs(interp, 1, objv, "command ?varName?");
+    if ((objc < 2) || (objc > 4)) {
+	Tcl_WrongNumArgs(interp, 1, objv, "command ?varName? ?optionVarName?");
 	return TCL_ERROR;
     }
 
@@ -247,18 +248,71 @@
      * stack rendering objv invalid.
      */
     
-    if (objc == 3) {
+    if (objc >= 3) {
 	varNamePtr = objv[2];
     }
+    if (objc == 4) {
+	optionVarNamePtr = objv[3];
+    }
 
     result = Tcl_EvalObjEx(interp, objv[1], 0);
     
-    if (objc == 3) {
-	if (Tcl_ObjSetVar2(interp, varNamePtr, NULL,
-		Tcl_GetObjResult(interp), 0) == NULL) {
+    if (objc >= 3) {
+	if (NULL == Tcl_ObjSetVar2(interp, varNamePtr, NULL,
+		Tcl_GetObjResult(interp), 0)) {
 	    Tcl_ResetResult(interp);
 	    Tcl_AppendToObj(Tcl_GetObjResult(interp),  
 	            "couldn't save command result in variable", -1);
+	    return TCL_ERROR;
+	}
+    }
+    if (objc == 4) {
+	Interp  *iPtr = (Interp *) interp;
+	Tcl_Obj *options = Tcl_DuplicateObj(iPtr->returnOpts);
+	Tcl_Obj *value = NULL;
+
+	if (result != TCL_RETURN) {
+	    Tcl_DictObjPut(NULL, options,
+		    iPtr->returnCodeKey, Tcl_NewIntObj(result));
+	    Tcl_DictObjPut(NULL, options,
+		    iPtr->returnLevelKey, Tcl_NewIntObj(0));
+	}
+
+	if (iPtr->flags & ERR_IN_PROGRESS) {
+	    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));
+	    }
+	}
+
+	if (iPtr->flags & ERROR_CODE_SET) {
+	    value = NULL;
+	    Tcl_DictObjGet(NULL, options, iPtr->returnErrorcodeKey, &value);
+	    if (NULL == value) {
+		Tcl_DictObjPut(NULL, options, iPtr->returnErrorcodeKey,
+			Tcl_ObjGetVar2(interp, iPtr->execEnvPtr->errorCode,
+			NULL, TCL_GLOBAL_ONLY));
+	    }
+	}
+
+	if (result == TCL_ERROR) {
+	    value = NULL;
+	    Tcl_DictObjGet(NULL, options, iPtr->returnErrorlineKey, &value);
+	    if (NULL == value) {
+		Tcl_DictObjPut(NULL, options, iPtr->returnErrorlineKey,
+			Tcl_NewIntObj(iPtr->errorLine));
+	    }
+	}
+
+	if (NULL ==
+		Tcl_ObjSetVar2(interp, optionVarNamePtr, NULL, options, 0)) {
+	    Tcl_DecrRefCount(options);
+	    Tcl_ResetResult(interp);
+	    Tcl_AppendToObj(Tcl_GetObjResult(interp),  
+	            "couldn't save return options in variable", -1);
 	    return TCL_ERROR;
 	}
     }
Index: generic/tclCmdMZ.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdMZ.c,v
retrieving revision 1.84
diff -u -r1.84 tclCmdMZ.c
--- generic/tclCmdMZ.c	7 Apr 2003 16:55:13 -0000	1.84
+++ generic/tclCmdMZ.c	10 Apr 2003 17:07:29 -0000
@@ -934,74 +934,148 @@
     Tcl_Obj *CONST objv[];	/* Argument objects. */
 {
     Interp *iPtr = (Interp *) interp;
-    int optionLen, argLen, code, result;
+    int code, level;
+    Tcl_Obj *valuePtr;
+
+    /* Start with the default options */
+    if (iPtr->returnOpts != iPtr->defaultReturnOpts) {
+	Tcl_DecrRefCount(iPtr->returnOpts);
+	iPtr->returnOpts = iPtr->defaultReturnOpts;
+	Tcl_IncrRefCount(iPtr->returnOpts);
+    }
+
+    objv++, objc--;
+    if (objc) {
+	/* We're going to add our options, so manage Tcl_Obj sharing */
+	Tcl_DecrRefCount(iPtr->returnOpts);
+	iPtr->returnOpts = Tcl_DuplicateObj(iPtr->returnOpts);
+	Tcl_IncrRefCount(iPtr->returnOpts);
+    }
+    
+    for (;  objc > 1;  objv += 2, objc -= 2) {
+	int optLen;
+	CONST char *opt = Tcl_GetStringFromObj(objv[0], &optLen);
+	if ((optLen == 8) && (*opt == '-') && (strcmp(opt, "-options") == 0)) {
+	    Tcl_DictSearch search;
+	    int done = 0;
+	    Tcl_Obj *keyPtr;
+	    Tcl_Obj *dict = objv[1];
+
+	    nestedOptions:
+	    if (TCL_ERROR == Tcl_DictObjFirst(NULL, dict,
+		    &search, &keyPtr, &valuePtr, &done)) {
+		/* Value is not a legal dictionary */
+		Tcl_DecrRefCount(iPtr->returnOpts);
+		iPtr->returnOpts = iPtr->defaultReturnOpts;
+		Tcl_IncrRefCount(iPtr->returnOpts);
+		Tcl_ResetResult(interp);
+		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+			"bad -options value: expected dictionary but got \"",
+			Tcl_GetString(objv[1]), "\"", (char *) NULL);
+		return TCL_ERROR;
+	    }
+
+	    while (!done) {
+		Tcl_DictObjPut(NULL, iPtr->returnOpts, keyPtr, valuePtr);
+		Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done);
+	    }
+
+	    valuePtr = NULL;
+	    Tcl_DictObjGet(NULL, iPtr->returnOpts,
+		    iPtr->returnOptionsKey, &valuePtr);
+	    if (valuePtr != NULL) {
+		dict = valuePtr;
+		goto nestedOptions;
+	    }
 
-    if (iPtr->errorInfo != NULL) {
-	ckfree(iPtr->errorInfo);
-	iPtr->errorInfo = NULL;
-    }
-    if (iPtr->errorCode != NULL) {
-	ckfree(iPtr->errorCode);
-	iPtr->errorCode = NULL;
-    }
-    code = TCL_OK;
-    
-    for (objv++, objc--;  objc > 1;  objv += 2, objc -= 2) {
-	char *option = Tcl_GetStringFromObj(objv[0], &optionLen);
-	char *arg = Tcl_GetStringFromObj(objv[1], &argLen);
-    	
-	if (strcmp(option, "-code") == 0) {
-	    register int c = arg[0];
-	    if ((c == 'o') && (strcmp(arg, "ok") == 0)) {
-		code = TCL_OK;
-	    } else if ((c == 'e') && (strcmp(arg, "error") == 0)) {
-		code = TCL_ERROR;
-	    } else if ((c == 'r') && (strcmp(arg, "return") == 0)) {
-		code = TCL_RETURN;
-	    } else if ((c == 'b') && (strcmp(arg, "break") == 0)) {
-		code = TCL_BREAK;
-	    } else if ((c == 'c') && (strcmp(arg, "continue") == 0)) {
-		code = TCL_CONTINUE;
-	    } else {
-		result = Tcl_GetIntFromObj((Tcl_Interp *) NULL, objv[1],
-		        &code);
-		if (result != TCL_OK) {
-		    Tcl_ResetResult(interp);
-		    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
-			    "bad completion code \"",
-			    Tcl_GetString(objv[1]),
-			    "\": must be ok, error, return, break, ",
-			    "continue, or an integer", (char *) NULL);
-		    return result;
-		}
-	    }
-	} else if (strcmp(option, "-errorinfo") == 0) {
-	    iPtr->errorInfo =
-		(char *) ckalloc((unsigned) (strlen(arg) + 1));
-	    strcpy(iPtr->errorInfo, arg);
-	} else if (strcmp(option, "-errorcode") == 0) {
-	    iPtr->errorCode =
-		(char *) ckalloc((unsigned) (strlen(arg) + 1));
-	    strcpy(iPtr->errorCode, arg);
 	} else {
+	    Tcl_DictObjPut(NULL, iPtr->returnOpts, objv[0], objv[1]);
+	}
+    }
+
+    /* Check for bogus -code value */
+    Tcl_DictObjGet(NULL, iPtr->returnOpts, iPtr->returnCodeKey, &valuePtr);
+    if (TCL_ERROR == Tcl_GetIntFromObj(NULL, valuePtr, &code)) {
+	static CONST char *returnCodes[] = {
+	    "ok", "error", "return", "break", "continue"
+	};
+
+	if (TCL_ERROR == Tcl_GetIndexFromObj(NULL, valuePtr, returnCodes,
+		NULL, TCL_EXACT, &code)) {
+	    /* Value is not a legal return code */
+	    Tcl_DecrRefCount(iPtr->returnOpts);
+	    iPtr->returnOpts = iPtr->defaultReturnOpts;
+	    Tcl_IncrRefCount(iPtr->returnOpts);
+	    Tcl_ResetResult(interp);
 	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
-		    "bad option \"", option,
-		    "\": must be -code, -errorcode, or -errorinfo",
-		    (char *) NULL);
+		    "bad completion code \"",
+		    Tcl_GetString(valuePtr),
+		    "\": must be ok, error, return, break, ",
+		    "continue, or an integer", (char *) NULL);
 	    return TCL_ERROR;
 	}
+	/* Have a legal string value for a return code; convert to integer */
+	Tcl_DictObjPut(NULL, iPtr->returnOpts,
+		iPtr->returnCodeKey, Tcl_NewIntObj(code));
     }
-    
-    if (objc == 1) {
-	/*
-	 * Set the interpreter's object result. An inline version of
-	 * Tcl_SetObjResult.
-	 */
 
+    /* Check for bogus -level value */
+    Tcl_DictObjGet(NULL, iPtr->returnOpts, iPtr->returnLevelKey, &valuePtr);
+    if (TCL_ERROR == Tcl_GetIntFromObj(NULL, valuePtr, &level) || (level < 0)) {
+	/* Value is not a legal level */
+	Tcl_DecrRefCount(iPtr->returnOpts);
+	iPtr->returnOpts = iPtr->defaultReturnOpts;
+	Tcl_IncrRefCount(iPtr->returnOpts);
+	Tcl_ResetResult(interp);
+	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+		"bad -level value: expected non-negative integer but got \"",
+		Tcl_GetString(valuePtr), "\"", (char *) NULL);
+	return TCL_ERROR;
+    }
+
+    /* 
+     * Convert [return -code return -level X] to
+     * [return -code ok -level X+1]
+     */
+    if (code == TCL_RETURN) {
+	level++;
+	Tcl_DictObjPut(NULL, iPtr->returnOpts,
+		iPtr->returnLevelKey, Tcl_NewIntObj(level));
+	Tcl_DictObjPut(NULL, iPtr->returnOpts,
+		iPtr->returnCodeKey, Tcl_NewIntObj(TCL_OK));
+    }
+
+    if (level == 0) {
+	if (code == TCL_ERROR) {
+	    valuePtr = NULL;
+	    Tcl_DictObjGet(NULL, iPtr->returnOpts,
+		    iPtr->returnErrorinfoKey, &valuePtr);
+	    if (valuePtr != NULL) {
+		int infoLen;
+		CONST char *info = Tcl_GetStringFromObj(valuePtr,&infoLen);
+		if (infoLen) {
+		    Tcl_AddObjErrorInfo(interp, info, infoLen);
+		    iPtr->flags |= ERR_ALREADY_LOGGED;
+		}
+	    }
+	    valuePtr = NULL;
+	    Tcl_DictObjGet(NULL, iPtr->returnOpts,
+		    iPtr->returnErrorcodeKey, &valuePtr);
+	    if (valuePtr != NULL) {
+		Tcl_SetVar2Ex(interp, "errorCode", NULL,
+			valuePtr, TCL_GLOBAL_ONLY);
+		iPtr->flags |= ERROR_CODE_SET;
+	    }
+	}
+    } else {
+	code = TCL_RETURN;
+    }
+
+    if (objc == 1) {
 	Tcl_SetObjResult(interp, objv[0]);
     }
-    iPtr->returnCode = code;
-    return TCL_RETURN;
+    return code;
+
 }
 
 /*
@@ -3853,7 +3927,7 @@
 				 * information. */
 {
     Interp *iPtr = (Interp *) interp;
-    int stateCode;
+    Tcl_Obj *stateReturnOpts;
     Tcl_SavedResult state;
     TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) clientData;
     int code;
@@ -3879,7 +3953,7 @@
 
 	/*
 	 * Execute the command.  Save the interp's result used for the
-	 * command, including the value of iPtr->returnCode which may be
+	 * command, including the value of iPtr->returnOpts which may be
 	 * modified when Tcl_Eval is invoked. We discard any object
 	 * result the command returns.
 	 *
@@ -3889,7 +3963,8 @@
 	 */
 
 	Tcl_SaveResult(interp, &state);
-	stateCode = iPtr->returnCode;
+	stateReturnOpts = iPtr->returnOpts;
+	Tcl_IncrRefCount(stateReturnOpts);
 	if (flags & TCL_TRACE_DESTROYED) {
 	    tcmdPtr->flags |= TCL_TRACE_DESTROYED;
 	}
@@ -3901,7 +3976,12 @@
 	}
 
 	Tcl_RestoreResult(interp, &state);
-	iPtr->returnCode = stateCode;
+	if (iPtr->returnOpts != stateReturnOpts) {
+	    Tcl_DecrRefCount(iPtr->returnOpts);
+	    iPtr->returnOpts = stateReturnOpts;
+	    Tcl_IncrRefCount(iPtr->returnOpts);
+	}
+	Tcl_DecrRefCount(stateReturnOpts);
 	
 	Tcl_DStringFree(&cmd);
     }
@@ -4304,7 +4384,7 @@
 	 */
 	if (call) {
 	    Tcl_SavedResult state;
-	    int stateCode;
+	    Tcl_Obj *stateReturnOpts;
 	    Tcl_DString cmd;
 	    Tcl_DString sub;
 	    int i;
@@ -4353,13 +4433,14 @@
 	    
 	    /*
 	     * Execute the command.  Save the interp's result used for
-	     * the command, including the value of iPtr->returnCode which
+	     * the command, including the value of iPtr->returnOpts which
 	     * may be modified when Tcl_Eval is invoked.  We discard any
 	     * object result the command returns.
 	     */
 
 	    Tcl_SaveResult(interp, &state);
-	    stateCode = iPtr->returnCode;
+	    stateReturnOpts = iPtr->returnOpts;
+	    Tcl_IncrRefCount(stateReturnOpts);
 
 	    tcmdPtr->flags |= TCL_TRACE_EXEC_IN_PROGRESS;
 	    iPtr->flags    |= INTERP_TRACE_IN_PROGRESS;
@@ -4379,10 +4460,15 @@
             if (traceCode == TCL_OK) {
 		/* Restore result if trace execution was successful */
 		Tcl_RestoreResult(interp, &state);
-		iPtr->returnCode = stateCode;
+		if (iPtr->returnOpts != stateReturnOpts) {
+		    Tcl_DecrRefCount(iPtr->returnOpts);
+		    iPtr->returnOpts = stateReturnOpts;
+		    Tcl_IncrRefCount(iPtr->returnOpts);
+		}
             } else {
 		Tcl_DiscardResult(&state);
 	    }
+	    Tcl_DecrRefCount(stateReturnOpts);
 
 	    Tcl_DStringFree(&cmd);
 	}
Index: generic/tclCompCmds.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompCmds.c,v
retrieving revision 1.46
diff -u -r1.46 tclCompCmds.c
--- generic/tclCompCmds.c	7 Apr 2003 20:00:47 -0000	1.46
+++ generic/tclCompCmds.c	10 Apr 2003 17:07:29 -0000
@@ -246,11 +246,12 @@
     int code;
     int savedStackDepth = envPtr->currStackDepth;
 
+    /*
+     * If syntax does not match what we expect for [catch], do not
+     * compile.  Let runtime checks determine if syntax has changed.
+     */
     if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) {
-	Tcl_ResetResult(interp);
-	Tcl_AppendToObj(Tcl_GetObjResult(interp),
-	        "wrong # args: should be \"catch command ?varName?\"", -1);
-	return TCL_ERROR;
+	return TCL_OUT_LINE_COMPILE;
     }
 
     /*
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.97
diff -u -r1.97 tclExecute.c
--- generic/tclExecute.c	1 Apr 2003 07:18:37 -0000	1.97
+++ generic/tclExecute.c	10 Apr 2003 17:07:30 -0000
@@ -1003,6 +1003,11 @@
 	 */
 	
 	codePtr->refCount++;
+	if (iPtr->returnOpts != iPtr->defaultReturnOpts) {
+	    Tcl_DecrRefCount(iPtr->returnOpts);
+	    iPtr->returnOpts = iPtr->defaultReturnOpts;
+	    Tcl_IncrRefCount(iPtr->returnOpts);
+	}
 	iPtr->numLevels++;
 	result = TclExecuteByteCode(interp, codePtr);
 	iPtr->numLevels--;
@@ -1225,7 +1230,11 @@
 #endif
     switch (*pc) {
     case INST_RETURN:
-	iPtr->returnCode = TCL_OK;
+	if (iPtr->returnOpts != iPtr->defaultReturnOpts) {
+	    Tcl_DecrRefCount(iPtr->returnOpts);
+	    iPtr->returnOpts = iPtr->defaultReturnOpts;
+	    Tcl_IncrRefCount(iPtr->returnOpts);
+	}
 	result = TCL_RETURN;
     case INST_DONE:
 	if (stackTop <= initStackTop) {
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.123
diff -u -r1.123 tclInt.h
--- generic/tclInt.h	5 Apr 2003 01:41:23 -0000	1.123
+++ generic/tclInt.h	10 Apr 2003 17:07:30 -0000
@@ -1206,12 +1206,9 @@
     ActiveVarTrace *activeVarTracePtr;
 				/* First in list of active traces for
 				 * interp, or NULL if no active traces. */
-    int returnCode;		/* Completion code to return if current
-				 * procedure exits with TCL_RETURN code. */
-    char *errorInfo;		/* Value to store in errorInfo if returnCode
-				 * is TCL_ERROR.  Malloc'ed, may be NULL */
-    char *errorCode;		/* Value to store in errorCode if returnCode
-				 * is TCL_ERROR.  Malloc'ed, may be NULL */
+    int unused2;		/* No longer used (was returnCode) */
+    char *unused3;		/* No longer used (was errorInfo) */
+    char *unused4;		/* No longer used (was errorCode) */
 
     /*
      * Information used by Tcl_AppendResult to keep track of partial
@@ -1305,6 +1302,18 @@
     int tracesForbiddingInline; /* Count of traces (in the list headed by
 				 * tracePtr) that forbid inline bytecode
 				 * compilation */
+
+    /* Fields used to manage extensible return options (TIP 90) */
+    Tcl_Obj *returnOpts;	/* A dictionary holding the options to the
+				 * last [return] command */
+    Tcl_Obj *defaultReturnOpts; /* Default [return] options */
+    Tcl_Obj *returnCodeKey;	/* holds "-code" */
+    Tcl_Obj *returnErrorcodeKey;	/* holds "-errorcode" */
+    Tcl_Obj *returnErrorinfoKey;	/* holds "-errorinfo" */
+    Tcl_Obj *returnErrorlineKey;	/* holds "-errorline" */
+    Tcl_Obj *returnLevelKey;	/* holds "-level" */
+    Tcl_Obj *returnOptionsKey;	/* holds "-options" */
+
     /*
      * Statistical information about the bytecode compiler and interpreter's
      * operation.
Index: generic/tclProc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclProc.c,v
retrieving revision 1.44
diff -u -r1.44 tclProc.c
--- generic/tclProc.c	11 Dec 2002 21:29:52 -0000	1.44
+++ generic/tclProc.c	10 Apr 2003 17:07:30 -0000
@@ -1077,7 +1077,6 @@
     }
 #endif /*TCL_COMPILE_DEBUG*/
 
-    iPtr->returnCode = TCL_OK;
     procPtr->refCount++;
     result = TclCompEvalObj(interp, procPtr->bodyPtr);
     procPtr->refCount--;
@@ -1409,8 +1408,8 @@
  * TclUpdateReturnInfo --
  *
  *	This procedure is called when procedures return, and at other
- *	points where the TCL_RETURN code is used.  It examines fields
- *	such as iPtr->returnCode and iPtr->errorCode and modifies
+ *	points where the TCL_RETURN code is used.  It examines values
+ *	stored in the iPtr->returnOpts dictionary and modifies
  *	the real return status accordingly.
  *
  * Results:
@@ -1428,21 +1427,46 @@
     Interp *iPtr;		/* Interpreter for which TCL_RETURN
 				 * exception is being processed. */
 {
-    int code;
+    int level, code = TCL_RETURN;
     char *errorCode;
+    Tcl_Obj *valuePtr;
 
-    code = iPtr->returnCode;
-    iPtr->returnCode = TCL_OK;
+    Tcl_DictObjGet(NULL, iPtr->returnOpts, iPtr->returnLevelKey, &valuePtr);
+    Tcl_GetIntFromObj(NULL, valuePtr, &level);
+    level--;
+    if (level < 0) {
+	Tcl_Panic("TclUpdateReturnInfo: negative return level");
+    }
+    if (Tcl_IsShared(iPtr->returnOpts)) {
+	Tcl_DecrRefCount(iPtr->returnOpts);
+	iPtr->returnOpts = Tcl_DuplicateObj(iPtr->returnOpts);
+	Tcl_IncrRefCount(iPtr->returnOpts);
+    }
+    Tcl_DictObjPut(NULL, iPtr->returnOpts,
+	    iPtr->returnLevelKey, Tcl_NewIntObj(level));
+
+    if (level == 0) {
+	/* Now we've reached the level to return the requested -code */
+	Tcl_DictObjGet(NULL, iPtr->returnOpts, iPtr->returnCodeKey, &valuePtr);
+	Tcl_GetIntFromObj(NULL, valuePtr, &code);
+    }
     if (code == TCL_ERROR) {
-	errorCode = ((iPtr->errorCode != NULL) ? iPtr->errorCode : "NONE");
-	Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorCode,
-	        NULL, Tcl_NewStringObj(errorCode, -1),
-		TCL_GLOBAL_ONLY);
+	Tcl_DictObjGet(NULL, iPtr->returnOpts,
+		iPtr->returnErrorcodeKey, &valuePtr);
+	if (valuePtr == NULL) {
+	    Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorCode,
+	            NULL, Tcl_NewStringObj("NONE", -1), TCL_GLOBAL_ONLY);
+	} else {
+	    Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorCode,
+	            NULL, valuePtr, TCL_GLOBAL_ONLY);
+	}
 	iPtr->flags |= ERROR_CODE_SET;
-	if (iPtr->errorInfo != NULL) {
+
+	Tcl_DictObjGet(NULL, iPtr->returnOpts,
+		iPtr->returnErrorinfoKey, &valuePtr);
+	if (valuePtr != NULL) {
 	    Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorInfo,
-	            NULL, Tcl_NewStringObj(iPtr->errorInfo, -1),
-		    TCL_GLOBAL_ONLY);
+	            NULL, valuePtr, TCL_GLOBAL_ONLY);
 	    iPtr->flags |= ERR_IN_PROGRESS;
 	}
     }
Index: generic/tclResult.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclResult.c,v
retrieving revision 1.5
diff -u -r1.5 tclResult.c
--- generic/tclResult.c	25 Jan 2002 20:40:55 -0000	1.5
+++ generic/tclResult.c	10 Apr 2003 17:07:31 -0000
@@ -1046,7 +1046,12 @@
 	((Interp *) targetInterp)->flags |= (ERR_IN_PROGRESS | ERROR_CODE_SET);
     }
 
-    ((Interp *) targetInterp)->returnCode = ((Interp *) sourceInterp)->returnCode;
+    /* This may need examination for safety */
+    Tcl_DecrRefCount( ((Interp *) targetInterp)->returnOpts );
+    ((Interp *) targetInterp)->returnOpts = 
+	    ((Interp *) sourceInterp)->returnOpts;
+    Tcl_IncrRefCount( ((Interp *) targetInterp)->returnOpts );
+
     Tcl_SetObjResult(targetInterp, Tcl_GetObjResult(sourceInterp));
     Tcl_ResetResult(sourceInterp);
 }