Tcl Source Code

Artifact [9029e07239]
Login

Artifact 9029e072393510c3bb988da0d1d843d2ebf67715:

Attachment "1338280-84.patch" to ticket [1338280fff] added by dgp 2005-11-03 00:10:18.
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.118.2.18
diff -u -r1.118.2.18 tclInt.h
--- generic/tclInt.h	10 Oct 2005 21:33:09 -0000	1.118.2.18
+++ generic/tclInt.h	2 Nov 2005 17:08:41 -0000
@@ -1652,6 +1652,7 @@
 			    Tcl_Obj *arrayNameObj, Tcl_Obj *arrayElemObj));
 EXTERN int		TclCheckBadOctal _ANSI_ARGS_((Tcl_Interp *interp,
 			    CONST char *value));
+EXTERN void		TclDeleteNamespaceVars _ANSI_ARGS_((Namespace *nsPtr));
 EXTERN void		TclExpandTokenArray _ANSI_ARGS_((
 			    Tcl_Parse *parsePtr));
 EXTERN int		TclFileAttrsCmd _ANSI_ARGS_((Tcl_Interp *interp,
Index: generic/tclNamesp.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclNamesp.c,v
retrieving revision 1.31.2.8
diff -u -r1.31.2.8 tclNamesp.c
--- generic/tclNamesp.c	26 Jul 2005 16:20:44 -0000	1.31.2.8
+++ generic/tclNamesp.c	2 Nov 2005 17:08:41 -0000
@@ -629,7 +629,7 @@
              * variable list one last time.
 	     */
 
-            TclDeleteVars((Interp *) nsPtr->interp, &nsPtr->varTable);
+            TclDeleteNamespaceVars(nsPtr);
 	    
             Tcl_DeleteHashTable(&nsPtr->childTable);
             Tcl_DeleteHashTable(&nsPtr->cmdTable);
@@ -713,7 +713,7 @@
 	    Tcl_IncrRefCount(errorCode);
 	}
 
-        TclDeleteVars(iPtr, &nsPtr->varTable);
+        TclDeleteNamespaceVars(nsPtr);
         Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS);
 
 	if (errorInfo) {
@@ -732,7 +732,7 @@
 	 * frees it, so we reinitialize it afterwards.
 	 */
     
-        TclDeleteVars(iPtr, &nsPtr->varTable);
+        TclDeleteNamespaceVars(nsPtr);
         Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS);
     }
 
Index: generic/tclVar.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclVar.c,v
retrieving revision 1.69.2.9
diff -u -r1.69.2.9 tclVar.c
--- generic/tclVar.c	23 Oct 2005 22:01:31 -0000	1.69.2.9
+++ generic/tclVar.c	2 Nov 2005 17:08:42 -0000
@@ -66,7 +66,9 @@
 			    CONST char *operation, CONST char *reason));
 static int		SetArraySearchObj _ANSI_ARGS_((Tcl_Interp *interp,
 			    Tcl_Obj *objPtr));
-
+static void		UnsetVarStruct _ANSI_ARGS_((Var *varPtr, Var *arrayPtr,
+			    Interp *iPtr, CONST char *part1, CONST char *part2,
+			    int flags));
 
 /*
  * Functions defined in this file that may be exported in the future
@@ -1986,39 +1988,43 @@
  *----------------------------------------------------------------------
  */
 
