Tcl Source Code

Artifact [1795ad01b4]
Login

Artifact 1795ad01b4d1600f26d85c3e09e516ed23e0f460:

Attachment "290-4-20061106.diff" to ticket [1587317fff] added by ecky-l 2006-11-07 02:56:00.
Only in tcl.290/: .cdtproject
Only in tcl.290/: .project
Only in tcl.290/: .settings
diff -ubr tcl.orig/generic/tclBasic.c tcl.290/generic/tclBasic.c
--- tcl.orig/generic/tclBasic.c	Sat Nov  4 00:09:33 2006
+++ tcl.290/generic/tclBasic.c	Sat Nov  4 16:24:17 2006
@@ -399,6 +399,13 @@
     iPtr->chanMsg = NULL;
 
     /*
+	 * TIP 290: initialize the exceptionCommand and exceptionCommandFlags members
+	 */
+	iPtr->exceptionCommand = NULL;
+	iPtr->exceptionCommandFlags = 0;
+    iPtr->catchLevel = 0;
+	
+    /*
      * Initialize the compilation and execution statistics kept for this
      * interpreter.
      */
@@ -3519,6 +3526,53 @@
     if (savedVarFramePtr) {
 	iPtr->varFramePtr = savedVarFramePtr;
     }
+
+    /* 
+     * TIP 290 Execute the exceptHandler that was registered with the interp.
+     *
+     * Do this only if the error was not thrown already and dependend on 
+     * -caught/-uncaught (stored in exceptionCommandFlags).
+     *
+     * The return code of the exception and the result are appended to the
+     * command before execution
+     */
+    if (code != TCL_OK && iPtr->exceptionCommand != NULL 
+            && !(iPtr->exceptionCommandFlags & EXCEPTCMD_FINISHED)
+            && !(iPtr->exceptionCommandFlags & EXCEPTCMD_RUNNING)) {
+
+        int uncatched = (iPtr->catchLevel <= 0 
+            && (iPtr->exceptionCommandFlags & EXCEPTCMD_ONUNCAUGHT)); 
+        int catched = (iPtr->catchLevel > 0 
+            && (iPtr->exceptionCommandFlags & EXCEPTCMD_ONCAUGHT));
+        if (uncatched || catched) {
+            Tcl_DString cmdBuf;
+            int i, cmdLen;
+            char *cmdString;
+            Tcl_Obj *exceptCmd = Tcl_DuplicateObj(iPtr->exceptionCommand);
+            Tcl_ListObjAppendElement (interp, exceptCmd, Tcl_NewIntObj(code));
+            Tcl_ListObjAppendElement (interp, exceptCmd, Tcl_GetObjResult(interp));
+            
+            /* Log the error, so that it is available in the handler */
+            Tcl_DStringInit(&cmdBuf);
+            for (i = 0; i < objc; i++) {
+                Tcl_DStringAppendElement(&cmdBuf, Tcl_GetString(objv[i]));
+            }
+            cmdString = Tcl_DStringValue(&cmdBuf);
+            cmdLen = Tcl_DStringLength(&cmdBuf);
+            Tcl_LogCommandInfo(interp, cmdString, cmdString, cmdLen);
+            
+            iPtr->exceptionCommandFlags |= EXCEPTCMD_RUNNING;
+            code = Tcl_EvalObj(interp, exceptCmd);
+            iPtr->exceptionCommandFlags &= ~EXCEPTCMD_RUNNING;
+            iPtr->exceptionCommandFlags |= EXCEPTCMD_FINISHED;
+            
+            if (cmdLen != 0) {
+                Tcl_DStringFree(&cmdBuf);
+            }
+            
+        }
+    }
+
     return code;
 }
 
