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 *----------------------------------------------------------------------
79 Tcl_GetVar(interp
, varName
, flags
)
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. */
89 * If varName refers to an array (it ends with a parenthesized
90 * element name), then handle it specially.
93 for (p
= varName
; *p
!= '\0'; p
++) {
100 } while (*p
!= '\0');
107 result
= Tcl_GetVar2(interp
, varName
, open
+ 1, flags
);
111 strcmp("a", "b"); /* XXX SGI compiler optimizer bug */
118 return Tcl_GetVar2(interp
, varName
, (char *) NULL
, flags
);
122 *----------------------------------------------------------------------
126 * Return the value of a Tcl variable, given a two-part name
127 * consisting of array name and element within array.
130 * The return value points to the current value of the variable
131 * given by name1 and name2. If the specified variable doesn't
132 * exist, or if there is a clash in array usage, then NULL is
133 * returned and a message will be left in interp->result if the
134 * TCL_LEAVE_ERR_MSG flag is set. Note: the return value is
135 * only valid up until the next call to Tcl_SetVar or Tcl_SetVar2;
136 * if you depend on the value lasting longer than that, then make
137 * yourself a private copy.
142 *----------------------------------------------------------------------
146 Tcl_GetVar2(interp
, name1
, name2
, flags
)
147 Tcl_Interp
*interp
; /* Command interpreter in which variable is
148 * to be looked up. */
149 char *name1
; /* Name of array (if name2 is NULL) or
150 * name of variable. */
151 char *name2
; /* If non-null, gives name of element in
153 int flags
; /* OR-ed combination of TCL_GLOBAL_ONLY
154 * or TCL_LEAVE_ERR_MSG bits. */
158 Interp
*iPtr
= (Interp
*) interp
;
159 Var
*arrayPtr
= NULL
;
162 * Lookup the first name.
165 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
166 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, name1
);
168 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, name1
);
171 if (flags
& TCL_LEAVE_ERR_MSG
) {
172 VarErrMsg(interp
, name1
, name2
, "read", noSuchVar
);
176 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
177 if (varPtr
->flags
& VAR_UPVAR
) {
178 hPtr
= varPtr
->value
.upvarPtr
;
179 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
183 * If this is an array reference, then remember the traces on the array
184 * and lookup the element within the array.
188 if (varPtr
->flags
& VAR_UNDEFINED
) {
189 if (flags
& TCL_LEAVE_ERR_MSG
) {
190 VarErrMsg(interp
, name1
, name2
, "read", noSuchVar
);
193 } else if (!(varPtr
->flags
& VAR_ARRAY
)) {
194 if (flags
& TCL_LEAVE_ERR_MSG
) {
195 VarErrMsg(interp
, name1
, name2
, "read", needArray
);
200 hPtr
= Tcl_FindHashEntry(varPtr
->value
.tablePtr
, name2
);
202 if (flags
& TCL_LEAVE_ERR_MSG
) {
203 VarErrMsg(interp
, name1
, name2
, "read", noSuchElement
);
207 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
211 * Invoke any traces that have been set for the variable.
214 if ((varPtr
->tracePtr
!= NULL
)
215 || ((arrayPtr
!= NULL
) && (arrayPtr
->tracePtr
!= NULL
))) {
218 msg
= CallTraces(iPtr
, arrayPtr
, hPtr
, name1
, name2
,
219 (flags
& TCL_GLOBAL_ONLY
) | TCL_TRACE_READS
);
221 VarErrMsg(interp
, name1
, name2
, "read", msg
);
226 * Watch out! The variable could have gotten re-allocated to
227 * a larger size. Fortunately the hash table entry will still
231 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
233 if (varPtr
->flags
& (VAR_UNDEFINED
|VAR_UPVAR
|VAR_ARRAY
)) {
234 if (flags
& TCL_LEAVE_ERR_MSG
) {
235 VarErrMsg(interp
, name1
, name2
, "read", noSuchVar
);
239 return varPtr
->value
.string
;
243 *----------------------------------------------------------------------
247 * Change the value of a variable.
250 * Returns a pointer to the malloc'ed string holding the new
251 * value of the variable. The caller should not modify this
252 * string. If the write operation was disallowed then NULL
253 * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then
254 * an explanatory message will be left in interp->result.
257 * If varName is defined as a local or global variable in interp,
258 * its value is changed to newValue. If varName isn't currently
259 * defined, then a new global variable by that name is created.
261 *----------------------------------------------------------------------
265 Tcl_SetVar(interp
, varName
, newValue
, flags
)
266 Tcl_Interp
*interp
; /* Command interpreter in which varName is
267 * to be looked up. */
268 char *varName
; /* Name of a variable in interp. */
269 char *newValue
; /* New value for varName. */
270 int flags
; /* Various flags that tell how to set value:
271 * any of TCL_GLOBAL_ONLY, TCL_APPEND_VALUE,
272 * TCL_LIST_ELEMENT, TCL_NO_SPACE, or
273 * TCL_LEAVE_ERR_MSG. */
278 * If varName refers to an array (it ends with a parenthesized
279 * element name), then handle it specially.
282 for (p
= varName
; *p
!= '\0'; p
++) {
289 } while (*p
!= '\0');
296 result
= Tcl_SetVar2(interp
, varName
, open
+1, newValue
, flags
);
304 return Tcl_SetVar2(interp
, varName
, (char *) NULL
, newValue
, flags
);
308 *----------------------------------------------------------------------
312 * Given a two-part variable name, which may refer either to a
313 * scalar variable or an element of an array, change the value
314 * of the variable. If the named scalar or array or element
315 * doesn't exist then create one.
318 * Returns a pointer to the malloc'ed string holding the new
319 * value of the variable. The caller should not modify this
320 * string. If the write operation was disallowed because an
321 * array was expected but not found (or vice versa), then NULL
322 * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then
323 * an explanatory message will be left in interp->result.
326 * The value of the given variable is set. If either the array
327 * or the entry didn't exist then a new one is created.
329 *----------------------------------------------------------------------
333 Tcl_SetVar2(interp
, name1
, name2
, newValue
, flags
)
334 Tcl_Interp
*interp
; /* Command interpreter in which variable is
335 * to be looked up. */
336 char *name1
; /* If name2 is NULL, this is name of scalar
337 * variable. Otherwise it is name of array. */
338 char *name2
; /* Name of an element within array, or NULL. */
339 char *newValue
; /* New value for variable. */
340 int flags
; /* Various flags that tell how to set value:
341 * any of TCL_GLOBAL_ONLY, TCL_APPEND_VALUE,
342 * TCL_LIST_ELEMENT, and TCL_NO_SPACE, or
343 * TCL_LEAVE_ERR_MSG . */
346 register Var
*varPtr
= NULL
;
347 /* Initial value only used to stop compiler
348 * from complaining; not really needed. */
349 register Interp
*iPtr
= (Interp
*) interp
;
350 int length
, new, listFlags
;
351 Var
*arrayPtr
= NULL
;
354 * Lookup the first name.
357 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
358 hPtr
= Tcl_CreateHashEntry(&iPtr
->globalTable
, name1
, &new);
360 hPtr
= Tcl_CreateHashEntry(&iPtr
->varFramePtr
->varTable
,
364 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
365 if (varPtr
->flags
& VAR_UPVAR
) {
366 hPtr
= varPtr
->value
.upvarPtr
;
367 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
372 * If this is an array reference, then create a new array (if
373 * needed), remember any traces on the array, and lookup the
374 * element within the array.
380 Tcl_SetHashValue(hPtr
, varPtr
);
381 varPtr
->flags
= VAR_ARRAY
;
382 varPtr
->value
.tablePtr
= (Tcl_HashTable
*)
383 ckalloc(sizeof(Tcl_HashTable
));
384 Tcl_InitHashTable(varPtr
->value
.tablePtr
, TCL_STRING_KEYS
);
386 if (varPtr
->flags
& VAR_UNDEFINED
) {
387 varPtr
->flags
= VAR_ARRAY
;
388 varPtr
->value
.tablePtr
= (Tcl_HashTable
*)
389 ckalloc(sizeof(Tcl_HashTable
));
390 Tcl_InitHashTable(varPtr
->value
.tablePtr
, TCL_STRING_KEYS
);
391 } else if (!(varPtr
->flags
& VAR_ARRAY
)) {
392 if (flags
& TCL_LEAVE_ERR_MSG
) {
393 VarErrMsg(interp
, name1
, name2
, "set", needArray
);
399 hPtr
= Tcl_CreateHashEntry(varPtr
->value
.tablePtr
, name2
, &new);
403 * Compute how many bytes will be needed for newValue (leave space
404 * for a separating space between list elements).
407 if (flags
& TCL_LIST_ELEMENT
) {
408 length
= Tcl_ScanElement(newValue
, &listFlags
) + 1;
410 length
= strlen(newValue
);
414 * If the variable doesn't exist then create a new one. If it
415 * does exist then clear its current value unless this is an
420 varPtr
= NewVar(length
);
421 Tcl_SetHashValue(hPtr
, varPtr
);
422 if ((arrayPtr
!= NULL
) && (arrayPtr
->searchPtr
!= NULL
)) {
423 DeleteSearches(arrayPtr
);
426 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
427 if (varPtr
->flags
& VAR_ARRAY
) {
428 if (flags
& TCL_LEAVE_ERR_MSG
) {
429 VarErrMsg(interp
, name1
, name2
, "set", isArray
);
433 if (!(flags
& TCL_APPEND_VALUE
) || (varPtr
->flags
& VAR_UNDEFINED
)) {
434 varPtr
->valueLength
= 0;
439 * Make sure there's enough space to hold the variable's
440 * new value. If not, enlarge the variable's space.
443 if ((length
+ varPtr
->valueLength
) >= varPtr
->valueSpace
) {
447 newSize
= 2*varPtr
->valueSpace
;
448 if (newSize
<= (length
+ varPtr
->valueLength
)) {
451 newVarPtr
= NewVar(newSize
);
452 newVarPtr
->valueLength
= varPtr
->valueLength
;
453 newVarPtr
->upvarUses
= varPtr
->upvarUses
;
454 newVarPtr
->tracePtr
= varPtr
->tracePtr
;
455 strcpy(newVarPtr
->value
.string
, varPtr
->value
.string
);
456 Tcl_SetHashValue(hPtr
, newVarPtr
);
457 ckfree((char *) varPtr
);
462 * Append the new value to the variable, either as a list
463 * element or as a string.
466 if (flags
& TCL_LIST_ELEMENT
) {
467 if ((varPtr
->valueLength
> 0) && !(flags
& TCL_NO_SPACE
)) {
468 varPtr
->value
.string
[varPtr
->valueLength
] = ' ';
469 varPtr
->valueLength
++;
471 varPtr
->valueLength
+= Tcl_ConvertElement(newValue
,
472 varPtr
->value
.string
+ varPtr
->valueLength
, listFlags
);
473 varPtr
->value
.string
[varPtr
->valueLength
] = 0;
475 strcpy(varPtr
->value
.string
+ varPtr
->valueLength
, newValue
);
476 varPtr
->valueLength
+= length
;
478 varPtr
->flags
&= ~VAR_UNDEFINED
;
481 * Invoke any write traces for the variable.
484 if ((varPtr
->tracePtr
!= NULL
)
485 || ((arrayPtr
!= NULL
) && (arrayPtr
->tracePtr
!= NULL
))) {
488 msg
= CallTraces(iPtr
, arrayPtr
, hPtr
, name1
, name2
,
489 (flags
& TCL_GLOBAL_ONLY
) | TCL_TRACE_WRITES
);
491 VarErrMsg(interp
, name1
, name2
, "set", msg
);
496 * Watch out! The variable could have gotten re-allocated to
497 * a larger size. Fortunately the hash table entry will still
501 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
503 return varPtr
->value
.string
;
507 *----------------------------------------------------------------------
511 * Delete a variable, so that it may not be accessed anymore.
514 * Returns 0 if the variable was successfully deleted, -1
515 * if the variable can't be unset. In the event of an error,
516 * if the TCL_LEAVE_ERR_MSG flag is set then an error message
517 * is left in interp->result.
520 * If varName is defined as a local or global variable in interp,
523 *----------------------------------------------------------------------
527 Tcl_UnsetVar(interp
, varName
, flags
)
528 Tcl_Interp
*interp
; /* Command interpreter in which varName is
529 * to be looked up. */
530 char *varName
; /* Name of a variable in interp. May be
531 * either a scalar name or an array name
532 * or an element in an array. */
533 int flags
; /* OR-ed combination of any of
534 * TCL_GLOBAL_ONLY or TCL_LEAVE_ERR_MSG. */
540 * Figure out whether this is an array reference, then call
541 * Tcl_UnsetVar2 to do all the real work.
544 for (p
= varName
; *p
!= '\0'; p
++) {
550 } while (*p
!= '\0');
557 result
= Tcl_UnsetVar2(interp
, varName
, open
+1, flags
);
565 return Tcl_UnsetVar2(interp
, varName
, (char *) NULL
, flags
);
569 *----------------------------------------------------------------------
573 * Delete a variable, given a 2-part name.
576 * Returns 0 if the variable was successfully deleted, -1
577 * if the variable can't be unset. In the event of an error,
578 * if the TCL_LEAVE_ERR_MSG flag is set then an error message
579 * is left in interp->result.
582 * If name1 and name2 indicate a local or global variable in interp,
583 * it is deleted. If name1 is an array name and name2 is NULL, then
584 * the whole array is deleted.
586 *----------------------------------------------------------------------
590 Tcl_UnsetVar2(interp
, name1
, name2
, flags
)
591 Tcl_Interp
*interp
; /* Command interpreter in which varName is
592 * to be looked up. */
593 char *name1
; /* Name of variable or array. */
594 char *name2
; /* Name of element within array or NULL. */
595 int flags
; /* OR-ed combination of any of
596 * TCL_GLOBAL_ONLY or TCL_LEAVE_ERR_MSG. */
598 Tcl_HashEntry
*hPtr
, dummyEntry
;
599 Var
*varPtr
, dummyVar
;
600 Interp
*iPtr
= (Interp
*) interp
;
601 Var
*arrayPtr
= NULL
;
603 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
604 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, name1
);
606 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, name1
);
609 if (flags
& TCL_LEAVE_ERR_MSG
) {
610 VarErrMsg(interp
, name1
, name2
, "unset", noSuchVar
);
614 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
617 * For global variables referenced in procedures, leave the procedure's
618 * reference variable in place, but unset the global variable. Can't
619 * decrement the actual variable's use count, since we didn't delete
620 * the reference variable.
623 if (varPtr
->flags
& VAR_UPVAR
) {
624 hPtr
= varPtr
->value
.upvarPtr
;
625 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
629 * If the variable being deleted is an element of an array, then
630 * remember trace procedures on the overall array and find the
635 if (!(varPtr
->flags
& VAR_ARRAY
)) {
636 if (flags
& TCL_LEAVE_ERR_MSG
) {
637 VarErrMsg(interp
, name1
, name2
, "unset", needArray
);
641 if (varPtr
->searchPtr
!= NULL
) {
642 DeleteSearches(varPtr
);
645 hPtr
= Tcl_FindHashEntry(varPtr
->value
.tablePtr
, name2
);
647 if (flags
& TCL_LEAVE_ERR_MSG
) {
648 VarErrMsg(interp
, name1
, name2
, "unset", noSuchElement
);
652 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
656 * If there is a trace active on this variable or if the variable
657 * is already being deleted then don't delete the variable: it
658 * isn't safe, since there are procedures higher up on the stack
659 * that will use pointers to the variable. Also don't delete an
660 * array if there are traces active on any of its elements.
664 (VAR_TRACE_ACTIVE
|VAR_ELEMENT_ACTIVE
)) {
665 if (flags
& TCL_LEAVE_ERR_MSG
) {
666 VarErrMsg(interp
, name1
, name2
, "unset", traceActive
);
672 * The code below is tricky, because of the possibility that
673 * a trace procedure might try to access a variable being
674 * deleted. To handle this situation gracefully, copy the
675 * contents of the variable and its hash table entry to
676 * dummy variables, then clean up the actual variable so that
677 * it's been completely deleted before the traces are called.
678 * Then call the traces, and finally clean up the variable's
679 * storage using the dummy copies.
683 Tcl_SetHashValue(&dummyEntry
, &dummyVar
);
684 if (varPtr
->upvarUses
== 0) {
685 Tcl_DeleteHashEntry(hPtr
);
686 ckfree((char *) varPtr
);
688 varPtr
->flags
= VAR_UNDEFINED
;
689 varPtr
->tracePtr
= NULL
;
693 * Call trace procedures for the variable being deleted and delete
697 if ((dummyVar
.tracePtr
!= NULL
)
698 || ((arrayPtr
!= NULL
) && (arrayPtr
->tracePtr
!= NULL
))) {
699 (void) CallTraces(iPtr
, arrayPtr
, &dummyEntry
, name1
, name2
,
700 (flags
& TCL_GLOBAL_ONLY
) | TCL_TRACE_UNSETS
);
701 while (dummyVar
.tracePtr
!= NULL
) {
702 VarTrace
*tracePtr
= dummyVar
.tracePtr
;
703 dummyVar
.tracePtr
= tracePtr
->nextPtr
;
704 ckfree((char *) tracePtr
);
709 * If the variable is an array, delete all of its elements. This
710 * must be done after calling the traces on the array, above (that's
711 * the way traces are defined).
714 if (dummyVar
.flags
& VAR_ARRAY
) {
715 DeleteArray(iPtr
, name1
, &dummyVar
,
716 (flags
& TCL_GLOBAL_ONLY
) | TCL_TRACE_UNSETS
);
718 if (dummyVar
.flags
& VAR_UNDEFINED
) {
719 if (flags
& TCL_LEAVE_ERR_MSG
) {
720 VarErrMsg(interp
, name1
, name2
, "unset",
721 (name2
== NULL
) ? noSuchVar
: noSuchElement
);
729 *----------------------------------------------------------------------
733 * Arrange for reads and/or writes to a variable to cause a
734 * procedure to be invoked, which can monitor the operations
735 * and/or change their actions.
738 * A standard Tcl return value.
741 * A trace is set up on the variable given by varName, such that
742 * future references to the variable will be intermediated by
743 * proc. See the manual entry for complete details on the calling
746 *----------------------------------------------------------------------
750 Tcl_TraceVar(interp
, varName
, flags
, proc
, clientData
)
751 Tcl_Interp
*interp
; /* Interpreter in which variable is
753 char *varName
; /* Name of variable; may end with "(index)"
754 * to signify an array reference. */
755 int flags
; /* OR-ed collection of bits, including any
756 * of TCL_TRACE_READS, TCL_TRACE_WRITES,
757 * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
758 Tcl_VarTraceProc
*proc
; /* Procedure to call when specified ops are
759 * invoked upon varName. */
760 ClientData clientData
; /* Arbitrary argument to pass to proc. */
765 * If varName refers to an array (it ends with a parenthesized
766 * element name), then handle it specially.
769 for (p
= varName
; *p
!= '\0'; p
++) {
776 } while (*p
!= '\0');
783 result
= Tcl_TraceVar2(interp
, varName
, open
+1, flags
,
792 return Tcl_TraceVar2(interp
, varName
, (char *) NULL
, flags
,
797 *----------------------------------------------------------------------
801 * Arrange for reads and/or writes to a variable to cause a
802 * procedure to be invoked, which can monitor the operations
803 * and/or change their actions.
806 * A standard Tcl return value.
809 * A trace is set up on the variable given by name1 and name2, such
810 * that future references to the variable will be intermediated by
811 * proc. See the manual entry for complete details on the calling
814 *----------------------------------------------------------------------
818 Tcl_TraceVar2(interp
, name1
, name2
, flags
, proc
, clientData
)
819 Tcl_Interp
*interp
; /* Interpreter in which variable is
821 char *name1
; /* Name of scalar variable or array. */
822 char *name2
; /* Name of element within array; NULL means
823 * trace applies to scalar variable or array
825 int flags
; /* OR-ed collection of bits, including any
826 * of TCL_TRACE_READS, TCL_TRACE_WRITES,
827 * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
828 Tcl_VarTraceProc
*proc
; /* Procedure to call when specified ops are
829 * invoked upon varName. */
830 ClientData clientData
; /* Arbitrary argument to pass to proc. */
833 Var
*varPtr
= NULL
; /* Initial value only used to stop compiler
834 * from complaining; not really needed. */
835 Interp
*iPtr
= (Interp
*) interp
;
836 register VarTrace
*tracePtr
;
840 * Locate the variable, making a new (undefined) one if necessary.
843 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
844 hPtr
= Tcl_CreateHashEntry(&iPtr
->globalTable
, name1
, &new);
846 hPtr
= Tcl_CreateHashEntry(&iPtr
->varFramePtr
->varTable
, name1
, &new);
849 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
850 if (varPtr
->flags
& VAR_UPVAR
) {
851 hPtr
= varPtr
->value
.upvarPtr
;
852 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
857 * If the trace is to be on an array element, make sure that the
858 * variable is an array variable. If the variable doesn't exist
859 * then define it as an empty array. Then find the specific
866 Tcl_SetHashValue(hPtr
, varPtr
);
867 varPtr
->flags
= VAR_ARRAY
;
868 varPtr
->value
.tablePtr
= (Tcl_HashTable
*)
869 ckalloc(sizeof(Tcl_HashTable
));
870 Tcl_InitHashTable(varPtr
->value
.tablePtr
, TCL_STRING_KEYS
);
872 if (varPtr
->flags
& VAR_UNDEFINED
) {
873 varPtr
->flags
= VAR_ARRAY
;
874 varPtr
->value
.tablePtr
= (Tcl_HashTable
*)
875 ckalloc(sizeof(Tcl_HashTable
));
876 Tcl_InitHashTable(varPtr
->value
.tablePtr
, TCL_STRING_KEYS
);
877 } else if (!(varPtr
->flags
& VAR_ARRAY
)) {
878 iPtr
->result
= needArray
;
882 hPtr
= Tcl_CreateHashEntry(varPtr
->value
.tablePtr
, name2
, &new);
886 if ((name2
!= NULL
) && (varPtr
->searchPtr
!= NULL
)) {
887 DeleteSearches(varPtr
);
890 varPtr
->flags
= VAR_UNDEFINED
;
891 Tcl_SetHashValue(hPtr
, varPtr
);
893 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
897 * Set up trace information.
900 tracePtr
= (VarTrace
*) ckalloc(sizeof(VarTrace
));
901 tracePtr
->traceProc
= proc
;
902 tracePtr
->clientData
= clientData
;
903 tracePtr
->flags
= flags
&
904 (TCL_TRACE_READS
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
);
905 tracePtr
->nextPtr
= varPtr
->tracePtr
;
906 varPtr
->tracePtr
= tracePtr
;
911 *----------------------------------------------------------------------
915 * Remove a previously-created trace for a variable.
921 * If there exists a trace for the variable given by varName
922 * with the given flags, proc, and clientData, then that trace
925 *----------------------------------------------------------------------
929 Tcl_UntraceVar(interp
, varName
, flags
, proc
, clientData
)
930 Tcl_Interp
*interp
; /* Interpreter containing traced variable. */
931 char *varName
; /* Name of variable; may end with "(index)"
932 * to signify an array reference. */
933 int flags
; /* OR-ed collection of bits describing
934 * current trace, including any of
935 * TCL_TRACE_READS, TCL_TRACE_WRITES,
936 * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
937 Tcl_VarTraceProc
*proc
; /* Procedure assocated with trace. */
938 ClientData clientData
; /* Arbitrary argument to pass to proc. */
943 * If varName refers to an array (it ends with a parenthesized
944 * element name), then handle it specially.
947 for (p
= varName
; *p
!= '\0'; p
++) {
953 } while (*p
!= '\0');
960 Tcl_UntraceVar2(interp
, varName
, open
+1, flags
, proc
, clientData
);
968 Tcl_UntraceVar2(interp
, varName
, (char *) NULL
, flags
, proc
, clientData
);
972 *----------------------------------------------------------------------
976 * Remove a previously-created trace for a variable.
982 * If there exists a trace for the variable given by name1
983 * and name2 with the given flags, proc, and clientData, then
984 * that trace is removed.
986 *----------------------------------------------------------------------
990 Tcl_UntraceVar2(interp
, name1
, name2
, flags
, proc
, clientData
)
991 Tcl_Interp
*interp
; /* Interpreter containing traced variable. */
992 char *name1
; /* Name of variable or array. */
993 char *name2
; /* Name of element within array; NULL means
994 * trace applies to scalar variable or array
996 int flags
; /* OR-ed collection of bits describing
997 * current trace, including any of
998 * TCL_TRACE_READS, TCL_TRACE_WRITES,
999 * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
1000 Tcl_VarTraceProc
*proc
; /* Procedure assocated with trace. */
1001 ClientData clientData
; /* Arbitrary argument to pass to proc. */
1003 register VarTrace
*tracePtr
;
1006 Interp
*iPtr
= (Interp
*) interp
;
1007 Tcl_HashEntry
*hPtr
;
1008 ActiveVarTrace
*activePtr
;
1011 * First, lookup the variable.
1014 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
1015 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, name1
);
1017 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, name1
);
1022 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1023 if (varPtr
->flags
& VAR_UPVAR
) {
1024 hPtr
= varPtr
->value
.upvarPtr
;
1025 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1027 if (name2
!= NULL
) {
1028 if (!(varPtr
->flags
& VAR_ARRAY
)) {
1031 hPtr
= Tcl_FindHashEntry(varPtr
->value
.tablePtr
, name2
);
1035 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1038 flags
&= (TCL_TRACE_READS
| TCL_TRACE_WRITES
| TCL_TRACE_UNSETS
);
1039 for (tracePtr
= varPtr
->tracePtr
, prevPtr
= NULL
; ;
1040 prevPtr
= tracePtr
, tracePtr
= tracePtr
->nextPtr
) {
1041 if (tracePtr
== NULL
) {
1044 if ((tracePtr
->traceProc
== proc
) && (tracePtr
->flags
== flags
)
1045 && (tracePtr
->clientData
== clientData
)) {
1051 * The code below makes it possible to delete traces while traces
1052 * are active: it makes sure that the deleted trace won't be
1053 * processed by CallTraces.
1056 for (activePtr
= iPtr
->activeTracePtr
; activePtr
!= NULL
;
1057 activePtr
= activePtr
->nextPtr
) {
1058 if (activePtr
->nextTracePtr
== tracePtr
) {
1059 activePtr
->nextTracePtr
= tracePtr
->nextPtr
;
1062 if (prevPtr
== NULL
) {
1063 varPtr
->tracePtr
= tracePtr
->nextPtr
;
1065 prevPtr
->nextPtr
= tracePtr
->nextPtr
;
1067 ckfree((char *) tracePtr
);
1071 *----------------------------------------------------------------------
1073 * Tcl_VarTraceInfo --
1075 * Return the clientData value associated with a trace on a
1076 * variable. This procedure can also be used to step through
1077 * all of the traces on a particular variable that have the
1078 * same trace procedure.
1081 * The return value is the clientData value associated with
1082 * a trace on the given variable. Information will only be
1083 * returned for a trace with proc as trace procedure. If
1084 * the clientData argument is NULL then the first such trace is
1085 * returned; otherwise, the next relevant one after the one
1086 * given by clientData will be returned. If the variable
1087 * doesn't exist, or if there are no (more) traces for it,
1088 * then NULL is returned.
1093 *----------------------------------------------------------------------
1097 Tcl_VarTraceInfo(interp
, varName
, flags
, proc
, prevClientData
)
1098 Tcl_Interp
*interp
; /* Interpreter containing variable. */
1099 char *varName
; /* Name of variable; may end with "(index)"
1100 * to signify an array reference. */
1101 int flags
; /* 0 or TCL_GLOBAL_ONLY. */
1102 Tcl_VarTraceProc
*proc
; /* Procedure assocated with trace. */
1103 ClientData prevClientData
; /* If non-NULL, gives last value returned
1104 * by this procedure, so this call will
1105 * return the next trace after that one.
1106 * If NULL, this call will return the
1112 * If varName refers to an array (it ends with a parenthesized
1113 * element name), then handle it specially.
1116 for (p
= varName
; *p
!= '\0'; p
++) {
1123 } while (*p
!= '\0');
1130 result
= Tcl_VarTraceInfo2(interp
, varName
, open
+1, flags
, proc
,
1139 return Tcl_VarTraceInfo2(interp
, varName
, (char *) NULL
, flags
, proc
,
1144 *----------------------------------------------------------------------
1146 * Tcl_VarTraceInfo2 --
1148 * Same as Tcl_VarTraceInfo, except takes name in two pieces
1152 * Same as Tcl_VarTraceInfo.
1157 *----------------------------------------------------------------------
1161 Tcl_VarTraceInfo2(interp
, name1
, name2
, flags
, proc
, prevClientData
)
1162 Tcl_Interp
*interp
; /* Interpreter containing variable. */
1163 char *name1
; /* Name of variable or array. */
1164 char *name2
; /* Name of element within array; NULL means
1165 * trace applies to scalar variable or array
1167 int flags
; /* 0 or TCL_GLOBAL_ONLY. */
1168 Tcl_VarTraceProc
*proc
; /* Procedure assocated with trace. */
1169 ClientData prevClientData
; /* If non-NULL, gives last value returned
1170 * by this procedure, so this call will
1171 * return the next trace after that one.
1172 * If NULL, this call will return the
1175 register VarTrace
*tracePtr
;
1177 Interp
*iPtr
= (Interp
*) interp
;
1178 Tcl_HashEntry
*hPtr
;
1181 * First, lookup the variable.
1184 if ((flags
& TCL_GLOBAL_ONLY
) || (iPtr
->varFramePtr
== NULL
)) {
1185 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, name1
);
1187 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, name1
);
1192 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1193 if (varPtr
->flags
& VAR_UPVAR
) {
1194 hPtr
= varPtr
->value
.upvarPtr
;
1195 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1197 if (name2
!= NULL
) {
1198 if (!(varPtr
->flags
& VAR_ARRAY
)) {
1201 hPtr
= Tcl_FindHashEntry(varPtr
->value
.tablePtr
, name2
);
1205 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1209 * Find the relevant trace, if any, and return its clientData.
1212 tracePtr
= varPtr
->tracePtr
;
1213 if (prevClientData
!= NULL
) {
1214 for ( ; tracePtr
!= NULL
; tracePtr
= tracePtr
->nextPtr
) {
1215 if ((tracePtr
->clientData
== prevClientData
)
1216 && (tracePtr
->traceProc
== proc
)) {
1217 tracePtr
= tracePtr
->nextPtr
;
1222 for ( ; tracePtr
!= NULL
; tracePtr
= tracePtr
->nextPtr
) {
1223 if (tracePtr
->traceProc
== proc
) {
1224 return tracePtr
->clientData
;
1231 *----------------------------------------------------------------------
1235 * This procedure is invoked to process the "set" Tcl command.
1236 * See the user documentation for details on what it does.
1239 * A standard Tcl result value.
1242 * A variable's value may be changed.
1244 *----------------------------------------------------------------------
1249 Tcl_SetCmd(dummy
, interp
, argc
, argv
)
1250 ClientData dummy
; /* Not used. */
1251 register Tcl_Interp
*interp
; /* Current interpreter. */
1252 int argc
; /* Number of arguments. */
1253 char **argv
; /* Argument strings. */
1258 value
= Tcl_GetVar(interp
, argv
[1], TCL_LEAVE_ERR_MSG
);
1259 if (value
== NULL
) {
1262 interp
->result
= value
;
1264 } else if (argc
== 3) {
1267 result
= Tcl_SetVar(interp
, argv
[1], argv
[2], TCL_LEAVE_ERR_MSG
);
1268 if (result
== NULL
) {
1271 interp
->result
= result
;
1274 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1275 argv
[0], " varName ?newValue?\"", (char *) NULL
);
1281 *----------------------------------------------------------------------
1285 * This procedure is invoked to process the "unset" Tcl command.
1286 * See the user documentation for details on what it does.
1289 * A standard Tcl result value.
1292 * See the user documentation.
1294 *----------------------------------------------------------------------
1299 Tcl_UnsetCmd(dummy
, interp
, argc
, argv
)
1300 ClientData dummy
; /* Not used. */
1301 register Tcl_Interp
*interp
; /* Current interpreter. */
1302 int argc
; /* Number of arguments. */
1303 char **argv
; /* Argument strings. */
1308 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1309 argv
[0], " varName ?varName ...?\"", (char *) NULL
);
1312 for (i
= 1; i
< argc
; i
++) {
1313 if (Tcl_UnsetVar(interp
, argv
[i
], TCL_LEAVE_ERR_MSG
) != 0) {
1321 *----------------------------------------------------------------------
1325 * This procedure is invoked to process the "append" Tcl command.
1326 * See the user documentation for details on what it does.
1329 * A standard Tcl result value.
1332 * A variable's value may be changed.
1334 *----------------------------------------------------------------------
1339 Tcl_AppendCmd(dummy
, interp
, argc
, argv
)
1340 ClientData dummy
; /* Not used. */
1341 register Tcl_Interp
*interp
; /* Current interpreter. */
1342 int argc
; /* Number of arguments. */
1343 char **argv
; /* Argument strings. */
1346 char *result
= NULL
; /* (Initialization only needed to keep
1347 * the compiler from complaining) */
1350 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1351 argv
[0], " varName value ?value ...?\"", (char *) NULL
);
1355 for (i
= 2; i
< argc
; i
++) {
1356 result
= Tcl_SetVar(interp
, argv
[1], argv
[i
],
1357 TCL_APPEND_VALUE
|TCL_LEAVE_ERR_MSG
);
1358 if (result
== NULL
) {
1362 interp
->result
= result
;
1367 *----------------------------------------------------------------------
1371 * This procedure is invoked to process the "lappend" Tcl command.
1372 * See the user documentation for details on what it does.
1375 * A standard Tcl result value.
1378 * A variable's value may be changed.
1380 *----------------------------------------------------------------------
1385 Tcl_LappendCmd(dummy
, interp
, argc
, argv
)
1386 ClientData dummy
; /* Not used. */
1387 register Tcl_Interp
*interp
; /* Current interpreter. */
1388 int argc
; /* Number of arguments. */
1389 char **argv
; /* Argument strings. */
1392 char *result
= NULL
; /* (Initialization only needed to keep
1393 * the compiler from complaining) */
1396 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1397 argv
[0], " varName value ?value ...?\"", (char *) NULL
);
1401 for (i
= 2; i
< argc
; i
++) {
1402 result
= Tcl_SetVar(interp
, argv
[1], argv
[i
],
1403 TCL_APPEND_VALUE
|TCL_LIST_ELEMENT
|TCL_LEAVE_ERR_MSG
);
1404 if (result
== NULL
) {
1408 interp
->result
= result
;
1413 *----------------------------------------------------------------------
1417 * This procedure is invoked to process the "array" Tcl command.
1418 * See the user documentation for details on what it does.
1421 * A standard Tcl result value.
1424 * See the user documentation.
1426 *----------------------------------------------------------------------
1431 Tcl_ArrayCmd(dummy
, interp
, argc
, argv
)
1432 ClientData dummy
; /* Not used. */
1433 register Tcl_Interp
*interp
; /* Current interpreter. */
1434 int argc
; /* Number of arguments. */
1435 char **argv
; /* Argument strings. */
1440 Tcl_HashEntry
*hPtr
;
1441 Interp
*iPtr
= (Interp
*) interp
;
1444 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1445 argv
[0], " option arrayName ?arg ...?\"", (char *) NULL
);
1450 * Locate the array variable (and it better be an array).
1453 if (iPtr
->varFramePtr
== NULL
) {
1454 hPtr
= Tcl_FindHashEntry(&iPtr
->globalTable
, argv
[2]);
1456 hPtr
= Tcl_FindHashEntry(&iPtr
->varFramePtr
->varTable
, argv
[2]);
1460 Tcl_AppendResult(interp
, "\"", argv
[2], "\" isn't an array",
1464 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1465 if (varPtr
->flags
& VAR_UPVAR
) {
1466 varPtr
= (Var
*) Tcl_GetHashValue(varPtr
->value
.upvarPtr
);
1468 if (!(varPtr
->flags
& VAR_ARRAY
)) {
1473 * Dispatch based on the option.
1477 length
= strlen(argv
[1]);
1478 if ((c
== 'a') && (strncmp(argv
[1], "anymore", length
) == 0)) {
1479 ArraySearch
*searchPtr
;
1482 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1483 argv
[0], " anymore arrayName searchId\"", (char *) NULL
);
1486 searchPtr
= ParseSearchId(interp
, varPtr
, argv
[2], argv
[3]);
1487 if (searchPtr
== NULL
) {
1493 if (searchPtr
->nextEntry
!= NULL
) {
1494 varPtr2
= (Var
*) Tcl_GetHashValue(searchPtr
->nextEntry
);
1495 if (!(varPtr2
->flags
& VAR_UNDEFINED
)) {
1499 searchPtr
->nextEntry
= Tcl_NextHashEntry(&searchPtr
->search
);
1500 if (searchPtr
->nextEntry
== NULL
) {
1501 interp
->result
= "0";
1505 interp
->result
= "1";
1507 } else if ((c
== 'd') && (strncmp(argv
[1], "donesearch", length
) == 0)) {
1508 ArraySearch
*searchPtr
, *prevPtr
;
1511 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1512 argv
[0], " donesearch arrayName searchId\"", (char *) NULL
);
1515 searchPtr
= ParseSearchId(interp
, varPtr
, argv
[2], argv
[3]);
1516 if (searchPtr
== NULL
) {
1519 if (varPtr
->searchPtr
== searchPtr
) {
1520 varPtr
->searchPtr
= searchPtr
->nextPtr
;
1522 for (prevPtr
= varPtr
->searchPtr
; ; prevPtr
= prevPtr
->nextPtr
) {
1523 if (prevPtr
->nextPtr
== searchPtr
) {
1524 prevPtr
->nextPtr
= searchPtr
->nextPtr
;
1529 ckfree((char *) searchPtr
);
1530 } else if ((c
== 'n') && (strncmp(argv
[1], "names", length
) == 0)
1532 Tcl_HashSearch search
;
1536 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1537 argv
[0], " names arrayName\"", (char *) NULL
);
1540 for (hPtr
= Tcl_FirstHashEntry(varPtr
->value
.tablePtr
, &search
);
1541 hPtr
!= NULL
; hPtr
= Tcl_NextHashEntry(&search
)) {
1542 varPtr2
= (Var
*) Tcl_GetHashValue(hPtr
);
1543 if (varPtr2
->flags
& VAR_UNDEFINED
) {
1546 Tcl_AppendElement(interp
,
1547 Tcl_GetHashKey(varPtr
->value
.tablePtr
, hPtr
), 0);
1549 } else if ((c
== 'n') && (strncmp(argv
[1], "nextelement", length
) == 0)
1551 ArraySearch
*searchPtr
;
1552 Tcl_HashEntry
*hPtr
;
1555 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1556 argv
[0], " nextelement arrayName searchId\"",
1560 searchPtr
= ParseSearchId(interp
, varPtr
, argv
[2], argv
[3]);
1561 if (searchPtr
== NULL
) {
1567 hPtr
= searchPtr
->nextEntry
;
1569 hPtr
= Tcl_NextHashEntry(&searchPtr
->search
);
1574 searchPtr
->nextEntry
= NULL
;
1576 varPtr2
= (Var
*) Tcl_GetHashValue(hPtr
);
1577 if (!(varPtr2
->flags
& VAR_UNDEFINED
)) {
1581 interp
->result
= Tcl_GetHashKey(varPtr
->value
.tablePtr
, hPtr
);
1582 } else if ((c
== 's') && (strncmp(argv
[1], "size", length
) == 0)
1584 Tcl_HashSearch search
;
1589 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1590 argv
[0], " size arrayName\"", (char *) NULL
);
1594 for (hPtr
= Tcl_FirstHashEntry(varPtr
->value
.tablePtr
, &search
);
1595 hPtr
!= NULL
; hPtr
= Tcl_NextHashEntry(&search
)) {
1596 varPtr2
= (Var
*) Tcl_GetHashValue(hPtr
);
1597 if (varPtr2
->flags
& VAR_UNDEFINED
) {
1602 sprintf(interp
->result
, "%d", size
);
1603 } else if ((c
== 's') && (strncmp(argv
[1], "startsearch", length
) == 0)
1605 ArraySearch
*searchPtr
;
1608 Tcl_AppendResult(interp
, "wrong # args: should be \"",
1609 argv
[0], " startsearch arrayName\"", (char *) NULL
);
1612 searchPtr
= (ArraySearch
*) ckalloc(sizeof(ArraySearch
));
1613 if (varPtr
->searchPtr
== NULL
) {
1615 Tcl_AppendResult(interp
, "s-1-", argv
[2], (char *) NULL
);
1619 searchPtr
->id
= varPtr
->searchPtr
->id
+ 1;
1620 sprintf(string
, "%d", searchPtr
->id
);
1621 Tcl_AppendResult(interp
, "s-", string
, "-", argv
[2],
1624 searchPtr
->varPtr
= varPtr
;
1625 searchPtr
->nextEntry
= Tcl_FirstHashEntry(varPtr
->value
.tablePtr
,
1626 &searchPtr
->search
);
1627 searchPtr
->nextPtr
= varPtr
->searchPtr
;
1628 varPtr
->searchPtr
= searchPtr
;
1630 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
1631 "\": should be anymore, donesearch, names, nextelement, ",
1632 "size, or startsearch", (char *) NULL
);
1639 *----------------------------------------------------------------------
1643 * This procedure is invoked to process the "global" Tcl command.
1644 * See the user documentation for details on what it does.
1647 * A standard Tcl result value.
1650 * See the user documentation.
1652 *----------------------------------------------------------------------
1657 Tcl_GlobalCmd(dummy
, interp
, argc
, argv
)
1658 ClientData dummy
; /* Not used. */
1659 Tcl_Interp
*interp
; /* Current interpreter. */
1660 int argc
; /* Number of arguments. */
1661 char **argv
; /* Argument strings. */
1663 Var
*varPtr
, *gVarPtr
;
1664 register Interp
*iPtr
= (Interp
*) interp
;
1665 Tcl_HashEntry
*hPtr
, *hPtr2
;
1669 Tcl_AppendResult((Tcl_Interp
*) iPtr
, "wrong # args: should be \"",
1670 argv
[0], " varName ?varName ...?\"", (char *) NULL
);
1673 if (iPtr
->varFramePtr
== NULL
) {
1677 for (argc
--, argv
++; argc
> 0; argc
--, argv
++) {
1678 hPtr
= Tcl_CreateHashEntry(&iPtr
->globalTable
, *argv
, &new);
1680 gVarPtr
= NewVar(0);
1681 gVarPtr
->flags
|= VAR_UNDEFINED
;
1682 Tcl_SetHashValue(hPtr
, gVarPtr
);
1684 gVarPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1686 hPtr2
= Tcl_CreateHashEntry(&iPtr
->varFramePtr
->varTable
, *argv
, &new);
1689 varPtr
= (Var
*) Tcl_GetHashValue(hPtr2
);
1690 if (varPtr
->flags
& VAR_UPVAR
) {
1693 Tcl_AppendResult((Tcl_Interp
*) iPtr
, "variable \"", *argv
,
1694 "\" already exists", (char *) NULL
);
1699 varPtr
->flags
|= VAR_UPVAR
;
1700 varPtr
->value
.upvarPtr
= hPtr
;
1701 gVarPtr
->upvarUses
++;
1702 Tcl_SetHashValue(hPtr2
, varPtr
);
1708 *----------------------------------------------------------------------
1712 * This procedure is invoked to process the "upvar" Tcl command.
1713 * See the user documentation for details on what it does.
1716 * A standard Tcl result value.
1719 * See the user documentation.
1721 *----------------------------------------------------------------------
1726 Tcl_UpvarCmd(dummy
, interp
, argc
, argv
)
1727 ClientData dummy
; /* Not used. */
1728 Tcl_Interp
*interp
; /* Current interpreter. */
1729 int argc
; /* Number of arguments. */
1730 char **argv
; /* Argument strings. */
1732 register Interp
*iPtr
= (Interp
*) interp
;
1734 CallFrame
*framePtr
;
1736 Tcl_HashTable
*upVarTablePtr
;
1737 Tcl_HashEntry
*hPtr
, *hPtr2
;
1743 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
1744 " ?level? otherVar localVar ?otherVar localVar ...?\"",
1750 * Find the hash table containing the variable being referenced.
1753 result
= TclGetFrame(interp
, argv
[1], &framePtr
);
1759 if (framePtr
== NULL
) {
1760 upVarTablePtr
= &iPtr
->globalTable
;
1762 upVarTablePtr
= &framePtr
->varTable
;
1765 if ((argc
& 1) != 0) {
1770 * Iterate over all the pairs of (local variable, other variable)
1771 * names. For each pair, create a hash table entry in the upper
1772 * context (if the name wasn't there already), then associate it
1773 * with a new local variable.
1777 hPtr
= Tcl_CreateHashEntry(upVarTablePtr
, argv
[0], &new);
1779 upVarPtr
= NewVar(0);
1780 upVarPtr
->flags
|= VAR_UNDEFINED
;
1781 Tcl_SetHashValue(hPtr
, upVarPtr
);
1783 upVarPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1784 if (upVarPtr
->flags
& VAR_UPVAR
) {
1785 hPtr
= upVarPtr
->value
.upvarPtr
;
1786 upVarPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1790 hPtr2
= Tcl_CreateHashEntry(&iPtr
->varFramePtr
->varTable
,
1793 Tcl_AppendResult((Tcl_Interp
*) iPtr
, "variable \"", argv
[1],
1794 "\" already exists", (char *) NULL
);
1798 varPtr
->flags
|= VAR_UPVAR
;
1799 varPtr
->value
.upvarPtr
= hPtr
;
1800 upVarPtr
->upvarUses
++;
1801 Tcl_SetHashValue(hPtr2
, varPtr
);
1810 *----------------------------------------------------------------------
1814 * This procedure is called to recycle all the storage space
1815 * associated with a table of variables. For this procedure
1816 * to work correctly, it must not be possible for any of the
1817 * variable in the table to be accessed from Tcl commands
1818 * (e.g. from trace procedures).
1824 * Variables are deleted and trace procedures are invoked, if
1827 *----------------------------------------------------------------------
1831 TclDeleteVars(iPtr
, tablePtr
)
1832 Interp
*iPtr
; /* Interpreter to which variables belong. */
1833 Tcl_HashTable
*tablePtr
; /* Hash table containing variables to
1836 Tcl_HashSearch search
;
1837 Tcl_HashEntry
*hPtr
;
1838 register Var
*varPtr
;
1839 int flags
, globalFlag
;
1841 flags
= TCL_TRACE_UNSETS
;
1842 if (tablePtr
== &iPtr
->globalTable
) {
1843 flags
|= TCL_INTERP_DESTROYED
| TCL_GLOBAL_ONLY
;
1845 for (hPtr
= Tcl_FirstHashEntry(tablePtr
, &search
); hPtr
!= NULL
;
1846 hPtr
= Tcl_NextHashEntry(&search
)) {
1847 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1850 * For global/upvar variables referenced in procedures, free up the
1851 * local space and then decrement the reference count on the
1852 * variable referred to. If there are no more references to the
1853 * global/upvar and it is undefined and has no traces set, then
1854 * follow on and delete the referenced variable too.
1858 if (varPtr
->flags
& VAR_UPVAR
) {
1859 hPtr
= varPtr
->value
.upvarPtr
;
1860 ckfree((char *) varPtr
);
1861 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1862 varPtr
->upvarUses
--;
1863 if ((varPtr
->upvarUses
!= 0) || !(varPtr
->flags
& VAR_UNDEFINED
)
1864 || (varPtr
->tracePtr
!= NULL
)) {
1867 globalFlag
= TCL_GLOBAL_ONLY
;
1871 * Invoke traces on the variable that is being deleted, then
1872 * free up the variable's space (no need to free the hash entry
1873 * here, unless we're dealing with a global variable: the
1874 * hash entries will be deleted automatically when the whole
1875 * table is deleted).
1878 if (varPtr
->tracePtr
!= NULL
) {
1879 (void) CallTraces(iPtr
, (Var
*) NULL
, hPtr
,
1880 Tcl_GetHashKey(tablePtr
, hPtr
), (char *) NULL
,
1881 flags
| globalFlag
);
1882 while (varPtr
->tracePtr
!= NULL
) {
1883 VarTrace
*tracePtr
= varPtr
->tracePtr
;
1884 varPtr
->tracePtr
= tracePtr
->nextPtr
;
1885 ckfree((char *) tracePtr
);
1888 if (varPtr
->flags
& VAR_ARRAY
) {
1889 DeleteArray(iPtr
, Tcl_GetHashKey(tablePtr
, hPtr
), varPtr
,
1890 flags
| globalFlag
);
1893 Tcl_DeleteHashEntry(hPtr
);
1895 ckfree((char *) varPtr
);
1897 Tcl_DeleteHashTable(tablePtr
);
1901 *----------------------------------------------------------------------
1905 * This procedure is invoked to find and invoke relevant
1906 * trace procedures associated with a particular operation on
1907 * a variable. This procedure invokes traces both on the
1908 * variable and on its containing array (where relevant).
1911 * The return value is NULL if no trace procedures were invoked, or
1912 * if all the invoked trace procedures returned successfully.
1913 * The return value is non-zero if a trace procedure returned an
1914 * error (in this case no more trace procedures were invoked after
1915 * the error was returned). In this case the return value is a
1916 * pointer to a static string describing the error.
1919 * Almost anything can happen, depending on trace; this procedure
1920 * itself doesn't have any side effects.
1922 *----------------------------------------------------------------------
1926 CallTraces(iPtr
, arrayPtr
, hPtr
, name1
, name2
, flags
)
1927 Interp
*iPtr
; /* Interpreter containing variable. */
1928 register Var
*arrayPtr
; /* Pointer to array variable that
1929 * contains the variable, or NULL if
1930 * the variable isn't an element of an
1932 Tcl_HashEntry
*hPtr
; /* Hash table entry corresponding to
1933 * variable whose traces are to be
1935 char *name1
, *name2
; /* Variable's two-part name. */
1936 int flags
; /* Flags to pass to trace procedures:
1937 * indicates what's happening to
1938 * variable, plus other stuff like
1939 * TCL_GLOBAL_ONLY and
1940 * TCL_INTERP_DESTROYED. */
1943 register VarTrace
*tracePtr
;
1944 ActiveVarTrace active
;
1946 int savedArrayFlags
= 0; /* (Initialization not needed except
1947 * to prevent compiler warning) */
1950 * If there are already similar trace procedures active for the
1951 * variable, don't call them again.
1954 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
1955 if (varPtr
->flags
& VAR_TRACE_ACTIVE
) {
1958 varPtr
->flags
|= VAR_TRACE_ACTIVE
;
1961 * Invoke traces on the array containing the variable, if relevant.
1965 active
.nextPtr
= iPtr
->activeTracePtr
;
1966 iPtr
->activeTracePtr
= &active
;
1967 if (arrayPtr
!= NULL
) {
1968 savedArrayFlags
= arrayPtr
->flags
;
1969 arrayPtr
->flags
|= VAR_ELEMENT_ACTIVE
;
1970 for (tracePtr
= arrayPtr
->tracePtr
; tracePtr
!= NULL
;
1971 tracePtr
= active
.nextTracePtr
) {
1972 active
.nextTracePtr
= tracePtr
->nextPtr
;
1973 if (!(tracePtr
->flags
& flags
)) {
1976 result
= (*tracePtr
->traceProc
)(tracePtr
->clientData
,
1977 (Tcl_Interp
*) iPtr
, name1
, name2
, flags
);
1978 if (result
!= NULL
) {
1979 if (flags
& TCL_TRACE_UNSETS
) {
1989 * Invoke traces on the variable itself.
1992 if (flags
& TCL_TRACE_UNSETS
) {
1993 flags
|= TCL_TRACE_DESTROYED
;
1995 for (tracePtr
= varPtr
->tracePtr
; tracePtr
!= NULL
;
1996 tracePtr
= active
.nextTracePtr
) {
1997 active
.nextTracePtr
= tracePtr
->nextPtr
;
1998 if (!(tracePtr
->flags
& flags
)) {
2001 result
= (*tracePtr
->traceProc
)(tracePtr
->clientData
,
2002 (Tcl_Interp
*) iPtr
, name1
, name2
, flags
);
2003 if (result
!= NULL
) {
2004 if (flags
& TCL_TRACE_UNSETS
) {
2013 * Restore the variable's flags, remove the record of our active
2014 * traces, and then return. Remember that the variable could have
2015 * been re-allocated during the traces, but its hash entry won't
2020 if (arrayPtr
!= NULL
) {
2021 arrayPtr
->flags
= savedArrayFlags
;
2023 varPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
2024 varPtr
->flags
&= ~VAR_TRACE_ACTIVE
;
2025 iPtr
->activeTracePtr
= active
.nextPtr
;
2030 *----------------------------------------------------------------------
2034 * Create a new variable with a given initial value.
2037 * The return value is a pointer to the new variable structure.
2038 * The variable will not be part of any hash table yet, and its
2039 * upvarUses count is initialized to 0. Its initial value will
2040 * be empty, but "space" bytes will be available in the value
2044 * Storage gets allocated.
2046 *----------------------------------------------------------------------
2051 int space
; /* Minimum amount of space to allocate
2052 * for variable's value. */
2055 register Var
*varPtr
;
2057 extra
= space
- sizeof(varPtr
->value
);
2060 space
= sizeof(varPtr
->value
);
2062 varPtr
= (Var
*) ckalloc((unsigned) (sizeof(Var
) + extra
));
2063 varPtr
->valueLength
= 0;
2064 varPtr
->valueSpace
= space
;
2065 varPtr
->upvarUses
= 0;
2066 varPtr
->tracePtr
= NULL
;
2067 varPtr
->searchPtr
= NULL
;
2069 varPtr
->value
.string
[0] = 0;
2074 *----------------------------------------------------------------------
2078 * This procedure translates from a string to a pointer to an
2079 * active array search (if there is one that matches the string).
2082 * The return value is a pointer to the array search indicated
2083 * by string, or NULL if there isn't one. If NULL is returned,
2084 * interp->result contains an error message.
2089 *----------------------------------------------------------------------
2092 static ArraySearch
*
2093 ParseSearchId(interp
, varPtr
, varName
, string
)
2094 Tcl_Interp
*interp
; /* Interpreter containing variable. */
2095 Var
*varPtr
; /* Array variable search is for. */
2096 char *varName
; /* Name of array variable that search is
2097 * supposed to be for. */
2098 char *string
; /* String containing id of search. Must have
2099 * form "search-num-var" where "num" is a
2100 * decimal number and "var" is a variable
2105 ArraySearch
*searchPtr
;
2108 * Parse the id into the three parts separated by dashes.
2111 if ((string
[0] != 's') || (string
[1] != '-')) {
2113 Tcl_AppendResult(interp
, "illegal search identifier \"", string
,
2114 "\"", (char *) NULL
);
2117 id
= strtoul(string
+2, &end
, 10);
2118 if ((end
== (string
+2)) || (*end
!= '-')) {
2121 if (strcmp(end
+1, varName
) != 0) {
2122 Tcl_AppendResult(interp
, "search identifier \"", string
,
2123 "\" isn't for variable \"", varName
, "\"", (char *) NULL
);
2128 * Search through the list of active searches on the interpreter
2129 * to see if the desired one exists.
2132 for (searchPtr
= varPtr
->searchPtr
; searchPtr
!= NULL
;
2133 searchPtr
= searchPtr
->nextPtr
) {
2134 if (searchPtr
->id
== id
) {
2138 Tcl_AppendResult(interp
, "couldn't find search \"", string
, "\"",
2144 *----------------------------------------------------------------------
2148 * This procedure is called to free up all of the searches
2149 * associated with an array variable.
2155 * Memory is released to the storage allocator.
2157 *----------------------------------------------------------------------
2161 DeleteSearches(arrayVarPtr
)
2162 register Var
*arrayVarPtr
; /* Variable whose searches are
2165 ArraySearch
*searchPtr
;
2167 while (arrayVarPtr
->searchPtr
!= NULL
) {
2168 searchPtr
= arrayVarPtr
->searchPtr
;
2169 arrayVarPtr
->searchPtr
= searchPtr
->nextPtr
;
2170 ckfree((char *) searchPtr
);
2175 *----------------------------------------------------------------------
2179 * This procedure is called to free up everything in an array
2180 * variable. It's the caller's responsibility to make sure
2181 * that the array is no longer accessible before this procedure
2188 * All storage associated with varPtr's array elements is deleted
2189 * (including the hash table). Any delete trace procedures for
2190 * array elements are invoked.
2192 *----------------------------------------------------------------------
2196 DeleteArray(iPtr
, arrayName
, varPtr
, flags
)
2197 Interp
*iPtr
; /* Interpreter containing array. */
2198 char *arrayName
; /* Name of array (used for trace
2200 Var
*varPtr
; /* Pointer to variable structure. */
2201 int flags
; /* Flags to pass to CallTraces:
2202 * TCL_TRACE_UNSETS and sometimes
2203 * TCL_INTERP_DESTROYED and/or
2204 * TCL_GLOBAL_ONLY. */
2206 Tcl_HashSearch search
;
2207 register Tcl_HashEntry
*hPtr
;
2208 register Var
*elPtr
;
2210 DeleteSearches(varPtr
);
2211 for (hPtr
= Tcl_FirstHashEntry(varPtr
->value
.tablePtr
, &search
);
2212 hPtr
!= NULL
; hPtr
= Tcl_NextHashEntry(&search
)) {
2213 elPtr
= (Var
*) Tcl_GetHashValue(hPtr
);
2214 if (elPtr
->tracePtr
!= NULL
) {
2215 (void) CallTraces(iPtr
, (Var
*) NULL
, hPtr
, arrayName
,
2216 Tcl_GetHashKey(varPtr
->value
.tablePtr
, hPtr
), flags
);
2217 while (elPtr
->tracePtr
!= NULL
) {
2218 VarTrace
*tracePtr
= elPtr
->tracePtr
;
2219 elPtr
->tracePtr
= tracePtr
->nextPtr
;
2220 ckfree((char *) tracePtr
);
2223 if (elPtr
->flags
& VAR_SEARCHES_POSSIBLE
) {
2224 panic("DeleteArray found searches on array alement!");
2226 ckfree((char *) elPtr
);
2228 Tcl_DeleteHashTable(varPtr
->value
.tablePtr
);
2229 ckfree((char *) varPtr
->value
.tablePtr
);
2233 *----------------------------------------------------------------------
2237 * Generate a reasonable error message describing why a variable
2244 * Interp->result is reset to hold a message identifying the
2245 * variable given by name1 and name2 and describing why the
2246 * variable operation failed.
2248 *----------------------------------------------------------------------
2252 VarErrMsg(interp
, name1
, name2
, operation
, reason
)
2253 Tcl_Interp
*interp
; /* Interpreter in which to record message. */
2254 char *name1
, *name2
; /* Variable's two-part name. */
2255 char *operation
; /* String describing operation that failed,
2256 * e.g. "read", "set", or "unset". */
2257 char *reason
; /* String describing why operation failed. */
2259 Tcl_ResetResult(interp
);
2260 Tcl_AppendResult(interp
, "can't ", operation
, " \"", name1
, (char *) NULL
);
2261 if (name2
!= NULL
) {
2262 Tcl_AppendResult(interp
, "(", name2
, ")", (char *) NULL
);
2264 Tcl_AppendResult(interp
, "\": ", reason
, (char *) NULL
);