-int
-TclObjUnsetVar2(interp, part1Ptr, part2, flags)
-    Tcl_Interp *interp;		/* Command interpreter in which varName is
-				 * to be looked up. */
-    Tcl_Obj *part1Ptr;		/* Name of variable or array. */
-    CONST char *part2;		/* Name of element within array or NULL. */
-    int flags;			/* OR-ed combination of any of
-				 * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
-				 * TCL_LEAVE_ERR_MSG. */
+static void
+UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags)
+    Var *varPtr;
+    Var *arrayPtr;
+    Interp *iPtr;
+    CONST char *part1;
+    CONST char *part2;
+    int flags;
 {
     Var dummyVar;
-    Var *varPtr, *dummyVarPtr;
-    Interp *iPtr = (Interp *) interp;
-    Var *arrayPtr;
+    Var *dummyVarPtr;
     ActiveVarTrace *activePtr;
-    Tcl_Obj *objPtr;
-    int result;
-    char *part1;
-
-    part1 = TclGetString(part1Ptr);
-    varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "unset",
-	    /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
-    if (varPtr == NULL) {
-	return TCL_ERROR;
-    }
- 
-    result = (TclIsVarUndefined(varPtr)? TCL_ERROR : TCL_OK);
 
     if ((arrayPtr != NULL) && (arrayPtr->searchPtr != NULL)) {
 	DeleteSearches(arrayPtr);
     }
 
     /*
+     * For global/upvar variables referenced in procedures, decrement
+     * the reference count on the variable referred to, and free
+     * the referenced variable if it's no longer needed. 
+     */
+
+    if (TclIsVarLink(varPtr)) {
+	Var *linkPtr = varPtr->value.linkPtr;
+	linkPtr->refCount--;
+	if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr)
+		&& (linkPtr->tracePtr == NULL)
+		&& (linkPtr->flags & VAR_IN_HASHTABLE)) {
+	    if (linkPtr->hPtr != NULL) {
+		Tcl_DeleteHashEntry(linkPtr->hPtr);
+	    }
+	    ckfree((char *) linkPtr);
+	}
+    }
+
+    /*
      * The code below is tricky, because of the possibility that
      * a trace procedure might try to access a variable being
      * deleted. To handle this situation gracefully, do things
@@ -2039,15 +2045,6 @@
     varPtr->searchPtr = NULL;
 
     /*
-     * Keep the variable alive until we're done with it. We used to
-     * increase/decrease the refCount for each operation, making it
-     * hard to find [Bug 735335] - caused by unsetting the variable
-     * whose value was the variable's name.
-     */
-    
-    varPtr->refCount++;
-
-    /*
      * Call trace procedures for the variable being deleted. Then delete
      * its traces. Be sure to abort any other traces for the variable
      * that are still pending. Special tricks:
@@ -2104,7 +2101,7 @@
     }
     if (TclIsVarScalar(dummyVarPtr)
 	    && (dummyVarPtr->value.objPtr != NULL)) {
-	objPtr = dummyVarPtr->value.objPtr;
+	Tcl_Obj *objPtr = dummyVarPtr->value.objPtr;
 	TclDecrRefCount(objPtr);
 	dummyVarPtr->value.objPtr = NULL;
     }
@@ -2118,6 +2115,44 @@
 	varPtr->refCount--;
     }
 
+}
+
+int
+TclObjUnsetVar2(interp, part1Ptr, part2, flags)
+    Tcl_Interp *interp;		/* Command interpreter in which varName is
+				 * to be looked up. */
+    Tcl_Obj *part1Ptr;		/* Name of variable or array. */
+    CONST char *part2;		/* Name of element within array or NULL. */
+    int flags;			/* OR-ed combination of any of
+				 * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
+				 * TCL_LEAVE_ERR_MSG. */
+{
+    Var *varPtr;
+    Interp *iPtr = (Interp *) interp;
+    Var *arrayPtr;
+    int result;
+    char *part1;
+
+    part1 = TclGetString(part1Ptr);
+    varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "unset",
+	    /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
+    if (varPtr == NULL) {
+	return TCL_ERROR;
+    }
+ 
+    result = (TclIsVarUndefined(varPtr)? TCL_ERROR : TCL_OK);
+
+    /*
+     * Keep the variable alive until we're done with it. We used to
+     * increase/decrease the refCount for each operation, making it
+     * hard to find [Bug 735335] - caused by unsetting the variable
+     * whose value was the variable's name.
+     */
+    
+    varPtr->refCount++;
+
+    UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags);
+
     /*
      * It's an error to unset an undefined variable.
      */
@@ -4532,6 +4567,58 @@
  */
 
 void
+TclDeleteNamespaceVars(nsPtr)
+    Namespace *nsPtr;
+{
+    Tcl_HashTable *tablePtr = &nsPtr->varTable;
+    Tcl_Interp *interp = nsPtr->interp;
+    Interp *iPtr = (Interp *)interp;
+    Tcl_HashSearch search;
+    Tcl_HashEntry *hPtr;
+    int flags = 0;
+    Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
+
+    /*
+     * Determine what flags to pass to the trace callback procedures.
+     */
+
+    if (nsPtr == iPtr->globalNsPtr) {
+	flags = TCL_GLOBAL_ONLY;
+    } else if (nsPtr == currNsPtr) {
+	flags = TCL_NAMESPACE_ONLY;
+    }
+    if (Tcl_InterpDeleted(interp)) {
+	flags |= TCL_INTERP_DESTROYED;
+    }
+
+    for (hPtr = Tcl_FirstHashEntry(tablePtr, &search);  hPtr != NULL;
+	 hPtr = Tcl_FirstHashEntry(tablePtr, &search)) {
+	register Var *varPtr = (Var *) Tcl_GetHashValue(hPtr);
+	Tcl_Obj *objPtr = Tcl_NewObj();
+	varPtr->refCount++;	/* Make sure we get to remove from hash */
+	Tcl_IncrRefCount(objPtr); 
+	Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, objPtr);
+	UnsetVarStruct(varPtr, NULL, iPtr, Tcl_GetString(objPtr), NULL, flags);
+	Tcl_DecrRefCount(objPtr); /* free no longer needed obj */
+	varPtr->refCount--;
+
+	/* Remove the variable from the table and force it undefined
+	 * in case an unset trace brought it back from the dead */
+	Tcl_DeleteHashEntry(hPtr);
+	varPtr->hPtr = NULL;
+	TclSetVarUndefined(varPtr);
+	TclSetVarScalar(varPtr);
+	while (varPtr->tracePtr != NULL) {
+	    VarTrace *tracePtr = varPtr->tracePtr;
+	    varPtr->tracePtr = tracePtr->nextPtr;
+	    Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC);
+	}
+	CleanupVar(varPtr, NULL);
+    }
+    Tcl_DeleteHashTable(tablePtr);
+}
+
+void
 TclDeleteVars(iPtr, tablePtr)
     Interp *iPtr;		/* Interpreter to which variables belong. */
     Tcl_HashTable *tablePtr;	/* Hash table containing variables to