diff -ubr tcl.orig/generic/tclCmdAH.c tcl.290/generic/tclCmdAH.c
--- tcl.orig/generic/tclCmdAH.c	Thu Nov  2 16:57:54 2006
+++ tcl.290/generic/tclCmdAH.c	Sat Nov  4 13:13:50 2006
@@ -229,6 +229,7 @@
 {
     Tcl_Obj *varNamePtr = NULL;
     Tcl_Obj *optionVarNamePtr = NULL;
+    Interp *iPtr = (Interp*)interp;
     int result;
 
     if ((objc < 2) || (objc > 4)) {
@@ -244,7 +245,9 @@
 	optionVarNamePtr = objv[3];
     }
 
+    iPtr->catchLevel++;
     result = Tcl_EvalObjEx(interp, objv[1], 0);
+    iPtr->catchLevel--;
 
     /*
      * We disable catch in interpreters where the limit has been exceeded.
diff -ubr tcl.orig/generic/tclEvent.c tcl.290/generic/tclEvent.c
--- tcl.orig/generic/tclEvent.c	Tue Sep 19 22:07:34 2006
+++ tcl.290/generic/tclEvent.c	Sat Nov  4 16:07:34 2006
@@ -380,6 +380,7 @@
     return code;
 }
 
+
 /*
  *----------------------------------------------------------------------
  *
diff -ubr tcl.orig/generic/tclExecute.c tcl.290/generic/tclExecute.c
--- tcl.orig/generic/tclExecute.c	Thu Nov  2 15:58:08 2006
+++ tcl.290/generic/tclExecute.c	Sat Nov  4 16:12:25 2006
@@ -183,14 +183,19 @@
  * pair must surround any call inside TclExecuteByteCode (and a few other
  * procedures that use this scheme) that could result in a recursive call
  * to TclExecuteByteCode.
+ * 
+ * TIP 290: keep the catch level if necessary
  */
 
 #define CACHE_STACK_INFO() \
-    tosPtr = eePtr->tosPtr
+    tosPtr = eePtr->tosPtr;\
+    if (catchTop != initCatchTop) iPtr->catchLevel--
 
 #define DECACHE_STACK_INFO() \
     eePtr->tosPtr = tosPtr;\
-    checkInterp = 1
+    checkInterp = 1;\
+    if (catchTop != initCatchTop) iPtr->catchLevel++
+    
 
 
 /*
@@ -1794,6 +1799,13 @@
 	    /*Tcl_ResetResult(interp);*/
 	    result = TclEvalObjvInternal(interp, objc, objv, bytes, length, 0);
 	    CACHE_STACK_INFO();
+
+	    /*
+         * TIP 290: reset the EXCEPTCMD_FINISHED flag the top of catch stack
+         */
+        if (catchTop < 0) {
+            iPtr->exceptionCommandFlags &= ~EXCEPTCMD_FINISHED;
+        }
 
 	    /*
 	     * If the old stack is going to be released, it is safe to do so
diff -ubr tcl.orig/generic/tclInt.h tcl.290/generic/tclInt.h
--- tcl.orig/generic/tclInt.h	Thu Nov  2 16:57:54 2006
+++ tcl.290/generic/tclInt.h	Sat Nov  4 16:09:43 2006
@@ -1285,6 +1285,14 @@
 };
 
 /*
+ * TIP 290 Flags for running an exception command
+ */ 
+#define EXCEPTCMD_ONCAUGHT      1 /* Run the command on caught exceptions */
+#define EXCEPTCMD_ONUNCAUGHT    2 /* Run the command on uncaught exceptions */
+#define EXCEPTCMD_FINISHED    4 /* indicates that the command has been run for a particular exception */
+#define EXCEPTCMD_RUNNING     8 /* indicates that the exception command is currently running */
+
+/*
  *----------------------------------------------------------------
  * This structure defines an interpreter, which is a collection of commands
  * plus other state information related to interpreting commands, such as
@@ -1292,7 +1300,6 @@
  * tclBasic.c, but almost every Tcl source file uses something in here.
  *----------------------------------------------------------------
  */
-
 typedef struct Interp {
     /*
      * Note: the first three fields must match exactly the fields in a
@@ -1555,6 +1562,15 @@
     ByteCodeStats stats;	/* Holds compilation and execution statistics
 				 * for this interpreter. */
 #endif /* TCL_COMPILE_STATS */
+
+	Tcl_Obj* exceptionCommand; /* A script that is executed on errors */
+	int exceptionCommandFlags; /* Flags for executing the Error Script. */
+    int catchLevel; /* Level of [catch] commands . Is incremented 
+                             * on each encountered [catch]. If it is greater
+                             * than 0 during an error is thrown this means that
+                             * the error was catched elsewhere. We can react
+                             * accordingly
+                             */
 } Interp;
 
 /*
diff -ubr tcl.orig/generic/tclTrace.c tcl.290/generic/tclTrace.c
--- tcl.orig/generic/tclTrace.c	Mon Oct 23 21:36:55 2006
+++ tcl.290/generic/tclTrace.c	Mon Nov  6 19:23:00 2006
@@ -101,6 +101,7 @@
 static Tcl_TraceTypeObjCmd TraceVariableObjCmd;
 static Tcl_TraceTypeObjCmd TraceCommandObjCmd;
 static Tcl_TraceTypeObjCmd TraceExecutionObjCmd;
+static Tcl_TraceTypeObjCmd TraceExceptionObjCmd;
 
 /*
  * Each subcommand has a number of 'types' to which it can apply. Currently
@@ -110,12 +111,13 @@
  */
 
 static CONST char *traceTypeOptions[] = {
-    "execution", "command", "variable", NULL
+    "execution", "command", "variable", "exception", NULL
 };
 static Tcl_TraceTypeObjCmd *traceSubCmds[] = {
     TraceExecutionObjCmd,
     TraceCommandObjCmd,
     TraceVariableObjCmd,
+    TraceExceptionObjCmd
 };
 
 /*
@@ -181,7 +183,7 @@
     char *name, *flagOps, *p;
     /* Main sub commands to 'trace' */
     static CONST char *traceOptions[] = {
-	"add", "info", "remove",
+	"add", "info", "remove", "set", "unset",
 #ifndef TCL_REMOVE_OBSOLETE_TRACES
 	"variable", "vdelete", "vinfo",
 #endif
@@ -189,7 +191,7 @@
     };
     /* 'OLD' options are pre-Tcl-8.4 style */
     enum traceOptions {
-	TRACE_ADD, TRACE_INFO, TRACE_REMOVE,
+	TRACE_ADD, TRACE_INFO, TRACE_REMOVE, TRACE_SET, TRACE_UNSET,
 #ifndef TCL_REMOVE_OBSOLETE_TRACES
 	TRACE_OLD_VARIABLE, TRACE_OLD_VDELETE, TRACE_OLD_VINFO
 #endif
@@ -249,6 +251,23 @@
 	return (traceSubCmds[typeIndex])(interp, optionIndex, objc, objv);
 	break;
     }
+    case TRACE_SET:
+    case TRACE_UNSET: {
+    int typeIndex;
+    if (objc < 3) {
+        Tcl_WrongNumArgs(interp, 2, objv, "exception ?arg ...?");
+        return TCL_ERROR;
+    }
+    if (Tcl_GetIndexFromObj(interp, objv[2], traceTypeOptions, "option",
+        0, &typeIndex) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (typeIndex < 3) {
+        return TCL_ERROR;
+    }
+    return TraceExceptionObjCmd(interp, optionIndex, objc, objv);
+    break;
+    }
 
 #ifndef TCL_REMOVE_OBSOLETE_TRACES
     case TRACE_OLD_VARIABLE:
@@ -614,6 +633,109 @@
     }
     }
     return TCL_OK;
