Tcl Source Code

Artifact Content
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Artifact c13295e790c4c32d80c4f7834d623f548d6933c5:

Attachment "errorstack6.patch" to ticket [2868499fff] added by ferrieux 2009-11-04 00:20:26.
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.405
diff -u -p -r1.405 tclBasic.c
--- generic/tclBasic.c	31 Oct 2009 20:18:43 -0000	1.405
+++ generic/tclBasic.c	3 Nov 2009 17:16:19 -0000
@@ -530,6 +530,9 @@ Tcl_CreateInterp(void)
     iPtr->errorInfo = NULL;
     TclNewLiteralStringObj(iPtr->eiVar, "::errorInfo");
     Tcl_IncrRefCount(iPtr->eiVar);
+    iPtr->errorStack = Tcl_NewListObj(0, NULL);
+    Tcl_IncrRefCount(iPtr->errorStack);
+    iPtr->resetErrorStack = 1;
     iPtr->errorCode = NULL;
     TclNewLiteralStringObj(iPtr->ecVar, "::errorCode");
     Tcl_IncrRefCount(iPtr->ecVar);
@@ -1470,6 +1473,7 @@ DeleteInterpProc(
 	Tcl_DecrRefCount(iPtr->errorInfo);
 	iPtr->errorInfo = NULL;
     }
+    Tcl_DecrRefCount(iPtr->errorStack);
     if (iPtr->returnOpts) {
 	Tcl_DecrRefCount(iPtr->returnOpts);
     }
