summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorericm <ericm>2000-01-21 03:29:13 (GMT)
committerericm <ericm>2000-01-21 03:29:13 (GMT)
commitac4b7b9af8a470c5eace5289a1baa2272b88d8ac (patch)
treea768d15a2696f9c09dbf4f2cee292c1b142f1363
parente5a18035ecf52ade66229700d86a7c2f98253559 (diff)
downloadtcl-ac4b7b9af8a470c5eace5289a1baa2272b88d8ac.zip
tcl-ac4b7b9af8a470c5eace5289a1baa2272b88d8ac.tar.gz
tcl-ac4b7b9af8a470c5eace5289a1baa2272b88d8ac.tar.bz2
* var.test: Added tests for corrected variable behavior (bug #981).
* upvar.n: Expanded explanation of upvar behavior with respect to variable traces. (bugs 3917 1433 2110). * tclVar.c: Changed behavior of variable command when name refers to an element in an array (ie, "variable foo(x)") to always return an error, regardless of existance of that element in the array (now behavior is consistant with docs too) (bug #981).
-rw-r--r--doc/upvar.n24
-rw-r--r--generic/tclVar.c13
-rw-r--r--tests/var.test16
3 files changed, 49 insertions, 4 deletions
diff --git a/doc/upvar.n b/doc/upvar.n
index f62d646..3f6792c 100644
--- a/doc/upvar.n
+++ b/doc/upvar.n
@@ -5,7 +5,7 @@
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
-'\" RCS: @(#) $Id: upvar.n,v 1.2 1998/09/14 18:39:56 stanton Exp $
+'\" RCS: @(#) $Id: upvar.n,v 1.3 2000/01/21 03:29:13 ericm Exp $
'\"
.so man.macros
.TH upvar n "" Tcl "Tcl Built-In Commands"
@@ -76,8 +76,28 @@ by exiting the procedure in which it is defined. However, it is
possible to retarget an upvar variable by executing another \fBupvar\fR
command.
-.SH BUGS
+.SH Traces and upvar
.PP
+Upvar interacts with traces in a straightforward but possibly
+unexpected manner. If a variable trace is defined on \fIotherVar\fR, that
+trace will be triggered by actions involving \fImyVar\fR. However,
+the trace procedure will be passed the name of \fImyVar\fR, rather
+than the name of \fIotherVar\fR. Thus, the output of the following code
+will be \fBlocalVar\fR rather than \fBoriginalVar\fR:
+.CS
+\fBproc traceproc { name index op } {
+ puts $name
+}
+proc setByUpvar { name value } {
+ upvar $name localVar
+ set localVar $value
+}
+set originalVar 1
+trace variable originalVar w traceproc
+setByUpvar originalVar 2
+}\fR
+.CE
+
If \fIotherVar\fR refers to an element of an array, then variable
traces set for the entire array will not be invoked when \fImyVar\fR
is accessed (but traces on the particular element will still be
diff --git a/generic/tclVar.c b/generic/tclVar.c
index 277247e..834a8dc 100644
--- a/generic/tclVar.c
+++ b/generic/tclVar.c
@@ -14,7 +14,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclVar.c,v 1.15 2000/01/15 02:52:32 ericm Exp $
+ * RCS: @(#) $Id: tclVar.c,v 1.16 2000/01/21 03:29:14 ericm Exp $
*/
#include "tclInt.h"
@@ -33,6 +33,7 @@ static char *danglingElement = "upvar refers to element in deleted array";
static char *danglingVar = "upvar refers to variable in deleted namespace";
static char *badNamespace = "parent namespace doesn't exist";
static char *missingName = "missing variable name";
+static char *isArrayElement = "name refers to an element in an array";
/*
* Forward references to procedures defined later in this file:
@@ -3854,6 +3855,16 @@ Tcl_VariableObjCmd(dummy, interp, objc, objv)
varPtr = TclLookupVar(interp, varName, (char *) NULL,
(TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "define",
/*createPart1*/ 1, /*createPart2*/ 0, &arrayPtr);
+
+ if (arrayPtr != NULL) {
+ /*
+ * Variable cannot be an element in an array. If arrayPtr is
+ * non-null, it is, so throw up an error and return.
+ */
+ VarErrMsg(interp, varName, NULL, "define", isArrayElement);
+ return TCL_ERROR;
+ }
+
if (varPtr == NULL) {
return TCL_ERROR;
}
diff --git a/tests/var.test b/tests/var.test
index d363563..c4bb0c5 100644
--- a/tests/var.test
+++ b/tests/var.test
@@ -14,7 +14,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: var.test,v 1.12 2000/01/21 03:26:04 hobbs Exp $
+# RCS: @(#) $Id: var.test,v 1.13 2000/01/21 03:29:14 ericm Exp $
#
if {[lsearch [namespace children] ::tcltest] == -1} {
@@ -459,6 +459,20 @@ test var-7.13 {Tcl_VariableObjCmd, variable named ":"} {
p
}
} {{My name is ":"} :}
+test var-7.14 {Tcl_VariableObjCmd, array element parameter} {
+ catch {namespace eval test_ns_var { variable arrayvar(1) }} res
+ set res
+} "can't define \"arrayvar(1)\": name refers to an element in an array"
+test var-7.15 {Tcl_VariableObjCmd, array element parameter} {
+ catch {
+ namespace eval test_ns_var {
+ variable arrayvar
+ set arrayvar(1) x
+ variable arrayvar(1) y
+ }
+ } res
+ set res
+} "can't define \"arrayvar(1)\": name refers to an element in an array"
test var-8.1 {TclDeleteVars, "unset" traces are called with fully-qualified var names} {
catch {namespace delete test_ns_var}