+}
+
+static int
+TraceExceptionObjCmd(
+    Tcl_Interp *interp,     /* Current interpreter. */
+    int optionIndex,        /* Add, info or remove */
+    int objc,           /* Number of arguments. */
+    Tcl_Obj *CONST objv[])  /* Argument objects. */
+{
+    Interp *iPtr = (Interp*)interp;
+    enum traceOptions {
+    TRACE_ADD, TRACE_INFO, TRACE_REMOVE, TRACE_SET, TRACE_UNSET
+    };
+    
+    switch ((enum traceOptions) optionIndex) {
+        case TRACE_INFO: {
+        /*
+         * Return the currently set error script plus a tuple for -caught and 
+         * -uncaught that indicates when the script is executed
+         */
+        Tcl_Obj *result = Tcl_NewObj();
+        Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj("-caught", -1));
+        Tcl_ListObjAppendElement(interp, result, 
+            Tcl_NewBooleanObj(iPtr->exceptionCommandFlags & EXCEPTCMD_ONCAUGHT));
+        Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj("-uncaught", -1));
+        Tcl_ListObjAppendElement(interp, result, 
+            Tcl_NewBooleanObj(iPtr->exceptionCommandFlags & EXCEPTCMD_ONUNCAUGHT));
+        if (iPtr->exceptionCommand == NULL) {
+            Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj("", -1));
+        } else {
+            Tcl_ListObjAppendElement(interp, result, iPtr->exceptionCommand);
+        }
+        
+        Tcl_SetObjResult(interp, result);
+        return TCL_OK;
+        }
+        case TRACE_SET: {
+        break;
+        }
+        case TRACE_UNSET: {
+        Tcl_DecrRefCount(iPtr->exceptionCommand);
+        iPtr->exceptionCommand = NULL;
+        return TCL_OK;
+        }
+        default: {
+        Tcl_SetObjResult(interp, Tcl_NewStringObj(
+            "bad option, should be trace set|get|info exception", -1));
+        return TCL_ERROR;
+        }
+    }
+    
+    if (objc == 4) {
+        iPtr->exceptionCommand = objv[3];
+        Tcl_IncrRefCount (iPtr->exceptionCommand);
+        
+        return TCL_OK;
+    }
+    
+    if (objc == 5) {
+        char *flag = Tcl_GetString(objv[3]);
+        
+        if (*flag != '-') {
+            goto errorReturn;
+        }
+        if (strcmp(flag, "-caught") == 0) {
+            iPtr->exceptionCommandFlags = EXCEPTCMD_ONCAUGHT;
+        } else if (strcmp(flag, "-uncaught") == 0) {
+            iPtr->exceptionCommandFlags = EXCEPTCMD_ONUNCAUGHT;
+        } else {
+            goto errorReturn;
+        }
+        
+        iPtr->exceptionCommand = objv[4];
+        Tcl_IncrRefCount(iPtr->exceptionCommand);
+        
+        return TCL_OK;
+    }
+    
+    if (objc == 6) {
+        char *flag1 = Tcl_GetString(objv[3]), *flag2 = Tcl_GetString(objv[4]);
+        int valid = 0;
+        if (*flag1 != '-' || *flag2 != '-') {
+            goto errorReturn;
+        }
+        
+        valid = (strcmp(flag1, "-caught") == 0 && strcmp(flag2, "-uncaught") == 0)
+            || (strcmp(flag1, "-uncaught") == 0 && strcmp(flag2, "-caught") == 0);
+        if (!valid) {
+            goto errorReturn;
+        }
+        
+        iPtr->exceptionCommandFlags = EXCEPTCMD_ONCAUGHT|EXCEPTCMD_ONUNCAUGHT;
+        iPtr->exceptionCommand = objv[5];
+        Tcl_IncrRefCount(iPtr->exceptionCommand);
+        
+        return TCL_OK;
+    }
+    
+errorReturn:
+    iPtr->exceptionCommand = NULL;
+    iPtr->exceptionCommandFlags = 0;
+    Tcl_WrongNumArgs(interp, 3, objv, "?-caught? ?-uncaught? ?script?");
+    return TCL_ERROR;
 }
 
 /*
diff -ubr tcl.orig/tests/trace.test tcl.290/tests/trace.test
--- tcl.orig/tests/trace.test	Fri Nov  3 23:24:43 2006
+++ tcl.290/tests/trace.test	Mon Nov  6 19:34:46 2006
@@ -842,7 +842,7 @@
 
 test trace-14.5 {trace command, invalid option} {
     list [catch {trace gorp} msg] $msg
-} [list 1 "bad option \"gorp\": must be add, info, remove, variable, vdelete, or vinfo"]
+} [list 1 "bad option \"gorp\": must be add, info, remove, set, unset, variable, vdelete, or vinfo"]
 
 # Again, [trace ... command] and [trace ... variable] share syntax and
 # error message styles for their opList options; these loops test those 
Only in tcl.290/win: 280-latest-20061104.diff