4 * This file contains routines that implement Tcl variables
5 * (both scalars and arrays).
7 * The implementation of arrays is modelled after an initial
8 * implementation by Karl Lehenbauer, Mark Diekhans and
11 * Copyright 1987-1991 Regents of the University of California
12 * Permission to use, copy, modify, and distribute this
13 * software and its documentation for any purpose and without
14 * fee is hereby granted, provided that the above copyright
15 * notice appear in all copies. The University of California
16 * makes no representations about the suitability of this
17 * software for any purpose. It is provided "as is" without
18 * express or implied warranty.
22 static char rcsid
[] = "$Header: /user6/ouster/tcl/RCS/tclVar.c,v 1.27 92/05/07 09:24:59 ouster Exp $ SPRITE (Berkeley)";
28 * The strings below are used to indicate what went wrong when a
29 * variable access is denied.
32 static char *noSuchVar
= "no such variable";
33 static char *isArray
= "variable is array";
34 static char *needArray
= "variable isn't array";
35 static char *noSuchElement
= "no such element in array";
36 static char *traceActive
= "trace is active on variable";
39 * Forward references to procedures defined later in this file:
42 static char * CallTraces
_ANSI_ARGS_((Interp
*iPtr
, Var
*arrayPtr
,
43 Tcl_HashEntry
*hPtr
, char *name1
, char *name2
,
45 static void DeleteSearches
_ANSI_ARGS_((Var
*arrayVarPtr
));
46 static void DeleteArray
_ANSI_ARGS_((Interp
*iPtr
, char *arrayName
,
47 Var
*varPtr
, int flags
));
48 static Var
* NewVar
_ANSI_ARGS_((int space
));
49 static ArraySearch
* ParseSearchId
_ANSI_ARGS_((Tcl_Interp
*interp
,
50 Var
*varPtr
, char *varName
, char *string
));
51 static void VarErrMsg
_ANSI_ARGS_((Tcl_Interp
*interp
,
52 char *name1
, char *name2
, char *operation
,
56 *----------------------------------------------------------------------
60 * Return the value of a Tcl variable.
63 * The return value points to the current value of varName. If
64 * the variable is not defined or can't be read because of a clash
65 * in array usage then a NULL pointer is returned and an error
66 * message is left in interp->result if the TCL_LEAVE_ERR_MSG
67 * flag is set. Note: the return value is only valid up until
68 * the next call to Tcl_SetVar or Tcl_SetVar2; if you depend on
69 * the value lasting longer than that, then make yourself a private
75 *----------------------------------------------------------------------
80 Tcl_Interp
*interp
, /* Command interpreter in which varName is
82 char *varName
, /* Name of a variable in interp. */
83 int flags
/* OR-ed combination of TCL_GLOBAL_ONLY
84 * or TCL_LEAVE_ERR_MSG bits. */
90 * If varName refers to an array (it ends with a parenthesized
91 * element name), then handle it specially.
94 for (p
= varName
; *p
!= '\0'; p
++) {
101 } while (*p
!= '\0');
108 result
= Tcl_GetVar2(interp
, varName
, open
+ 1, flags
);
112 strcmp("a", "b"); /* XXX SGI compiler optimizer bug */
119 return Tcl_GetVar2(interp
, varName
, (char *) NULL
, flags
);
123 *----------------------------------------------------------------------
127 * Return the value of a Tcl variable, given a two-part name
128 * consisting of array name and element within array.
131 * The return value points to the current value of the variable
132 * given by name1 and name2. If the specified variable doesn't
133 * exist, or if there is a clash in array usage, then NULL is
134 * returned and a message will be left in interp->result if the
135 * TCL_LEAVE_ERR_MSG flag is set. Note: the return value is
136 * only valid up until the next call to Tcl_SetVar or Tcl_SetVar2;
137 * if you depend on the value lasting longer than that, then make
138 * yourself a private copy.
143 *----------------------------------------------------------------------
148 Tcl_Interp
*interp
, /* Command interpreter in which variable is
149 * to be looked up. */
150 char *name1
, /* Name of array (if name2 is NULL) or
151 * name of variable. */
152 char *name2
, /* If non-null, gives name of element in
154 int flags
/* OR-ed combination of TCL_GLOBAL_ONLY
155 * or TCL_LEAVE_ERR_MSG bits. */
160 Interp
*iPtr
= (Interp
*) interp
;
161 Var
*arrayPtr
= NULL
;
164 * Lookup the first name.
167 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
168 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, name1
);
170 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, name1
);
173 if (flags
& TCL_LEAVE_ERR_MSG
) {
174 VarErrMsg(interp
, name1
, name2
, "read", noSuchVar
);
178 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
179 if (varPtr
->flags
& VAR_UPVAR
) {
180 hPtr
= varPtr
->value
.upvarPtr
;
181 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
185 * If this is an array reference, then remember the traces on the array
186 * and lookup the element within the array.
190 if (varPtr
->flags
& VAR_UNDEFINED
) {
191 if (flags
& TCL_LEAVE_ERR_MSG
) {
192 VarErrMsg(interp
, name1
, name2
, "read", noSuchVar
);
195 } else if (!(varPtr
->flags
& VAR_ARRAY
)) {
196 if (flags
& TCL_LEAVE_ERR_MSG
) {
197 VarErrMsg(interp
, name1
, name2
, "read", needArray
);
202 hPtr
= Tcl_FindHashEntry(varPtr
->value
.tablePtr
, name2
);
204 if (flags
& TCL_LEAVE_ERR_MSG
) {
205 VarErrMsg(interp
, name1
, name2
, "read", noSuchElement
);
209 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
213 * Invoke any traces that have been set for the variable.
216 if ((varPtr
->tracePtr
!= NULL
)
217 || ((arrayPtr
!= NULL
) && (arrayPtr
->tracePtr
!= NULL
))) {
220 msg
= CallTraces(iPtr
, arrayPtr
, hPtr
, name1
, name2
,
221 (flags
& TCL_GLOBAL_ONLY
) | TCL_TRACE_READS
);
223 VarErrMsg(interp
, name1
, name2
, "read", msg
);
228 * Watch out! The variable could have gotten re-allocated to
229 * a larger size. Fortunately the hash table entry will still
233 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
235 if (varPtr
->flags
& (VAR_UNDEFINED
|VAR_UPVAR
|VAR_ARRAY
)) {
236 if (flags
& TCL_LEAVE_ERR_MSG
) {
237 VarErrMsg(interp
, name1
, name2
, "read", noSuchVar
);
241 return varPtr
->value
.string
;
245 *----------------------------------------------------------------------
249 * Change the value of a variable.
252 * Returns a pointer to the malloc'ed string holding the new
253 * value of the variable. The caller should not modify this
254 * string. If the write operation was disallowed then NULL
255 * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then
256 * an explanatory message will be left in interp->result.
259 * If varName is defined as a local or global variable in interp,
260 * its value is changed to newValue. If varName isn't currently
261 * defined, then a new global variable by that name is created.
263 *----------------------------------------------------------------------
268 Tcl_Interp
*interp
, /* Command interpreter in which varName is
269 * to be looked up. */
270 char *varName
, /* Name of a variable in interp. */
271 char *newValue
, /* New value for varName. */
272 int flags
/* Various flags that tell how to set value:
273 * any of TCL_GLOBAL_ONLY, TCL_APPEND_VALUE,
274 * TCL_LIST_ELEMENT, TCL_NO_SPACE, or
275 * TCL_LEAVE_ERR_MSG. */
281 * If varName refers to an array (it ends with a parenthesized
282 * element name), then handle it specially.
285 for (p
= varName
; *p
!= '\0'; p
++) {
292 } while (*p
!= '\0');
299 result
= Tcl_SetVar2(interp
, varName
, open
+1, newValue
, flags
);
307 return Tcl_SetVar2(interp
, varName
, (char *) NULL
, newValue
, flags
);
311 *----------------------------------------------------------------------
315 * Given a two-part variable name, which may refer either to a
316 * scalar variable or an element of an array, change the value
317 * of the variable. If the named scalar or array or element
318 * doesn't exist then create one.
321 * Returns a pointer to the malloc'ed string holding the new
322 * value of the variable. The caller should not modify this
323 * string. If the write operation was disallowed because an
324 * array was expected but not found (or vice versa), then NULL
325 * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then
326 * an explanatory message will be left in interp->result.
329 * The value of the given variable is set. If either the array
330 * or the entry didn't exist then a new one is created.
332 *----------------------------------------------------------------------
337 Tcl_Interp
*interp
, /* Command interpreter in which variable is
338 * to be looked up. */
339 char *name1
, /* If name2 is NULL, this is name of scalar
340 * variable. Otherwise it is name of array. */
341 char *name2
, /* Name of an element within array, or NULL. */
342 char *newValue
, /* New value for variable. */
343 int flags
/* Various flags that tell how to set value:
344 * any of TCL_GLOBAL_ONLY, TCL_APPEND_VALUE,
345 * TCL_LIST_ELEMENT, and TCL_NO_SPACE, or
346 * TCL_LEAVE_ERR_MSG . */
350 register Var
*varPtr
= NULL
;
351 /* Initial value only used to stop compiler
352 * from complaining; not really needed. */
353 register Interp
*iPtr
= (Interp
*) interp
;
354 int length
, new, listFlags
;
355 Var
*arrayPtr
= NULL
;
358 * Lookup the first name.
361 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
362 hPtr
= Tcl_CreateHashEntry(&iPtr
->globalTable
, name1
, &new);
364 hPtr
= Tcl_CreateHashEntry(&iPtr
->varFramePtr
->varTable
,
368 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
369 if (varPtr
->flags
& VAR_UPVAR
) {
370 hPtr
= varPtr
->value
.upvarPtr
;
371 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
376 * If this is an array reference, then create a new array (if
377 * needed), remember any traces on the array, and lookup the
378 * element within the array.
384 Tcl_SetHashValue(hPtr
, varPtr
);
385 varPtr
->flags
= VAR_ARRAY
;
386 varPtr
->value
.tablePtr
= (Tcl_HashTable
*)
387 ckalloc(sizeof(Tcl_HashTable
));
388 Tcl_InitHashTable(varPtr
->value
.tablePtr
, TCL_STRING_KEYS
);
390 if (varPtr
->flags
& VAR_UNDEFINED
) {
391 varPtr
->flags
= VAR_ARRAY
;
392 varPtr
->value
.tablePtr
= (Tcl_HashTable
*)
393 ckalloc(sizeof(Tcl_HashTable
));
394 Tcl_InitHashTable(varPtr
->value
.tablePtr
, TCL_STRING_KEYS
);
395 } else if (!(varPtr
->flags
& VAR_ARRAY
)) {
396 if (flags
& TCL_LEAVE_ERR_MSG
) {
397 VarErrMsg(interp
, name1
, name2
, "set", needArray
);
403 hPtr
= Tcl_CreateHashEntry(varPtr
->value
.tablePtr
, name2
, &new);
407 * Compute how many bytes will be needed for newValue (leave space
408 * for a separating space between list elements).
411 if (flags
& TCL_LIST_ELEMENT
) {
412 length
= Tcl_ScanElement(newValue
, &listFlags
) + 1;
414 length
= strlen(newValue
);
418 * If the variable doesn't exist then create a new one. If it
419 * does exist then clear its current value unless this is an
424 varPtr
= NewVar(length
);
425 Tcl_SetHashValue(hPtr
, varPtr
);
426 if ((arrayPtr
!= NULL
) && (arrayPtr
->searchPtr
!= NULL
)) {
427 DeleteSearches(arrayPtr
);
430 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
431 if (varPtr
->flags
& VAR_ARRAY
) {
432 if (flags
& TCL_LEAVE_ERR_MSG
) {
433 VarErrMsg(interp
, name1
, name2
, "set", isArray
);
437 if (!(flags
& TCL_APPEND_VALUE
) || (varPtr
->flags
& VAR_UNDEFINED
)) {
438 varPtr
->valueLength
= 0;
443 * Make sure there's enough space to hold the variable's
444 * new value. If not, enlarge the variable's space.
447 if ((length
+ varPtr
->valueLength
) >= varPtr
->valueSpace
) {
451 newSize
= 2*varPtr
->valueSpace
;
452 if (newSize
<= (length
+ varPtr
->valueLength
)) {
455 newVarPtr
= NewVar(newSize
);
456 newVarPtr
->valueLength
= varPtr
->valueLength
;
457 newVarPtr
->upvarUses
= varPtr
->upvarUses
;
458 newVarPtr
->tracePtr
= varPtr
->tracePtr
;
459 strcpy(newVarPtr
->value
.string
, varPtr
->value
.string
);
460 Tcl_SetHashValue(hPtr
, newVarPtr
);
461 ckfree((char *) varPtr
);
466 * Append the new value to the variable, either as a list
467 * element or as a string.
470 if (flags
& TCL_LIST_ELEMENT
) {
471 if ((varPtr
->valueLength
> 0) && !(flags
& TCL_NO_SPACE
)) {
472 varPtr
->value
.string
[varPtr
->valueLength
] = ' ';
473 varPtr
->valueLength
++;
475 varPtr
->valueLength
+= Tcl_ConvertElement(newValue
,
476 varPtr
->value
.string
+ varPtr
->valueLength
, listFlags
);
477 varPtr
->value
.string
[varPtr
->valueLength
] = 0;
479 strcpy(varPtr
->value
.string
+ varPtr
->valueLength
, newValue
);
480 varPtr
->valueLength
+= length
;
482 varPtr
->flags
&= ~VAR_UNDEFINED
;
485 * Invoke any write traces for the variable.
488 if ((varPtr
->tracePtr
!= NULL
)
489 || ((arrayPtr
!= NULL
) && (arrayPtr
->tracePtr
!= NULL
))) {
492 msg
= CallTraces(iPtr
, arrayPtr
, hPtr
, name1
, name2
,
493 (flags
& TCL_GLOBAL_ONLY
) | TCL_TRACE_WRITES
);
495 VarErrMsg(interp
, name1
, name2
, "set", msg
);
500 * Watch out! The variable could have gotten re-allocated to
501 * a larger size. Fortunately the hash table entry will still
505 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
507 return varPtr
->value
.string
;
511 *----------------------------------------------------------------------
515 * Delete a variable, so that it may not be accessed anymore.
518 * Returns 0 if the variable was successfully deleted, -1
519 * if the variable can't be unset. In the event of an error,
520 * if the TCL_LEAVE_ERR_MSG flag is set then an error message
521 * is left in interp->result.
524 * If varName is defined as a local or global variable in interp,
527 *----------------------------------------------------------------------
532 Tcl_Interp
*interp
, /* Command interpreter in which varName is
533 * to be looked up. */
534 char *varName
, /* Name of a variable in interp. May be
535 * either a scalar name or an array name
536 * or an element in an array. */
537 int flags
/* OR-ed combination of any of
538 * TCL_GLOBAL_ONLY or TCL_LEAVE_ERR_MSG. */
545 * Figure out whether this is an array reference, then call
546 * Tcl_UnsetVar2 to do all the real work.
549 for (p
= varName
; *p
!= '\0'; p
++) {
555 } while (*p
!= '\0');
562 result
= Tcl_UnsetVar2(interp
, varName
, open
+1, flags
);
570 return Tcl_UnsetVar2(interp
, varName
, (char *) NULL
, flags
);
574 *----------------------------------------------------------------------
578 * Delete a variable, given a 2-part name.
581 * Returns 0 if the variable was successfully deleted, -1
582 * if the variable can't be unset. In the event of an error,
583 * if the TCL_LEAVE_ERR_MSG flag is set then an error message
584 * is left in interp->result.
587 * If name1 and name2 indicate a local or global variable in interp,
588 * it is deleted. If name1 is an array name and name2 is NULL, then
589 * the whole array is deleted.
591 *----------------------------------------------------------------------
596 Tcl_Interp
*interp
, /* Command interpreter in which varName is
597 * to be looked up. */
598 char *name1
, /* Name of variable or array. */
599 char *name2
, /* Name of element within array or NULL. */
600 int flags
/* OR-ed combination of any of
601 * TCL_GLOBAL_ONLY or TCL_LEAVE_ERR_MSG. */
604 Tcl_HashEntry
*hPtr
, dummyEntry
;
605 Var
*varPtr
, dummyVar
;
606 Interp
*iPtr
= (Interp
*) interp
;
607 Var
*arrayPtr
= NULL
;
609 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
610 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, name1
);
612 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, name1
);
615 if (flags
& TCL_LEAVE_ERR_MSG
) {
616 VarErrMsg(interp
, name1
, name2
, "unset", noSuchVar
);
620 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
623 * For global variables referenced in procedures, leave the procedure's
624 * reference variable in place, but unset the global variable. Can't
625 * decrement the actual variable's use count, since we didn't delete
626 * the reference variable.
629 if (varPtr
->flags
& VAR_UPVAR
) {
630 hPtr
= varPtr
->value
.upvarPtr
;
631 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
635 * If the variable being deleted is an element of an array, then
636 * remember trace procedures on the overall array and find the
641 if (!(varPtr
->flags
& VAR_ARRAY
)) {
642 if (flags
& TCL_LEAVE_ERR_MSG
) {
643 VarErrMsg(interp
, name1
, name2
, "unset", needArray
);
647 if (varPtr
->searchPtr
!= NULL
) {
648 DeleteSearches(varPtr
);
651 hPtr
= Tcl_FindHashEntry(varPtr
->value
.tablePtr
, name2
);
653 if (flags
& TCL_LEAVE_ERR_MSG
) {
654 VarErrMsg(interp
, name1
, name2
, "unset", noSuchElement
);
658 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
662 * If there is a trace active on this variable or if the variable
663 * is already being deleted then don't delete the variable: it
664 * isn't safe, since there are procedures higher up on the stack
665 * that will use pointers to the variable. Also don't delete an
666 * array if there are traces active on any of its elements.
670 (VAR_TRACE_ACTIVE
|VAR_ELEMENT_ACTIVE
)) {
671 if (flags
& TCL_LEAVE_ERR_MSG
) {
672 VarErrMsg(interp
, name1
, name2
, "unset", traceActive
);
678 * The code below is tricky, because of the possibility that
679 * a trace procedure might try to access a variable being
680 * deleted. To handle this situation gracefully, copy the
681 * contents of the variable and its hash table entry to
682 * dummy variables, then clean up the actual variable so that
683 * it's been completely deleted before the traces are called.
684 * Then call the traces, and finally clean up the variable's
685 * storage using the dummy copies.
689 Tcl_SetHashValue(&dummyEntry
, &dummyVar
);
690 if (varPtr
->upvarUses
== 0) {
691 Tcl_DeleteHashEntry(hPtr
);
692 ckfree((char *) varPtr
);
694 varPtr
->flags
= VAR_UNDEFINED
;
695 varPtr
->tracePtr
= NULL
;
699 * Call trace procedures for the variable being deleted and delete
703 if ((dummyVar
.tracePtr
!= NULL
)
704 || ((arrayPtr
!= NULL
) && (arrayPtr
->tracePtr
!= NULL
))) {
705 (void) CallTraces(iPtr
, arrayPtr
, &dummyEntry
, name1
, name2
,
706 (flags
& TCL_GLOBAL_ONLY
) | TCL_TRACE_UNSETS
);
707 while (dummyVar
.tracePtr
!= NULL
) {
708 VarTrace
*tracePtr
= dummyVar
.tracePtr
;
709 dummyVar
.tracePtr
= tracePtr
->nextPtr
;
710 ckfree((char *) tracePtr
);
715 * If the variable is an array, delete all of its elements. This
716 * must be done after calling the traces on the array, above (that's
717 * the way traces are defined).
720 if (dummyVar
.flags
& VAR_ARRAY
) {
721 DeleteArray(iPtr
, name1
, &dummyVar
,
722 (flags
& TCL_GLOBAL_ONLY
) | TCL_TRACE_UNSETS
);
724 if (dummyVar
.flags
& VAR_UNDEFINED
) {
725 if (flags
& TCL_LEAVE_ERR_MSG
) {
726 VarErrMsg(interp
, name1
, name2
, "unset",
727 (name2
== NULL
) ? noSuchVar
: noSuchElement
);
735 *----------------------------------------------------------------------
739 * Arrange for reads and/or writes to a variable to cause a
740 * procedure to be invoked, which can monitor the operations
741 * and/or change their actions.
744 * A standard Tcl return value.
747 * A trace is set up on the variable given by varName, such that
748 * future references to the variable will be intermediated by
749 * proc. See the manual entry for complete details on the calling
752 *----------------------------------------------------------------------
757 Tcl_Interp
*interp
, /* Interpreter in which variable is
759 char *varName
, /* Name of variable; may end with "(index)"
760 * to signify an array reference. */
761 int flags
, /* OR-ed collection of bits, including any
762 * of TCL_TRACE_READS, TCL_TRACE_WRITES,
763 * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
764 Tcl_VarTraceProc
*proc
, /* Procedure to call when specified ops are
765 * invoked upon varName. */
766 ClientData clientData
/* Arbitrary argument to pass to proc. */
772 * If varName refers to an array (it ends with a parenthesized
773 * element name), then handle it specially.
776 for (p
= varName
; *p
!= '\0'; p
++) {
783 } while (*p
!= '\0');
790 result
= Tcl_TraceVar2(interp
, varName
, open
+1, flags
,
799 return Tcl_TraceVar2(interp
, varName
, (char *) NULL
, flags
,
804 *----------------------------------------------------------------------
808 * Arrange for reads and/or writes to a variable to cause a
809 * procedure to be invoked, which can monitor the operations
810 * and/or change their actions.
813 * A standard Tcl return value.
816 * A trace is set up on the variable given by name1 and name2, such
817 * that future references to the variable will be intermediated by
818 * proc. See the manual entry for complete details on the calling
821 *----------------------------------------------------------------------
826 Tcl_Interp
*interp
, /* Interpreter in which variable is
828 char *name1
, /* Name of scalar variable or array. */
829 char *name2
, /* Name of element within array; NULL means
830 * trace applies to scalar variable or array
832 int flags
, /* OR-ed collection of bits, including any
833 * of TCL_TRACE_READS, TCL_TRACE_WRITES,
834 * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
835 Tcl_VarTraceProc
*proc
, /* Procedure to call when specified ops are
836 * invoked upon varName. */
837 ClientData clientData
/* Arbitrary argument to pass to proc. */
841 Var
*varPtr
= NULL
; /* Initial value only used to stop compiler
842 * from complaining; not really needed. */
843 Interp
*iPtr
= (Interp
*) interp
;
844 register VarTrace
*tracePtr
;
848 * Locate the variable, making a new (undefined) one if necessary.
851 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
852 hPtr
= Tcl_CreateHashEntry(&iPtr
->globalTable
, name1
, &new);
854 hPtr
= Tcl_CreateHashEntry(&iPtr
->varFramePtr
->varTable
, name1
, &new);
857 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
858 if (varPtr
->flags
& VAR_UPVAR
) {
859 hPtr
= varPtr
->value
.upvarPtr
;
860 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
865 * If the trace is to be on an array element, make sure that the
866 * variable is an array variable. If the variable doesn't exist
867 * then define it as an empty array. Then find the specific
874 Tcl_SetHashValue(hPtr
, varPtr
);
875 varPtr
->flags
= VAR_ARRAY
;
876 varPtr
->value
.tablePtr
= (Tcl_HashTable
*)
877 ckalloc(sizeof(Tcl_HashTable
));
878 Tcl_InitHashTable(varPtr
->value
.tablePtr
, TCL_STRING_KEYS
);
880 if (varPtr
->flags
& VAR_UNDEFINED
) {
881 varPtr
->flags
= VAR_ARRAY
;
882 varPtr
->value
.tablePtr
= (Tcl_HashTable
*)
883 ckalloc(sizeof(Tcl_HashTable
));
884 Tcl_InitHashTable(varPtr
->value
.tablePtr
, TCL_STRING_KEYS
);
885 } else if (!(varPtr
->flags
& VAR_ARRAY
)) {
886 iPtr
->result
= needArray
;
890 hPtr
= Tcl_CreateHashEntry(varPtr
->value
.tablePtr
, name2
, &new);
894 if ((name2
!= NULL
) && (varPtr
->searchPtr
!= NULL
)) {
895 DeleteSearches(varPtr
);
898 varPtr
->flags
= VAR_UNDEFINED
;
899 Tcl_SetHashValue(hPtr
, varPtr
);
901 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
905 * Set up trace information.
908 tracePtr
= (VarTrace
*) ckalloc(sizeof(VarTrace
));
909 tracePtr
->traceProc
= proc
;
910 tracePtr
->clientData
= clientData
;
911 tracePtr
->flags
= flags
&
912 (TCL_TRACE_READS
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
);
913 tracePtr
->nextPtr
= varPtr
->tracePtr
;
914 varPtr
->tracePtr
= tracePtr
;
919 *----------------------------------------------------------------------
923 * Remove a previously-created trace for a variable.
929 * If there exists a trace for the variable given by varName
930 * with the given flags, proc, and clientData, then that trace
933 *----------------------------------------------------------------------
938 Tcl_Interp
*interp
, /* Interpreter containing traced variable. */
939 char *varName
, /* Name of variable; may end with "(index)"
940 * to signify an array reference. */
941 int flags
, /* OR-ed collection of bits describing
942 * current trace, including any of
943 * TCL_TRACE_READS, TCL_TRACE_WRITES,
944 * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
945 Tcl_VarTraceProc
*proc
, /* Procedure assocated with trace. */
946 ClientData clientData
/* Arbitrary argument to pass to proc. */
952 * If varName refers to an array (it ends with a parenthesized
953 * element name), then handle it specially.
956 for (p
= varName
; *p
!= '\0'; p
++) {
962 } while (*p
!= '\0');
969 Tcl_UntraceVar2(interp
, varName
, open
+1, flags
, proc
, clientData
);
977 Tcl_UntraceVar2(interp
, varName
, (char *) NULL
, flags
, proc
, clientData
);
981 *----------------------------------------------------------------------
985 * Remove a previously-created trace for a variable.
991 * If there exists a trace for the variable given by name1
992 * and name2 with the given flags, proc, and clientData, then
993 * that trace is removed.
995 *----------------------------------------------------------------------
1000 Tcl_Interp
*interp
, /* Interpreter containing traced variable. */
1001 char *name1
, /* Name of variable or array. */
1002 char *name2
, /* Name of element within array; NULL means
1003 * trace applies to scalar variable or array
1005 int flags
, /* OR-ed collection of bits describing
1006 * current trace, including any of
1007 * TCL_TRACE_READS, TCL_TRACE_WRITES,
1008 * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
1009 Tcl_VarTraceProc
*proc
, /* Procedure assocated with trace. */
1010 ClientData clientData
/* Arbitrary argument to pass to proc. */
1013 register VarTrace
*tracePtr
;
1016 Interp
*iPtr
= (Interp
*) interp
;
1017 Tcl_HashEntry
*hPtr
;
1018 ActiveVarTrace
*activePtr
;
1021 * First, lookup the variable.
1024 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
1025 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, name1
);
1027 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, name1
);
1032 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1033 if (varPtr
->flags
& VAR_UPVAR
) {
1034 hPtr
= varPtr
->value
.upvarPtr
;
1035 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1037 if (name2
!= NULL
) {
1038 if (!(varPtr
->flags
& VAR_ARRAY
)) {
1041 hPtr
= Tcl_FindHashEntry(varPtr
->value
.tablePtr
, name2
);
1045 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1048 flags
&= (TCL_TRACE_READS
| TCL_TRACE_WRITES
| TCL_TRACE_UNSETS
);
1049 for (tracePtr
= varPtr
->tracePtr
, prevPtr
= NULL
; ;
1050 prevPtr
= tracePtr
, tracePtr
= tracePtr
->nextPtr
) {
1051 if (tracePtr
== NULL
) {
1054 if ((tracePtr
->traceProc
== proc
) && (tracePtr
->flags
== flags
)
1055 && (tracePtr
->clientData
== clientData
)) {
1061 * The code below makes it possible to delete traces while traces
1062 * are active: it makes sure that the deleted trace won't be
1063 * processed by CallTraces.
1066 for (activePtr
= iPtr
->activeTracePtr
; activePtr
!= NULL
;
1067 activePtr
= activePtr
->nextPtr
) {
1068 if (activePtr
->nextTracePtr
== tracePtr
) {
1069 activePtr
->nextTracePtr
= tracePtr
->nextPtr
;
1072 if (prevPtr
== NULL
) {
1073 varPtr
->tracePtr
= tracePtr
->nextPtr
;
1075 prevPtr
->nextPtr
= tracePtr
->nextPtr
;
1077 ckfree((char *) tracePtr
);
1081 *----------------------------------------------------------------------
1083 * Tcl_VarTraceInfo --
1085 * Return the clientData value associated with a trace on a
1086 * variable. This procedure can also be used to step through
1087 * all of the traces on a particular variable that have the
1088 * same trace procedure.
1091 * The return value is the clientData value associated with
1092 * a trace on the given variable. Information will only be
1093 * returned for a trace with proc as trace procedure. If
1094 * the clientData argument is NULL then the first such trace is
1095 * returned; otherwise, the next relevant one after the one
1096 * given by clientData will be returned. If the variable
1097 * doesn't exist, or if there are no (more) traces for it,
1098 * then NULL is returned.
1103 *----------------------------------------------------------------------
1108 Tcl_Interp
*interp
, /* Interpreter containing variable. */
1109 char *varName
, /* Name of variable; may end with "(index)"
1110 * to signify an array reference. */
1111 int flags
, /* 0 or TCL_GLOBAL_ONLY. */
1112 Tcl_VarTraceProc
*proc
, /* Procedure assocated with trace. */
1113 ClientData prevClientData
/* If non-NULL, gives last value returned
1114 * by this procedure, so this call will
1115 * return the next trace after that one.
1116 * If NULL, this call will return the
1123 * If varName refers to an array (it ends with a parenthesized
1124 * element name), then handle it specially.
1127 for (p
= varName
; *p
!= '\0'; p
++) {
1134 } while (*p
!= '\0');
1141 result
= Tcl_VarTraceInfo2(interp
, varName
, open
+1, flags
, proc
,
1150 return Tcl_VarTraceInfo2(interp
, varName
, (char *) NULL
, flags
, proc
,
1155 *----------------------------------------------------------------------
1157 * Tcl_VarTraceInfo2 --
1159 * Same as Tcl_VarTraceInfo, except takes name in two pieces
1163 * Same as Tcl_VarTraceInfo.
1168 *----------------------------------------------------------------------
1173 Tcl_Interp
*interp
, /* Interpreter containing variable. */
1174 char *name1
, /* Name of variable or array. */
1175 char *name2
, /* Name of element within array; NULL means
1176 * trace applies to scalar variable or array
1178 int flags
, /* 0 or TCL_GLOBAL_ONLY. */
1179 Tcl_VarTraceProc
*proc
, /* Procedure assocated with trace. */
1180 ClientData prevClientData
/* If non-NULL, gives last value returned
1181 * by this procedure, so this call will
1182 * return the next trace after that one.
1183 * If NULL, this call will return the
1187 register VarTrace
*tracePtr
;
1189 Interp
*iPtr
= (Interp
*) interp
;
1190 Tcl_HashEntry
*hPtr
;
1193 * First, lookup the variable.
1196 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
1197 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, name1
);
1199 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, name1
);
1204 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1205 if (varPtr
->flags
& VAR_UPVAR
) {
1206 hPtr
= varPtr
->value
.upvarPtr
;
1207 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1209 if (name2
!= NULL
) {
1210 if (!(varPtr
->flags
& VAR_ARRAY
)) {
1213 hPtr
= Tcl_FindHashEntry(varPtr
->value
.tablePtr
, name2
);
1217 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1221 * Find the relevant trace, if any, and return its clientData.
1224 tracePtr
= varPtr
->tracePtr
;
1225 if (prevClientData
!= NULL
) {
1226 for ( ; tracePtr
!= NULL
; tracePtr
= tracePtr
->nextPtr
) {
1227 if ((tracePtr
->clientData
== prevClientData
)
1228 && (tracePtr
->traceProc
== proc
)) {
1229 tracePtr
= tracePtr
->nextPtr
;
1234 for ( ; tracePtr
!= NULL
; tracePtr
= tracePtr
->nextPtr
) {
1235 if (tracePtr
->traceProc
== proc
) {
1236 return tracePtr
->clientData
;
1243 *----------------------------------------------------------------------
1247 * This procedure is invoked to process the "set" Tcl command.
1248 * See the user documentation for details on what it does.
1251 * A standard Tcl result value.
1254 * A variable's value may be changed.
1256 *----------------------------------------------------------------------
1262 ClientData dummy
, /* Not used. */
1263 register Tcl_Interp
*interp
, /* Current interpreter. */
1264 int argc
, /* Number of arguments. */
1265 char **argv
/* Argument strings. */
1271 value
= Tcl_GetVar(interp
, argv
[1], TCL_LEAVE_ERR_MSG
);
1272 if (value
== NULL
) {
1275 interp
->result
= value
;
1277 } else if (argc
== 3) {
1280 result
= Tcl_SetVar(interp
, argv
[1], argv
[2], TCL_LEAVE_ERR_MSG
);
1281 if (result
== NULL
) {
1284 interp
->result
= result
;
1287 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1288 argv
[0], " varName ?newValue?\"", (char *) NULL
);
1294 *----------------------------------------------------------------------
1298 * This procedure is invoked to process the "unset" Tcl command.
1299 * See the user documentation for details on what it does.
1302 * A standard Tcl result value.
1305 * See the user documentation.
1307 *----------------------------------------------------------------------
1313 ClientData dummy
, /* Not used. */
1314 register Tcl_Interp
*interp
, /* Current interpreter. */
1315 int argc
, /* Number of arguments. */
1316 char **argv
/* Argument strings. */
1322 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1323 argv
[0], " varName ?varName ...?\"", (char *) NULL
);
1326 for (i
= 1; i
< argc
; i
++) {
1327 if (Tcl_UnsetVar(interp
, argv
[i
], TCL_LEAVE_ERR_MSG
) != 0) {
1335 *----------------------------------------------------------------------
1339 * This procedure is invoked to process the "append" Tcl command.
1340 * See the user documentation for details on what it does.
1343 * A standard Tcl result value.
1346 * A variable's value may be changed.
1348 *----------------------------------------------------------------------
1354 ClientData dummy
, /* Not used. */
1355 register Tcl_Interp
*interp
, /* Current interpreter. */
1356 int argc
, /* Number of arguments. */
1357 char **argv
/* Argument strings. */
1361 char *result
= NULL
; /* (Initialization only needed to keep
1362 * the compiler from complaining) */
1365 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1366 argv
[0], " varName value ?value ...?\"", (char *) NULL
);
1370 for (i
= 2; i
< argc
; i
++) {
1371 result
= Tcl_SetVar(interp
, argv
[1], argv
[i
],
1372 TCL_APPEND_VALUE
|TCL_LEAVE_ERR_MSG
);
1373 if (result
== NULL
) {
1377 interp
->result
= result
;
1382 *----------------------------------------------------------------------
1386 * This procedure is invoked to process the "lappend" Tcl command.
1387 * See the user documentation for details on what it does.
1390 * A standard Tcl result value.
1393 * A variable's value may be changed.
1395 *----------------------------------------------------------------------
1401 ClientData dummy
, /* Not used. */
1402 register Tcl_Interp
*interp
, /* Current interpreter. */
1403 int argc
, /* Number of arguments. */
1404 char **argv
/* Argument strings. */
1408 char *result
= NULL
; /* (Initialization only needed to keep
1409 * the compiler from complaining) */
1412 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1413 argv
[0], " varName value ?value ...?\"", (char *) NULL
);
1417 for (i
= 2; i
< argc
; i
++) {
1418 result
= Tcl_SetVar(interp
, argv
[1], argv
[i
],
1419 TCL_APPEND_VALUE
|TCL_LIST_ELEMENT
|TCL_LEAVE_ERR_MSG
);
1420 if (result
== NULL
) {
1424 interp
->result
= result
;
1429 *----------------------------------------------------------------------
1433 * This procedure is invoked to process the "array" Tcl command.
1434 * See the user documentation for details on what it does.
1437 * A standard Tcl result value.
1440 * See the user documentation.
1442 *----------------------------------------------------------------------
1448 ClientData dummy
, /* Not used. */
1449 register Tcl_Interp
*interp
, /* Current interpreter. */
1450 int argc
, /* Number of arguments. */
1451 char **argv
/* Argument strings. */
1457 Tcl_HashEntry
*hPtr
;
1458 Interp
*iPtr
= (Interp
*) interp
;
1461 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1462 argv
[0], " option arrayName ?arg ...?\"", (char *) NULL
);
1467 * Locate the array variable (and it better be an array).
1470 if (iPtr
->varFramePtr
== NULL
) {
1471 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, argv
[2]);
1473 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, argv
[2]);
1477 Tcl_AppendResult(interp
, "\"", argv
[2], "\" isn't an array",
1481 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1482 if (varPtr
->flags
& VAR_UPVAR
) {
1483 varPtr
= (Var
*) Tcl_GetHashValue(varPtr
->value
.upvarPtr
);
1485 if (!(varPtr
->flags
& VAR_ARRAY
)) {
1490 * Dispatch based on the option.
1494 length
= strlen(argv
[1]);
1495 if ((c
== 'a') && (strncmp(argv
[1], "anymore", length
) == 0)) {
1496 ArraySearch
*searchPtr
;
1499 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1500 argv
[0], " anymore arrayName searchId\"", (char *) NULL
);
1503 searchPtr
= ParseSearchId(interp
, varPtr
, argv
[2], argv
[3]);
1504 if (searchPtr
== NULL
) {
1510 if (searchPtr
->nextEntry
!= NULL
) {
1511 varPtr2
= (Var
*) Tcl_GetHashValue(searchPtr
->nextEntry
);
1512 if (!(varPtr2
->flags
& VAR_UNDEFINED
)) {
1516 searchPtr
->nextEntry
= Tcl_NextHashEntry(&searchPtr
->search
);
1517 if (searchPtr
->nextEntry
== NULL
) {
1518 interp
->result
= "0";
1522 interp
->result
= "1";
1524 } else if ((c
== 'd') && (strncmp(argv
[1], "donesearch", length
) == 0)) {
1525 ArraySearch
*searchPtr
, *prevPtr
;
1528 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1529 argv
[0], " donesearch arrayName searchId\"", (char *) NULL
);
1532 searchPtr
= ParseSearchId(interp
, varPtr
, argv
[2], argv
[3]);
1533 if (searchPtr
== NULL
) {
1536 if (varPtr
->searchPtr
== searchPtr
) {
1537 varPtr
->searchPtr
= searchPtr
->nextPtr
;
1539 for (prevPtr
= varPtr
->searchPtr
; ; prevPtr
= prevPtr
->nextPtr
) {
1540 if (prevPtr
->nextPtr
== searchPtr
) {
1541 prevPtr
->nextPtr
= searchPtr
->nextPtr
;
1546 ckfree((char *) searchPtr
);
1547 } else if ((c
== 'n') && (strncmp(argv
[1], "names", length
) == 0)
1549 Tcl_HashSearch search
;
1553 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1554 argv
[0], " names arrayName\"", (char *) NULL
);
1557 for (hPtr
= Tcl_FirstHashEntry(varPtr
->value
.tablePtr
, &search
);
1558 hPtr
!= NULL
; hPtr
= Tcl_NextHashEntry(&search
)) {
1559 varPtr2
= (Var
*) Tcl_GetHashValue(hPtr
);
1560 if (varPtr2
->flags
& VAR_UNDEFINED
) {
1563 Tcl_AppendElement(interp
,
1564 Tcl_GetHashKey(varPtr
->value
.tablePtr
, hPtr
), 0);
1566 } else if ((c
== 'n') && (strncmp(argv
[1], "nextelement", length
) == 0)
1568 ArraySearch
*searchPtr
;
1569 Tcl_HashEntry
*hPtr
;
1572 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1573 argv
[0], " nextelement arrayName searchId\"",
1577 searchPtr
= ParseSearchId(interp
, varPtr
, argv
[2], argv
[3]);
1578 if (searchPtr
== NULL
) {
1584 hPtr
= searchPtr
->nextEntry
;
1586 hPtr
= Tcl_NextHashEntry(&searchPtr
->search
);
1591 searchPtr
->nextEntry
= NULL
;
1593 varPtr2
= (Var
*) Tcl_GetHashValue(hPtr
);
1594 if (!(varPtr2
->flags
& VAR_UNDEFINED
)) {
1598 interp
->result
= Tcl_GetHashKey(varPtr
->value
.tablePtr
, hPtr
);
1599 } else if ((c
== 's') && (strncmp(argv
[1], "size", length
) == 0)
1601 Tcl_HashSearch search
;
1606 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1607 argv
[0], " size arrayName\"", (char *) NULL
);
1611 for (hPtr
= Tcl_FirstHashEntry(varPtr
->value
.tablePtr
, &search
);
1612 hPtr
!= NULL
; hPtr
= Tcl_NextHashEntry(&search
)) {
1613 varPtr2
= (Var
*) Tcl_GetHashValue(hPtr
);
1614 if (varPtr2
->flags
& VAR_UNDEFINED
) {
1619 sprintf(interp
->result
, "%d", size
);
1620 } else if ((c
== 's') && (strncmp(argv
[1], "startsearch", length
) == 0)
1622 ArraySearch
*searchPtr
;
1625 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1626 argv
[0], " startsearch arrayName\"", (char *) NULL
);
1629 searchPtr
= (ArraySearch
*) ckalloc(sizeof(ArraySearch
));
1630 if (varPtr
->searchPtr
== NULL
) {
1632 Tcl_AppendResult(interp
, "s-1-", argv
[2], (char *) NULL
);
1636 searchPtr
->id
= varPtr
->searchPtr
->id
+ 1;
1637 sprintf(string
, "%d", searchPtr
->id
);
1638 Tcl_AppendResult(interp
, "s-", string
, "-", argv
[2],
1641 searchPtr
->varPtr
= varPtr
;
1642 searchPtr
->nextEntry
= Tcl_FirstHashEntry(varPtr
->value
.tablePtr
,
1643 &searchPtr
->search
);
1644 searchPtr
->nextPtr
= varPtr
->searchPtr
;
1645 varPtr
->searchPtr
= searchPtr
;
1647 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
1648 "\": should be anymore, donesearch, names, nextelement, ",
1649 "size, or startsearch", (char *) NULL
);
1656 *----------------------------------------------------------------------
1660 * This procedure is invoked to process the "global" Tcl command.
1661 * See the user documentation for details on what it does.
1664 * A standard Tcl result value.
1667 * See the user documentation.
1669 *----------------------------------------------------------------------
1675 ClientData dummy
, /* Not used. */
1676 Tcl_Interp
*interp
, /* Current interpreter. */
1677 int argc
, /* Number of arguments. */
1678 char **argv
/* Argument strings. */
1681 Var
*varPtr
, *gVarPtr
;
1682 register Interp
*iPtr
= (Interp
*) interp
;
1683 Tcl_HashEntry
*hPtr
, *hPtr2
;
1687 Tcl_AppendResult((Tcl_Interp
*) iPtr
, "wrong # args: should be \"",
1688 argv
[0], " varName ?varName ...?\"", (char *) NULL
);
1691 if (iPtr
->varFramePtr
== NULL
) {
1695 for (argc
--, argv
++; argc
> 0; argc
--, argv
++) {
1696 hPtr
= Tcl_CreateHashEntry(&iPtr
->globalTable
, *argv
, &new);
1698 gVarPtr
= NewVar(0);
1699 gVarPtr
->flags
|= VAR_UNDEFINED
;
1700 Tcl_SetHashValue(hPtr
, gVarPtr
);
1702 gVarPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1704 hPtr2
= Tcl_CreateHashEntry(&iPtr
->varFramePtr
->varTable
, *argv
, &new);
1707 varPtr
= (Var
*) Tcl_GetHashValue(hPtr2
);
1708 if (varPtr
->flags
& VAR_UPVAR
) {
1711 Tcl_AppendResult((Tcl_Interp
*) iPtr
, "variable \"", *argv
,
1712 "\" already exists", (char *) NULL
);
1717 varPtr
->flags
|= VAR_UPVAR
;
1718 varPtr
->value
.upvarPtr
= hPtr
;
1719 gVarPtr
->upvarUses
++;
1720 Tcl_SetHashValue(hPtr2
, varPtr
);
1726 *----------------------------------------------------------------------
1730 * This procedure is invoked to process the "upvar" Tcl command.
1731 * See the user documentation for details on what it does.
1734 * A standard Tcl result value.
1737 * See the user documentation.
1739 *----------------------------------------------------------------------
1745 ClientData dummy
, /* Not used. */
1746 Tcl_Interp
*interp
, /* Current interpreter. */
1747 int argc
, /* Number of arguments. */
1748 char **argv
/* Argument strings. */
1751 register Interp
*iPtr
= (Interp
*) interp
;
1753 CallFrame
*framePtr
;
1755 Tcl_HashTable
*upVarTablePtr
;
1756 Tcl_HashEntry
*hPtr
, *hPtr2
;
1762 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
1763 " ?level? otherVar localVar ?otherVar localVar ...?\"",
1769 * Find the hash table containing the variable being referenced.
1772 result
= TclGetFrame(interp
, argv
[1], &framePtr
);
1778 if (framePtr
== NULL
) {
1779 upVarTablePtr
= &iPtr
->globalTable
;
1781 upVarTablePtr
= &framePtr
->varTable
;
1784 if ((argc
& 1) != 0) {
1789 * Iterate over all the pairs of (local variable, other variable)
1790 * names. For each pair, create a hash table entry in the upper
1791 * context (if the name wasn't there already), then associate it
1792 * with a new local variable.
1796 hPtr
= Tcl_CreateHashEntry(upVarTablePtr
, argv
[0], &new);
1798 upVarPtr
= NewVar(0);
1799 upVarPtr
->flags
|= VAR_UNDEFINED
;
1800 Tcl_SetHashValue(hPtr
, upVarPtr
);
1802 upVarPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1803 if (upVarPtr
->flags
& VAR_UPVAR
) {
1804 hPtr
= upVarPtr
->value
.upvarPtr
;
1805 upVarPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1809 hPtr2
= Tcl_CreateHashEntry(&iPtr
->varFramePtr
->varTable
,
1812 Tcl_AppendResult((Tcl_Interp
*) iPtr
, "variable \"", argv
[1],
1813 "\" already exists", (char *) NULL
);
1817 varPtr
->flags
|= VAR_UPVAR
;
1818 varPtr
->value
.upvarPtr
= hPtr
;
1819 upVarPtr
->upvarUses
++;
1820 Tcl_SetHashValue(hPtr2
, varPtr
);
1829 *----------------------------------------------------------------------
1833 * This procedure is called to recycle all the storage space
1834 * associated with a table of variables. For this procedure
1835 * to work correctly, it must not be possible for any of the
1836 * variable in the table to be accessed from Tcl commands
1837 * (e.g. from trace procedures).
1843 * Variables are deleted and trace procedures are invoked, if
1846 *----------------------------------------------------------------------
1851 Interp
*iPtr
, /* Interpreter to which variables belong. */
1852 Tcl_HashTable
*tablePtr
/* Hash table containing variables to
1856 Tcl_HashSearch search
;
1857 Tcl_HashEntry
*hPtr
;
1858 register Var
*varPtr
;
1859 int flags
, globalFlag
;
1861 flags
= TCL_TRACE_UNSETS
;
1862 if (tablePtr
== &iPtr
->globalTable
) {
1863 flags
|= TCL_INTERP_DESTROYED
| TCL_GLOBAL_ONLY
;
1865 for (hPtr
= Tcl_FirstHashEntry(tablePtr
, &search
); hPtr
!= NULL
;
1866 hPtr
= Tcl_NextHashEntry(&search
)) {
1867 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1870 * For global/upvar variables referenced in procedures, free up the
1871 * local space and then decrement the reference count on the
1872 * variable referred to. If there are no more references to the
1873 * global/upvar and it is undefined and has no traces set, then
1874 * follow on and delete the referenced variable too.
1878 if (varPtr
->flags
& VAR_UPVAR
) {
1879 hPtr
= varPtr
->value
.upvarPtr
;
1880 ckfree((char *) varPtr
);
1881 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1882 varPtr
->upvarUses
--;
1883 if ((varPtr
->upvarUses
!= 0) || !(varPtr
->flags
& VAR_UNDEFINED
)
1884 || (varPtr
->tracePtr
!= NULL
)) {
1887 globalFlag
= TCL_GLOBAL_ONLY
;
1891 * Invoke traces on the variable that is being deleted, then
1892 * free up the variable's space (no need to free the hash entry
1893 * here, unless we're dealing with a global variable: the
1894 * hash entries will be deleted automatically when the whole
1895 * table is deleted).
1898 if (varPtr
->tracePtr
!= NULL
) {
1899 (void) CallTraces(iPtr
, (Var
*) NULL
, hPtr
,
1900 Tcl_GetHashKey(tablePtr
, hPtr
), (char *) NULL
,
1901 flags
| globalFlag
);
1902 while (varPtr
->tracePtr
!= NULL
) {
1903 VarTrace
*tracePtr
= varPtr
->tracePtr
;
1904 varPtr
->tracePtr
= tracePtr
->nextPtr
;
1905 ckfree((char *) tracePtr
);
1908 if (varPtr
->flags
& VAR_ARRAY
) {
1909 DeleteArray(iPtr
, Tcl_GetHashKey(tablePtr
, hPtr
), varPtr
,
1910 flags
| globalFlag
);
1913 Tcl_DeleteHashEntry(hPtr
);
1915 ckfree((char *) varPtr
);
1917 Tcl_DeleteHashTable(tablePtr
);
1921 *----------------------------------------------------------------------
1925 * This procedure is invoked to find and invoke relevant
1926 * trace procedures associated with a particular operation on
1927 * a variable. This procedure invokes traces both on the
1928 * variable and on its containing array (where relevant).
1931 * The return value is NULL if no trace procedures were invoked, or
1932 * if all the invoked trace procedures returned successfully.
1933 * The return value is non-zero if a trace procedure returned an
1934 * error (in this case no more trace procedures were invoked after
1935 * the error was returned). In this case the return value is a
1936 * pointer to a static string describing the error.
1939 * Almost anything can happen, depending on trace; this procedure
1940 * itself doesn't have any side effects.
1942 *----------------------------------------------------------------------
1947 Interp
*iPtr
, /* Interpreter containing variable. */
1948 register Var
*arrayPtr
, /* Pointer to array variable that
1949 * contains the variable, or NULL if
1950 * the variable isn't an element of an
1952 Tcl_HashEntry
*hPtr
, /* Hash table entry corresponding to
1953 * variable whose traces are to be
1956 char *name2
, /* Variable's two-part name. */
1957 int flags
/* Flags to pass to trace procedures:
1958 * indicates what's happening to
1959 * variable, plus other stuff like
1960 * TCL_GLOBAL_ONLY and
1961 * TCL_INTERP_DESTROYED. */
1965 register VarTrace
*tracePtr
;
1966 ActiveVarTrace active
;
1968 int savedArrayFlags
= 0; /* (Initialization not needed except
1969 * to prevent compiler warning) */
1972 * If there are already similar trace procedures active for the
1973 * variable, don't call them again.
1976 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1977 if (varPtr
->flags
& VAR_TRACE_ACTIVE
) {
1980 varPtr
->flags
|= VAR_TRACE_ACTIVE
;
1983 * Invoke traces on the array containing the variable, if relevant.
1987 active
.nextPtr
= iPtr
->activeTracePtr
;
1988 iPtr
->activeTracePtr
= &active
;
1989 if (arrayPtr
!= NULL
) {
1990 savedArrayFlags
= arrayPtr
->flags
;
1991 arrayPtr
->flags
|= VAR_ELEMENT_ACTIVE
;
1992 for (tracePtr
= arrayPtr
->tracePtr
; tracePtr
!= NULL
;
1993 tracePtr
= active
.nextTracePtr
) {
1994 active
.nextTracePtr
= tracePtr
->nextPtr
;
1995 if (!(tracePtr
->flags
& flags
)) {
1998 result
= (*tracePtr
->traceProc
)(tracePtr
->clientData
,
1999 (Tcl_Interp
*) iPtr
, name1
, name2
, flags
);
2000 if (result
!= NULL
) {
2001 if (flags
& TCL_TRACE_UNSETS
) {
2011 * Invoke traces on the variable itself.
2014 if (flags
& TCL_TRACE_UNSETS
) {
2015 flags
|= TCL_TRACE_DESTROYED
;
2017 for (tracePtr
= varPtr
->tracePtr
; tracePtr
!= NULL
;
2018 tracePtr
= active
.nextTracePtr
) {
2019 active
.nextTracePtr
= tracePtr
->nextPtr
;
2020 if (!(tracePtr
->flags
& flags
)) {
2023 result
= (*tracePtr
->traceProc
)(tracePtr
->clientData
,
2024 (Tcl_Interp
*) iPtr
, name1
, name2
, flags
);
2025 if (result
!= NULL
) {
2026 if (flags
& TCL_TRACE_UNSETS
) {
2035 * Restore the variable's flags, remove the record of our active
2036 * traces, and then return. Remember that the variable could have
2037 * been re-allocated during the traces, but its hash entry won't
2042 if (arrayPtr
!= NULL
) {
2043 arrayPtr
->flags
= savedArrayFlags
;
2045 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
2046 varPtr
->flags
&= ~VAR_TRACE_ACTIVE
;
2047 iPtr
->activeTracePtr
= active
.nextPtr
;
2052 *----------------------------------------------------------------------
2056 * Create a new variable with a given initial value.
2059 * The return value is a pointer to the new variable structure.
2060 * The variable will not be part of any hash table yet, and its
2061 * upvarUses count is initialized to 0. Its initial value will
2062 * be empty, but "space" bytes will be available in the value
2066 * Storage gets allocated.
2068 *----------------------------------------------------------------------
2073 int space
/* Minimum amount of space to allocate
2074 * for variable's value. */
2078 register Var
*varPtr
;
2080 extra
= space
- sizeof(varPtr
->value
);
2083 space
= sizeof(varPtr
->value
);
2085 varPtr
= (Var
*) ckalloc((unsigned) (sizeof(Var
) + extra
));
2086 varPtr
->valueLength
= 0;
2087 varPtr
->valueSpace
= space
;
2088 varPtr
->upvarUses
= 0;
2089 varPtr
->tracePtr
= NULL
;
2090 varPtr
->searchPtr
= NULL
;
2092 varPtr
->value
.string
[0] = 0;
2097 *----------------------------------------------------------------------
2101 * This procedure translates from a string to a pointer to an
2102 * active array search (if there is one that matches the string).
2105 * The return value is a pointer to the array search indicated
2106 * by string, or NULL if there isn't one. If NULL is returned,
2107 * interp->result contains an error message.
2112 *----------------------------------------------------------------------
2115 static ArraySearch
*
2117 Tcl_Interp
*interp
, /* Interpreter containing variable. */
2118 Var
*varPtr
, /* Array variable search is for. */
2119 char *varName
, /* Name of array variable that search is
2120 * supposed to be for. */
2121 char *string
/* String containing id of search. Must have
2122 * form "search-num-var" where "num" is a
2123 * decimal number and "var" is a variable
2129 ArraySearch
*searchPtr
;
2132 * Parse the id into the three parts separated by dashes.
2135 if ((string
[0] != 's') || (string
[1] != '-')) {
2137 Tcl_AppendResult(interp
, "illegal search identifier \"", string
,
2138 "\"", (char *) NULL
);
2141 id
= strtoul(string
+2, &end
, 10);
2142 if ((end
== (string
+2)) || (*end
!= '-')) {
2145 if (strcmp(end
+1, varName
) != 0) {
2146 Tcl_AppendResult(interp
, "search identifier \"", string
,
2147 "\" isn't for variable \"", varName
, "\"", (char *) NULL
);
2152 * Search through the list of active searches on the interpreter
2153 * to see if the desired one exists.
2156 for (searchPtr
= varPtr
->searchPtr
; searchPtr
!= NULL
;
2157 searchPtr
= searchPtr
->nextPtr
) {
2158 if (searchPtr
->id
== id
) {
2162 Tcl_AppendResult(interp
, "couldn't find search \"", string
, "\"",
2168 *----------------------------------------------------------------------
2172 * This procedure is called to free up all of the searches
2173 * associated with an array variable.
2179 * Memory is released to the storage allocator.
2181 *----------------------------------------------------------------------
2186 register Var
*arrayVarPtr
/* Variable whose searches are
2190 ArraySearch
*searchPtr
;
2192 while (arrayVarPtr
->searchPtr
!= NULL
) {
2193 searchPtr
= arrayVarPtr
->searchPtr
;
2194 arrayVarPtr
->searchPtr
= searchPtr
->nextPtr
;
2195 ckfree((char *) searchPtr
);
2200 *----------------------------------------------------------------------
2204 * This procedure is called to free up everything in an array
2205 * variable. It's the caller's responsibility to make sure
2206 * that the array is no longer accessible before this procedure
2213 * All storage associated with varPtr's array elements is deleted
2214 * (including the hash table). Any delete trace procedures for
2215 * array elements are invoked.
2217 *----------------------------------------------------------------------
2222 Interp
*iPtr
, /* Interpreter containing array. */
2223 char *arrayName
, /* Name of array (used for trace
2225 Var
*varPtr
, /* Pointer to variable structure. */
2226 int flags
/* Flags to pass to CallTraces:
2227 * TCL_TRACE_UNSETS and sometimes
2228 * TCL_INTERP_DESTROYED and/or
2229 * TCL_GLOBAL_ONLY. */
2232 Tcl_HashSearch search
;
2233 register Tcl_HashEntry
*hPtr
;
2234 register Var
*elPtr
;
2236 DeleteSearches(varPtr
);
2237 for (hPtr
= Tcl_FirstHashEntry(varPtr
->value
.tablePtr
, &search
);
2238 hPtr
!= NULL
; hPtr
= Tcl_NextHashEntry(&search
)) {
2239 elPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
2240 if (elPtr
->tracePtr
!= NULL
) {
2241 (void) CallTraces(iPtr
, (Var
*) NULL
, hPtr
, arrayName
,
2242 Tcl_GetHashKey(varPtr
->value
.tablePtr
, hPtr
), flags
);
2243 while (elPtr
->tracePtr
!= NULL
) {
2244 VarTrace
*tracePtr
= elPtr
->tracePtr
;
2245 elPtr
->tracePtr
= tracePtr
->nextPtr
;
2246 ckfree((char *) tracePtr
);
2249 if (elPtr
->flags
& VAR_SEARCHES_POSSIBLE
) {
2250 panic("DeleteArray found searches on array alement!");
2252 ckfree((char *) elPtr
);
2254 Tcl_DeleteHashTable(varPtr
->value
.tablePtr
);
2255 ckfree((char *) varPtr
->value
.tablePtr
);
2259 *----------------------------------------------------------------------
2263 * Generate a reasonable error message describing why a variable
2270 * Interp->result is reset to hold a message identifying the
2271 * variable given by name1 and name2 and describing why the
2272 * variable operation failed.
2274 *----------------------------------------------------------------------
2279 Tcl_Interp
*interp
, /* Interpreter in which to record message. */
2281 char *name2
, /* Variable's two-part name. */
2282 char *operation
, /* String describing operation that failed,
2283 * e.g. "read", "set", or "unset". */
2284 char *reason
/* String describing why operation failed. */
2287 Tcl_ResetResult(interp
);
2288 Tcl_AppendResult(interp
, "can't ", operation
, " \"", name1
, (char *) NULL
);
2289 if (name2
!= NULL
) {
2290 Tcl_AppendResult(interp
, "(", name2
, ")", (char *) NULL
);
2292 Tcl_AppendResult(interp
, "\": ", reason
, (char *) NULL
);