Tcl Source Code

Artifact [9a301f9206]
Login

Artifact 9a301f920676871a39f715a23aa36f1345c4a14a:

Attachment "1065378.patch" to ticket [1065378fff] added by dgp 2004-11-16 04:10:12.
Index: generic/tclCmdMZ.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdMZ.c,v
retrieving revision 1.82.2.12
diff -u -r1.82.2.12 tclCmdMZ.c
--- generic/tclCmdMZ.c	30 Aug 2004 18:15:24 -0000	1.82.2.12
+++ generic/tclCmdMZ.c	15 Nov 2004 21:07:40 -0000
@@ -2976,9 +2976,8 @@
     int objc;				/* Number of arguments. */
     Tcl_Obj *CONST objv[];		/* Argument objects. */
 {
-    int optionIndex, commandLength;
-    char *name, *flagOps, *command, *p;
-    size_t length;
+    int optionIndex;
+    char *name, *flagOps, *p;
     /* Main sub commands to 'trace' */
     static CONST char *traceOptions[] = {
 	"add", "info", "remove", 
@@ -3025,105 +3024,52 @@
 	    return (traceSubCmds[typeIndex])(interp, optionIndex, objc, objv);
 	}
 #ifndef TCL_REMOVE_OBSOLETE_TRACES
-        case TRACE_OLD_VARIABLE: {
-	    int flags;
-	    TraceVarInfo *tvarPtr;
-	    if (objc != 5) {
-		Tcl_WrongNumArgs(interp, 2, objv, "name ops command");
-		return TCL_ERROR;
-	    }
-
-	    flags = 0;
-	    flagOps = Tcl_GetString(objv[3]);
-	    for (p = flagOps; *p != 0; p++) {
-		if (*p == 'r') {
-		    flags |= TCL_TRACE_READS;
-		} else if (*p == 'w') {
-		    flags |= TCL_TRACE_WRITES;
-		} else if (*p == 'u') {
-		    flags |= TCL_TRACE_UNSETS;
-		} else if (*p == 'a') {
-		    flags |= TCL_TRACE_ARRAY;
-		} else {
-		    goto badVarOps;
-		}
-	    }
-	    if (flags == 0) {
-		goto badVarOps;
-	    }
-	    flags |= TCL_TRACE_OLD_STYLE;
-	    
-	    command = Tcl_GetStringFromObj(objv[4], &commandLength);
-	    length = (size_t) commandLength;
-	    tvarPtr = (TraceVarInfo *) ckalloc((unsigned)
-		    (sizeof(TraceVarInfo) - sizeof(tvarPtr->command)
-			    + length + 1));
-	    tvarPtr->flags = flags;
-	    tvarPtr->length = length;
-	    flags |= TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT;
-	    strcpy(tvarPtr->command, command);
-	    name = Tcl_GetString(objv[2]);
-	    if (Tcl_TraceVar(interp, name, flags, TraceVarProc,
-		    (ClientData) tvarPtr) != TCL_OK) {
-		ckfree((char *) tvarPtr);
-		return TCL_ERROR;
-	    }
-	    break;
-	}
+        case TRACE_OLD_VARIABLE:
 	case TRACE_OLD_VDELETE: {
-	    int flags;
-	    TraceVarInfo *tvarPtr;
-	    ClientData clientData;
+	    Tcl_Obj *copyObjv[6];
+	    Tcl_Obj *opsList;
+	    int code, numFlags;
 
 	    if (objc != 5) {
 		Tcl_WrongNumArgs(interp, 2, objv, "name ops command");
 		return TCL_ERROR;
 	    }
 
-	    flags = 0;
-	    flagOps = Tcl_GetString(objv[3]);
+	    opsList = Tcl_NewObj();
+	    Tcl_IncrRefCount(opsList);
+	    flagOps = Tcl_GetStringFromObj(objv[3], &numFlags);
+	    if (numFlags == 0) {
+		Tcl_DecrRefCount(opsList);
+		goto badVarOps;
+	    }
 	    for (p = flagOps; *p != 0; p++) {
 		if (*p == 'r') {
-		    flags |= TCL_TRACE_READS;
+		    Tcl_ListObjAppendElement(NULL, opsList,
+			    Tcl_NewStringObj("read", -1));
 		} else if (*p == 'w') {
-		    flags |= TCL_TRACE_WRITES;
+		    Tcl_ListObjAppendElement(NULL, opsList,
+			    Tcl_NewStringObj("write", -1));
 		} else if (*p == 'u') {
-		    flags |= TCL_TRACE_UNSETS;
+		    Tcl_ListObjAppendElement(NULL, opsList,
+			    Tcl_NewStringObj("unset", -1));
 		} else if (*p == 'a') {
-		    flags |= TCL_TRACE_ARRAY;
+		    Tcl_ListObjAppendElement(NULL, opsList,
+			    Tcl_NewStringObj("array", -1));
 		} else {
+		    Tcl_DecrRefCount(opsList);
 		    goto badVarOps;
 		}
 	    }
-	    if (flags == 0) {
-		goto badVarOps;
-	    }
-	    flags |= TCL_TRACE_OLD_STYLE;
-
-	    /*
-	     * Search through all of our traces on this variable to
-	     * see if there's one with the given command.  If so, then
-	     * delete the first one that matches.
-	     */
-
-	    command = Tcl_GetStringFromObj(objv[4], &commandLength);
-	    length = (size_t) commandLength;
-	    clientData = 0;
-	    name = Tcl_GetString(objv[2]);
-	    while ((clientData = Tcl_VarTraceInfo(interp, name, 0,
-		    TraceVarProc, clientData)) != 0) {
-		tvarPtr = (TraceVarInfo *) clientData;
-		if ((tvarPtr->length == length) && (tvarPtr->flags == flags)
-			&& (strncmp(command, tvarPtr->command,
-				(size_t) length) == 0)) {
-		    Tcl_UntraceVar2(interp, name, NULL,
-			    flags | TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT,
-			    TraceVarProc, clientData);
-		    Tcl_EventuallyFree((ClientData) tvarPtr, TCL_DYNAMIC);
-		    break;
-		}
+	    copyObjv[0] = NULL;
+	    memcpy(copyObjv+1, objv, objc*sizeof(Tcl_Obj *));
+	    copyObjv[4] = opsList;
+	    if  (optionIndex == TRACE_OLD_VARIABLE) {
+		code = (traceSubCmds[2])(interp,TRACE_ADD,objc+1,copyObjv);
+	    } else {
+		code = (traceSubCmds[2])(interp,TRACE_REMOVE,objc+1,copyObjv);
 	    }
-	    break;
+	    Tcl_DecrRefCount(opsList);
+	    return code;
 	}
 	case TRACE_OLD_VINFO: {
 	    ClientData clientData;
@@ -3721,6 +3667,9 @@
 			(sizeof(TraceVarInfo) - sizeof(tvarPtr->command)
 				+ length + 1));
 		tvarPtr->flags = flags;
+		if (objv[0] == NULL) {
+		    tvarPtr->flags |= TCL_TRACE_OLD_STYLE;
+		}
 		tvarPtr->length = length;
 		flags |= TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT;
 		strcpy(tvarPtr->command, command);
@@ -3744,7 +3693,7 @@
 			TraceVarProc, clientData)) != 0) {
 		    tvarPtr = (TraceVarInfo *) clientData;
 		    if ((tvarPtr->length == length)
-			    && (tvarPtr->flags == flags)
+			    && ((tvarPtr->flags & ~TCL_TRACE_OLD_STYLE)==flags)
 			    && (strncmp(command, tvarPtr->command,
 				    (size_t) length) == 0)) {
 			Tcl_UntraceVar2(interp, name, NULL, 
Index: tests/trace.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/trace.test,v
retrieving revision 1.26.2.3
diff -u -r1.26.2.3 trace.test
--- tests/trace.test	29 Sep 2003 22:03:44 -0000	1.26.2.3
+++ tests/trace.test	15 Nov 2004 21:07:41 -0000
@@ -2132,6 +2132,13 @@
     set result
 } [list [list delete foo]]
 
+test trace-33.1 {variable match with remove variable} {
+    unset -nocomplain x
+    trace variable x w foo
+    trace remove variable x write foo
+    llength [trace info variable x]
+} 0
+
 # Delete procedures when done, so we don't clash with other tests
 # (e.g. foobar will clash with 'unknown' tests).
 catch {rename foobar {}}