@@ -8821,5 +8825,7 @@ TclInfoCoroutineCmd(
  * mode: c
  * c-basic-offset: 4
  * fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
  * End:
  */
Index: generic/tclCmdIL.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdIL.c,v
retrieving revision 1.171
diff -u -p -r1.171 tclCmdIL.c
--- generic/tclCmdIL.c	20 Aug 2009 10:56:55 -0000	1.171
+++ generic/tclCmdIL.c	3 Nov 2009 17:16:19 -0000
@@ -118,6 +118,9 @@ static int		InfoCompleteCmd(ClientData d
 			    int objc, Tcl_Obj *const objv[]);
 static int		InfoDefaultCmd(ClientData dummy, Tcl_Interp *interp,
 			    int objc, Tcl_Obj *const objv[]);
+/* TIP #348 - New 'info' subcommand 'errorstack' */
+static int		InfoErrorStackCmd(ClientData dummy, Tcl_Interp *interp,
+			    int objc, Tcl_Obj *const objv[]);
 /* TIP #280 - New 'info' subcommand 'frame' */
 static int		InfoFrameCmd(ClientData dummy, Tcl_Interp *interp,
 			    int objc, Tcl_Obj *const objv[]);
@@ -164,6 +167,7 @@ static const EnsembleImplMap defaultInfo
     {"complete",	   InfoCompleteCmd,	    NULL},
     {"coroutine",	   TclInfoCoroutineCmd,     NULL},
     {"default",		   InfoDefaultCmd,	    NULL},
+    {"errorstack",	   InfoErrorStackCmd,	    NULL},
     {"exists",		   TclInfoExistsCmd,	    TclCompileInfoExistsCmd},
     {"frame",		   InfoFrameCmd,	    NULL},
     {"functions",	   InfoFunctionsCmd,	    NULL},
@@ -1017,6 +1021,55 @@ InfoDefaultCmd(
 /*
  *----------------------------------------------------------------------
  *
+ * InfoErrorStackCmd --
+ *
+ *	Called to implement the "info errorstack" command that returns information
+ *	about the last error's call stack. Handles the following syntax:
+ *
+ *	    info errorstack ?interp?
+ *
+ * Results:
+ *	Returns TCL_OK if successful and TCL_ERROR if there is an error.
+ *
+ * Side effects:
+ *	Returns a result in the interpreter's result object. If there is an
+ *	error, the result is an error message.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+InfoErrorStackCmd(
+    ClientData dummy,		/* Not used. */
+    Tcl_Interp *interp,		/* Current interpreter. */
+    int objc,			/* Number of arguments. */
+    Tcl_Obj *const objv[])	/* Argument objects. */
+{
+    Tcl_Interp *target;
+    Interp *iPtr;
+
+    if ((objc != 1) && (objc != 2)) {
+	Tcl_WrongNumArgs(interp, 1, objv, "?interp?");
+	return TCL_ERROR;
+    }
+    
+    target = interp;
+    if (objc == 2) {
+        target = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
+        if (target == NULL) {
+            return TCL_ERROR;
+        }
+    }
+
+    iPtr = (Interp *) target;
+    Tcl_SetObjResult(interp, iPtr->errorStack);
+    
+    return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
  * TclInfoExistsCmd --
  *
  *	Called to implement the "info exists" command that determines whether
@@ -4388,5 +4441,7 @@ SelectObjFromSublist(
  * mode: c
  * c-basic-offset: 4
  * fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
  * End:
  */
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.445
diff -u -p -r1.445 tclInt.h
--- generic/tclInt.h	30 Sep 2009 03:11:26 -0000	1.445
+++ generic/tclInt.h	3 Nov 2009 17:16:21 -0000
@@ -1895,6 +1895,8 @@ typedef struct Interp {
     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. */
+    Tcl_Obj *errorStack;	/* [info errorstack] value (as a Tcl_Obj). */
+    int resetErrorStack;        /* controls cleaning up of ::errorStack */
     int returnLevel;		/* [return -level] parameter. */
 
     /*
Index: generic/tclNamesp.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclNamesp.c,v
retrieving revision 1.193
diff -u -p -r1.193 tclNamesp.c
--- generic/tclNamesp.c	30 Sep 2009 03:11:26 -0000	1.193
+++ generic/tclNamesp.c	3 Nov 2009 17:16:22 -0000
@@ -7574,7 +7574,7 @@ Tcl_LogCommandInfo(
 {
     register const char *p;
     Interp *iPtr = (Interp *) interp;
-    int overflow, limit = 150;
+    int overflow, limit = 150, len;
     Var *varPtr, *arrayPtr;
 
     if (iPtr->flags & ERR_ALREADY_LOGGED) {
@@ -7633,6 +7633,36 @@ Tcl_LogCommandInfo(
 		    TCL_GLOBAL_ONLY);
 	}
     }
+
+    /*
+     * TIP #348
+     */
+
+    if (Tcl_IsShared(iPtr->errorStack)) {
+        Tcl_Obj *newObj;
+            
+        newObj = Tcl_DuplicateObj(iPtr->errorStack);
+        Tcl_DecrRefCount(iPtr->errorStack);
+        Tcl_IncrRefCount(newObj);
+        iPtr->errorStack = newObj;
+    }
+    Tcl_ListObjLength(interp, iPtr->errorStack, &len);
+    if (iPtr->resetErrorStack) {
+        iPtr->resetErrorStack = 0;
+        /* reset while keeping the list intrep as much as possible */
+        Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
+        len=0;
+    } 
+    if (iPtr->varFramePtr != iPtr->rootFramePtr) {
+        Tcl_Obj *listPtr;
+        int result;
+        listPtr=Tcl_NewListObj(iPtr->varFramePtr->objc,
+                               iPtr->varFramePtr->objv);
+        result = Tcl_ListObjReplace(interp, iPtr->errorStack, len, 0, 1, &listPtr);
+        if (result != TCL_OK) {
+            Tcl_DecrRefCount(listPtr);
+        }
+    }
 }
 
 /*
@@ -7640,5 +7670,7 @@ Tcl_LogCommandInfo(
  * mode: c
  * c-basic-offset: 4
  * fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
  * End:
  */
Index: generic/tclResult.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclResult.c,v
retrieving revision 1.54
diff -u -p -r1.54 tclResult.c
--- generic/tclResult.c	17 Dec 2008 16:47:38 -0000	1.54
+++ generic/tclResult.c	3 Nov 2009 17:16:22 -0000
@@ -19,7 +19,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
 };
 
 /*
@@ -922,6 +922,7 @@ Tcl_ResetResult(
 	Tcl_DecrRefCount(iPtr->errorInfo);
 	iPtr->errorInfo = NULL;
     }
+    iPtr->resetErrorStack = 1;
     iPtr->returnLevel = 1;
     iPtr->returnCode = TCL_OK;
     if (iPtr->returnOpts) {
@@ -1158,6 +1159,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");
 
@@ -1503,6 +1505,7 @@ Tcl_GetReturnOptions(
 	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORLINE],
 		Tcl_NewIntObj(iPtr->errorLine));
     }
+    Tcl_DictObjPut(NULL, options, keys[KEY_ERRORSTACK], iPtr->errorStack);
     return options;
 }
 
@@ -1624,5 +1627,7 @@ Tcl_TransferResult(
  * mode: c
  * c-basic-offset: 4
  * fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
  * End:
  */
Index: tests/cmdMZ.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/cmdMZ.test,v
retrieving revision 1.26
diff -u -p -r1.26 cmdMZ.test
--- tests/cmdMZ.test	10 Sep 2008 13:50:05 -0000	1.26
+++ tests/cmdMZ.test	3 Nov 2009 17:16:23 -0000
@@ -119,18 +119,18 @@ proc dictSort {d} {
     return $result
 }
 
-test cmdMZ-return-2.0 {return option handling} {
+test cmdMZ-return-2.0 {return option handling} -body {
     list [catch return -> foo] [dictSort $foo]
-} {2 {-code 0 -level 1}}
-test cmdMZ-return-2.1 {return option handling} {
+} -match glob -result {2 {-code 0 -errorstack * -level 1}}
+test cmdMZ-return-2.1 {return option handling} -body {
     list [catch {return -bar soom} -> foo] [dictSort $foo]
-} {2 {-bar soom -code 0 -level 1}}
-test cmdMZ-return-2.2 {return option handling} {
+} -match glob -result {2 {-bar soom -code 0 -errorstack * -level 1}}
+test cmdMZ-return-2.2 {return option handling} -body {
     list [catch {return -code return} -> foo] [dictSort $foo]
-} {2 {-code 0 -level 2}}
-test cmdMZ-return-2.3 {return option handling} {
+} -match glob -result {2 {-code 0 -errorstack * -level 2}}
+test cmdMZ-return-2.3 {return option handling} -body {
     list [catch {return -code return -level 10} -> foo] [dictSort $foo]
-} {2 {-code 0 -level 11}}
+} -match glob -result {2 {-code 0 -errorstack * -level 11}}
 test cmdMZ-return-2.4 {return option handling} -body {
     return -level 0 -code error
 } -returnCodes error -result {}
@@ -149,14 +149,14 @@ test cmdMZ-return-2.8 {return option han
 test cmdMZ-return-2.9 {return option handling} -body {
     return -level 0 -code 10
 } -returnCodes 10 -result {}
-test cmdMZ-return-2.10 {return option handling} {
+test cmdMZ-return-2.10 {return option handling} -body {
     list [catch {return -level 0 -code error} -> foo] [dictSort $foo]
-} {1 {-code 1 -errorcode NONE -errorinfo {
+} -match glob -result {1 {-code 1 -errorcode NONE -errorinfo {
     while executing
-"return -level 0 -code error"} -errorline 1 -level 0}}
-test cmdMZ-return-2.11 {return option handling} {
+"return -level 0 -code error"} -errorline 1 -errorstack * -level 0}}
+test cmdMZ-return-2.11 {return option handling} -body {
     list [catch {return -level 0 -code break} -> foo] [dictSort $foo]
-} {3 {-code 3 -level 0}}
+} -match glob -result {3 {-code 3 -errorstack * -level 0}}
 test cmdMZ-return-2.12 {return option handling} -body {
     return -level 0 -code error -options {-code ok}
 } -returnCodes ok -result {}
Index: tests/error.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/error.test,v
retrieving revision 1.22
diff -u -p -r1.22 error.test
--- tests/error.test	28 Sep 2009 18:02:20 -0000	1.22
+++ tests/error.test	3 Nov 2009 17:16:23 -0000
@@ -153,6 +153,19 @@ test error-4.5 {errorInfo and errorCode 
     list [catch {error msg1 msg2 {}} msg] $msg $::errorInfo $::errorCode
 } {1 msg1 msg2 {}}
 
+test error-4.6 {errorstack via info } -body {
+    proc f x {g $x$x}
+    proc g x {error G:$x}
+    catch {f 12}
+    info errorstack
+} -match glob -result {{g 1212} {f 12} {namespace eval *}}
+test error-4.7 {errorstack via options dict } -body {
+    proc f x {g $x$x}
+    proc g x {error G:$x}
+    catch {f 12} m d
+    dict get $d -errorstack
+} -match glob -result {{g 1212} {f 12} {namespace eval *}}
+
 # Errors in error command itself
 
 test error-5.1 {errors in error command} {
@@ -207,6 +220,15 @@ test error-6.9 {catch must reset error s
     catch foo
     list $::errorCode
 } {NONE}
+test error-6.10 {catch must reset errorstack} -body {
+	proc f x {g $x$x}
+	proc g x {error G:$x}
+	catch {f 12}
+	set e1 [info errorstack]
+	catch {f 13}
+	set e2 [info errorstack]
+	list $e1 $e2
+} -match glob -result {{{g 1212} {f 12} {namespace eval *}} {{g 1313} {f 13} {namespace eval *}}}
 
 test error-7.1 {Bug 1397843} -body {
     variable cmds
Index: tests/execute.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/execute.test,v
retrieving revision 1.32
diff -u -p -r1.32 execute.test
--- tests/execute.test	24 Jun 2009 13:51:36 -0000	1.32
+++ tests/execute.test	3 Nov 2009 17:16:23 -0000
@@ -956,11 +956,11 @@ test execute-8.5 {Bug 2038069} -setup {
     demo
 } -cleanup {
     rename demo {}
-} -result {-code 1 -level 0 -errorcode NONE -errorinfo {FOO
+} -match glob -result {-code 1 -level 0 -errorcode NONE -errorinfo {FOO
     while executing
 "error FOO"
     invoked from within
-"catch [list error FOO] m o"} -errorline 2}
+"catch \[list error FOO\] m o"} -errorline 2 -errorstack *}
 
 test execute-9.1 {Interp result resetting [Bug 1522803]} {
     set c 0
Index: tests/info.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/info.test,v
retrieving revision 1.69
diff -u -p -r1.69 info.test
--- tests/info.test	29 Oct 2009 22:20:12 -0000	1.69
+++ tests/info.test	3 Nov 2009 17:16:23 -0000
@@ -676,16 +676,16 @@ test info-21.1 {miscellaneous error cond
 } -result {wrong # args: should be "info subcommand ?arg ...?"}
 test info-21.2 {miscellaneous error conditions} -returnCodes error -body {
     info gorp
-} -result {unknown or ambiguous subcommand "gorp": must be args, body, class, cmdcount, commands, complete, coroutine, default, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars}
+} -result {unknown or ambiguous subcommand "gorp": must be args, body, class, cmdcount, commands, complete, coroutine, default, errorstack, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars}
 test info-21.3 {miscellaneous error conditions} -returnCodes error -body {
     info c
-} -result {unknown or ambiguous subcommand "c": must be args, body, class, cmdcount, commands, complete, coroutine, default, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars}
+} -result {unknown or ambiguous subcommand "c": must be args, body, class, cmdcount, commands, complete, coroutine, default, errorstack, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars}
 test info-21.4 {miscellaneous error conditions} -returnCodes error -body {
     info l
-} -result {unknown or ambiguous subcommand "l": must be args, body, class, cmdcount, commands, complete, coroutine, default, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars}
+} -result {unknown or ambiguous subcommand "l": must be args, body, class, cmdcount, commands, complete, coroutine, default, errorstack, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars}
 test info-21.5 {miscellaneous error conditions} -returnCodes error -body {
     info s
-} -result {unknown or ambiguous subcommand "s": must be args, body, class, cmdcount, commands, complete, coroutine, default, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars}
+} -result {unknown or ambiguous subcommand "s": must be args, body, class, cmdcount, commands, complete, coroutine, default, errorstack, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars}
 
 ##
 # ### ### ### ######### ######### #########
Index: tests/init.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/init.test,v
retrieving revision 1.19
diff -u -p -r1.19 init.test
--- tests/init.test	25 Jul 2009 22:00:10 -0000	1.19
+++ tests/init.test	3 Nov 2009 17:16:23 -0000
@@ -181,7 +181,7 @@ test init-5.0 {return options passed thr
     list $code $foo $bar $code2 $foo2 $bar2
 } -cleanup {
     unset ::auto_index(::xxx)
-} -result {2 xxx {-errorcode NONE -code 1 -level 1} 2 xxx {-code 1 -level 1 -errorcode NONE}}
+} -match glob -result {2 xxx {-errorcode NONE -errorstack * -code 1 -level 1} 2 xxx {-code 1 -level 1 -errorcode NONE -errorstack *}}
 
 cleanupTests
 }	;#  End of [interp eval $testInterp]