OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [generic/] [tclVar.c] - Blame information for rev 1767

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclVar.c --
3
 *
4
 *      This file contains routines that implement Tcl variables
5
 *      (both scalars and arrays).
6
 *
7
 *      The implementation of arrays is modelled after an initial
8
 *      implementation by Mark Diekhans and Karl Lehenbauer.
9
 *
10
 * Copyright (c) 1987-1994 The Regents of the University of California.
11
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
12
 *
13
 * See the file "license.terms" for information on usage and redistribution
14
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15
 *
16
 * RCS: @(#) $Id: tclVar.c,v 1.1.1.1 2002-01-16 10:25:29 markom Exp $
17
 */
18
 
19
#include "tclInt.h"
20
#include "tclPort.h"
21
 
22
/*
23
 * The strings below are used to indicate what went wrong when a
24
 * variable access is denied.
25
 */
26
 
27
static char *noSuchVar =        "no such variable";
28
static char *isArray =          "variable is array";
29
static char *needArray =        "variable isn't array";
30
static char *noSuchElement =    "no such element in array";
31
static char *danglingUpvar =    "upvar refers to element in deleted array";
32
static char *badNamespace =     "parent namespace doesn't exist";
33
static char *missingName =      "missing variable name";
34
 
35
/*
36
 * Forward references to procedures defined later in this file:
37
 */
38
 
39
static  char *          CallTraces _ANSI_ARGS_((Interp *iPtr, Var *arrayPtr,
40
                            Var *varPtr, char *part1, char *part2,
41
                            int flags));
42
static void             CleanupVar _ANSI_ARGS_((Var *varPtr,
43
                            Var *arrayPtr));
44
static void             DeleteSearches _ANSI_ARGS_((Var *arrayVarPtr));
45
static void             DeleteArray _ANSI_ARGS_((Interp *iPtr,
46
                            char *arrayName, Var *varPtr, int flags));
47
static int              MakeUpvar _ANSI_ARGS_((
48
                            Interp *iPtr, CallFrame *framePtr,
49
                            char *otherP1, char *otherP2, int otherFlags,
50
                            char *myName, int myFlags));
51
static Var *            NewVar _ANSI_ARGS_((void));
52
static ArraySearch *    ParseSearchId _ANSI_ARGS_((Tcl_Interp *interp,
53
                            Var *varPtr, char *varName, char *string));
54
static void             VarErrMsg _ANSI_ARGS_((Tcl_Interp *interp,
55
                            char *part1, char *part2, char *operation,
56
                            char *reason));
57
 
58
/*
59
 *----------------------------------------------------------------------
60
 *
61
 * TclLookupVar --
62
 *
63
 *      This procedure is used by virtually all of the variable code to
64
 *      locate a variable given its name(s).
65
 *
66
 * Results:
67
 *      The return value is a pointer to the variable structure indicated by
68
 *      part1 and part2, or NULL if the variable couldn't be found. If the
69
 *      variable is found, *arrayPtrPtr is filled in with the address of the
70
 *      variable structure for the array that contains the variable (or NULL
71
 *      if the variable is a scalar). If the variable can't be found and
72
 *      either createPart1 or createPart2 are 1, a new as-yet-undefined
73
 *      (VAR_UNDEFINED) variable structure is created, entered into a hash
74
 *      table, and returned.
75
 *
76
 *      If the variable isn't found and creation wasn't specified, or some
77
 *      other error occurs, NULL is returned and an error message is left in
78
 *      interp->result if TCL_LEAVE_ERR_MSG is set in flags. (The result
79
 *      isn't put in interp->objResultPtr because this procedure is used
80
 *      by so many string-based routines.)
81
 *
82
 *      Note: it's possible for the variable returned to be VAR_UNDEFINED
83
 *      even if createPart1 or createPart2 are 1 (these only cause the hash
84
 *      table entry or array to be created). For example, the variable might
85
 *      be a global that has been unset but is still referenced by a
86
 *      procedure, or a variable that has been unset but it only being kept
87
 *      in existence (if VAR_UNDEFINED) by a trace.
88
 *
89
 * Side effects:
90
 *      New hashtable entries may be created if createPart1 or createPart2
91
 *      are 1.
92
 *
93
 *----------------------------------------------------------------------
94
 */
95
 
96
Var *
97
TclLookupVar(interp, part1, part2, flags, msg, createPart1, createPart2,
98
        arrayPtrPtr)
99
    Tcl_Interp *interp;         /* Interpreter to use for lookup. */
100
    char *part1;                /* If part2 isn't NULL, this is the name of
101
                                 * an array. Otherwise, if the
102
                                 * TCL_PARSE_PART1 flag bit is set this
103
                                 * is a full variable name that could
104
                                 * include a parenthesized array elemnt. If
105
                                 * TCL_PARSE_PART1 isn't present, then
106
                                 * this is the name of a scalar variable. */
107
    char *part2;                /* Name of element within array, or NULL. */
108
    int flags;                  /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
109
                                 * TCL_LEAVE_ERR_MSG, and
110
                                 * TCL_PARSE_PART1 bits matter. */
111
    char *msg;                  /* Verb to use in error messages, e.g.
112
                                 * "read" or "set". Only needed if
113
                                 * TCL_LEAVE_ERR_MSG is set in flags. */
114
    int createPart1;            /* If 1, create hash table entry for part 1
115
                                 * of name, if it doesn't already exist. If
116
                                 * 0, return error if it doesn't exist. */
117
    int createPart2;            /* If 1, create hash table entry for part 2
118
                                 * of name, if it doesn't already exist. If
119
                                 * 0, return error if it doesn't exist. */
120
    Var **arrayPtrPtr;          /* If the name refers to an element of an
121
                                 * array, *arrayPtrPtr gets filled in with
122
                                 * address of array variable. Otherwise
123
                                 * this is set to NULL. */
124
{
125
    Interp *iPtr = (Interp *) interp;
126
    CallFrame *varFramePtr = iPtr->varFramePtr;
127
                                /* Points to the procedure call frame whose
128
                                 * variables are currently in use. Same as
129
                                 * the current procedure's frame, if any,
130
                                 * unless an "uplevel" is executing. */
131
    Tcl_HashTable *tablePtr;    /* Points to the hashtable, if any, in which
132
                                 * to look up the variable. */
133
    Tcl_Var var;                /* Used to search for global names. */
134
    Var *varPtr;                /* Points to the Var structure returned for
135
                                 * the variable. */
136
    char *elName;               /* Name of array element or NULL; may be
137
                                 * same as part2, or may be openParen+1. */
138
    char *openParen, *closeParen;
139
                                /* If this procedure parses a name into
140
                                 * array and index, these point to the
141
                                 * parens around the index.  Otherwise they
142
                                 * are NULL. These are needed to restore
143
                                 * the parens after parsing the name. */
144
    Namespace *varNsPtr, *cxtNsPtr, *dummy1Ptr, *dummy2Ptr;
145
    ResolverScheme *resPtr;
146
    Tcl_HashEntry *hPtr;
147
    register char *p;
148
    int new, i, result;
149
 
150
    varPtr = NULL;
151
    *arrayPtrPtr = NULL;
152
    openParen = closeParen = NULL;
153
    varNsPtr = NULL;            /* set non-NULL if a nonlocal variable */
154
 
155
    /*
156
     * If the name hasn't been parsed into array name and index yet,
157
     * do it now.
158
     */
159
 
160
    elName = part2;
161
    if (flags & TCL_PARSE_PART1) {
162
        for (p = part1; ; p++) {
163
            if (*p == 0) {
164
                elName = NULL;
165
                break;
166
            }
167
            if (*p == '(') {
168
                openParen = p;
169
                do {
170
                    p++;
171
                } while (*p != '\0');
172
                p--;
173
                if (*p == ')') {
174
                    closeParen = p;
175
                    *openParen = 0;
176
                    elName = openParen+1;
177
                } else {
178
                    openParen = NULL;
179
                    elName = NULL;
180
                }
181
                break;
182
            }
183
        }
184
    }
185
 
186
    /*
187
     * If this namespace has a variable resolver, then give it first
188
     * crack at the variable resolution.  It may return a Tcl_Var
189
     * value, it may signal to continue onward, or it may signal
190
     * an error.
191
     */
192
    if ((flags & TCL_GLOBAL_ONLY) != 0 || iPtr->varFramePtr == NULL) {
193
        cxtNsPtr = iPtr->globalNsPtr;
194
    }
195
    else {
196
        cxtNsPtr = iPtr->varFramePtr->nsPtr;
197
    }
198
 
199
    if (cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) {
200
        resPtr = iPtr->resolverPtr;
201
 
202
        if (cxtNsPtr->varResProc) {
203
            result = (*cxtNsPtr->varResProc)(interp, part1,
204
                (Tcl_Namespace *) cxtNsPtr, flags, &var);
205
        } else {
206
            result = TCL_CONTINUE;
207
        }
208
 
209
        while (result == TCL_CONTINUE && resPtr) {
210
            if (resPtr->varResProc) {
211
                result = (*resPtr->varResProc)(interp, part1,
212
                    (Tcl_Namespace *) cxtNsPtr, flags, &var);
213
            }
214
            resPtr = resPtr->nextPtr;
215
        }
216
 
217
        if (result == TCL_OK) {
218
            varPtr = (Var *) var;
219
            goto lookupVarPart2;
220
        }
221
        else if (result != TCL_CONTINUE) {
222
            return (Var *) NULL;
223
        }
224
    }
225
 
226
    /*
227
     * Look up part1. Look it up as either a namespace variable or as a
228
     * local variable in a procedure call frame (varFramePtr).
229
     * Interpret part1 as a namespace variable if:
230
     *    1) so requested by a TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY flag,
231
     *    2) there is no active frame (we're at the global :: scope),
232
     *    3) the active frame was pushed to define the namespace context
233
     *       for a "namespace eval" or "namespace inscope" command,
234
     *    4) the name has namespace qualifiers ("::"s).
235
     * Otherwise, if part1 is a local variable, search first in the
236
     * frame's array of compiler-allocated local variables, then in its
237
     * hashtable for runtime-created local variables.
238
     *
239
     * If createPart1 and the variable isn't found, create the variable and,
240
     * if necessary, create varFramePtr's local var hashtable.
241
     */
242
 
243
    if (((flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) != 0)
244
                || (varFramePtr == NULL)
245
                || !varFramePtr->isProcCallFrame
246
                || (strstr(part1, "::") != NULL)) {
247
        char *tail;
248
 
249
        var = Tcl_FindNamespaceVar(interp, part1, (Tcl_Namespace *) NULL,
250
                flags);
251
        if (var != (Tcl_Var) NULL) {
252
            varPtr = (Var *) var;
253
        }
254
        if (varPtr == NULL) {
255
            if (flags & TCL_LEAVE_ERR_MSG) {
256
                Tcl_ResetResult(interp);
257
            }
258
            if (createPart1) {   /* var wasn't found so create it  */
259
                result = TclGetNamespaceForQualName(interp, part1,
260
                        (Namespace *) NULL, flags, &varNsPtr, &dummy1Ptr,
261
                        &dummy2Ptr, &tail);
262
                if (result != TCL_OK) {
263
                    if (flags & TCL_LEAVE_ERR_MSG) {
264
                        /*
265
                         * Move the interpreter's object result to the
266
                         * string result, then reset the object result.
267
                         * FAILS IF OBJECT RESULT'S STRING REP HAS NULLS.
268
                         */
269
 
270
                        Tcl_SetResult(interp,
271
                                TclGetStringFromObj(Tcl_GetObjResult(interp),
272
                                    (int *) NULL),
273
                                TCL_VOLATILE);
274
                    }
275
                    goto done;
276
                }
277
                if (varNsPtr == NULL) {
278
                    if (flags & TCL_LEAVE_ERR_MSG) {
279
                        VarErrMsg(interp, part1, part2, msg, badNamespace);
280
                    }
281
                    goto done;
282
                }
283
                if (tail == NULL) {
284
                    if (flags & TCL_LEAVE_ERR_MSG) {
285
                        VarErrMsg(interp, part1, part2, msg, missingName);
286
                    }
287
                    goto done;
288
                }
289
                hPtr = Tcl_CreateHashEntry(&varNsPtr->varTable, tail, &new);
290
                varPtr = NewVar();
291
                Tcl_SetHashValue(hPtr, varPtr);
292
                varPtr->hPtr = hPtr;
293
                varPtr->nsPtr = varNsPtr;
294
            } else {            /* var wasn't found and not to create it */
295
                if (flags & TCL_LEAVE_ERR_MSG) {
296
                    VarErrMsg(interp, part1, part2, msg, noSuchVar);
297
                }
298
                goto done;
299
            }
300
        }
301
    } else {                    /* local var: look in frame varFramePtr */
302
        Proc *procPtr = varFramePtr->procPtr;
303
        int localCt = procPtr->numCompiledLocals;
304
        CompiledLocal *localPtr = procPtr->firstLocalPtr;
305
        Var *localVarPtr = varFramePtr->compiledLocals;
306
        int part1Len = strlen(part1);
307
 
308
        for (i = 0;  i < localCt;  i++) {
309
            if (!TclIsVarTemporary(localPtr)) {
310
                char *localName = localVarPtr->name;
311
                if ((part1[0] == localName[0])
312
                        && (part1Len == localPtr->nameLength)
313
                        && (strcmp(part1, localName) == 0)) {
314
                    varPtr = localVarPtr;
315
                    break;
316
                }
317
            }
318
            localVarPtr++;
319
            localPtr = localPtr->nextPtr;
320
        }
321
        if (varPtr == NULL) {   /* look in the frame's var hash table */
322
            tablePtr = varFramePtr->varTablePtr;
323
            if (createPart1) {
324
                if (tablePtr == NULL) {
325
                    tablePtr = (Tcl_HashTable *)
326
                            ckalloc(sizeof(Tcl_HashTable));
327
                    Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS);
328
                    varFramePtr->varTablePtr = tablePtr;
329
                }
330
                hPtr = Tcl_CreateHashEntry(tablePtr, part1, &new);
331
                if (new) {
332
                    varPtr = NewVar();
333
                    Tcl_SetHashValue(hPtr, varPtr);
334
                    varPtr->hPtr = hPtr;
335
                    varPtr->nsPtr = NULL; /* a local variable */
336
                } else {
337
                    varPtr = (Var *) Tcl_GetHashValue(hPtr);
338
                }
339
            } else {
340
                hPtr = NULL;
341
                if (tablePtr != NULL) {
342
                    hPtr = Tcl_FindHashEntry(tablePtr, part1);
343
                }
344
                if (hPtr == NULL) {
345
                    if (flags & TCL_LEAVE_ERR_MSG) {
346
                        VarErrMsg(interp, part1, part2, msg, noSuchVar);
347
                    }
348
                    goto done;
349
                }
350
                varPtr = (Var *) Tcl_GetHashValue(hPtr);
351
            }
352
        }
353
    }
354
 
355
lookupVarPart2:
356
    if (openParen != NULL) {
357
        *openParen = '(';
358
        openParen = NULL;
359
    }
360
 
361
    /*
362
     * If varPtr is a link variable, we have a reference to some variable
363
     * that was created through an "upvar" or "global" command. Traverse
364
     * through any links until we find the referenced variable.
365
     */
366
 
367
    while (TclIsVarLink(varPtr)) {
368
        varPtr = varPtr->value.linkPtr;
369
    }
370
 
371
    /*
372
     * If we're not dealing with an array element, return varPtr.
373
     */
374
 
375
    if (elName == NULL) {
376
        goto done;
377
    }
378
 
379
    /*
380
     * We're dealing with an array element. Make sure the variable is an
381
     * array and look up the element (create the element if desired).
382
     */
383
 
384
    if (TclIsVarUndefined(varPtr) && !TclIsVarArrayElement(varPtr)) {
385
        if (!createPart1) {
386
            if (flags & TCL_LEAVE_ERR_MSG) {
387
                VarErrMsg(interp, part1, part2, msg, noSuchVar);
388
            }
389
            varPtr = NULL;
390
            goto done;
391
        }
392
        TclSetVarArray(varPtr);
393
        TclClearVarUndefined(varPtr);
394
        varPtr->value.tablePtr =
395
                (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
396
        Tcl_InitHashTable(varPtr->value.tablePtr, TCL_STRING_KEYS);
397
    } else if (!TclIsVarArray(varPtr)) {
398
        if (flags & TCL_LEAVE_ERR_MSG) {
399
            VarErrMsg(interp, part1, part2, msg, needArray);
400
        }
401
        varPtr = NULL;
402
        goto done;
403
    }
404
    *arrayPtrPtr = varPtr;
405
    if (closeParen != NULL) {
406
        *closeParen = 0;
407
    }
408
    if (createPart2) {
409
        hPtr = Tcl_CreateHashEntry(varPtr->value.tablePtr, elName, &new);
410
        if (closeParen != NULL) {
411
            *closeParen = ')';
412
        }
413
        if (new) {
414
            if (varPtr->searchPtr != NULL) {
415
                DeleteSearches(varPtr);
416
            }
417
            varPtr = NewVar();
418
            Tcl_SetHashValue(hPtr, varPtr);
419
            varPtr->hPtr = hPtr;
420
            varPtr->nsPtr = varNsPtr;
421
            TclSetVarArrayElement(varPtr);
422
        }
423
    } else {
424
        hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, elName);
425
        if (closeParen != NULL) {
426
            *closeParen = ')';
427
        }
428
        if (hPtr == NULL) {
429
            if (flags & TCL_LEAVE_ERR_MSG) {
430
                VarErrMsg(interp, part1, part2, msg, noSuchElement);
431
            }
432
            varPtr = NULL;
433
            goto done;
434
        }
435
    }
436
    varPtr = (Var *) Tcl_GetHashValue(hPtr);
437
 
438
    done:
439
    if (openParen != NULL) {
440
        *openParen = '(';
441
    }
442
    return varPtr;
443
}
444
 
445
/*
446
 *----------------------------------------------------------------------
447
 *
448
 * Tcl_GetVar --
449
 *
450
 *      Return the value of a Tcl variable as a string.
451
 *
452
 * Results:
453
 *      The return value points to the current value of varName as a string.
454
 *      If the variable is not defined or can't be read because of a clash
455
 *      in array usage then a NULL pointer is returned and an error message
456
 *      is left in interp->result if the TCL_LEAVE_ERR_MSG flag is set.
457
 *      Note: the return value is only valid up until the next change to the
458
 *      variable; if you depend on the value lasting longer than that, then
459
 *      make yourself a private copy.
460
 *
461
 * Side effects:
462
 *      None.
463
 *
464
 *----------------------------------------------------------------------
465
 */
466
 
467
char *
468
Tcl_GetVar(interp, varName, flags)
469
    Tcl_Interp *interp;         /* Command interpreter in which varName is
470
                                 * to be looked up. */
471
    char *varName;              /* Name of a variable in interp. */
472
    int flags;                  /* OR-ed combination of TCL_GLOBAL_ONLY,
473
                                 * TCL_NAMESPACE_ONLY or TCL_LEAVE_ERR_MSG
474
                                 * bits. */
475
{
476
    return Tcl_GetVar2(interp, varName, (char *) NULL,
477
                       (flags | TCL_PARSE_PART1));
478
}
479
 
480
/*
481
 *----------------------------------------------------------------------
482
 *
483
 * Tcl_GetVar2 --
484
 *
485
 *      Return the value of a Tcl variable as a string, given a two-part
486
 *      name consisting of array name and element within array.
487
 *
488
 * Results:
489
 *      The return value points to the current value of the variable given
490
 *      by part1 and part2 as a string. If the specified variable doesn't
491
 *      exist, or if there is a clash in array usage, then NULL is returned
492
 *      and a message will be left in interp->result if the
493
 *      TCL_LEAVE_ERR_MSG flag is set. Note: the return value is only valid
494
 *      up until the next change to the variable; if you depend on the value
495
 *      lasting longer than that, then make yourself a private copy.
496
 *
497
 * Side effects:
498
 *      None.
499
 *
500
 *----------------------------------------------------------------------
501
 */
502
 
503
char *
504
Tcl_GetVar2(interp, part1, part2, flags)
505
    Tcl_Interp *interp;         /* Command interpreter in which variable is
506
                                 * to be looked up. */
507
    char *part1;                /* Name of an array (if part2 is non-NULL)
508
                                 * or the name of a variable. */
509
    char *part2;                /* If non-NULL, gives the name of an element
510
                                 * in the array part1. */
511
    int flags;                  /* OR-ed combination of TCL_GLOBAL_ONLY,
512
                                 * TCL_NAMESPACE_ONLY, TCL_LEAVE_ERR_MSG,
513
                                 * and TCL_PARSE_PART1 bits. */
514
{
515
    register Tcl_Obj *part1Ptr;
516
    register Tcl_Obj *part2Ptr = NULL;
517
    Tcl_Obj *objPtr;
518
    int length;
519
 
520
    length = strlen(part1);
521
    TclNewObj(part1Ptr);
522
    TclInitStringRep(part1Ptr, part1, length);
523
    Tcl_IncrRefCount(part1Ptr);
524
 
525
    if (part2 != NULL) {
526
        length = strlen(part2);
527
        TclNewObj(part2Ptr);
528
        TclInitStringRep(part2Ptr, part2, length);
529
        Tcl_IncrRefCount(part2Ptr);
530
    }
531
 
532
    objPtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags);
533
 
534
    TclDecrRefCount(part1Ptr);      /* done with the part1 name object */
535
    if (part2Ptr != NULL) {
536
        TclDecrRefCount(part2Ptr);  /* and the part2 name object */
537
    }
538
 
539
    if (objPtr == NULL) {
540
        /*
541
         * Move the interpreter's object result to the string result,
542
         * then reset the object result.
543
         * FAILS IF OBJECT RESULT'S STRING REPRESENTATION CONTAINS NULLS.
544
         */
545
 
546
        Tcl_SetResult(interp,
547
                TclGetStringFromObj(Tcl_GetObjResult(interp), (int *) NULL),
548
                TCL_VOLATILE);
549
        return NULL;
550
    }
551
 
552
    /*
553
     * THIS FAILS IF Tcl_ObjGetVar2's RESULT'S STRING REP HAS A NULL BYTE.
554
     */
555
 
556
    return TclGetStringFromObj(objPtr, (int *) NULL);
557
}
558
 
559
/*
560
 *----------------------------------------------------------------------
561
 *
562
 * Tcl_ObjGetVar2 --
563
 *
564
 *      Return the value of a Tcl variable as a Tcl object, given a
565
 *      two-part name consisting of array name and element within array.
566
 *
567
 * Results:
568
 *      The return value points to the current object value of the variable
569
 *      given by part1Ptr and part2Ptr. If the specified variable doesn't
570
 *      exist, or if there is a clash in array usage, then NULL is returned
571
 *      and a message will be left in the interpreter's result if the
572
 *      TCL_LEAVE_ERR_MSG flag is set.
573
 *
574
 * Side effects:
575
 *      The ref count for the returned object is _not_ incremented to
576
 *      reflect the returned reference; if you want to keep a reference to
577
 *      the object you must increment its ref count yourself.
578
 *
579
 *----------------------------------------------------------------------
580
 */
581
 
582
Tcl_Obj *
583
Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags)
584
    Tcl_Interp *interp;         /* Command interpreter in which variable is
585
                                 * to be looked up. */
586
    register Tcl_Obj *part1Ptr; /* Points to an object holding the name of
587
                                 * an array (if part2 is non-NULL) or the
588
                                 * name of a variable. */
589
    register Tcl_Obj *part2Ptr; /* If non-null, points to an object holding
590
                                 * the name of an element in the array
591
                                 * part1Ptr. */
592
    int flags;                  /* OR-ed combination of TCL_GLOBAL_ONLY,
593
                                 * TCL_LEAVE_ERR_MSG, and
594
                                 * TCL_PARSE_PART1 bits. */
595
{
596
    Interp *iPtr = (Interp *) interp;
597
    register Var *varPtr;
598
    Var *arrayPtr;
599
    char *part1, *msg;
600
    char *part2 = NULL;
601
 
602
    /*
603
     * THIS FAILS IF A NAME OBJECT'S STRING REP HAS A NULL BYTE.
604
     */
605
 
606
    part1 = TclGetStringFromObj(part1Ptr, (int *) NULL);
607
    if (part2Ptr != NULL) {
608
        part2 = TclGetStringFromObj(part2Ptr, (int *) NULL);
609
    }
610
    varPtr = TclLookupVar(interp, part1, part2, flags, "read",
611
            /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr);
612
    if (varPtr == NULL) {
613
        return NULL;
614
    }
615
 
616
    /*
617
     * Invoke any traces that have been set for the variable.
618
     */
619
 
620
    if ((varPtr->tracePtr != NULL)
621
            || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
622
        msg = CallTraces(iPtr, arrayPtr, varPtr, part1, part2,
623
                (flags & (TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY|TCL_PARSE_PART1)) | TCL_TRACE_READS);
624
        if (msg != NULL) {
625
            if (flags & TCL_LEAVE_ERR_MSG) {
626
                VarErrMsg(interp, part1, part2, "read", msg);
627
            }
628
            goto errorReturn;
629
        }
630
    }
631
 
632
    /*
633
     * Return the element if it's an existing scalar variable.
634
     */
635
 
636
    if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
637
        return varPtr->value.objPtr;
638
    }
639
 
640
    if (flags & TCL_LEAVE_ERR_MSG) {
641
        if (TclIsVarUndefined(varPtr) && (arrayPtr != NULL)
642
                && !TclIsVarUndefined(arrayPtr)) {
643
            msg = noSuchElement;
644
        } else if (TclIsVarArray(varPtr)) {
645
            msg = isArray;
646
        } else {
647
            msg = noSuchVar;
648
        }
649
        VarErrMsg(interp, part1, part2, "read", msg);
650
    }
651
 
652
    /*
653
     * An error. If the variable doesn't exist anymore and no-one's using
654
     * it, then free up the relevant structures and hash table entries.
655
     */
656
 
657
    errorReturn:
658
    if (TclIsVarUndefined(varPtr)) {
659
        CleanupVar(varPtr, arrayPtr);
660
    }
661
    return NULL;
662
}
663
 
664
/*
665
 *----------------------------------------------------------------------
666
 *
667
 * TclGetIndexedScalar --
668
 *
669
 *      Return the Tcl object value of a local scalar variable in the active
670
 *      procedure, given its index in the procedure's array of compiler
671
 *      allocated local variables.
672
 *
673
 * Results:
674
 *      The return value points to the current object value of the variable
675
 *      given by localIndex. If the specified variable doesn't exist, or
676
 *      there is a clash in array usage, or an error occurs while executing
677
 *      variable traces, then NULL is returned and a message will be left in
678
 *      the interpreter's result if leaveErrorMsg is 1.
679
 *
680
 * Side effects:
681
 *      The ref count for the returned object is _not_ incremented to
682
 *      reflect the returned reference; if you want to keep a reference to
683
 *      the object you must increment its ref count yourself.
684
 *
685
 *----------------------------------------------------------------------
686
 */
687
 
688
Tcl_Obj *
689
TclGetIndexedScalar(interp, localIndex, leaveErrorMsg)
690
    Tcl_Interp *interp;         /* Command interpreter in which variable is
691
                                 * to be looked up. */
692
    int localIndex;             /* Index of variable in procedure's array
693
                                 * of local variables. */
694
    int leaveErrorMsg;          /* 1 if to leave an error message in
695
                                 * interpreter's result on an error.
696
                                 * Otherwise no error message is left. */
697
{
698
    Interp *iPtr = (Interp *) interp;
699
    CallFrame *varFramePtr = iPtr->varFramePtr;
700
                                /* Points to the procedure call frame whose
701
                                 * variables are currently in use. Same as
702
                                 * the current procedure's frame, if any,
703
                                 * unless an "uplevel" is executing. */
704
    Var *compiledLocals = varFramePtr->compiledLocals;
705
    Var *varPtr;                /* Points to the variable's in-frame Var
706
                                 * structure. */
707
    char *varName;              /* Name of the local variable. */
708
    char *msg;
709
 
710
#ifdef TCL_COMPILE_DEBUG
711
    Proc *procPtr = varFramePtr->procPtr;
712
    int localCt = procPtr->numCompiledLocals;
713
 
714
    if (compiledLocals == NULL) {
715
        fprintf(stderr, "\nTclGetIndexedScalar: can't get local %i in frame 0x%x, no compiled locals\n",
716
                    localIndex, (unsigned int) varFramePtr);
717
        panic("TclGetIndexedScalar: no compiled locals in frame 0x%x",
718
              (unsigned int) varFramePtr);
719
    }
720
    if ((localIndex < 0) || (localIndex >= localCt)) {
721
        fprintf(stderr, "\nTclGetIndexedScalar: can't get local %i in frame 0x%x with %i locals\n",
722
                    localIndex, (unsigned int) varFramePtr, localCt);
723
        panic("TclGetIndexedScalar: bad local index %i in frame 0x%x",
724
              localIndex, (unsigned int) varFramePtr);
725
    }
726
#endif /* TCL_COMPILE_DEBUG */
727
 
728
    varPtr = &(compiledLocals[localIndex]);
729
    varName = varPtr->name;
730
 
731
    /*
732
     * If varPtr is a link variable, we have a reference to some variable
733
     * that was created through an "upvar" or "global" command, or we have a
734
     * reference to a variable in an enclosing namespace. Traverse through
735
     * any links until we find the referenced variable.
736
     */
737
 
738
    while (TclIsVarLink(varPtr)) {
739
        varPtr = varPtr->value.linkPtr;
740
    }
741
 
742
    /*
743
     * Invoke any traces that have been set for the variable.
744
     */
745
 
746
    if (varPtr->tracePtr != NULL) {
747
        msg = CallTraces(iPtr, /*arrayPtr*/ NULL, varPtr, varName, NULL,
748
                TCL_TRACE_READS);
749
        if (msg != NULL) {
750
            if (leaveErrorMsg) {
751
                VarErrMsg(interp, varName, NULL, "read", msg);
752
            }
753
            return NULL;
754
        }
755
    }
756
 
757
    /*
758
     * Make sure we're dealing with a scalar variable and not an array, and
759
     * that the variable exists (isn't undefined).
760
     */
761
 
762
    if (!TclIsVarScalar(varPtr) || TclIsVarUndefined(varPtr)) {
763
        if (leaveErrorMsg) {
764
            if (TclIsVarArray(varPtr)) {
765
                msg = isArray;
766
            } else {
767
                msg = noSuchVar;
768
            }
769
            VarErrMsg(interp, varName, NULL, "read", msg);
770
        }
771
        return NULL;
772
    }
773
    return varPtr->value.objPtr;
774
}
775
 
776
/*
777
 *----------------------------------------------------------------------
778
 *
779
 * TclGetElementOfIndexedArray --
780
 *
781
 *      Return the Tcl object value for an element in a local array
782
 *      variable. The element is named by the object elemPtr while the
783
 *      array is specified by its index in the active procedure's array
784
 *      of compiler allocated local variables.
785
 *
786
 * Results:
787
 *      The return value points to the current object value of the
788
 *      element. If the specified array or element doesn't exist, or there
789
 *      is a clash in array usage, or an error occurs while executing
790
 *      variable traces, then NULL is returned and a message will be left in
791
 *      the interpreter's result if leaveErrorMsg is 1.
792
 *
793
 * Side effects:
794
 *      The ref count for the returned object is _not_ incremented to
795
 *      reflect the returned reference; if you want to keep a reference to
796
 *      the object you must increment its ref count yourself.
797
 *
798
 *----------------------------------------------------------------------
799
 */
800
 
801
Tcl_Obj *
802
TclGetElementOfIndexedArray(interp, localIndex, elemPtr, leaveErrorMsg)
803
    Tcl_Interp *interp;         /* Command interpreter in which variable is
804
                                 * to be looked up. */
805
    int localIndex;             /* Index of array variable in procedure's
806
                                 * array of local variables. */
807
    Tcl_Obj *elemPtr;           /* Points to an object holding the name of
808
                                 * an element to get in the array. */
809
    int leaveErrorMsg;          /* 1 if to leave an error message in
810
                                 * the interpreter's result on an error.
811
                                 * Otherwise no error message is left. */
812
{
813
    Interp *iPtr = (Interp *) interp;
814
    CallFrame *varFramePtr = iPtr->varFramePtr;
815
                                /* Points to the procedure call frame whose
816
                                 * variables are currently in use. Same as
817
                                 * the current procedure's frame, if any,
818
                                 * unless an "uplevel" is executing. */
819
    Var *compiledLocals = varFramePtr->compiledLocals;
820
    Var *arrayPtr;              /* Points to the array's in-frame Var
821
                                 * structure. */
822
    char *arrayName;            /* Name of the local array. */
823
    Tcl_HashEntry *hPtr;
824
    Var *varPtr = NULL;         /* Points to the element's Var structure
825
                                 * that we return. Initialized to avoid
826
                                 * compiler warning. */
827
    char *elem, *msg;
828
    int new;
829
 
830
#ifdef TCL_COMPILE_DEBUG
831
    Proc *procPtr = varFramePtr->procPtr;
832
    int localCt = procPtr->numCompiledLocals;
833
 
834
    if (compiledLocals == NULL) {
835
        fprintf(stderr, "\nTclGetElementOfIndexedArray: can't get element of local %i in frame 0x%x, no compiled locals\n",
836
                    localIndex, (unsigned int) varFramePtr);
837
        panic("TclGetIndexedScalar: no compiled locals in frame 0x%x",
838
              (unsigned int) varFramePtr);
839
    }
840
    if ((localIndex < 0) || (localIndex >= localCt)) {
841
        fprintf(stderr, "\nTclGetIndexedScalar: can't get element of local %i in frame 0x%x with %i locals\n",
842
                    localIndex, (unsigned int) varFramePtr, localCt);
843
        panic("TclGetElementOfIndexedArray: bad local index %i in frame 0x%x",
844
              localIndex, (unsigned int) varFramePtr);
845
    }
846
#endif /* TCL_COMPILE_DEBUG */
847
 
848
    /*
849
     * THIS FAILS IF THE ELEMENT NAME OBJECT'S STRING REP HAS A NULL BYTE.
850
     */
851
 
852
    elem = Tcl_GetStringFromObj(elemPtr, (int *) NULL);
853
    arrayPtr = &(compiledLocals[localIndex]);
854
    arrayName = arrayPtr->name;
855
 
856
    /*
857
     * If arrayPtr is a link variable, we have a reference to some variable
858
     * that was created through an "upvar" or "global" command, or we have a
859
     * reference to a variable in an enclosing namespace. Traverse through
860
     * any links until we find the referenced variable.
861
     */
862
 
863
    while (TclIsVarLink(arrayPtr)) {
864
        arrayPtr = arrayPtr->value.linkPtr;
865
    }
866
 
867
    /*
868
     * Make sure we're dealing with an array and that the array variable
869
     * exists (isn't undefined).
870
     */
871
 
872
    if (!TclIsVarArray(arrayPtr) || TclIsVarUndefined(arrayPtr)) {
873
        if (leaveErrorMsg) {
874
            VarErrMsg(interp, arrayName, elem, "read", noSuchVar);
875
        }
876
        goto errorReturn;
877
    }
878
 
879
    /*
880
     * Look up the element. Note that we must create the element (but leave
881
     * it marked undefined) if it does not already exist. This allows a
882
     * trace to create new array elements "on the fly" that did not exist
883
     * before. A trace is always passed a variable for the array element. If
884
     * the trace does not define the variable, it will be deleted below (at
885
     * errorReturn) and an error returned.
886
     */
887
 
888
    hPtr = Tcl_CreateHashEntry(arrayPtr->value.tablePtr, elem, &new);
889
    if (new) {
890
        if (arrayPtr->searchPtr != NULL) {
891
            DeleteSearches(arrayPtr);
892
        }
893
        varPtr = NewVar();
894
        Tcl_SetHashValue(hPtr, varPtr);
895
        varPtr->hPtr = hPtr;
896
        varPtr->nsPtr = varFramePtr->nsPtr;
897
        TclSetVarArrayElement(varPtr);
898
    } else {
899
        varPtr = (Var *) Tcl_GetHashValue(hPtr);
900
    }
901
 
902
    /*
903
     * Invoke any traces that have been set for the element variable.
904
     */
905
 
906
    if ((varPtr->tracePtr != NULL)
907
            || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
908
        msg = CallTraces(iPtr, arrayPtr, varPtr, arrayName, elem,
909
                TCL_TRACE_READS);
910
        if (msg != NULL) {
911
            if (leaveErrorMsg) {
912
                VarErrMsg(interp, arrayName, elem, "read", msg);
913
            }
914
            goto errorReturn;
915
        }
916
    }
917
 
918
    /*
919
     * Return the element if it's an existing scalar variable.
920
     */
921
 
922
    if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
923
        return varPtr->value.objPtr;
924
    }
925
 
926
    if (leaveErrorMsg) {
927
        if (TclIsVarArray(varPtr)) {
928
            msg = isArray;
929
        } else {
930
            msg = noSuchVar;
931
        }
932
        VarErrMsg(interp, arrayName, elem, "read", msg);
933
    }
934
 
935
    /*
936
     * An error. If the variable doesn't exist anymore and no-one's using
937
     * it, then free up the relevant structures and hash table entries.
938
     */
939
 
940
    errorReturn:
941
    if ((varPtr != NULL) && TclIsVarUndefined(varPtr)) {
942
        CleanupVar(varPtr, NULL); /* the array is not in a hashtable */
943
    }
944
    return NULL;
945
}
946
 
947
/*
948
 *----------------------------------------------------------------------
949
 *
950
 * Tcl_SetCmd --
951
 *
952
 *      This procedure is invoked to process the "set" Tcl command.
953
 *      See the user documentation for details on what it does.
954
 *
955
 * Results:
956
 *      A standard Tcl result value.
957
 *
958
 * Side effects:
959
 *      A variable's value may be changed.
960
 *
961
 *----------------------------------------------------------------------
962
 */
963
 
964
        /* ARGSUSED */
965
int
966
Tcl_SetCmd(dummy, interp, argc, argv)
967
    ClientData dummy;                   /* Not used. */
968
    register Tcl_Interp *interp;        /* Current interpreter. */
969
    int argc;                           /* Number of arguments. */
970
    char **argv;                        /* Argument strings. */
971
{
972
    if (argc == 2) {
973
        char *value;
974
 
975
        value = Tcl_GetVar2(interp, argv[1], (char *) NULL,
976
                TCL_LEAVE_ERR_MSG|TCL_PARSE_PART1);
977
        if (value == NULL) {
978
            return TCL_ERROR;
979
        }
980
        Tcl_SetResult(interp, value, TCL_VOLATILE);
981
        return TCL_OK;
982
    } else if (argc == 3) {
983
        char *result;
984
 
985
        result = Tcl_SetVar2(interp, argv[1], (char *) NULL, argv[2],
986
                TCL_LEAVE_ERR_MSG|TCL_PARSE_PART1);
987
        if (result == NULL) {
988
            return TCL_ERROR;
989
        }
990
        Tcl_SetResult(interp, result, TCL_VOLATILE);
991
        return TCL_OK;
992
    } else {
993
        Tcl_AppendResult(interp, "wrong # args: should be \"",
994
                argv[0], " varName ?newValue?\"", (char *) NULL);
995
        return TCL_ERROR;
996
    }
997
}
998
 
999
/*
1000
 *----------------------------------------------------------------------
1001
 *
1002
 * Tcl_SetVar --
1003
 *
1004
 *      Change the value of a variable.
1005
 *
1006
 * Results:
1007
 *      Returns a pointer to the malloc'ed string which is the character
1008
 *      representation of the variable's new value. The caller must not
1009
 *      modify this string. If the write operation was disallowed then NULL
1010
 *      is returned; if the TCL_LEAVE_ERR_MSG flag is set, then an
1011
 *      explanatory message will be left in interp->result. Note that the
1012
 *      returned string may not be the same as newValue; this is because
1013
 *      variable traces may modify the variable's value.
1014
 *
1015
 * Side effects:
1016
 *      If varName is defined as a local or global variable in interp,
1017
 *      its value is changed to newValue. If varName isn't currently
1018
 *      defined, then a new global variable by that name is created.
1019
 *
1020
 *----------------------------------------------------------------------
1021
 */
1022
 
1023
char *
1024
Tcl_SetVar(interp, varName, newValue, flags)
1025
    Tcl_Interp *interp;         /* Command interpreter in which varName is
1026
                                 * to be looked up. */
1027
    char *varName;              /* Name of a variable in interp. */
1028
    char *newValue;             /* New value for varName. */
1029
    int flags;                  /* Various flags that tell how to set value:
1030
                                 * any of TCL_GLOBAL_ONLY,
1031
                                 * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
1032
                                 * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG. */
1033
{
1034
    return Tcl_SetVar2(interp, varName, (char *) NULL, newValue,
1035
                       (flags | TCL_PARSE_PART1));
1036
}
1037
 
1038
/*
1039
 *----------------------------------------------------------------------
1040
 *
1041
 * Tcl_SetVar2 --
1042
 *
1043
 *      Given a two-part variable name, which may refer either to a
1044
 *      scalar variable or an element of an array, change the value
1045
 *      of the variable.  If the named scalar or array or element
1046
 *      doesn't exist then create one.
1047
 *
1048
 * Results:
1049
 *      Returns a pointer to the malloc'ed string which is the character
1050
 *      representation of the variable's new value. The caller must not
1051
 *      modify this string. If the write operation was disallowed because an
1052
 *      array was expected but not found (or vice versa), then NULL is
1053
 *      returned; if the TCL_LEAVE_ERR_MSG flag is set, then an explanatory
1054
 *      message will be left in interp->result. Note that the returned
1055
 *      string may not be the same as newValue; this is because variable
1056
 *      traces may modify the variable's value.
1057
 *
1058
 * Side effects:
1059
 *      The value of the given variable is set. If either the array
1060
 *      or the entry didn't exist then a new one is created.
1061
 *
1062
 *----------------------------------------------------------------------
1063
 */
1064
 
1065
char *
1066
Tcl_SetVar2(interp, part1, part2, newValue, flags)
1067
    Tcl_Interp *interp;         /* Command interpreter in which variable is
1068
                                 * to be looked up. */
1069
    char *part1;                /* If part2 is NULL, this is name of scalar
1070
                                 * variable. Otherwise it is the name of
1071
                                 * an array. */
1072
    char *part2;                /* Name of an element within an array, or
1073
                                 * NULL. */
1074
    char *newValue;             /* New value for variable. */
1075
    int flags;                  /* Various flags that tell how to set value:
1076
                                 * any of TCL_GLOBAL_ONLY,
1077
                                 * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
1078
                                 * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG, or
1079
                                 * TCL_PARSE_PART1. */
1080
{
1081
    register Tcl_Obj *valuePtr;
1082
    register Tcl_Obj *part1Ptr;
1083
    register Tcl_Obj *part2Ptr = NULL;
1084
    Tcl_Obj *varValuePtr;
1085
    int length;
1086
 
1087
    /*
1088
     * Create an object holding the variable's new value and use
1089
     * Tcl_ObjSetVar2 to actually set the variable.
1090
     */
1091
 
1092
    length = newValue ? strlen(newValue) : 0;
1093
    TclNewObj(valuePtr);
1094
    TclInitStringRep(valuePtr, newValue, length);
1095
    Tcl_IncrRefCount(valuePtr);
1096
 
1097
    length = strlen(part1) ;
1098
    TclNewObj(part1Ptr);
1099
    TclInitStringRep(part1Ptr, part1, length);
1100
    Tcl_IncrRefCount(part1Ptr);
1101
 
1102
    if (part2 != NULL) {
1103
        length = strlen(part2);
1104
        TclNewObj(part2Ptr);
1105
        TclInitStringRep(part2Ptr, part2, length);
1106
        Tcl_IncrRefCount(part2Ptr);
1107
    }
1108
 
1109
    varValuePtr = Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, valuePtr,
1110
            flags);
1111
 
1112
    TclDecrRefCount(part1Ptr);      /* done with the part1 name object */
1113
    if (part2Ptr != NULL) {
1114
        TclDecrRefCount(part2Ptr);  /* and the part2 name object */
1115
    }
1116
    Tcl_DecrRefCount(valuePtr); /* done with the object */
1117
 
1118
    if (varValuePtr == NULL) {
1119
        /*
1120
         * Move the interpreter's object result to the string result,
1121
         * then reset the object result.
1122
         * FAILS IF OBJECT RESULT'S STRING REPRESENTATION CONTAINS NULLS.
1123
         */
1124
 
1125
        Tcl_SetResult(interp,
1126
                TclGetStringFromObj(Tcl_GetObjResult(interp), (int *) NULL),
1127
                TCL_VOLATILE);
1128
        return NULL;
1129
    }
1130
 
1131
    /*
1132
     * THIS FAILS IF Tcl_ObjSetVar2's RESULT'S STRING REP HAS A NULL BYTE.
1133
     */
1134
 
1135
    return TclGetStringFromObj(varValuePtr, (int *) NULL);
1136
}
1137
 
1138
/*
1139
 *----------------------------------------------------------------------
1140
 *
1141
 * Tcl_ObjSetVar2 --
1142
 *
1143
 *      Given a two-part variable name, which may refer either to a scalar
1144
 *      variable or an element of an array, change the value of the variable
1145
 *      to a new Tcl object value. If the named scalar or array or element
1146
 *      doesn't exist then create one.
1147
 *
1148
 * Results:
1149
 *      Returns a pointer to the Tcl_Obj holding the new value of the
1150
 *      variable. If the write operation was disallowed because an array was
1151
 *      expected but not found (or vice versa), then NULL is returned; if
1152
 *      the TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will
1153
 *      be left in the interpreter's result. Note that the returned object
1154
 *      may not be the same one referenced by newValuePtr; this is because
1155
 *      variable traces may modify the variable's value.
1156
 *
1157
 * Side effects:
1158
 *      The value of the given variable is set. If either the array or the
1159
 *      entry didn't exist then a new variable is created.
1160
 *
1161
 *      The reference count is decremented for any old value of the variable
1162
 *      and incremented for its new value. If the new value for the variable
1163
 *      is not the same one referenced by newValuePtr (perhaps as a result
1164
 *      of a variable trace), then newValuePtr's ref count is left unchanged
1165
 *      by Tcl_ObjSetVar2. newValuePtr's ref count is also left unchanged if
1166
 *      we are appending it as a string value: that is, if "flags" includes
1167
 *      TCL_APPEND_VALUE but not TCL_LIST_ELEMENT.
1168
 *
1169
 *      The reference count for the returned object is _not_ incremented: if
1170
 *      you want to keep a reference to the object you must increment its
1171
 *      ref count yourself.
1172
 *
1173
 *----------------------------------------------------------------------
1174
 */
1175
 
1176
Tcl_Obj *
1177
Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, newValuePtr, flags)
1178
    Tcl_Interp *interp;         /* Command interpreter in which variable is
1179
                                 * to be found. */
1180
    register Tcl_Obj *part1Ptr; /* Points to an object holding the name of
1181
                                 * an array (if part2 is non-NULL) or the
1182
                                 * name of a variable. */
1183
    register Tcl_Obj *part2Ptr; /* If non-null, points to an object holding
1184
                                 * the name of an element in the array
1185
                                 * part1Ptr. */
1186
    Tcl_Obj *newValuePtr;       /* New value for variable. */
1187
    int flags;                  /* Various flags that tell how to set value:
1188
                                 * any of TCL_GLOBAL_ONLY,
1189
                                 * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
1190
                                 * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG, or
1191
                                 * TCL_PARSE_PART1. */
1192
{
1193
    Interp *iPtr = (Interp *) interp;
1194
    register Var *varPtr;
1195
    Var *arrayPtr;
1196
    Tcl_Obj *oldValuePtr;
1197
    Tcl_Obj *resultPtr = NULL;
1198
    char *part1, *bytes;
1199
    char *part2 = NULL;
1200
    int length, result;
1201
 
1202
    /*
1203
     * THIS FAILS IF A NAME OBJECT'S STRING REP HAS A NULL BYTE.
1204
     */
1205
 
1206
    part1 = TclGetStringFromObj(part1Ptr, (int *) NULL);
1207
    if (part2Ptr != NULL) {
1208
        part2 = TclGetStringFromObj(part2Ptr, (int *) NULL);
1209
    }
1210
 
1211
    varPtr = TclLookupVar(interp, part1, part2, flags, "set",
1212
            /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
1213
    if (varPtr == NULL) {
1214
        return NULL;
1215
    }
1216
 
1217
    /*
1218
     * If the variable is in a hashtable and its hPtr field is NULL, then we
1219
     * have an upvar to an array element where the array was deleted,
1220
     * leaving the element dangling at the end of the upvar. Generate an
1221
     * error (allowing the variable to be reset would screw up our storage
1222
     * allocation and is meaningless anyway).
1223
     */
1224
 
1225
    if ((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL)) {
1226
        if (flags & TCL_LEAVE_ERR_MSG) {
1227
            VarErrMsg(interp, part1, part2, "set", danglingUpvar);
1228
        }
1229
        return NULL;
1230
    }
1231
 
1232
    /*
1233
     * It's an error to try to set an array variable itself.
1234
     */
1235
 
1236
    if (TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
1237
        if (flags & TCL_LEAVE_ERR_MSG) {
1238
            VarErrMsg(interp, part1, part2, "set", isArray);
1239
        }
1240
        return NULL;
1241
    }
1242
 
1243
    /*
1244
     * At this point, if we were appending, we used to call read traces: we
1245
     * treated append as a read-modify-write. However, it seemed unlikely to
1246
     * us that a real program would be interested in such reads being done
1247
     * during a set operation.
1248
     */
1249
 
1250
    /*
1251
     * Set the variable's new value. If appending, append the new value to
1252
     * the variable, either as a list element or as a string. Also, if
1253
     * appending, then if the variable's old value is unshared we can modify
1254
     * it directly, otherwise we must create a new copy to modify: this is
1255
     * "copy on write".
1256
     */
1257
 
1258
    oldValuePtr = varPtr->value.objPtr;
1259
    if (flags & TCL_APPEND_VALUE) {
1260
        if (TclIsVarUndefined(varPtr) && (oldValuePtr != NULL)) {
1261
            Tcl_DecrRefCount(oldValuePtr);     /* discard old value */
1262
            varPtr->value.objPtr = NULL;
1263
            oldValuePtr = NULL;
1264
        }
1265
        if (flags & TCL_LIST_ELEMENT) {        /* append list element */
1266
            if (oldValuePtr == NULL) {
1267
                TclNewObj(oldValuePtr);
1268
                varPtr->value.objPtr = oldValuePtr;
1269
                Tcl_IncrRefCount(oldValuePtr); /* since var is reference */
1270
            } else if (Tcl_IsShared(oldValuePtr)) {
1271
                varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr);
1272
                Tcl_DecrRefCount(oldValuePtr);
1273
                oldValuePtr = varPtr->value.objPtr;
1274
                Tcl_IncrRefCount(oldValuePtr); /* since var is reference */
1275
            }
1276
            result = Tcl_ListObjAppendElement(interp, oldValuePtr,
1277
                    newValuePtr);
1278
            if (result != TCL_OK) {
1279
                return NULL;
1280
            }
1281
        } else {                               /* append string */
1282
            /*
1283
             * We append newValuePtr's bytes but don't change its ref count.
1284
             */
1285
 
1286
            bytes = Tcl_GetStringFromObj(newValuePtr, &length);
1287
            if (oldValuePtr == NULL) {
1288
                varPtr->value.objPtr = Tcl_NewStringObj(bytes, length);
1289
                Tcl_IncrRefCount(varPtr->value.objPtr);
1290
            } else {
1291
                if (Tcl_IsShared(oldValuePtr)) {   /* append to copy */
1292
                    varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr);
1293
                    TclDecrRefCount(oldValuePtr);
1294
                    oldValuePtr = varPtr->value.objPtr;
1295
                    Tcl_IncrRefCount(oldValuePtr); /* since var is ref */
1296
                }
1297
                Tcl_AppendToObj(oldValuePtr, bytes, length);
1298
            }
1299
        }
1300
    } else {
1301
        if (flags & TCL_LIST_ELEMENT) {        /* set var to list element */
1302
            int neededBytes, listFlags;
1303
 
1304
            /*
1305
             * We set the variable to the result of converting newValuePtr's
1306
             * string rep to a list element. We do not change newValuePtr's
1307
             * ref count.
1308
             */
1309
 
1310
            if (oldValuePtr != NULL) {
1311
                Tcl_DecrRefCount(oldValuePtr); /* discard old value */
1312
            }
1313
            bytes = Tcl_GetStringFromObj(newValuePtr, &length);
1314
            neededBytes = Tcl_ScanElement(bytes, &listFlags);
1315
            oldValuePtr = Tcl_NewObj();
1316
            oldValuePtr->bytes = (char *)
1317
                    ckalloc((unsigned) (neededBytes + 1));
1318
            oldValuePtr->length = Tcl_ConvertElement(bytes,
1319
                    oldValuePtr->bytes, listFlags);
1320
            varPtr->value.objPtr = oldValuePtr;
1321
            Tcl_IncrRefCount(varPtr->value.objPtr);
1322
        } else if (newValuePtr != oldValuePtr) {
1323
            varPtr->value.objPtr = newValuePtr;
1324
            Tcl_IncrRefCount(newValuePtr);      /* var is another ref */
1325
            if (oldValuePtr != NULL) {
1326
                TclDecrRefCount(oldValuePtr);   /* discard old value */
1327
            }
1328
        }
1329
    }
1330
    TclSetVarScalar(varPtr);
1331
    TclClearVarUndefined(varPtr);
1332
    if (arrayPtr != NULL) {
1333
        TclClearVarUndefined(arrayPtr);
1334
    }
1335
 
1336
    /*
1337
     * Invoke any write traces for the variable.
1338
     */
1339
 
1340
    if ((varPtr->tracePtr != NULL)
1341
            || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
1342
        char *msg = CallTraces(iPtr, arrayPtr, varPtr, part1, part2,
1343
                (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_PARSE_PART1)) | TCL_TRACE_WRITES);
1344
        if (msg != NULL) {
1345
            if (flags & TCL_LEAVE_ERR_MSG) {
1346
                VarErrMsg(interp, part1, part2, "set", msg);
1347
            }
1348
            goto cleanup;
1349
        }
1350
    }
1351
 
1352
    /*
1353
     * Return the variable's value unless the variable was changed in some
1354
     * gross way by a trace (e.g. it was unset and then recreated as an
1355
     * array).
1356
     */
1357
 
1358
    if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
1359
        return varPtr->value.objPtr;
1360
    }
1361
 
1362
    /*
1363
     * A trace changed the value in some gross way. Return an empty string
1364
     * object.
1365
     */
1366
 
1367
    resultPtr = iPtr->emptyObjPtr;
1368
 
1369
    /*
1370
     * If the variable doesn't exist anymore and no-one's using it, then
1371
     * free up the relevant structures and hash table entries.
1372
     */
1373
 
1374
    cleanup:
1375
    if (TclIsVarUndefined(varPtr)) {
1376
        CleanupVar(varPtr, arrayPtr);
1377
    }
1378
    return resultPtr;
1379
}
1380
 
1381
/*
1382
 *----------------------------------------------------------------------
1383
 *
1384
 * TclSetIndexedScalar --
1385
 *
1386
 *      Change the Tcl object value of a local scalar variable in the active
1387
 *      procedure, given its compile-time allocated index in the procedure's
1388
 *      array of local variables.
1389
 *
1390
 * Results:
1391
 *      Returns a pointer to the Tcl_Obj holding the new value of the
1392
 *      variable given by localIndex. If the specified variable doesn't
1393
 *      exist, or there is a clash in array usage, or an error occurs while
1394
 *      executing variable traces, then NULL is returned and a message will
1395
 *      be left in the interpreter's result if leaveErrorMsg is 1. Note
1396
 *      that the returned object may not be the same one referenced by
1397
 *      newValuePtr; this is because variable traces may modify the
1398
 *      variable's value.
1399
 *
1400
 * Side effects:
1401
 *      The value of the given variable is set. The reference count is
1402
 *      decremented for any old value of the variable and incremented for
1403
 *      its new value. If as a result of a variable trace the new value for
1404
 *      the variable is not the same one referenced by newValuePtr, then
1405
 *      newValuePtr's ref count is left unchanged. The ref count for the
1406
 *      returned object is _not_ incremented to reflect the returned
1407
 *      reference; if you want to keep a reference to the object you must
1408
 *      increment its ref count yourself. This procedure does not create
1409
 *      new variables, but only sets those recognized at compile time.
1410
 *
1411
 *----------------------------------------------------------------------
1412
 */
1413
 
1414
Tcl_Obj *
1415
TclSetIndexedScalar(interp, localIndex, newValuePtr, leaveErrorMsg)
1416
    Tcl_Interp *interp;         /* Command interpreter in which variable is
1417
                                 * to be found. */
1418
    int localIndex;             /* Index of variable in procedure's array
1419
                                 * of local variables. */
1420
    Tcl_Obj *newValuePtr;       /* New value for variable. */
1421
    int leaveErrorMsg;          /* 1 if to leave an error message in
1422
                                 * the interpreter's result on an error.
1423
                                 * Otherwise no error message is left. */
1424
{
1425
    Interp *iPtr = (Interp *) interp;
1426
    CallFrame *varFramePtr = iPtr->varFramePtr;
1427
                                /* Points to the procedure call frame whose
1428
                                 * variables are currently in use. Same as
1429
                                 * the current procedure's frame, if any,
1430
                                 * unless an "uplevel" is executing. */
1431
    Var *compiledLocals = varFramePtr->compiledLocals;
1432
    register Var *varPtr;       /* Points to the variable's in-frame Var
1433
                                 * structure. */
1434
    char *varName;              /* Name of the local variable. */
1435
    Tcl_Obj *oldValuePtr;
1436
    Tcl_Obj *resultPtr = NULL;
1437
 
1438
#ifdef TCL_COMPILE_DEBUG
1439
    Proc *procPtr = varFramePtr->procPtr;
1440
    int localCt = procPtr->numCompiledLocals;
1441
 
1442
    if (compiledLocals == NULL) {
1443
        fprintf(stderr, "\nTclSetIndexedScalar: can't set local %i in frame 0x%x, no compiled locals\n",
1444
                    localIndex, (unsigned int) varFramePtr);
1445
        panic("TclSetIndexedScalar: no compiled locals in frame 0x%x",
1446
              (unsigned int) varFramePtr);
1447
    }
1448
    if ((localIndex < 0) || (localIndex >= localCt)) {
1449
        fprintf(stderr, "\nTclSetIndexedScalar: can't set local %i in frame 0x%x with %i locals\n",
1450
                    localIndex, (unsigned int) varFramePtr, localCt);
1451
        panic("TclSetIndexedScalar: bad local index %i in frame 0x%x",
1452
              localIndex, (unsigned int) varFramePtr);
1453
    }
1454
#endif /* TCL_COMPILE_DEBUG */
1455
 
1456
    varPtr = &(compiledLocals[localIndex]);
1457
    varName = varPtr->name;
1458
 
1459
    /*
1460
     * If varPtr is a link variable, we have a reference to some variable
1461
     * that was created through an "upvar" or "global" command, or we have a
1462
     * reference to a variable in an enclosing namespace. Traverse through
1463
     * any links until we find the referenced variable.
1464
     */
1465
 
1466
    while (TclIsVarLink(varPtr)) {
1467
        varPtr = varPtr->value.linkPtr;
1468
    }
1469
 
1470
    /*
1471
     * If the variable is in a hashtable and its hPtr field is NULL, then we
1472
     * have an upvar to an array element where the array was deleted,
1473
     * leaving the element dangling at the end of the upvar. Generate an
1474
     * error (allowing the variable to be reset would screw up our storage
1475
     * allocation and is meaningless anyway).
1476
     */
1477
 
1478
    if ((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL)) {
1479
        if (leaveErrorMsg) {
1480
            VarErrMsg(interp, varName, NULL, "set", danglingUpvar);
1481
        }
1482
        return NULL;
1483
    }
1484
 
1485
    /*
1486
     * It's an error to try to set an array variable itself.
1487
     */
1488
 
1489
    if (TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
1490
        if (leaveErrorMsg) {
1491
            VarErrMsg(interp, varName, NULL, "set", isArray);
1492
        }
1493
        return NULL;
1494
    }
1495
 
1496
    /*
1497
     * Set the variable's new value and discard its old value. We don't
1498
     * append with this "set" procedure so the old value isn't needed.
1499
     */
1500
 
1501
    oldValuePtr = varPtr->value.objPtr;
1502
    if (newValuePtr != oldValuePtr) {        /* set new value */
1503
        varPtr->value.objPtr = newValuePtr;
1504
        Tcl_IncrRefCount(newValuePtr);       /* var is another ref to obj */
1505
        if (oldValuePtr != NULL) {
1506
            TclDecrRefCount(oldValuePtr);    /* discard old value */
1507
        }
1508
    }
1509
    TclSetVarScalar(varPtr);
1510
    TclClearVarUndefined(varPtr);
1511
 
1512
    /*
1513
     * Invoke any write traces for the variable.
1514
     */
1515
 
1516
    if (varPtr->tracePtr != NULL) {
1517
        char *msg = CallTraces(iPtr, /*arrayPtr*/ NULL, varPtr,
1518
                varName, (char *) NULL, TCL_TRACE_WRITES);
1519
        if (msg != NULL) {
1520
            if (leaveErrorMsg) {
1521
                VarErrMsg(interp, varName, NULL, "set", msg);
1522
            }
1523
            goto cleanup;
1524
        }
1525
    }
1526
 
1527
    /*
1528
     * Return the variable's value unless the variable was changed in some
1529
     * gross way by a trace (e.g. it was unset and then recreated as an
1530
     * array). If it was changed is a gross way, just return an empty string
1531
     * object.
1532
     */
1533
 
1534
    if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
1535
        return varPtr->value.objPtr;
1536
    }
1537
 
1538
    resultPtr = Tcl_NewObj();
1539
 
1540
    /*
1541
     * If the variable doesn't exist anymore and no-one's using it, then
1542
     * free up the relevant structures and hash table entries.
1543
     */
1544
 
1545
    cleanup:
1546
    if (TclIsVarUndefined(varPtr)) {
1547
        CleanupVar(varPtr, NULL);
1548
    }
1549
    return resultPtr;
1550
}
1551
 
1552
/*
1553
 *----------------------------------------------------------------------
1554
 *
1555
 * TclSetElementOfIndexedArray --
1556
 *
1557
 *      Change the Tcl object value of an element in a local array
1558
 *      variable. The element is named by the object elemPtr while the array
1559
 *      is specified by its index in the active procedure's array of
1560
 *      compiler allocated local variables.
1561
 *
1562
 * Results:
1563
 *      Returns a pointer to the Tcl_Obj holding the new value of the
1564
 *      element. If the specified array or element doesn't exist, or there
1565
 *      is a clash in array usage, or an error occurs while executing
1566
 *      variable traces, then NULL is returned and a message will be left in
1567
 *      the interpreter's result if leaveErrorMsg is 1. Note that the
1568
 *      returned object may not be the same one referenced by newValuePtr;
1569
 *      this is because variable traces may modify the variable's value.
1570
 *
1571
 * Side effects:
1572
 *      The value of the given array element is set. The reference count is
1573
 *      decremented for any old value of the element and incremented for its
1574
 *      new value. If as a result of a variable trace the new value for the
1575
 *      element is not the same one referenced by newValuePtr, then
1576
 *      newValuePtr's ref count is left unchanged. The ref count for the
1577
 *      returned object is _not_ incremented to reflect the returned
1578
 *      reference; if you want to keep a reference to the object you must
1579
 *      increment its ref count yourself. This procedure will not create new
1580
 *      array variables, but only sets elements of those arrays recognized
1581
 *      at compile time. However, if the entry doesn't exist then a new
1582
 *      variable is created.
1583
 *
1584
 *----------------------------------------------------------------------
1585
 */
1586
 
1587
Tcl_Obj *
1588
TclSetElementOfIndexedArray(interp, localIndex, elemPtr, newValuePtr,
1589
        leaveErrorMsg)
1590
    Tcl_Interp *interp;         /* Command interpreter in which the array is
1591
                                 * to be found. */
1592
    int localIndex;             /* Index of array variable in procedure's
1593
                                 * array of local variables. */
1594
    Tcl_Obj *elemPtr;           /* Points to an object holding the name of
1595
                                 * an element to set in the array. */
1596
    Tcl_Obj *newValuePtr;       /* New value for variable. */
1597
    int leaveErrorMsg;          /* 1 if to leave an error message in
1598
                                 * the interpreter's result on an error.
1599
                                 * Otherwise no error message is left. */
1600
{
1601
    Interp *iPtr = (Interp *) interp;
1602
    CallFrame *varFramePtr = iPtr->varFramePtr;
1603
                                /* Points to the procedure call frame whose
1604
                                 * variables are currently in use. Same as
1605
                                 * the current procedure's frame, if any,
1606
                                 * unless an "uplevel" is executing. */
1607
    Var *compiledLocals = varFramePtr->compiledLocals;
1608
    Var *arrayPtr;              /* Points to the array's in-frame Var
1609
                                 * structure. */
1610
    char *arrayName;            /* Name of the local array. */
1611
    char *elem;
1612
    Tcl_HashEntry *hPtr;
1613
    Var *varPtr = NULL;         /* Points to the element's Var structure
1614
                                 * that we return. */
1615
    Tcl_Obj *resultPtr = NULL;
1616
    Tcl_Obj *oldValuePtr;
1617
    int new;
1618
 
1619
#ifdef TCL_COMPILE_DEBUG
1620
    Proc *procPtr = varFramePtr->procPtr;
1621
    int localCt = procPtr->numCompiledLocals;
1622
 
1623
    if (compiledLocals == NULL) {
1624
        fprintf(stderr, "\nTclSetElementOfIndexedArray: can't set element of local %i in frame 0x%x, no compiled locals\n",
1625
                    localIndex, (unsigned int) varFramePtr);
1626
        panic("TclSetIndexedScalar: no compiled locals in frame 0x%x",
1627
              (unsigned int) varFramePtr);
1628
    }
1629
    if ((localIndex < 0) || (localIndex >= localCt)) {
1630
        fprintf(stderr, "\nTclSetIndexedScalar: can't set elememt of local %i in frame 0x%x with %i locals\n",
1631
                    localIndex, (unsigned int) varFramePtr, localCt);
1632
        panic("TclSetElementOfIndexedArray: bad local index %i in frame 0x%x",
1633
              localIndex, (unsigned int) varFramePtr);
1634
    }
1635
#endif /* TCL_COMPILE_DEBUG */
1636
 
1637
    /*
1638
     * THIS FAILS IF THE ELEMENT NAME OBJECT'S STRING REP HAS A NULL BYTE.
1639
     */
1640
 
1641
    elem = Tcl_GetStringFromObj(elemPtr, (int *) NULL);
1642
    arrayPtr = &(compiledLocals[localIndex]);
1643
    arrayName = arrayPtr->name;
1644
 
1645
    /*
1646
     * If arrayPtr is a link variable, we have a reference to some variable
1647
     * that was created through an "upvar" or "global" command, or we have a
1648
     * reference to a variable in an enclosing namespace. Traverse through
1649
     * any links until we find the referenced variable.
1650
     */
1651
 
1652
    while (TclIsVarLink(arrayPtr)) {
1653
        arrayPtr = arrayPtr->value.linkPtr;
1654
    }
1655
 
1656
    /*
1657
     * Make sure we're dealing with an array.
1658
     */
1659
 
1660
    if (TclIsVarUndefined(arrayPtr) && !TclIsVarArrayElement(arrayPtr)) {
1661
        TclSetVarArray(arrayPtr);
1662
        arrayPtr->value.tablePtr =
1663
                (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
1664
        Tcl_InitHashTable(arrayPtr->value.tablePtr, TCL_STRING_KEYS);
1665
        TclClearVarUndefined(arrayPtr);
1666
    } else if (!TclIsVarArray(arrayPtr)) {
1667
        if (leaveErrorMsg) {
1668
            VarErrMsg(interp, arrayName, elem, "set", needArray);
1669
        }
1670
        goto errorReturn;
1671
    }
1672
 
1673
    /*
1674
     * Look up the element.
1675
     */
1676
 
1677
    hPtr = Tcl_CreateHashEntry(arrayPtr->value.tablePtr, elem, &new);
1678
    if (new) {
1679
        if (arrayPtr->searchPtr != NULL) {
1680
            DeleteSearches(arrayPtr);
1681
        }
1682
        varPtr = NewVar();
1683
        Tcl_SetHashValue(hPtr, varPtr);
1684
        varPtr->hPtr = hPtr;
1685
        varPtr->nsPtr = varFramePtr->nsPtr;
1686
        TclSetVarArrayElement(varPtr);
1687
    }
1688
    varPtr = (Var *) Tcl_GetHashValue(hPtr);
1689
 
1690
    /*
1691
     * It's an error to try to set an array variable itself.
1692
     */
1693
 
1694
    if (TclIsVarArray(varPtr)) {
1695
        if (leaveErrorMsg) {
1696
            VarErrMsg(interp, arrayName, elem, "set", isArray);
1697
        }
1698
        goto errorReturn;
1699
    }
1700
 
1701
    /*
1702
     * Set the variable's new value and discard the old one. We don't
1703
     * append with this "set" procedure so the old value isn't needed.
1704
     */
1705
 
1706
    oldValuePtr = varPtr->value.objPtr;
1707
    if (newValuePtr != oldValuePtr) {        /* set new value */
1708
        varPtr->value.objPtr = newValuePtr;
1709
        Tcl_IncrRefCount(newValuePtr);       /* var is another ref to obj */
1710
        if (oldValuePtr != NULL) {
1711
            TclDecrRefCount(oldValuePtr);    /* discard old value */
1712
        }
1713
    }
1714
    TclSetVarScalar(varPtr);
1715
    TclClearVarUndefined(varPtr);
1716
 
1717
    /*
1718
     * Invoke any write traces for the element variable.
1719
     */
1720
 
1721
    if ((varPtr->tracePtr != NULL)
1722
            || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
1723
        char *msg = CallTraces(iPtr, arrayPtr, varPtr, arrayName, elem,
1724
                TCL_TRACE_WRITES);
1725
        if (msg != NULL) {
1726
            if (leaveErrorMsg) {
1727
                VarErrMsg(interp, arrayName, elem, "set", msg);
1728
            }
1729
            goto errorReturn;
1730
        }
1731
    }
1732
 
1733
    /*
1734
     * Return the element's value unless it was changed in some gross way by
1735
     * a trace (e.g. it was unset and then recreated as an array). If it was
1736
     * changed is a gross way, just return an empty string object.
1737
     */
1738
 
1739
    if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
1740
        return varPtr->value.objPtr;
1741
    }
1742
 
1743
    resultPtr = Tcl_NewObj();
1744
 
1745
    /*
1746
     * An error. If the variable doesn't exist anymore and no-one's using
1747
     * it, then free up the relevant structures and hash table entries.
1748
     */
1749
 
1750
    errorReturn:
1751
    if (varPtr != NULL) {
1752
        if (TclIsVarUndefined(varPtr)) {
1753
            CleanupVar(varPtr, NULL); /* note: array isn't in hashtable */
1754
        }
1755
    }
1756
    return resultPtr;
1757
}
1758
 
1759
/*
1760
 *----------------------------------------------------------------------
1761
 *
1762
 * TclIncrVar2 --
1763
 *
1764
 *      Given a two-part variable name, which may refer either to a scalar
1765
 *      variable or an element of an array, increment the Tcl object value
1766
 *      of the variable by a specified amount.
1767
 *
1768
 * Results:
1769
 *      Returns a pointer to the Tcl_Obj holding the new value of the
1770
 *      variable. If the specified variable doesn't exist, or there is a
1771
 *      clash in array usage, or an error occurs while executing variable
1772
 *      traces, then NULL is returned and a message will be left in
1773
 *      the interpreter's result.
1774
 *
1775
 * Side effects:
1776
 *      The value of the given variable is incremented by the specified
1777
 *      amount. If either the array or the entry didn't exist then a new
1778
 *      variable is created. The ref count for the returned object is _not_
1779
 *      incremented to reflect the returned reference; if you want to keep a
1780
 *      reference to the object you must increment its ref count yourself.
1781
 *
1782
 *----------------------------------------------------------------------
1783
 */
1784
 
1785
Tcl_Obj *
1786
TclIncrVar2(interp, part1Ptr, part2Ptr, incrAmount, part1NotParsed)
1787
    Tcl_Interp *interp;         /* Command interpreter in which variable is
1788
                                 * to be found. */
1789
    Tcl_Obj *part1Ptr;          /* Points to an object holding the name of
1790
                                 * an array (if part2 is non-NULL) or the
1791
                                 * name of a variable. */
1792
    Tcl_Obj *part2Ptr;          /* If non-null, points to an object holding
1793
                                 * the name of an element in the array
1794
                                 * part1Ptr. */
1795
    long incrAmount;            /* Amount to be added to variable. */
1796
    int part1NotParsed;         /* 1 if part1 hasn't yet been parsed into
1797
                                 * an array name and index (if any). */
1798
{
1799
    register Tcl_Obj *varValuePtr;
1800
    Tcl_Obj *resultPtr;
1801
    int createdNewObj;          /* Set 1 if var's value object is shared
1802
                                 * so we must increment a copy (i.e. copy
1803
                                 * on write). */
1804
    long i;
1805
    int flags, result;
1806
 
1807
    flags = TCL_LEAVE_ERR_MSG;
1808
    if (part1NotParsed) {
1809
        flags |= TCL_PARSE_PART1;
1810
    }
1811
 
1812
    varValuePtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags);
1813
    if (varValuePtr == NULL) {
1814
        Tcl_AddObjErrorInfo(interp,
1815
                "\n    (reading value of variable to increment)", -1);
1816
        return NULL;
1817
    }
1818
 
1819
    /*
1820
     * Increment the variable's value. If the object is unshared we can
1821
     * modify it directly, otherwise we must create a new copy to modify:
1822
     * this is "copy on write". Then free the variable's old string
1823
     * representation, if any, since it will no longer be valid.
1824
     */
1825
 
1826
    createdNewObj = 0;
1827
    if (Tcl_IsShared(varValuePtr)) {
1828
        varValuePtr = Tcl_DuplicateObj(varValuePtr);
1829
        createdNewObj = 1;
1830
    }
1831
    result = Tcl_GetLongFromObj(interp, varValuePtr, &i);
1832
    if (result != TCL_OK) {
1833
        if (createdNewObj) {
1834
            Tcl_DecrRefCount(varValuePtr); /* free unneeded copy */
1835
        }
1836
        return NULL;
1837
    }
1838
    Tcl_SetLongObj(varValuePtr, (i + incrAmount));
1839
 
1840
    /*
1841
     * Store the variable's new value and run any write traces.
1842
     */
1843
 
1844
    resultPtr = Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, varValuePtr,
1845
            flags);
1846
    if (resultPtr == NULL) {
1847
        return NULL;
1848
    }
1849
    return resultPtr;
1850
}
1851
 
1852
/*
1853
 *----------------------------------------------------------------------
1854
 *
1855
 * TclIncrIndexedScalar --
1856
 *
1857
 *      Increments the Tcl object value of a local scalar variable in the
1858
 *      active procedure, given its compile-time allocated index in the
1859
 *      procedure's array of local variables.
1860
 *
1861
 * Results:
1862
 *      Returns a pointer to the Tcl_Obj holding the new value of the
1863
 *      variable given by localIndex. If the specified variable doesn't
1864
 *      exist, or there is a clash in array usage, or an error occurs while
1865
 *      executing variable traces, then NULL is returned and a message will
1866
 *      be left in the interpreter's result.
1867
 *
1868
 * Side effects:
1869
 *      The value of the given variable is incremented by the specified
1870
 *      amount. The ref count for the returned object is _not_ incremented
1871
 *      to reflect the returned reference; if you want to keep a reference
1872
 *      to the object you must increment its ref count yourself.
1873
 *
1874
 *----------------------------------------------------------------------
1875
 */
1876
 
1877
Tcl_Obj *
1878
TclIncrIndexedScalar(interp, localIndex, incrAmount)
1879
    Tcl_Interp *interp;         /* Command interpreter in which variable is
1880
                                 * to be found. */
1881
    int localIndex;             /* Index of variable in procedure's array
1882
                                 * of local variables. */
1883
    long incrAmount;            /* Amount to be added to variable. */
1884
{
1885
    register Tcl_Obj *varValuePtr;
1886
    Tcl_Obj *resultPtr;
1887
    int createdNewObj;          /* Set 1 if var's value object is shared
1888
                                 * so we must increment a copy (i.e. copy
1889
                                 * on write). */
1890
    long i;
1891
    int result;
1892
 
1893
    varValuePtr = TclGetIndexedScalar(interp, localIndex,
1894
                                      /*leaveErrorMsg*/ 1);
1895
    if (varValuePtr == NULL) {
1896
        Tcl_AddObjErrorInfo(interp,
1897
                "\n    (reading value of variable to increment)", -1);
1898
        return NULL;
1899
    }
1900
 
1901
    /*
1902
     * Reach into the object's representation to extract and increment the
1903
     * variable's value. If the object is unshared we can modify it
1904
     * directly, otherwise we must create a new copy to modify: this is
1905
     * "copy on write". Then free the variable's old string representation,
1906
     * if any, since it will no longer be valid.
1907
     */
1908
 
1909
    createdNewObj = 0;
1910
    if (Tcl_IsShared(varValuePtr)) {
1911
        createdNewObj = 1;
1912
        varValuePtr = Tcl_DuplicateObj(varValuePtr);
1913
    }
1914
    result = Tcl_GetLongFromObj(interp, varValuePtr, &i);
1915
    if (result != TCL_OK) {
1916
        if (createdNewObj) {
1917
            Tcl_DecrRefCount(varValuePtr); /* free unneeded copy */
1918
        }
1919
        return NULL;
1920
    }
1921
    Tcl_SetLongObj(varValuePtr, (i + incrAmount));
1922
 
1923
    /*
1924
     * Store the variable's new value and run any write traces.
1925
     */
1926
 
1927
    resultPtr = TclSetIndexedScalar(interp, localIndex, varValuePtr,
1928
                                    /*leaveErrorMsg*/ 1);
1929
    if (resultPtr == NULL) {
1930
        return NULL;
1931
    }
1932
    return resultPtr;
1933
}
1934
 
1935
/*
1936
 *----------------------------------------------------------------------
1937
 *
1938
 * TclIncrElementOfIndexedArray --
1939
 *
1940
 *      Increments the Tcl object value of an element in a local array
1941
 *      variable. The element is named by the object elemPtr while the array
1942
 *      is specified by its index in the active procedure's array of
1943
 *      compiler allocated local variables.
1944
 *
1945
 * Results:
1946
 *      Returns a pointer to the Tcl_Obj holding the new value of the
1947
 *      element. If the specified array or element doesn't exist, or there
1948
 *      is a clash in array usage, or an error occurs while executing
1949
 *      variable traces, then NULL is returned and a message will be left in
1950
 *      the interpreter's result.
1951
 *
1952
 * Side effects:
1953
 *      The value of the given array element is incremented by the specified
1954
 *      amount. The ref count for the returned object is _not_ incremented
1955
 *      to reflect the returned reference; if you want to keep a reference
1956
 *      to the object you must increment its ref count yourself. If the
1957
 *      entry doesn't exist then a new variable is created.
1958
 *
1959
 *----------------------------------------------------------------------
1960
 */
1961
 
1962
Tcl_Obj *
1963
TclIncrElementOfIndexedArray(interp, localIndex, elemPtr, incrAmount)
1964
    Tcl_Interp *interp;         /* Command interpreter in which the array is
1965
                                 * to be found. */
1966
    int localIndex;             /* Index of array variable in procedure's
1967
                                 * array of local variables. */
1968
    Tcl_Obj *elemPtr;           /* Points to an object holding the name of
1969
                                 * an element to increment in the array. */
1970
    long incrAmount;            /* Amount to be added to variable. */
1971
{
1972
    register Tcl_Obj *varValuePtr;
1973
    Tcl_Obj *resultPtr;
1974
    int createdNewObj;          /* Set 1 if var's value object is shared
1975
                                 * so we must increment a copy (i.e. copy
1976
                                 * on write). */
1977
    long i;
1978
    int result;
1979
 
1980
    varValuePtr = TclGetElementOfIndexedArray(interp, localIndex, elemPtr,
1981
                                              /*leaveErrorMsg*/ 1);
1982
    if (varValuePtr == NULL) {
1983
        Tcl_AddObjErrorInfo(interp,
1984
                "\n    (reading value of variable to increment)", -1);
1985
        return NULL;
1986
    }
1987
 
1988
    /*
1989
     * Reach into the object's representation to extract and increment the
1990
     * variable's value. If the object is unshared we can modify it
1991
     * directly, otherwise we must create a new copy to modify: this is
1992
     * "copy on write". Then free the variable's old string representation,
1993
     * if any, since it will no longer be valid.
1994
     */
1995
 
1996
    createdNewObj = 0;
1997
    if (Tcl_IsShared(varValuePtr)) {
1998
        createdNewObj = 1;
1999
        varValuePtr = Tcl_DuplicateObj(varValuePtr);
2000
    }
2001
    result = Tcl_GetLongFromObj(interp, varValuePtr, &i);
2002
    if (result != TCL_OK) {
2003
        if (createdNewObj) {
2004
            Tcl_DecrRefCount(varValuePtr); /* free unneeded copy */
2005
        }
2006
        return NULL;
2007
    }
2008
    Tcl_SetLongObj(varValuePtr, (i + incrAmount));
2009
 
2010
    /*
2011
     * Store the variable's new value and run any write traces.
2012
     */
2013
 
2014
    resultPtr = TclSetElementOfIndexedArray(interp, localIndex, elemPtr,
2015
                                            varValuePtr,
2016
                                            /*leaveErrorMsg*/ 1);
2017
    if (resultPtr == NULL) {
2018
        return NULL;
2019
    }
2020
    return resultPtr;
2021
}
2022
 
2023
/*
2024
 *----------------------------------------------------------------------
2025
 *
2026
 * Tcl_UnsetVar --
2027
 *
2028
 *      Delete a variable, so that it may not be accessed anymore.
2029
 *
2030
 * Results:
2031
 *      Returns TCL_OK if the variable was successfully deleted, TCL_ERROR
2032
 *      if the variable can't be unset.  In the event of an error,
2033
 *      if the TCL_LEAVE_ERR_MSG flag is set then an error message
2034
 *      is left in interp->result.
2035
 *
2036
 * Side effects:
2037
 *      If varName is defined as a local or global variable in interp,
2038
 *      it is deleted.
2039
 *
2040
 *----------------------------------------------------------------------
2041
 */
2042
 
2043
int
2044
Tcl_UnsetVar(interp, varName, flags)
2045
    Tcl_Interp *interp;         /* Command interpreter in which varName is
2046
                                 * to be looked up. */
2047
    char *varName;              /* Name of a variable in interp.  May be
2048
                                 * either a scalar name or an array name
2049
                                 * or an element in an array. */
2050
    int flags;                  /* OR-ed combination of any of
2051
                                 * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY or
2052
                                 * TCL_LEAVE_ERR_MSG. */
2053
{
2054
    return Tcl_UnsetVar2(interp, varName, (char *) NULL,
2055
            (flags | TCL_PARSE_PART1));
2056
}
2057
 
2058
/*
2059
 *----------------------------------------------------------------------
2060
 *
2061
 * Tcl_UnsetVar2 --
2062
 *
2063
 *      Delete a variable, given a 2-part name.
2064
 *
2065
 * Results:
2066
 *      Returns TCL_OK if the variable was successfully deleted, TCL_ERROR
2067
 *      if the variable can't be unset.  In the event of an error,
2068
 *      if the TCL_LEAVE_ERR_MSG flag is set then an error message
2069
 *      is left in interp->result.
2070
 *
2071
 * Side effects:
2072
 *      If part1 and part2 indicate a local or global variable in interp,
2073
 *      it is deleted.  If part1 is an array name and part2 is NULL, then
2074
 *      the whole array is deleted.
2075
 *
2076
 *----------------------------------------------------------------------
2077
 */
2078
 
2079
int
2080
Tcl_UnsetVar2(interp, part1, part2, flags)
2081
    Tcl_Interp *interp;         /* Command interpreter in which varName is
2082
                                 * to be looked up. */
2083
    char *part1;                /* Name of variable or array. */
2084
    char *part2;                /* Name of element within array or NULL. */
2085
    int flags;                  /* OR-ed combination of any of
2086
                                 * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
2087
                                 * TCL_LEAVE_ERR_MSG, or
2088
                                 * TCL_PARSE_PART1. */
2089
{
2090
    Var dummyVar;
2091
    Var *varPtr, *dummyVarPtr;
2092
    Interp *iPtr = (Interp *) interp;
2093
    Var *arrayPtr;
2094
    ActiveVarTrace *activePtr;
2095
    Tcl_Obj *objPtr;
2096
    int result;
2097
 
2098
    varPtr = TclLookupVar(interp, part1, part2, flags, "unset",
2099
            /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
2100
    if (varPtr == NULL) {
2101
        return TCL_ERROR;
2102
    }
2103
    result = (TclIsVarUndefined(varPtr)? TCL_ERROR : TCL_OK);
2104
 
2105
    if ((arrayPtr != NULL) && (arrayPtr->searchPtr != NULL)) {
2106
        DeleteSearches(arrayPtr);
2107
    }
2108
 
2109
    /*
2110
     * The code below is tricky, because of the possibility that
2111
     * a trace procedure might try to access a variable being
2112
     * deleted. To handle this situation gracefully, do things
2113
     * in three steps:
2114
     * 1. Copy the contents of the variable to a dummy variable
2115
     *    structure, and mark the original Var structure as undefined.
2116
     * 2. Invoke traces and clean up the variable, using the dummy copy.
2117
     * 3. If at the end of this the original variable is still
2118
     *    undefined and has no outstanding references, then delete
2119
     *    it (but it could have gotten recreated by a trace).
2120
     */
2121
 
2122
    dummyVar = *varPtr;
2123
    TclSetVarUndefined(varPtr);
2124
    TclSetVarScalar(varPtr);
2125
    varPtr->value.objPtr = NULL; /* dummyVar points to any value object */
2126
    varPtr->tracePtr = NULL;
2127
    varPtr->searchPtr = NULL;
2128
 
2129
    /*
2130
     * Call trace procedures for the variable being deleted. Then delete
2131
     * its traces. Be sure to abort any other traces for the variable
2132
     * that are still pending. Special tricks:
2133
     * 1. We need to increment varPtr's refCount around this: CallTraces
2134
     *    will use dummyVar so it won't increment varPtr's refCount itself.
2135
     * 2. Turn off the VAR_TRACE_ACTIVE flag in dummyVar: we want to
2136
     *    call unset traces even if other traces are pending.
2137
     */
2138
 
2139
    if ((dummyVar.tracePtr != NULL)
2140
            || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
2141
        varPtr->refCount++;
2142
        dummyVar.flags &= ~VAR_TRACE_ACTIVE;
2143
        (void) CallTraces(iPtr, arrayPtr, &dummyVar, part1, part2,
2144
                (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_PARSE_PART1)) | TCL_TRACE_UNSETS);
2145
        while (dummyVar.tracePtr != NULL) {
2146
            VarTrace *tracePtr = dummyVar.tracePtr;
2147
            dummyVar.tracePtr = tracePtr->nextPtr;
2148
            ckfree((char *) tracePtr);
2149
        }
2150
        for (activePtr = iPtr->activeTracePtr;  activePtr != NULL;
2151
                activePtr = activePtr->nextPtr) {
2152
            if (activePtr->varPtr == varPtr) {
2153
                activePtr->nextTracePtr = NULL;
2154
            }
2155
        }
2156
        varPtr->refCount--;
2157
    }
2158
 
2159
    /*
2160
     * If the variable is an array, delete all of its elements. This must be
2161
     * done after calling the traces on the array, above (that's the way
2162
     * traces are defined). If it is a scalar, "discard" its object
2163
     * (decrement the ref count of its object, if any).
2164
     */
2165
 
2166
    dummyVarPtr = &dummyVar;
2167
    if (TclIsVarArray(dummyVarPtr) && !TclIsVarUndefined(dummyVarPtr)) {
2168
        DeleteArray(iPtr, part1, dummyVarPtr,
2169
            (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS);
2170
    }
2171
    if (TclIsVarScalar(dummyVarPtr)
2172
            && (dummyVarPtr->value.objPtr != NULL)) {
2173
        objPtr = dummyVarPtr->value.objPtr;
2174
        TclDecrRefCount(objPtr);
2175
        dummyVarPtr->value.objPtr = NULL;
2176
    }
2177
 
2178
    /*
2179
     * If the variable was a namespace variable, decrement its reference
2180
     * count. We are in the process of destroying its namespace so that
2181
     * namespace will no longer "refer" to the variable.
2182
     */
2183
 
2184
    if (varPtr->flags & VAR_NAMESPACE_VAR) {
2185
        varPtr->flags &= ~VAR_NAMESPACE_VAR;
2186
        varPtr->refCount--;
2187
    }
2188
 
2189
    /*
2190
     * It's an error to unset an undefined variable.
2191
     */
2192
 
2193
    if (result != TCL_OK) {
2194
        if (flags & TCL_LEAVE_ERR_MSG) {
2195
            VarErrMsg(interp, part1, part2, "unset",
2196
                    ((arrayPtr == NULL) ? noSuchVar : noSuchElement));
2197
        }
2198
    }
2199
 
2200
    /*
2201
     * Finally, if the variable is truly not in use then free up its Var
2202
     * structure and remove it from its hash table, if any. The ref count of
2203
     * its value object, if any, was decremented above.
2204
     */
2205
 
2206
    CleanupVar(varPtr, arrayPtr);
2207
    return result;
2208
}
2209
 
2210
/*
2211
 *----------------------------------------------------------------------
2212
 *
2213
 * Tcl_TraceVar --
2214
 *
2215
 *      Arrange for reads and/or writes to a variable to cause a
2216
 *      procedure to be invoked, which can monitor the operations
2217
 *      and/or change their actions.
2218
 *
2219
 * Results:
2220
 *      A standard Tcl return value.
2221
 *
2222
 * Side effects:
2223
 *      A trace is set up on the variable given by varName, such that
2224
 *      future references to the variable will be intermediated by
2225
 *      proc.  See the manual entry for complete details on the calling
2226
 *      sequence for proc.
2227
 *
2228
 *----------------------------------------------------------------------
2229
 */
2230
 
2231
int
2232
Tcl_TraceVar(interp, varName, flags, proc, clientData)
2233
    Tcl_Interp *interp;         /* Interpreter in which variable is
2234
                                 * to be traced. */
2235
    char *varName;              /* Name of variable;  may end with "(index)"
2236
                                 * to signify an array reference. */
2237
    int flags;                  /* OR-ed collection of bits, including any
2238
                                 * of TCL_TRACE_READS, TCL_TRACE_WRITES,
2239
                                 * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY, and
2240
                                 * TCL_NAMESPACE_ONLY. */
2241
    Tcl_VarTraceProc *proc;     /* Procedure to call when specified ops are
2242
                                 * invoked upon varName. */
2243
    ClientData clientData;      /* Arbitrary argument to pass to proc. */
2244
{
2245
    return Tcl_TraceVar2(interp, varName, (char *) NULL,
2246
            (flags | TCL_PARSE_PART1), proc, clientData);
2247
}
2248
 
2249
/*
2250
 *----------------------------------------------------------------------
2251
 *
2252
 * Tcl_TraceVar2 --
2253
 *
2254
 *      Arrange for reads and/or writes to a variable to cause a
2255
 *      procedure to be invoked, which can monitor the operations
2256
 *      and/or change their actions.
2257
 *
2258
 * Results:
2259
 *      A standard Tcl return value.
2260
 *
2261
 * Side effects:
2262
 *      A trace is set up on the variable given by part1 and part2, such
2263
 *      that future references to the variable will be intermediated by
2264
 *      proc.  See the manual entry for complete details on the calling
2265
 *      sequence for proc.
2266
 *
2267
 *----------------------------------------------------------------------
2268
 */
2269
 
2270
int
2271
Tcl_TraceVar2(interp, part1, part2, flags, proc, clientData)
2272
    Tcl_Interp *interp;         /* Interpreter in which variable is
2273
                                 * to be traced. */
2274
    char *part1;                /* Name of scalar variable or array. */
2275
    char *part2;                /* Name of element within array;  NULL means
2276
                                 * trace applies to scalar variable or array
2277
                                 * as-a-whole. */
2278
    int flags;                  /* OR-ed collection of bits, including any
2279
                                 * of TCL_TRACE_READS, TCL_TRACE_WRITES,
2280
                                 * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY,
2281
                                 * TCL_NAMESPACE_ONLY and
2282
                                 * TCL_PARSE_PART1. */
2283
    Tcl_VarTraceProc *proc;     /* Procedure to call when specified ops are
2284
                                 * invoked upon varName. */
2285
    ClientData clientData;      /* Arbitrary argument to pass to proc. */
2286
{
2287
    Var *varPtr, *arrayPtr;
2288
    register VarTrace *tracePtr;
2289
 
2290
    varPtr = TclLookupVar(interp, part1, part2, (flags | TCL_LEAVE_ERR_MSG),
2291
            "trace", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
2292
    if (varPtr == NULL) {
2293
        return TCL_ERROR;
2294
    }
2295
 
2296
    /*
2297
     * Set up trace information.
2298
     */
2299
 
2300
    tracePtr = (VarTrace *) ckalloc(sizeof(VarTrace));
2301
    tracePtr->traceProc = proc;
2302
    tracePtr->clientData = clientData;
2303
    tracePtr->flags =
2304
            flags & (TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS);
2305
    tracePtr->nextPtr = varPtr->tracePtr;
2306
    varPtr->tracePtr = tracePtr;
2307
    return TCL_OK;
2308
}
2309
 
2310
/*
2311
 *----------------------------------------------------------------------
2312
 *
2313
 * Tcl_UntraceVar --
2314
 *
2315
 *      Remove a previously-created trace for a variable.
2316
 *
2317
 * Results:
2318
 *      None.
2319
 *
2320
 * Side effects:
2321
 *      If there exists a trace for the variable given by varName
2322
 *      with the given flags, proc, and clientData, then that trace
2323
 *      is removed.
2324
 *
2325
 *----------------------------------------------------------------------
2326
 */
2327
 
2328
void
2329
Tcl_UntraceVar(interp, varName, flags, proc, clientData)
2330
    Tcl_Interp *interp;         /* Interpreter containing variable. */
2331
    char *varName;              /* Name of variable; may end with "(index)"
2332
                                 * to signify an array reference. */
2333
    int flags;                  /* OR-ed collection of bits describing
2334
                                 * current trace, including any of
2335
                                 * TCL_TRACE_READS, TCL_TRACE_WRITES,
2336
                                 * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY
2337
                                 * and TCL_NAMESPACE_ONLY. */
2338
    Tcl_VarTraceProc *proc;     /* Procedure assocated with trace. */
2339
    ClientData clientData;      /* Arbitrary argument to pass to proc. */
2340
{
2341
    Tcl_UntraceVar2(interp, varName, (char *) NULL,
2342
                    (flags | TCL_PARSE_PART1), proc, clientData);
2343
}
2344
 
2345
/*
2346
 *----------------------------------------------------------------------
2347
 *
2348
 * Tcl_UntraceVar2 --
2349
 *
2350
 *      Remove a previously-created trace for a variable.
2351
 *
2352
 * Results:
2353
 *      None.
2354
 *
2355
 * Side effects:
2356
 *      If there exists a trace for the variable given by part1
2357
 *      and part2 with the given flags, proc, and clientData, then
2358
 *      that trace is removed.
2359
 *
2360
 *----------------------------------------------------------------------
2361
 */
2362
 
2363
void
2364
Tcl_UntraceVar2(interp, part1, part2, flags, proc, clientData)
2365
    Tcl_Interp *interp;         /* Interpreter containing variable. */
2366
    char *part1;                /* Name of variable or array. */
2367
    char *part2;                /* Name of element within array;  NULL means
2368
                                 * trace applies to scalar variable or array
2369
                                 * as-a-whole. */
2370
    int flags;                  /* OR-ed collection of bits describing
2371
                                 * current trace, including any of
2372
                                 * TCL_TRACE_READS, TCL_TRACE_WRITES,
2373
                                 * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY,
2374
                                 * TCL_NAMESPACE_ONLY and
2375
                                 * TCL_PARSE_PART1. */
2376
    Tcl_VarTraceProc *proc;     /* Procedure assocated with trace. */
2377
    ClientData clientData;      /* Arbitrary argument to pass to proc. */
2378
{
2379
    register VarTrace *tracePtr;
2380
    VarTrace *prevPtr;
2381
    Var *varPtr, *arrayPtr;
2382
    Interp *iPtr = (Interp *) interp;
2383
    ActiveVarTrace *activePtr;
2384
 
2385
    varPtr = TclLookupVar(interp, part1, part2,
2386
            flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_PARSE_PART1),
2387
            /*msg*/ (char *) NULL,
2388
            /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
2389
    if (varPtr == NULL) {
2390
        return;
2391
    }
2392
 
2393
    flags &= (TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS);
2394
    for (tracePtr = varPtr->tracePtr, prevPtr = NULL;  ;
2395
            prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) {
2396
        if (tracePtr == NULL) {
2397
            return;
2398
        }
2399
        if ((tracePtr->traceProc == proc) && (tracePtr->flags == flags)
2400
                && (tracePtr->clientData == clientData)) {
2401
            break;
2402
        }
2403
    }
2404
 
2405
    /*
2406
     * The code below makes it possible to delete traces while traces
2407
     * are active: it makes sure that the deleted trace won't be
2408
     * processed by CallTraces.
2409
     */
2410
 
2411
    for (activePtr = iPtr->activeTracePtr;  activePtr != NULL;
2412
            activePtr = activePtr->nextPtr) {
2413
        if (activePtr->nextTracePtr == tracePtr) {
2414
            activePtr->nextTracePtr = tracePtr->nextPtr;
2415
        }
2416
    }
2417
    if (prevPtr == NULL) {
2418
        varPtr->tracePtr = tracePtr->nextPtr;
2419
    } else {
2420
        prevPtr->nextPtr = tracePtr->nextPtr;
2421
    }
2422
    ckfree((char *) tracePtr);
2423
 
2424
    /*
2425
     * If this is the last trace on the variable, and the variable is
2426
     * unset and unused, then free up the variable.
2427
     */
2428
 
2429
    if (TclIsVarUndefined(varPtr)) {
2430
        CleanupVar(varPtr, (Var *) NULL);
2431
    }
2432
}
2433
 
2434
/*
2435
 *----------------------------------------------------------------------
2436
 *
2437
 * Tcl_VarTraceInfo --
2438
 *
2439
 *      Return the clientData value associated with a trace on a
2440
 *      variable.  This procedure can also be used to step through
2441
 *      all of the traces on a particular variable that have the
2442
 *      same trace procedure.
2443
 *
2444
 * Results:
2445
 *      The return value is the clientData value associated with
2446
 *      a trace on the given variable.  Information will only be
2447
 *      returned for a trace with proc as trace procedure.  If
2448
 *      the clientData argument is NULL then the first such trace is
2449
 *      returned;  otherwise, the next relevant one after the one
2450
 *      given by clientData will be returned.  If the variable
2451
 *      doesn't exist, or if there are no (more) traces for it,
2452
 *      then NULL is returned.
2453
 *
2454
 * Side effects:
2455
 *      None.
2456
 *
2457
 *----------------------------------------------------------------------
2458
 */
2459
 
2460
ClientData
2461
Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData)
2462
    Tcl_Interp *interp;         /* Interpreter containing variable. */
2463
    char *varName;              /* Name of variable;  may end with "(index)"
2464
                                 * to signify an array reference. */
2465
    int flags;                  /* 0, TCL_GLOBAL_ONLY, or
2466
                                 * TCL_NAMESPACE_ONLY. */
2467
    Tcl_VarTraceProc *proc;     /* Procedure assocated with trace. */
2468
    ClientData prevClientData;  /* If non-NULL, gives last value returned
2469
                                 * by this procedure, so this call will
2470
                                 * return the next trace after that one.
2471
                                 * If NULL, this call will return the
2472
                                 * first trace. */
2473
{
2474
    return Tcl_VarTraceInfo2(interp, varName, (char *) NULL,
2475
            (flags | TCL_PARSE_PART1), proc, prevClientData);
2476
}
2477
 
2478
/*
2479
 *----------------------------------------------------------------------
2480
 *
2481
 * Tcl_VarTraceInfo2 --
2482
 *
2483
 *      Same as Tcl_VarTraceInfo, except takes name in two pieces
2484
 *      instead of one.
2485
 *
2486
 * Results:
2487
 *      Same as Tcl_VarTraceInfo.
2488
 *
2489
 * Side effects:
2490
 *      None.
2491
 *
2492
 *----------------------------------------------------------------------
2493
 */
2494
 
2495
ClientData
2496
Tcl_VarTraceInfo2(interp, part1, part2, flags, proc, prevClientData)
2497
    Tcl_Interp *interp;         /* Interpreter containing variable. */
2498
    char *part1;                /* Name of variable or array. */
2499
    char *part2;                /* Name of element within array;  NULL means
2500
                                 * trace applies to scalar variable or array
2501
                                 * as-a-whole. */
2502
    int flags;                  /* OR-ed combination of TCL_GLOBAL_ONLY,
2503
                                 * TCL_NAMESPACE_ONLY, and
2504
                                 * TCL_PARSE_PART1. */
2505
    Tcl_VarTraceProc *proc;     /* Procedure assocated with trace. */
2506
    ClientData prevClientData;  /* If non-NULL, gives last value returned
2507
                                 * by this procedure, so this call will
2508
                                 * return the next trace after that one.
2509
                                 * If NULL, this call will return the
2510
                                 * first trace. */
2511
{
2512
    register VarTrace *tracePtr;
2513
    Var *varPtr, *arrayPtr;
2514
 
2515
    varPtr = TclLookupVar(interp, part1, part2,
2516
            flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_PARSE_PART1),
2517
            /*msg*/ (char *) NULL,
2518
            /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
2519
    if (varPtr == NULL) {
2520
        return NULL;
2521
    }
2522
 
2523
    /*
2524
     * Find the relevant trace, if any, and return its clientData.
2525
     */
2526
 
2527
    tracePtr = varPtr->tracePtr;
2528
    if (prevClientData != NULL) {
2529
        for ( ;  tracePtr != NULL;  tracePtr = tracePtr->nextPtr) {
2530
            if ((tracePtr->clientData == prevClientData)
2531
                    && (tracePtr->traceProc == proc)) {
2532
                tracePtr = tracePtr->nextPtr;
2533
                break;
2534
            }
2535
        }
2536
    }
2537
    for ( ;  tracePtr != NULL;  tracePtr = tracePtr->nextPtr) {
2538
        if (tracePtr->traceProc == proc) {
2539
            return tracePtr->clientData;
2540
        }
2541
    }
2542
    return NULL;
2543
}
2544
 
2545
/*
2546
 *----------------------------------------------------------------------
2547
 *
2548
 * Tcl_UnsetObjCmd --
2549
 *
2550
 *      This object-based procedure is invoked to process the "unset" Tcl
2551
 *      command. See the user documentation for details on what it does.
2552
 *
2553
 * Results:
2554
 *      A standard Tcl object result value.
2555
 *
2556
 * Side effects:
2557
 *      See the user documentation.
2558
 *
2559
 *----------------------------------------------------------------------
2560
 */
2561
 
2562
        /* ARGSUSED */
2563
int
2564
Tcl_UnsetObjCmd(dummy, interp, objc, objv)
2565
    ClientData dummy;           /* Not used. */
2566
    Tcl_Interp *interp;         /* Current interpreter. */
2567
    int objc;                   /* Number of arguments. */
2568
    Tcl_Obj *CONST objv[];      /* Argument objects. */
2569
{
2570
    register int i;
2571
    register char *name;
2572
 
2573
    if (objc < 2) {
2574
        Tcl_WrongNumArgs(interp, 1, objv, "varName ?varName ...?");
2575
        return TCL_ERROR;
2576
    }
2577
 
2578
    for (i = 1;  i < objc;  i++) {
2579
        /*
2580
         * THIS FAILS IF A NAME OBJECT'S STRING REP HAS A NULL BYTE.
2581
         */
2582
 
2583
        name = Tcl_GetStringFromObj(objv[i], (int *) NULL);
2584
        if (Tcl_UnsetVar2(interp, name, (char *) NULL,
2585
                (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1)) != TCL_OK) {
2586
            return TCL_ERROR;
2587
        }
2588
    }
2589
    return TCL_OK;
2590
}
2591
 
2592
/*
2593
 *----------------------------------------------------------------------
2594
 *
2595
 * Tcl_AppendObjCmd --
2596
 *
2597
 *      This object-based procedure is invoked to process the "append"
2598
 *      Tcl command. See the user documentation for details on what it does.
2599
 *
2600
 * Results:
2601
 *      A standard Tcl object result value.
2602
 *
2603
 * Side effects:
2604
 *      A variable's value may be changed.
2605
 *
2606
 *----------------------------------------------------------------------
2607
 */
2608
 
2609
        /* ARGSUSED */
2610
int
2611
Tcl_AppendObjCmd(dummy, interp, objc, objv)
2612
    ClientData dummy;           /* Not used. */
2613
    Tcl_Interp *interp;         /* Current interpreter. */
2614
    int objc;                   /* Number of arguments. */
2615
    Tcl_Obj *CONST objv[];      /* Argument objects. */
2616
{
2617
    register Tcl_Obj *varValuePtr = NULL;
2618
                                        /* Initialized to avoid compiler
2619
                                         * warning. */
2620
    int i;
2621
 
2622
    if (objc < 2) {
2623
        Tcl_WrongNumArgs(interp, 1, objv, "varName ?value value ...?");
2624
        return TCL_ERROR;
2625
    }
2626
 
2627
    if (objc == 2) {
2628
        varValuePtr = Tcl_ObjGetVar2(interp, objv[1], (Tcl_Obj *) NULL,
2629
                (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
2630
        if (varValuePtr == NULL) {
2631
            return TCL_ERROR;
2632
        }
2633
    } else {
2634
        for (i = 2;  i < objc;  i++) {
2635
            varValuePtr = Tcl_ObjSetVar2(interp, objv[1], (Tcl_Obj *) NULL,
2636
                objv[i],
2637
                (TCL_APPEND_VALUE | TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
2638
            if (varValuePtr == NULL) {
2639
                return TCL_ERROR;
2640
            }
2641
        }
2642
    }
2643
 
2644
    Tcl_SetObjResult(interp, varValuePtr);
2645
    return TCL_OK;
2646
}
2647
 
2648
/*
2649
 *----------------------------------------------------------------------
2650
 *
2651
 * Tcl_LappendObjCmd --
2652
 *
2653
 *      This object-based procedure is invoked to process the "lappend"
2654
 *      Tcl command. See the user documentation for details on what it does.
2655
 *
2656
 * Results:
2657
 *      A standard Tcl object result value.
2658
 *
2659
 * Side effects:
2660
 *      A variable's value may be changed.
2661
 *
2662
 *----------------------------------------------------------------------
2663
 */
2664
 
2665
        /* ARGSUSED */
2666
int
2667
Tcl_LappendObjCmd(dummy, interp, objc, objv)
2668
    ClientData dummy;           /* Not used. */
2669
    Tcl_Interp *interp;         /* Current interpreter. */
2670
    int objc;                   /* Number of arguments. */
2671
    Tcl_Obj *CONST objv[];      /* Argument objects. */
2672
{
2673
    Tcl_Obj *varValuePtr, *newValuePtr;
2674
    register List *listRepPtr;
2675
    register Tcl_Obj **elemPtrs;
2676
    int numElems, numRequired, createdNewObj, createVar, i, j;
2677
 
2678
    if (objc < 2) {
2679
        Tcl_WrongNumArgs(interp, 1, objv, "varName ?value value ...?");
2680
        return TCL_ERROR;
2681
    }
2682
 
2683
    if (objc == 2) {
2684
        newValuePtr = Tcl_ObjGetVar2(interp, objv[1], (Tcl_Obj *) NULL,
2685
            (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
2686
        if (newValuePtr == NULL) {
2687
            /*
2688
             * The variable doesn't exist yet. Just create it with an empty
2689
             * initial value.
2690
             */
2691
 
2692
            Tcl_Obj *nullObjPtr = Tcl_NewObj();
2693
            newValuePtr = Tcl_ObjSetVar2(interp, objv[1], NULL,
2694
                    nullObjPtr, (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
2695
            if (newValuePtr == NULL) {
2696
                Tcl_DecrRefCount(nullObjPtr); /* free unneeded object */
2697
                return TCL_ERROR;
2698
            }
2699
        }
2700
    } else {
2701
        /*
2702
         * We have arguments to append. We used to call Tcl_ObjSetVar2 to
2703
         * append each argument one at a time to ensure that traces were run
2704
         * for each append step. We now append the arguments all at once
2705
         * because it's faster. Note that a read trace and a write trace for
2706
         * the variable will now each only be called once. Also, if the
2707
         * variable's old value is unshared we modify it directly, otherwise
2708
         * we create a new copy to modify: this is "copy on write".
2709
         */
2710
 
2711
        createdNewObj = 0;
2712
        createVar = 1;
2713
        varValuePtr = Tcl_ObjGetVar2(interp, objv[1], (Tcl_Obj *) NULL,
2714
                TCL_PARSE_PART1);
2715
        if (varValuePtr == NULL) {
2716
            /*
2717
             * We couldn't read the old value: either the var doesn't yet
2718
             * exist or it's an array element. If it's new, we will try to
2719
             * create it with Tcl_ObjSetVar2 below.
2720
             */
2721
 
2722
            char *name, *p;
2723
            int nameBytes, i;
2724
 
2725
            name = TclGetStringFromObj(objv[1], &nameBytes);
2726
            for (i = 0, p = name;  i < nameBytes;  i++, p++) {
2727
                if (*p == '(') {
2728
                    p = (name + nameBytes-1);
2729
                    if (*p == ')') { /* last char is ')' => array ref */
2730
                        createVar = 0;
2731
                    }
2732
                    break;
2733
                }
2734
            }
2735
            varValuePtr = Tcl_NewObj();
2736
            createdNewObj = 1;
2737
        } else if (Tcl_IsShared(varValuePtr)) {
2738
            varValuePtr = Tcl_DuplicateObj(varValuePtr);
2739
            createdNewObj = 1;
2740
        }
2741
 
2742
        /*
2743
         * Convert the variable's old value to a list object if necessary.
2744
         */
2745
 
2746
        if (varValuePtr->typePtr != &tclListType) {
2747
            int result = tclListType.setFromAnyProc(interp, varValuePtr);
2748
            if (result != TCL_OK) {
2749
                if (createdNewObj) {
2750
                    Tcl_DecrRefCount(varValuePtr); /* free unneeded obj. */
2751
                }
2752
                return result;
2753
            }
2754
        }
2755
        listRepPtr = (List *) varValuePtr->internalRep.otherValuePtr;
2756
        elemPtrs = listRepPtr->elements;
2757
        numElems = listRepPtr->elemCount;
2758
 
2759
        /*
2760
         * If there is no room in the current array of element pointers,
2761
         * allocate a new, larger array and copy the pointers to it.
2762
         */
2763
 
2764
        numRequired = numElems + (objc-2);
2765
        if (numRequired > listRepPtr->maxElemCount) {
2766
            int newMax = (2 * numRequired);
2767
            Tcl_Obj **newElemPtrs = (Tcl_Obj **)
2768
                    ckalloc((unsigned) (newMax * sizeof(Tcl_Obj *)));
2769
 
2770
            memcpy((VOID *) newElemPtrs, (VOID *) elemPtrs,
2771
                    (size_t) (numElems * sizeof(Tcl_Obj *)));
2772
            listRepPtr->maxElemCount = newMax;
2773
            listRepPtr->elements = newElemPtrs;
2774
            ckfree((char *) elemPtrs);
2775
            elemPtrs = newElemPtrs;
2776
        }
2777
 
2778
        /*
2779
         * Insert the new elements at the end of the list.
2780
         */
2781
 
2782
        for (i = 2, j = numElems;  i < objc;  i++, j++) {
2783
            elemPtrs[j] = objv[i];
2784
            Tcl_IncrRefCount(objv[i]);
2785
        }
2786
        listRepPtr->elemCount = numRequired;
2787
 
2788
        /*
2789
         * Invalidate and free any old string representation since it no
2790
         * longer reflects the list's internal representation.
2791
         */
2792
 
2793
        Tcl_InvalidateStringRep(varValuePtr);
2794
 
2795
        /*
2796
         * Now store the list object back into the variable. If there is an
2797
         * error setting the new value, decrement its ref count if it
2798
         * was new and we didn't create the variable.
2799
         */
2800
 
2801
        newValuePtr = Tcl_ObjSetVar2(interp, objv[1], (Tcl_Obj *) NULL,
2802
                varValuePtr, (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
2803
        if (newValuePtr == NULL) {
2804
            if (createdNewObj && !createVar) {
2805
                Tcl_DecrRefCount(varValuePtr); /* free unneeded obj */
2806
            }
2807
            return TCL_ERROR;
2808
        }
2809
    }
2810
 
2811
    /*
2812
     * Set the interpreter's object result to refer to the variable's value
2813
     * object.
2814
     */
2815
 
2816
    Tcl_SetObjResult(interp, newValuePtr);
2817
    return TCL_OK;
2818
}
2819
 
2820
/*
2821
 *----------------------------------------------------------------------
2822
 *
2823
 * Tcl_ArrayObjCmd --
2824
 *
2825
 *      This object-based procedure is invoked to process the "array" Tcl
2826
 *      command. See the user documentation for details on what it does.
2827
 *
2828
 * Results:
2829
 *      A standard Tcl result object.
2830
 *
2831
 * Side effects:
2832
 *      See the user documentation.
2833
 *
2834
 *----------------------------------------------------------------------
2835
 */
2836
 
2837
        /* ARGSUSED */
2838
int
2839
Tcl_ArrayObjCmd(dummy, interp, objc, objv)
2840
    ClientData dummy;           /* Not used. */
2841
    Tcl_Interp *interp;         /* Current interpreter. */
2842
    int objc;                   /* Number of arguments. */
2843
    Tcl_Obj *CONST objv[];      /* Argument objects. */
2844
{
2845
    /*
2846
     * The list of constants below should match the arrayOptions string array
2847
     * below.
2848
     */
2849
 
2850
    enum {ARRAY_ANYMORE, ARRAY_DONESEARCH,  ARRAY_EXISTS, ARRAY_GET,
2851
          ARRAY_NAMES, ARRAY_NEXTELEMENT, ARRAY_SET, ARRAY_SIZE,
2852
          ARRAY_STARTSEARCH};
2853
    static char *arrayOptions[] = {"anymore", "donesearch", "exists",
2854
            "get", "names", "nextelement", "set", "size", "startsearch",
2855
            (char *) NULL};
2856
 
2857
    Var *varPtr, *arrayPtr;
2858
    Tcl_HashEntry *hPtr;
2859
    Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
2860
    int notArray;
2861
    char *varName;
2862
    int index, result;
2863
 
2864
 
2865
    if (objc < 3) {
2866
        Tcl_WrongNumArgs(interp, 1, objv, "option arrayName ?arg ...?");
2867
        return TCL_ERROR;
2868
    }
2869
 
2870
    if (Tcl_GetIndexFromObj(interp, objv[1], arrayOptions, "option", 0, &index)
2871
            != TCL_OK) {
2872
        return TCL_ERROR;
2873
    }
2874
 
2875
    /*
2876
     * Locate the array variable (and it better be an array).
2877
     * THIS FAILS IF A NAME OBJECT'S STRING REP HAS A NULL BYTE.
2878
     */
2879
 
2880
    varName = TclGetStringFromObj(objv[2], (int *) NULL);
2881
    varPtr = TclLookupVar(interp, varName, (char *) NULL, /*flags*/ 0,
2882
            /*msg*/ 0, /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
2883
 
2884
    notArray = 0;
2885
    if ((varPtr == NULL) || !TclIsVarArray(varPtr)
2886
            || TclIsVarUndefined(varPtr)) {
2887
        notArray = 1;
2888
    }
2889
 
2890
    switch (index) {
2891
        case ARRAY_ANYMORE: {
2892
            ArraySearch *searchPtr;
2893
            char *searchId;
2894
 
2895
            if (objc != 4) {
2896
                Tcl_WrongNumArgs(interp, 2, objv,
2897
                        "arrayName searchId");
2898
                return TCL_ERROR;
2899
            }
2900
            if (notArray) {
2901
                goto error;
2902
            }
2903
            searchId = Tcl_GetStringFromObj(objv[3], (int *) NULL);
2904
            searchPtr = ParseSearchId(interp, varPtr, varName, searchId);
2905
            if (searchPtr == NULL) {
2906
                return TCL_ERROR;
2907
            }
2908
            while (1) {
2909
                Var *varPtr2;
2910
 
2911
                if (searchPtr->nextEntry != NULL) {
2912
                    varPtr2 = (Var *) Tcl_GetHashValue(searchPtr->nextEntry);
2913
                    if (!TclIsVarUndefined(varPtr2)) {
2914
                        break;
2915
                    }
2916
                }
2917
                searchPtr->nextEntry = Tcl_NextHashEntry(&searchPtr->search);
2918
                if (searchPtr->nextEntry == NULL) {
2919
                    Tcl_SetIntObj(resultPtr, 0);
2920
                    return TCL_OK;
2921
                }
2922
            }
2923
            Tcl_SetIntObj(resultPtr, 1);
2924
            break;
2925
        }
2926
        case ARRAY_DONESEARCH: {
2927
            ArraySearch *searchPtr, *prevPtr;
2928
            char *searchId;
2929
 
2930
            if (objc != 4) {
2931
                Tcl_WrongNumArgs(interp, 2, objv,
2932
                        "arrayName searchId");
2933
                return TCL_ERROR;
2934
            }
2935
            if (notArray) {
2936
                goto error;
2937
            }
2938
            searchId = Tcl_GetStringFromObj(objv[3], (int *) NULL);
2939
            searchPtr = ParseSearchId(interp, varPtr, varName, searchId);
2940
            if (searchPtr == NULL) {
2941
                return TCL_ERROR;
2942
            }
2943
            if (varPtr->searchPtr == searchPtr) {
2944
                varPtr->searchPtr = searchPtr->nextPtr;
2945
            } else {
2946
                for (prevPtr = varPtr->searchPtr;  ;
2947
                        prevPtr = prevPtr->nextPtr) {
2948
                    if (prevPtr->nextPtr == searchPtr) {
2949
                        prevPtr->nextPtr = searchPtr->nextPtr;
2950
                        break;
2951
                    }
2952
                }
2953
            }
2954
            ckfree((char *) searchPtr);
2955
            break;
2956
        }
2957
        case ARRAY_EXISTS: {
2958
            if (objc != 3) {
2959
                Tcl_WrongNumArgs(interp, 2, objv, "arrayName");
2960
                return TCL_ERROR;
2961
            }
2962
            Tcl_SetIntObj(resultPtr, !notArray);
2963
            break;
2964
        }
2965
        case ARRAY_GET: {
2966
            Tcl_HashSearch search;
2967
            Var *varPtr2;
2968
            char *pattern = NULL;
2969
            char *name;
2970
            Tcl_Obj *namePtr, *valuePtr;
2971
 
2972
            if ((objc != 3) && (objc != 4)) {
2973
                Tcl_WrongNumArgs(interp, 2, objv, "arrayName ?pattern?");
2974
                return TCL_ERROR;
2975
            }
2976
            if (notArray) {
2977
                return TCL_OK;
2978
            }
2979
            if (objc == 4) {
2980
                pattern = Tcl_GetStringFromObj(objv[3], (int *) NULL);
2981
            }
2982
            for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
2983
                    hPtr != NULL;  hPtr = Tcl_NextHashEntry(&search)) {
2984
                varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
2985
                if (TclIsVarUndefined(varPtr2)) {
2986
                    continue;
2987
                }
2988
                name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr);
2989
                if ((objc == 4) && !Tcl_StringMatch(name, pattern)) {
2990
                    continue;   /* element name doesn't match pattern */
2991
                }
2992
 
2993
                namePtr = Tcl_NewStringObj(name, -1);
2994
                result = Tcl_ListObjAppendElement(interp, resultPtr,
2995
                        namePtr);
2996
                if (result != TCL_OK) {
2997
                    Tcl_DecrRefCount(namePtr); /* free unneeded name obj */
2998
                    return result;
2999
                }
3000
 
3001
                valuePtr = Tcl_ObjGetVar2(interp, objv[2], namePtr,
3002
                        TCL_LEAVE_ERR_MSG);
3003
                if (valuePtr == NULL) {
3004
                    Tcl_DecrRefCount(namePtr); /* free unneeded name obj */
3005
                    return result;
3006
                }
3007
                result = Tcl_ListObjAppendElement(interp, resultPtr,
3008
                        valuePtr);
3009
                if (result != TCL_OK) {
3010
                    Tcl_DecrRefCount(namePtr); /* free unneeded name obj */
3011
                    return result;
3012
                }
3013
            }
3014
            break;
3015
        }
3016
        case ARRAY_NAMES: {
3017
            Tcl_HashSearch search;
3018
            Var *varPtr2;
3019
            char *pattern = NULL;
3020
            char *name;
3021
            Tcl_Obj *namePtr;
3022
 
3023
            if ((objc != 3) && (objc != 4)) {
3024
                Tcl_WrongNumArgs(interp, 2, objv, "arrayName ?pattern?");
3025
                return TCL_ERROR;
3026
            }
3027
            if (notArray) {
3028
                return TCL_OK;
3029
            }
3030
            if (objc == 4) {
3031
                pattern = Tcl_GetStringFromObj(objv[3], (int *) NULL);
3032
            }
3033
            for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
3034
                    hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
3035
                varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
3036
                if (TclIsVarUndefined(varPtr2)) {
3037
                    continue;
3038
                }
3039
                name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr);
3040
                if ((objc == 4) && !Tcl_StringMatch(name, pattern)) {
3041
                    continue;   /* element name doesn't match pattern */
3042
                }
3043
 
3044
                namePtr = Tcl_NewStringObj(name, -1);
3045
                result = Tcl_ListObjAppendElement(interp, resultPtr, namePtr);
3046
                if (result != TCL_OK) {
3047
                    Tcl_DecrRefCount(namePtr); /* free unneeded name object */
3048
                    return result;
3049
                }
3050
            }
3051
            break;
3052
        }
3053
        case ARRAY_NEXTELEMENT: {
3054
            ArraySearch *searchPtr;
3055
            char *searchId;
3056
            Tcl_HashEntry *hPtr;
3057
 
3058
            if (objc != 4) {
3059
                Tcl_WrongNumArgs(interp, 2, objv,
3060
                        "arrayName searchId");
3061
                return TCL_ERROR;
3062
            }
3063
            if (notArray) {
3064
                goto error;
3065
            }
3066
            searchId = Tcl_GetStringFromObj(objv[3], (int *) NULL);
3067
            searchPtr = ParseSearchId(interp, varPtr, varName, searchId);
3068
            if (searchPtr == NULL) {
3069
                return TCL_ERROR;
3070
            }
3071
            while (1) {
3072
                Var *varPtr2;
3073
 
3074
                hPtr = searchPtr->nextEntry;
3075
                if (hPtr == NULL) {
3076
                    hPtr = Tcl_NextHashEntry(&searchPtr->search);
3077
                    if (hPtr == NULL) {
3078
                        return TCL_OK;
3079
                    }
3080
                } else {
3081
                    searchPtr->nextEntry = NULL;
3082
                }
3083
                varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
3084
                if (!TclIsVarUndefined(varPtr2)) {
3085
                    break;
3086
                }
3087
            }
3088
            Tcl_SetStringObj(resultPtr,
3089
                    Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), -1);
3090
            break;
3091
        }
3092
        case ARRAY_SET: {
3093
            Tcl_Obj **elemPtrs;
3094
            int listLen, i, result;
3095
 
3096
            if (objc != 4) {
3097
                Tcl_WrongNumArgs(interp, 2, objv, "arrayName list");
3098
                return TCL_ERROR;
3099
            }
3100
            result = Tcl_ListObjGetElements(interp, objv[3], &listLen,
3101
                    &elemPtrs);
3102
            if (result != TCL_OK) {
3103
                return result;
3104
            }
3105
            if (listLen & 1) {
3106
                Tcl_ResetResult(interp);
3107
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
3108
                        "list must have an even number of elements", -1);
3109
                return TCL_ERROR;
3110
            }
3111
            if (listLen > 0) {
3112
                for (i = 0;  i < listLen;  i += 2) {
3113
                    if (Tcl_ObjSetVar2(interp, objv[2], elemPtrs[i],
3114
                            elemPtrs[i+1], TCL_LEAVE_ERR_MSG) == NULL) {
3115
                        result = TCL_ERROR;
3116
                        break;
3117
                    }
3118
                }
3119
                return result;
3120
            }
3121
 
3122
            /*
3123
             * The list is empty make sure we have an array, or create
3124
             * one if necessary.
3125
             */
3126
 
3127
            if (varPtr != NULL) {
3128
                if (!TclIsVarUndefined(varPtr) && TclIsVarArray(varPtr)) {
3129
                    /*
3130
                     * Already an array, done.
3131
                     */
3132
 
3133
                    return TCL_OK;
3134
                }
3135
                if (TclIsVarArrayElement(varPtr) ||
3136
                        !TclIsVarUndefined(varPtr)) {
3137
                    /*
3138
                     * Either an array element, or a scalar: lose!
3139
                     */
3140
 
3141
                    VarErrMsg(interp, varName, (char *)NULL, "array set",
3142
                            needArray);
3143
                    return TCL_ERROR;
3144
                }
3145
            } else {
3146
                /*
3147
                 * Create variable for new array.
3148
                 */
3149
 
3150
                varPtr = TclLookupVar(interp, varName, (char *) NULL, 0, 0,
3151
                        /*createPart1*/ 1, /*createPart2*/ 0,
3152
                        &arrayPtr);
3153
            }
3154
            TclSetVarArray(varPtr);
3155
            TclClearVarUndefined(varPtr);
3156
            varPtr->value.tablePtr =
3157
                (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
3158
            Tcl_InitHashTable(varPtr->value.tablePtr, TCL_STRING_KEYS);
3159
          return TCL_OK;
3160
        }
3161
        case ARRAY_SIZE: {
3162
            Tcl_HashSearch search;
3163
            Var *varPtr2;
3164
            int size;
3165
 
3166
            if (objc != 3) {
3167
                Tcl_WrongNumArgs(interp, 2, objv, "arrayName");
3168
                return TCL_ERROR;
3169
            }
3170
            size = 0;
3171
            if (!notArray) {
3172
                for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr,
3173
                        &search);
3174
                        hPtr != NULL;  hPtr = Tcl_NextHashEntry(&search)) {
3175
                    varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
3176
                    if (TclIsVarUndefined(varPtr2)) {
3177
                        continue;
3178
                    }
3179
                    size++;
3180
                }
3181
            }
3182
            Tcl_SetIntObj(resultPtr, size);
3183
            break;
3184
        }
3185
        case ARRAY_STARTSEARCH: {
3186
            ArraySearch *searchPtr;
3187
 
3188
            if (objc != 3) {
3189
                Tcl_WrongNumArgs(interp, 2, objv, "arrayName");
3190
                return TCL_ERROR;
3191
            }
3192
            if (notArray) {
3193
                goto error;
3194
            }
3195
            searchPtr = (ArraySearch *) ckalloc(sizeof(ArraySearch));
3196
            if (varPtr->searchPtr == NULL) {
3197
                searchPtr->id = 1;
3198
                Tcl_AppendStringsToObj(resultPtr, "s-1-", varName,
3199
                        (char *) NULL);
3200
            } else {
3201
                char string[20];
3202
 
3203
                searchPtr->id = varPtr->searchPtr->id + 1;
3204
                TclFormatInt(string, searchPtr->id);
3205
                Tcl_AppendStringsToObj(resultPtr, "s-", string, "-", varName,
3206
                    (char *) NULL);
3207
            }
3208
            searchPtr->varPtr = varPtr;
3209
            searchPtr->nextEntry = Tcl_FirstHashEntry(varPtr->value.tablePtr,
3210
                    &searchPtr->search);
3211
            searchPtr->nextPtr = varPtr->searchPtr;
3212
            varPtr->searchPtr = searchPtr;
3213
            break;
3214
        }
3215
    }
3216
    return TCL_OK;
3217
 
3218
    error:
3219
    Tcl_AppendStringsToObj(resultPtr, "\"", varName, "\" isn't an array",
3220
            (char *) NULL);
3221
    return TCL_ERROR;
3222
}
3223
 
3224
/*
3225
 *----------------------------------------------------------------------
3226
 *
3227
 * MakeUpvar --
3228
 *
3229
 *      This procedure does all of the work of the "global" and "upvar"
3230
 *      commands.
3231
 *
3232
 * Results:
3233
 *      A standard Tcl completion code. If an error occurs then an
3234
 *      error message is left in iPtr->result.
3235
 *
3236
 * Side effects:
3237
 *      The variable given by myName is linked to the variable in framePtr
3238
 *      given by otherP1 and otherP2, so that references to myName are
3239
 *      redirected to the other variable like a symbolic link.
3240
 *
3241
 *----------------------------------------------------------------------
3242
 */
3243
 
3244
static int
3245
MakeUpvar(iPtr, framePtr, otherP1, otherP2, otherFlags, myName, myFlags)
3246
    Interp *iPtr;               /* Interpreter containing variables. Used
3247
                                 * for error messages, too. */
3248
    CallFrame *framePtr;        /* Call frame containing "other" variable.
3249
                                 * NULL means use global :: context. */
3250
    char *otherP1, *otherP2;    /* Two-part name of variable in framePtr. */
3251
    int otherFlags;             /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
3252
                                 * indicates scope of "other" variable. */
3253
    char *myName;               /* Name of variable which will refer to
3254
                                 * otherP1/otherP2. Must be a scalar. */
3255
    int myFlags;                /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
3256
                                 * indicates scope of myName. */
3257
{
3258
    Tcl_HashEntry *hPtr;
3259
    Var *otherPtr, *varPtr, *arrayPtr;
3260
    CallFrame *varFramePtr;
3261
    CallFrame *savedFramePtr = NULL;  /* Init. to avoid compiler warning. */
3262
    Tcl_HashTable *tablePtr;
3263
    Namespace *nsPtr, *altNsPtr, *dummyNsPtr;
3264
    char *tail;
3265
    int new, result;
3266
 
3267
    /*
3268
     * Find "other" in "framePtr". If not looking up other in just the
3269
     * current namespace, temporarily replace the current var frame
3270
     * pointer in the interpreter in order to use TclLookupVar.
3271
     */
3272
 
3273
    if (!(otherFlags & TCL_NAMESPACE_ONLY)) {
3274
        savedFramePtr = iPtr->varFramePtr;
3275
        iPtr->varFramePtr = framePtr;
3276
    }
3277
    otherPtr = TclLookupVar((Tcl_Interp *) iPtr, otherP1, otherP2,
3278
            (otherFlags | TCL_LEAVE_ERR_MSG), "access",
3279
            /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
3280
    if (!(otherFlags & TCL_NAMESPACE_ONLY)) {
3281
        iPtr->varFramePtr = savedFramePtr;
3282
    }
3283
    if (otherPtr == NULL) {
3284
        return TCL_ERROR;
3285
    }
3286
 
3287
    /*
3288
     * Now create a hashtable entry for "myName". Create it as either a
3289
     * namespace variable or as a local variable in a procedure call
3290
     * frame. Interpret myName as a namespace variable if:
3291
     *    1) so requested by a TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY flag,
3292
     *    2) there is no active frame (we're at the global :: scope),
3293
     *    3) the active frame was pushed to define the namespace context
3294
     *       for a "namespace eval" or "namespace inscope" command,
3295
     *    4) the name has namespace qualifiers ("::"s).
3296
     * If creating myName in the active procedure, look first in the
3297
     * frame's array of compiler-allocated local variables, then in its
3298
     * hashtable for runtime-created local variables. Create that
3299
     * procedure's local variable hashtable if necessary.
3300
     */
3301
 
3302
    varFramePtr = iPtr->varFramePtr;
3303
    if ((myFlags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY))
3304
                || (varFramePtr == NULL)
3305
                || !varFramePtr->isProcCallFrame
3306
                || (strstr(myName, "::") != NULL)) {
3307
        result = TclGetNamespaceForQualName((Tcl_Interp *) iPtr, myName,
3308
                (Namespace *) NULL, (myFlags | TCL_LEAVE_ERR_MSG),
3309
                &nsPtr, &altNsPtr, &dummyNsPtr, &tail);
3310
        if (result != TCL_OK) {
3311
            return result;
3312
        }
3313
        if (nsPtr == NULL) {
3314
            nsPtr = altNsPtr;
3315
        }
3316
        if (nsPtr == NULL) {
3317
            Tcl_AppendResult((Tcl_Interp *) iPtr, "bad variable name \"",
3318
                myName, "\": unknown namespace", (char *) NULL);
3319
            return TCL_ERROR;
3320
        }
3321
 
3322
        /*
3323
         * Check that we are not trying to create a namespace var linked to
3324
         * a local variable in a procedure. If we allowed this, the local
3325
         * variable in the shorter-lived procedure frame could go away
3326
         * leaving the namespace var's reference invalid.
3327
         */
3328
 
3329
        if ((otherP2 ? arrayPtr->nsPtr : otherPtr->nsPtr) == NULL) {
3330
            Tcl_AppendResult((Tcl_Interp *) iPtr, "bad variable name \"",
3331
                    myName, "\": upvar won't create namespace variable that refers to procedure variable",
3332
                    (char *) NULL);
3333
            return TCL_ERROR;
3334
        }
3335
 
3336
        hPtr = Tcl_CreateHashEntry(&nsPtr->varTable, tail, &new);
3337
        if (new) {
3338
            varPtr = NewVar();
3339
            Tcl_SetHashValue(hPtr, varPtr);
3340
            varPtr->hPtr = hPtr;
3341
            varPtr->nsPtr = nsPtr;
3342
        } else {
3343
            varPtr = (Var *) Tcl_GetHashValue(hPtr);
3344
        }
3345
    } else {                    /* look in the call frame */
3346
        Proc *procPtr = varFramePtr->procPtr;
3347
        int localCt = procPtr->numCompiledLocals;
3348
        CompiledLocal *localPtr = procPtr->firstLocalPtr;
3349
        Var *localVarPtr = varFramePtr->compiledLocals;
3350
        int nameLen = strlen(myName);
3351
        int i;
3352
 
3353
        varPtr = NULL;
3354
        for (i = 0;  i < localCt;  i++) {
3355
            if (!TclIsVarTemporary(localPtr)) {
3356
                char *localName = localVarPtr->name;
3357
                if ((myName[0] == localName[0])
3358
                        && (nameLen == localPtr->nameLength)
3359
                        && (strcmp(myName, localName) == 0)) {
3360
                    varPtr = localVarPtr;
3361
                    new = 0;
3362
                    break;
3363
                }
3364
            }
3365
            localVarPtr++;
3366
            localPtr = localPtr->nextPtr;
3367
        }
3368
        if (varPtr == NULL) {   /* look in frame's local var hashtable */
3369
            tablePtr = varFramePtr->varTablePtr;
3370
            if (tablePtr == NULL) {
3371
                tablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
3372
                Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS);
3373
                varFramePtr->varTablePtr = tablePtr;
3374
            }
3375
            hPtr = Tcl_CreateHashEntry(tablePtr, myName, &new);
3376
            if (new) {
3377
                varPtr = NewVar();
3378
                Tcl_SetHashValue(hPtr, varPtr);
3379
                varPtr->hPtr = hPtr;
3380
                varPtr->nsPtr = varFramePtr->nsPtr;
3381
            } else {
3382
                varPtr = (Var *) Tcl_GetHashValue(hPtr);
3383
            }
3384
        }
3385
    }
3386
 
3387
    if (!new) {
3388
        /*
3389
         * The variable already exists. Make sure this variable "varPtr"
3390
         * isn't the same as "otherPtr" (avoid circular links). Also, if
3391
         * it's not an upvar then it's an error. If it is an upvar, then
3392
         * just disconnect it from the thing it currently refers to.
3393
         */
3394
 
3395
        if (varPtr == otherPtr) {
3396
            Tcl_SetResult((Tcl_Interp *) iPtr,
3397
                    "can't upvar from variable to itself", TCL_STATIC);
3398
            return TCL_ERROR;
3399
        }
3400
        if (TclIsVarLink(varPtr)) {
3401
            Var *linkPtr = varPtr->value.linkPtr;
3402
            if (linkPtr == otherPtr) {
3403
                return TCL_OK;
3404
            }
3405
            linkPtr->refCount--;
3406
            if (TclIsVarUndefined(linkPtr)) {
3407
                CleanupVar(linkPtr, (Var *) NULL);
3408
            }
3409
        } else if (!TclIsVarUndefined(varPtr)) {
3410
            Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName,
3411
                "\" already exists", (char *) NULL);
3412
            return TCL_ERROR;
3413
        } else if (varPtr->tracePtr != NULL) {
3414
            Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName,
3415
                "\" has traces: can't use for upvar", (char *) NULL);
3416
            return TCL_ERROR;
3417
        }
3418
    }
3419
    TclSetVarLink(varPtr);
3420
    TclClearVarUndefined(varPtr);
3421
    varPtr->value.linkPtr = otherPtr;
3422
    otherPtr->refCount++;
3423
    return TCL_OK;
3424
}
3425
 
3426
/*
3427
 *----------------------------------------------------------------------
3428
 *
3429
 * Tcl_UpVar --
3430
 *
3431
 *      This procedure links one variable to another, just like
3432
 *      the "upvar" command.
3433
 *
3434
 * Results:
3435
 *      A standard Tcl completion code.  If an error occurs then
3436
 *      an error message is left in interp->result.
3437
 *
3438
 * Side effects:
3439
 *      The variable in frameName whose name is given by varName becomes
3440
 *      accessible under the name localName, so that references to
3441
 *      localName are redirected to the other variable like a symbolic
3442
 *      link.
3443
 *
3444
 *----------------------------------------------------------------------
3445
 */
3446
 
3447
int
3448
Tcl_UpVar(interp, frameName, varName, localName, flags)
3449
    Tcl_Interp *interp;         /* Command interpreter in which varName is
3450
                                 * to be looked up. */
3451
    char *frameName;            /* Name of the frame containing the source
3452
                                 * variable, such as "1" or "#0". */
3453
    char *varName;              /* Name of a variable in interp to link to.
3454
                                 * May be either a scalar name or an
3455
                                 * element in an array. */
3456
    char *localName;            /* Name of link variable. */
3457
    int flags;                  /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
3458
                                 * indicates scope of localName. */
3459
{
3460
    int result;
3461
    CallFrame *framePtr;
3462
    register char *p;
3463
 
3464
    result = TclGetFrame(interp, frameName, &framePtr);
3465
    if (result == -1) {
3466
        return TCL_ERROR;
3467
    }
3468
 
3469
    /*
3470
     * Figure out whether varName is an array reference, then call
3471
     * MakeUpvar to do all the real work.
3472
     */
3473
 
3474
    for (p = varName;  *p != '\0';  p++) {
3475
        if (*p == '(') {
3476
            char *openParen = p;
3477
            do {
3478
                p++;
3479
            } while (*p != '\0');
3480
            p--;
3481
            if (*p != ')') {
3482
                goto scalar;
3483
            }
3484
            *openParen = '\0';
3485
            *p = '\0';
3486
            result = MakeUpvar((Interp *) interp, framePtr, varName,
3487
                    openParen+1, 0, localName, flags);
3488
            *openParen = '(';
3489
            *p = ')';
3490
            return result;
3491
        }
3492
    }
3493
 
3494
    scalar:
3495
    return MakeUpvar((Interp *) interp, framePtr, varName, (char *) NULL,
3496
            0, localName, flags);
3497
}
3498
 
3499
/*
3500
 *----------------------------------------------------------------------
3501
 *
3502
 * Tcl_UpVar2 --
3503
 *
3504
 *      This procedure links one variable to another, just like
3505
 *      the "upvar" command.
3506
 *
3507
 * Results:
3508
 *      A standard Tcl completion code.  If an error occurs then
3509
 *      an error message is left in interp->result.
3510
 *
3511
 * Side effects:
3512
 *      The variable in frameName whose name is given by part1 and
3513
 *      part2 becomes accessible under the name localName, so that
3514
 *      references to localName are redirected to the other variable
3515
 *      like a symbolic link.
3516
 *
3517
 *----------------------------------------------------------------------
3518
 */
3519
 
3520
int
3521
Tcl_UpVar2(interp, frameName, part1, part2, localName, flags)
3522
    Tcl_Interp *interp;         /* Interpreter containing variables.  Used
3523
                                 * for error messages too. */
3524
    char *frameName;            /* Name of the frame containing the source
3525
                                 * variable, such as "1" or "#0". */
3526
    char *part1, *part2;        /* Two parts of source variable name to
3527
                                 * link to. */
3528
    char *localName;            /* Name of link variable. */
3529
    int flags;                  /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
3530
                                 * indicates scope of localName. */
3531
{
3532
    int result;
3533
    CallFrame *framePtr;
3534
 
3535
    result = TclGetFrame(interp, frameName, &framePtr);
3536
    if (result == -1) {
3537
        return TCL_ERROR;
3538
    }
3539
    return MakeUpvar((Interp *) interp, framePtr, part1, part2, 0,
3540
            localName, flags);
3541
}
3542
 
3543
/*
3544
 *----------------------------------------------------------------------
3545
 *
3546
 * Tcl_GetVariableFullName --
3547
 *
3548
 *      Given a Tcl_Var token returned by Tcl_FindNamespaceVar, this
3549
 *      procedure appends to an object the namespace variable's full
3550
 *      name, qualified by a sequence of parent namespace names.
3551
 *
3552
 * Results:
3553
 *      None.
3554
 *
3555
 * Side effects:
3556
 *      The variable's fully-qualified name is appended to the string
3557
 *      representation of objPtr.
3558
 *
3559
 *----------------------------------------------------------------------
3560
 */
3561
 
3562
void
3563
Tcl_GetVariableFullName(interp, variable, objPtr)
3564
    Tcl_Interp *interp;         /* Interpreter containing the variable. */
3565
    Tcl_Var variable;           /* Token for the variable returned by a
3566
                                 * previous call to Tcl_FindNamespaceVar. */
3567
    Tcl_Obj *objPtr;            /* Points to the object onto which the
3568
                                 * variable's full name is appended. */
3569
{
3570
    Interp *iPtr = (Interp *) interp;
3571
    register Var *varPtr = (Var *) variable;
3572
    char *name;
3573
 
3574
    /*
3575
     * Add the full name of the containing namespace (if any), followed by
3576
     * the "::" separator, then the variable name.
3577
     */
3578
 
3579
    if (varPtr != NULL) {
3580
        if (!TclIsVarArrayElement(varPtr)) {
3581
            if (varPtr->nsPtr != NULL) {
3582
                Tcl_AppendToObj(objPtr, varPtr->nsPtr->fullName, -1);
3583
                if (varPtr->nsPtr != iPtr->globalNsPtr) {
3584
                    Tcl_AppendToObj(objPtr, "::", 2);
3585
                }
3586
            }
3587
            if (varPtr->name != NULL) {
3588
                Tcl_AppendToObj(objPtr, varPtr->name, -1);
3589
            } else if (varPtr->hPtr != NULL) {
3590
                name = Tcl_GetHashKey(varPtr->hPtr->tablePtr, varPtr->hPtr);
3591
                Tcl_AppendToObj(objPtr, name, -1);
3592
            }
3593
        }
3594
    }
3595
}
3596
 
3597
/*
3598
 *----------------------------------------------------------------------
3599
 *
3600
 * Tcl_GlobalObjCmd --
3601
 *
3602
 *      This object-based procedure is invoked to process the "global" Tcl
3603
 *      command. See the user documentation for details on what it does.
3604
 *
3605
 * Results:
3606
 *      A standard Tcl object result value.
3607
 *
3608
 * Side effects:
3609
 *      See the user documentation.
3610
 *
3611
 *----------------------------------------------------------------------
3612
 */
3613
 
3614
int
3615
Tcl_GlobalObjCmd(dummy, interp, objc, objv)
3616
    ClientData dummy;           /* Not used. */
3617
    Tcl_Interp *interp;         /* Current interpreter. */
3618
    int objc;                   /* Number of arguments. */
3619
    Tcl_Obj *CONST objv[];      /* Argument objects. */
3620
{
3621
    Interp *iPtr = (Interp *) interp;
3622
    register Tcl_Obj *objPtr;
3623
    char *varName;
3624
    register char *tail;
3625
    int result, i;
3626
 
3627
    if (objc < 2) {
3628
        Tcl_WrongNumArgs(interp, 1, objv, "varName ?varName ...?");
3629
        return TCL_ERROR;
3630
    }
3631
 
3632
    /*
3633
     * If we are not executing inside a Tcl procedure, just return.
3634
     */
3635
 
3636
    if ((iPtr->varFramePtr == NULL)
3637
            || !iPtr->varFramePtr->isProcCallFrame) {
3638
        return TCL_OK;
3639
    }
3640
 
3641
    for (i = 1;  i < objc;  i++) {
3642
        /*
3643
         * Make a local variable linked to its counterpart in the global ::
3644
         * namespace.
3645
         */
3646
 
3647
        objPtr = objv[i];
3648
        varName = Tcl_GetStringFromObj(objPtr, (int *) NULL);
3649
 
3650
        /*
3651
         * The variable name might have a scope qualifier, but the name for
3652
         * the local "link" variable must be the simple name at the tail.
3653
         */
3654
 
3655
        for (tail = varName;  *tail != '\0';  tail++) {
3656
            /* empty body */
3657
        }
3658
        while ((tail > varName) && ((*tail != ':') || (*(tail-1) != ':'))) {
3659
            tail--;
3660
        }
3661
        if (*tail == ':') {
3662
            tail++;
3663
        }
3664
 
3665
        /*
3666
         * Link to the variable "varName" in the global :: namespace.
3667
         */
3668
 
3669
        result = MakeUpvar(iPtr, (CallFrame *) NULL,
3670
                varName, (char *) NULL, /*otherFlags*/ TCL_GLOBAL_ONLY,
3671
                /*myName*/ tail, /*myFlags*/ 0);
3672
        if (result != TCL_OK) {
3673
            return result;
3674
        }
3675
    }
3676
    return TCL_OK;
3677
}
3678
 
3679
/*
3680
 *----------------------------------------------------------------------
3681
 *
3682
 * Tcl_VariableObjCmd --
3683
 *
3684
 *      Invoked to implement the "variable" command that creates one or more
3685
 *      global variables. Handles the following syntax:
3686
 *
3687
 *          variable ?name value...? name ?value?
3688
 *
3689
 *      One or more variables can be created. The variables are initialized
3690
 *      with the specified values. The value for the last variable is
3691
 *      optional.
3692
 *
3693
 *      If the variable does not exist, it is created and given the optional
3694
 *      value. If it already exists, it is simply set to the optional
3695
 *      value. Normally, "name" is an unqualified name, so it is created in
3696
 *      the current namespace. If it includes namespace qualifiers, it can
3697
 *      be created in another namespace.
3698
 *
3699
 *      If the variable command is executed inside a Tcl procedure, it
3700
 *      creates a local variable linked to the newly-created namespace
3701
 *      variable.
3702
 *
3703
 * Results:
3704
 *      Returns TCL_OK if the variable is found or created. Returns
3705
 *      TCL_ERROR if anything goes wrong.
3706
 *
3707
 * Side effects:
3708
 *      If anything goes wrong, this procedure returns an error message
3709
 *      as the result in the interpreter's result object.
3710
 *
3711
 *----------------------------------------------------------------------
3712
 */
3713
 
3714
int
3715
Tcl_VariableObjCmd(dummy, interp, objc, objv)
3716
    ClientData dummy;           /* Not used. */
3717
    Tcl_Interp *interp;         /* Current interpreter. */
3718
    int objc;                   /* Number of arguments. */
3719
    Tcl_Obj *CONST objv[];      /* Argument objects. */
3720
{
3721
    Interp *iPtr = (Interp *) interp;
3722
    char *varName, *tail;
3723
    Var *varPtr, *arrayPtr;
3724
    Tcl_Obj *varValuePtr;
3725
    int i, result;
3726
 
3727
    for (i = 1;  i < objc;  i = i+2) {
3728
        /*
3729
         * Look up each variable in the current namespace context, creating
3730
         * it if necessary.
3731
         */
3732
 
3733
        varName = Tcl_GetStringFromObj(objv[i], (int *) NULL);
3734
        varPtr = TclLookupVar(interp, varName, (char *) NULL,
3735
                (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "define",
3736
                /*createPart1*/ 1, /*createPart2*/ 0, &arrayPtr);
3737
        if (varPtr == NULL) {
3738
            return TCL_ERROR;
3739
        }
3740
 
3741
        /*
3742
         * Mark the variable as a namespace variable and increment its
3743
         * reference count so that it will persist until its namespace is
3744
         * destroyed or until the variable is unset.
3745
         */
3746
 
3747
        if (!(varPtr->flags & VAR_NAMESPACE_VAR)) {
3748
            varPtr->flags |= VAR_NAMESPACE_VAR;
3749
            varPtr->refCount++;
3750
        }
3751
 
3752
        /*
3753
         * If a value was specified, set the variable to that value.
3754
         * Otherwise, if the variable is new, leave it undefined.
3755
         * (If the variable already exists and no value was specified,
3756
         * leave its value unchanged; just create the local link if
3757
         * we're in a Tcl procedure).
3758
         */
3759
 
3760
        if (i+1 < objc) {       /* a value was specified */
3761
            varValuePtr = Tcl_ObjSetVar2(interp, objv[i], (Tcl_Obj *) NULL,
3762
                    objv[i+1], (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG));
3763
            if (varValuePtr == NULL) {
3764
                return TCL_ERROR;
3765
            }
3766
        }
3767
 
3768
        /*
3769
         * If we are executing inside a Tcl procedure, create a local
3770
         * variable linked to the new namespace variable "varName".
3771
         */
3772
 
3773
        if ((iPtr->varFramePtr != NULL)
3774
                && iPtr->varFramePtr->isProcCallFrame) {
3775
            /*
3776
             * varName might have a scope qualifier, but the name for the
3777
             * local "link" variable must be the simple name at the tail.
3778
             */
3779
 
3780
            for (tail = varName;  *tail != '\0';  tail++) {
3781
                /* empty body */
3782
            }
3783
            while ((tail > varName)
3784
                    && ((*tail != ':') || (*(tail-1) != ':'))) {
3785
                tail--;
3786
            }
3787
            if (*tail == ':') {
3788
                tail++;
3789
            }
3790
 
3791
            /*
3792
             * Create a local link "tail" to the variable "varName" in the
3793
             * current namespace.
3794
             */
3795
 
3796
            result = MakeUpvar(iPtr, (CallFrame *) NULL,
3797
                    /*otherP1*/ varName, /*otherP2*/ (char *) NULL,
3798
                    /*otherFlags*/ TCL_NAMESPACE_ONLY,
3799
                    /*myName*/ tail, /*myFlags*/ 0);
3800
            if (result != TCL_OK) {
3801
                return result;
3802
            }
3803
        }
3804
    }
3805
    return TCL_OK;
3806
}
3807
 
3808
/*
3809
 *----------------------------------------------------------------------
3810
 *
3811
 * Tcl_UpvarObjCmd --
3812
 *
3813
 *      This object-based procedure is invoked to process the "upvar"
3814
 *      Tcl command. See the user documentation for details on what it does.
3815
 *
3816
 * Results:
3817
 *      A standard Tcl object result value.
3818
 *
3819
 * Side effects:
3820
 *      See the user documentation.
3821
 *
3822
 *----------------------------------------------------------------------
3823
 */
3824
 
3825
        /* ARGSUSED */
3826
int
3827
Tcl_UpvarObjCmd(dummy, interp, objc, objv)
3828
    ClientData dummy;           /* Not used. */
3829
    Tcl_Interp *interp;         /* Current interpreter. */
3830
    int objc;                   /* Number of arguments. */
3831
    Tcl_Obj *CONST objv[];      /* Argument objects. */
3832
{
3833
    register Interp *iPtr = (Interp *) interp;
3834
    CallFrame *framePtr;
3835
    char *frameSpec, *otherVarName, *myVarName;
3836
    register char *p;
3837
    int result;
3838
 
3839
    if (objc < 3) {
3840
        upvarSyntax:
3841
        Tcl_WrongNumArgs(interp, 1, objv,
3842
                "?level? otherVar localVar ?otherVar localVar ...?");
3843
        return TCL_ERROR;
3844
    }
3845
 
3846
    /*
3847
     * Find the call frame containing each of the "other variables" to be
3848
     * linked to. FAILS IF objv[1]'s STRING REP CONTAINS NULLS.
3849
     */
3850
 
3851
    frameSpec = Tcl_GetStringFromObj(objv[1], (int *) NULL);
3852
    result = TclGetFrame(interp, frameSpec, &framePtr);
3853
    if (result == -1) {
3854
        return TCL_ERROR;
3855
    }
3856
    objc -= result+1;
3857
    if ((objc & 1) != 0) {
3858
        goto upvarSyntax;
3859
    }
3860
    objv += result+1;
3861
 
3862
    /*
3863
     * Iterate over each (other variable, local variable) pair.
3864
     * Divide the other variable name into two parts, then call
3865
     * MakeUpvar to do all the work of linking it to the local variable.
3866
     */
3867
 
3868
    for ( ;  objc > 0;  objc -= 2, objv += 2) {
3869
        myVarName = Tcl_GetStringFromObj(objv[1], (int *) NULL);
3870
        otherVarName = Tcl_GetStringFromObj(objv[0], (int *) NULL);
3871
        for (p = otherVarName;  *p != 0;  p++) {
3872
            if (*p == '(') {
3873
                char *openParen = p;
3874
 
3875
                do {
3876
                    p++;
3877
                } while (*p != '\0');
3878
                p--;
3879
                if (*p != ')') {
3880
                    goto scalar;
3881
                }
3882
                *openParen = '\0';
3883
                *p = '\0';
3884
                result = MakeUpvar(iPtr, framePtr,
3885
                        otherVarName, openParen+1, /*otherFlags*/ 0,
3886
                        myVarName, /*flags*/ 0);
3887
                *openParen = '(';
3888
                *p = ')';
3889
                goto checkResult;
3890
            }
3891
        }
3892
        scalar:
3893
        result = MakeUpvar(iPtr, framePtr, otherVarName, (char *) NULL, 0,
3894
                myVarName, /*flags*/ 0);
3895
 
3896
        checkResult:
3897
        if (result != TCL_OK) {
3898
            return TCL_ERROR;
3899
        }
3900
    }
3901
    return TCL_OK;
3902
}
3903
 
3904
/*
3905
 *----------------------------------------------------------------------
3906
 *
3907
 * CallTraces --
3908
 *
3909
 *      This procedure is invoked to find and invoke relevant
3910
 *      trace procedures associated with a particular operation on
3911
 *      a variable. This procedure invokes traces both on the
3912
 *      variable and on its containing array (where relevant).
3913
 *
3914
 * Results:
3915
 *      The return value is NULL if no trace procedures were invoked, or
3916
 *      if all the invoked trace procedures returned successfully.
3917
 *      The return value is non-NULL if a trace procedure returned an
3918
 *      error (in this case no more trace procedures were invoked after
3919
 *      the error was returned). In this case the return value is a
3920
 *      pointer to a static string describing the error.
3921
 *
3922
 * Side effects:
3923
 *      Almost anything can happen, depending on trace; this procedure
3924
 *      itself doesn't have any side effects.
3925
 *
3926
 *----------------------------------------------------------------------
3927
 */
3928
 
3929
static char *
3930
CallTraces(iPtr, arrayPtr, varPtr, part1, part2, flags)
3931
    Interp *iPtr;               /* Interpreter containing variable. */
3932
    register Var *arrayPtr;     /* Pointer to array variable that contains
3933
                                 * the variable, or NULL if the variable
3934
                                 * isn't an element of an array. */
3935
    Var *varPtr;                /* Variable whose traces are to be
3936
                                 * invoked. */
3937
    char *part1, *part2;        /* Variable's two-part name. */
3938
    int flags;                  /* Flags passed to trace procedures:
3939
                                 * indicates what's happening to variable,
3940
                                 * plus other stuff like TCL_GLOBAL_ONLY,
3941
                                 * TCL_NAMESPACE_ONLY, and
3942
                                 * TCL_INTERP_DESTROYED. May also contain
3943
                                 * TCL_PARSE_PART1, which should not be
3944
                                 * passed through to callbacks. */
3945
{
3946
    register VarTrace *tracePtr;
3947
    ActiveVarTrace active;
3948
    char *result, *openParen, *p;
3949
    Tcl_DString nameCopy;
3950
    int copiedName;
3951
 
3952
    /*
3953
     * If there are already similar trace procedures active for the
3954
     * variable, don't call them again.
3955
     */
3956
 
3957
    if (varPtr->flags & VAR_TRACE_ACTIVE) {
3958
        return NULL;
3959
    }
3960
    varPtr->flags |= VAR_TRACE_ACTIVE;
3961
    varPtr->refCount++;
3962
 
3963
    /*
3964
     * If the variable name hasn't been parsed into array name and
3965
     * element, do it here.  If there really is an array element,
3966
     * make a copy of the original name so that NULLs can be
3967
     * inserted into it to separate the names (can't modify the name
3968
     * string in place, because the string might get used by the
3969
     * callbacks we invoke).
3970
     */
3971
 
3972
    copiedName = 0;
3973
    if (flags & TCL_PARSE_PART1) {
3974
        for (p = part1; ; p++) {
3975
            if (*p == 0) {
3976
                break;
3977
            }
3978
            if (*p == '(') {
3979
                openParen = p;
3980
                do {
3981
                    p++;
3982
                } while (*p != '\0');
3983
                p--;
3984
                if (*p == ')') {
3985
                    Tcl_DStringInit(&nameCopy);
3986
                    Tcl_DStringAppend(&nameCopy, part1, (p-part1));
3987
                    part2 = Tcl_DStringValue(&nameCopy)
3988
                            + (openParen + 1 - part1);
3989
                    part2[-1] = 0;
3990
                    part1 = Tcl_DStringValue(&nameCopy);
3991
                    copiedName = 1;
3992
                }
3993
                break;
3994
            }
3995
        }
3996
    }
3997
    flags &= ~TCL_PARSE_PART1;
3998
 
3999
    /*
4000
     * Invoke traces on the array containing the variable, if relevant.
4001
     */
4002
 
4003
    result = NULL;
4004
    active.nextPtr = iPtr->activeTracePtr;
4005
    iPtr->activeTracePtr = &active;
4006
    if (arrayPtr != NULL) {
4007
        arrayPtr->refCount++;
4008
        active.varPtr = arrayPtr;
4009
        for (tracePtr = arrayPtr->tracePtr;  tracePtr != NULL;
4010
                tracePtr = active.nextTracePtr) {
4011
            active.nextTracePtr = tracePtr->nextPtr;
4012
            if (!(tracePtr->flags & flags)) {
4013
                continue;
4014
            }
4015
            result = (*tracePtr->traceProc)(tracePtr->clientData,
4016
                    (Tcl_Interp *) iPtr, part1, part2, flags);
4017
            if (result != NULL) {
4018
                if (flags & TCL_TRACE_UNSETS) {
4019
                    result = NULL;
4020
                } else {
4021
                    goto done;
4022
                }
4023
            }
4024
        }
4025
    }
4026
 
4027
    /*
4028
     * Invoke traces on the variable itself.
4029
     */
4030
 
4031
    if (flags & TCL_TRACE_UNSETS) {
4032
        flags |= TCL_TRACE_DESTROYED;
4033
    }
4034
    active.varPtr = varPtr;
4035
    for (tracePtr = varPtr->tracePtr; tracePtr != NULL;
4036
            tracePtr = active.nextTracePtr) {
4037
        active.nextTracePtr = tracePtr->nextPtr;
4038
        if (!(tracePtr->flags & flags)) {
4039
            continue;
4040
        }
4041
        result = (*tracePtr->traceProc)(tracePtr->clientData,
4042
                (Tcl_Interp *) iPtr, part1, part2, flags);
4043
        if (result != NULL) {
4044
            if (flags & TCL_TRACE_UNSETS) {
4045
                result = NULL;
4046
            } else {
4047
                goto done;
4048
            }
4049
        }
4050
    }
4051
 
4052
    /*
4053
     * Restore the variable's flags, remove the record of our active
4054
     * traces, and then return.
4055
     */
4056
 
4057
    done:
4058
    if (arrayPtr != NULL) {
4059
        arrayPtr->refCount--;
4060
    }
4061
    if (copiedName) {
4062
        Tcl_DStringFree(&nameCopy);
4063
    }
4064
    varPtr->flags &= ~VAR_TRACE_ACTIVE;
4065
    varPtr->refCount--;
4066
    iPtr->activeTracePtr = active.nextPtr;
4067
    return result;
4068
}
4069
 
4070
/*
4071
 *----------------------------------------------------------------------
4072
 *
4073
 * NewVar --
4074
 *
4075
 *      Create a new heap-allocated variable that will eventually be
4076
 *      entered into a hashtable.
4077
 *
4078
 * Results:
4079
 *      The return value is a pointer to the new variable structure. It is
4080
 *      marked as a scalar variable (and not a link or array variable). Its
4081
 *      value initially is NULL. The variable is not part of any hash table
4082
 *      yet. Since it will be in a hashtable and not in a call frame, its
4083
 *      name field is set NULL. It is initially marked as undefined.
4084
 *
4085
 * Side effects:
4086
 *      Storage gets allocated.
4087
 *
4088
 *----------------------------------------------------------------------
4089
 */
4090
 
4091
static Var *
4092
NewVar()
4093
{
4094
    register Var *varPtr;
4095
 
4096
    varPtr = (Var *) ckalloc(sizeof(Var));
4097
    varPtr->value.objPtr = NULL;
4098
    varPtr->name = NULL;
4099
    varPtr->nsPtr = NULL;
4100
    varPtr->hPtr = NULL;
4101
    varPtr->refCount = 0;
4102
    varPtr->tracePtr = NULL;
4103
    varPtr->searchPtr = NULL;
4104
    varPtr->flags = (VAR_SCALAR | VAR_UNDEFINED | VAR_IN_HASHTABLE);
4105
    return varPtr;
4106
}
4107
 
4108
/*
4109
 *----------------------------------------------------------------------
4110
 *
4111
 * ParseSearchId --
4112
 *
4113
 *      This procedure translates from a string to a pointer to an
4114
 *      active array search (if there is one that matches the string).
4115
 *
4116
 * Results:
4117
 *      The return value is a pointer to the array search indicated
4118
 *      by string, or NULL if there isn't one.  If NULL is returned,
4119
 *      interp->result contains an error message.
4120
 *
4121
 * Side effects:
4122
 *      None.
4123
 *
4124
 *----------------------------------------------------------------------
4125
 */
4126
 
4127
static ArraySearch *
4128
ParseSearchId(interp, varPtr, varName, string)
4129
    Tcl_Interp *interp;         /* Interpreter containing variable. */
4130
    Var *varPtr;                /* Array variable search is for. */
4131
    char *varName;              /* Name of array variable that search is
4132
                                 * supposed to be for. */
4133
    char *string;               /* String containing id of search. Must have
4134
                                 * form "search-num-var" where "num" is a
4135
                                 * decimal number and "var" is a variable
4136
                                 * name. */
4137
{
4138
    char *end;
4139
    int id;
4140
    ArraySearch *searchPtr;
4141
 
4142
    /*
4143
     * Parse the id into the three parts separated by dashes.
4144
     */
4145
 
4146
    if ((string[0] != 's') || (string[1] != '-')) {
4147
        syntax:
4148
        Tcl_AppendResult(interp, "illegal search identifier \"", string,
4149
                "\"", (char *) NULL);
4150
        return NULL;
4151
    }
4152
    id = strtoul(string+2, &end, 10);
4153
    if ((end == (string+2)) || (*end != '-')) {
4154
        goto syntax;
4155
    }
4156
    if (strcmp(end+1, varName) != 0) {
4157
        Tcl_AppendResult(interp, "search identifier \"", string,
4158
                "\" isn't for variable \"", varName, "\"", (char *) NULL);
4159
        return NULL;
4160
    }
4161
 
4162
    /*
4163
     * Search through the list of active searches on the interpreter
4164
     * to see if the desired one exists.
4165
     */
4166
 
4167
    for (searchPtr = varPtr->searchPtr; searchPtr != NULL;
4168
            searchPtr = searchPtr->nextPtr) {
4169
        if (searchPtr->id == id) {
4170
            return searchPtr;
4171
        }
4172
    }
4173
    Tcl_AppendResult(interp, "couldn't find search \"", string, "\"",
4174
            (char *) NULL);
4175
    return NULL;
4176
}
4177
 
4178
/*
4179
 *----------------------------------------------------------------------
4180
 *
4181
 * DeleteSearches --
4182
 *
4183
 *      This procedure is called to free up all of the searches
4184
 *      associated with an array variable.
4185
 *
4186
 * Results:
4187
 *      None.
4188
 *
4189
 * Side effects:
4190
 *      Memory is released to the storage allocator.
4191
 *
4192
 *----------------------------------------------------------------------
4193
 */
4194
 
4195
static void
4196
DeleteSearches(arrayVarPtr)
4197
    register Var *arrayVarPtr;          /* Variable whose searches are
4198
                                         * to be deleted. */
4199
{
4200
    ArraySearch *searchPtr;
4201
 
4202
    while (arrayVarPtr->searchPtr != NULL) {
4203
        searchPtr = arrayVarPtr->searchPtr;
4204
        arrayVarPtr->searchPtr = searchPtr->nextPtr;
4205
        ckfree((char *) searchPtr);
4206
    }
4207
}
4208
 
4209
/*
4210
 *----------------------------------------------------------------------
4211
 *
4212
 * TclDeleteVars --
4213
 *
4214
 *      This procedure is called to recycle all the storage space
4215
 *      associated with a table of variables. For this procedure
4216
 *      to work correctly, it must not be possible for any of the
4217
 *      variables in the table to be accessed from Tcl commands
4218
 *      (e.g. from trace procedures).
4219
 *
4220
 * Results:
4221
 *      None.
4222
 *
4223
 * Side effects:
4224
 *      Variables are deleted and trace procedures are invoked, if
4225
 *      any are declared.
4226
 *
4227
 *----------------------------------------------------------------------
4228
 */
4229
 
4230
void
4231
TclDeleteVars(iPtr, tablePtr)
4232
    Interp *iPtr;               /* Interpreter to which variables belong. */
4233
    Tcl_HashTable *tablePtr;    /* Hash table containing variables to
4234
                                 * delete. */
4235
{
4236
    Tcl_Interp *interp = (Tcl_Interp *) iPtr;
4237
    Tcl_HashSearch search;
4238
    Tcl_HashEntry *hPtr;
4239
    register Var *varPtr;
4240
    Var *linkPtr;
4241
    int flags;
4242
    ActiveVarTrace *activePtr;
4243
    Tcl_Obj *objPtr;
4244
    Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
4245
 
4246
    /*
4247
     * Determine what flags to pass to the trace callback procedures.
4248
     */
4249
 
4250
    flags = TCL_TRACE_UNSETS;
4251
    if (tablePtr == &iPtr->globalNsPtr->varTable) {
4252
        flags |= (TCL_INTERP_DESTROYED | TCL_GLOBAL_ONLY);
4253
    } else if (tablePtr == &currNsPtr->varTable) {
4254
        flags |= TCL_NAMESPACE_ONLY;
4255
    }
4256
 
4257
    for (hPtr = Tcl_FirstHashEntry(tablePtr, &search);  hPtr != NULL;
4258
            hPtr = Tcl_NextHashEntry(&search)) {
4259
        varPtr = (Var *) Tcl_GetHashValue(hPtr);
4260
 
4261
        /*
4262
         * For global/upvar variables referenced in procedures, decrement
4263
         * the reference count on the variable referred to, and free
4264
         * the referenced variable if it's no longer needed. Don't delete
4265
         * the hash entry for the other variable if it's in the same table
4266
         * as us: this will happen automatically later on.
4267
         */
4268
 
4269
        if (TclIsVarLink(varPtr)) {
4270
            linkPtr = varPtr->value.linkPtr;
4271
            linkPtr->refCount--;
4272
            if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr)
4273
                    && (linkPtr->tracePtr == NULL)
4274
                    && (linkPtr->flags & VAR_IN_HASHTABLE)) {
4275
                if (linkPtr->hPtr == NULL) {
4276
                    ckfree((char *) linkPtr);
4277
                } else if (linkPtr->hPtr->tablePtr != tablePtr) {
4278
                    Tcl_DeleteHashEntry(linkPtr->hPtr);
4279
                    ckfree((char *) linkPtr);
4280
                }
4281
            }
4282
        }
4283
 
4284
        /*
4285
         * Invoke traces on the variable that is being deleted, then
4286
         * free up the variable's space (no need to free the hash entry
4287
         * here, unless we're dealing with a global variable: the
4288
         * hash entries will be deleted automatically when the whole
4289
         * table is deleted). Note that we give CallTraces the variable's
4290
         * fully-qualified name so that any called trace procedures can
4291
         * refer to these variables being deleted.
4292
         */
4293
 
4294
        if (varPtr->tracePtr != NULL) {
4295
            objPtr = Tcl_NewObj();
4296
            Tcl_IncrRefCount(objPtr); /* until done with traces */
4297
            Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, objPtr);
4298
            (void) CallTraces(iPtr, (Var *) NULL, varPtr,
4299
                    Tcl_GetStringFromObj(objPtr, (int *) NULL),
4300
                    (char *) NULL, flags);
4301
            Tcl_DecrRefCount(objPtr); /* free no longer needed obj */
4302
 
4303
            while (varPtr->tracePtr != NULL) {
4304
                VarTrace *tracePtr = varPtr->tracePtr;
4305
                varPtr->tracePtr = tracePtr->nextPtr;
4306
                ckfree((char *) tracePtr);
4307
            }
4308
            for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
4309
                    activePtr = activePtr->nextPtr) {
4310
                if (activePtr->varPtr == varPtr) {
4311
                    activePtr->nextTracePtr = NULL;
4312
                }
4313
            }
4314
        }
4315
 
4316
        if (TclIsVarArray(varPtr)) {
4317
            DeleteArray(iPtr, Tcl_GetHashKey(tablePtr, hPtr), varPtr,
4318
                    flags);
4319
            varPtr->value.tablePtr = NULL;
4320
        }
4321
        if (TclIsVarScalar(varPtr) && (varPtr->value.objPtr != NULL)) {
4322
            objPtr = varPtr->value.objPtr;
4323
            TclDecrRefCount(objPtr);
4324
            varPtr->value.objPtr = NULL;
4325
        }
4326
        varPtr->hPtr = NULL;
4327
        varPtr->tracePtr = NULL;
4328
        TclSetVarUndefined(varPtr);
4329
        TclSetVarScalar(varPtr);
4330
 
4331
        /*
4332
         * If the variable was a namespace variable, decrement its
4333
         * reference count. We are in the process of destroying its
4334
         * namespace so that namespace will no longer "refer" to the
4335
         * variable.
4336
         */
4337
 
4338
        if (varPtr->flags & VAR_NAMESPACE_VAR) {
4339
            varPtr->flags &= ~VAR_NAMESPACE_VAR;
4340
            varPtr->refCount--;
4341
        }
4342
 
4343
        /*
4344
         * Recycle the variable's memory space if there aren't any upvar's
4345
         * pointing to it. If there are upvars to this variable, then the
4346
         * variable will get freed when the last upvar goes away.
4347
         */
4348
 
4349
        if (varPtr->refCount == 0) {
4350
            ckfree((char *) varPtr); /* this Var must be VAR_IN_HASHTABLE */
4351
        }
4352
    }
4353
    Tcl_DeleteHashTable(tablePtr);
4354
}
4355
 
4356
/*
4357
 *----------------------------------------------------------------------
4358
 *
4359
 * TclDeleteCompiledLocalVars --
4360
 *
4361
 *      This procedure is called to recycle storage space associated with
4362
 *      the compiler-allocated array of local variables in a procedure call
4363
 *      frame. This procedure resembles TclDeleteVars above except that each
4364
 *      variable is stored in a call frame and not a hash table. For this
4365
 *      procedure to work correctly, it must not be possible for any of the
4366
 *      variable in the table to be accessed from Tcl commands (e.g. from
4367
 *      trace procedures).
4368
 *
4369
 * Results:
4370
 *      None.
4371
 *
4372
 * Side effects:
4373
 *      Variables are deleted and trace procedures are invoked, if
4374
 *      any are declared.
4375
 *
4376
 *----------------------------------------------------------------------
4377
 */
4378
 
4379
void
4380
TclDeleteCompiledLocalVars(iPtr, framePtr)
4381
    Interp *iPtr;               /* Interpreter to which variables belong. */
4382
    CallFrame *framePtr;        /* Procedure call frame containing
4383
                                 * compiler-assigned local variables to
4384
                                 * delete. */
4385
{
4386
    register Var *varPtr;
4387
    int flags;                  /* Flags passed to trace procedures. */
4388
    Var *linkPtr;
4389
    ActiveVarTrace *activePtr;
4390
    int numLocals, i;
4391
 
4392
    flags = TCL_TRACE_UNSETS;
4393
    numLocals = framePtr->numCompiledLocals;
4394
    varPtr = framePtr->compiledLocals;
4395
    for (i = 0;  i < numLocals;  i++) {
4396
        /*
4397
         * For global/upvar variables referenced in procedures, decrement
4398
         * the reference count on the variable referred to, and free
4399
         * the referenced variable if it's no longer needed. Don't delete
4400
         * the hash entry for the other variable if it's in the same table
4401
         * as us: this will happen automatically later on.
4402
         */
4403
 
4404
        if (TclIsVarLink(varPtr)) {
4405
            linkPtr = varPtr->value.linkPtr;
4406
            linkPtr->refCount--;
4407
            if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr)
4408
                    && (linkPtr->tracePtr == NULL)
4409
                    && (linkPtr->flags & VAR_IN_HASHTABLE)) {
4410
                if (linkPtr->hPtr == NULL) {
4411
                    ckfree((char *) linkPtr);
4412
                } else {
4413
                    Tcl_DeleteHashEntry(linkPtr->hPtr);
4414
                    ckfree((char *) linkPtr);
4415
                }
4416
            }
4417
        }
4418
 
4419
        /*
4420
         * Invoke traces on the variable that is being deleted. Then delete
4421
         * the variable's trace records.
4422
         */
4423
 
4424
        if (varPtr->tracePtr != NULL) {
4425
            (void) CallTraces(iPtr, (Var *) NULL, varPtr,
4426
                    varPtr->name, (char *) NULL, flags);
4427
            while (varPtr->tracePtr != NULL) {
4428
                VarTrace *tracePtr = varPtr->tracePtr;
4429
                varPtr->tracePtr = tracePtr->nextPtr;
4430
                ckfree((char *) tracePtr);
4431
            }
4432
            for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
4433
                    activePtr = activePtr->nextPtr) {
4434
                if (activePtr->varPtr == varPtr) {
4435
                    activePtr->nextTracePtr = NULL;
4436
                }
4437
            }
4438
        }
4439
 
4440
        /*
4441
         * Now if the variable is an array, delete its element hash table.
4442
         * Otherwise, if it's a scalar variable, decrement the ref count
4443
         * of its value.
4444
         */
4445
 
4446
        if (TclIsVarArray(varPtr) && (varPtr->value.tablePtr != NULL)) {
4447
            DeleteArray(iPtr, varPtr->name, varPtr, flags);
4448
        }
4449
        if (TclIsVarScalar(varPtr) && (varPtr->value.objPtr != NULL)) {
4450
            TclDecrRefCount(varPtr->value.objPtr);
4451
            varPtr->value.objPtr = NULL;
4452
        }
4453
        varPtr->hPtr = NULL;
4454
        varPtr->tracePtr = NULL;
4455
        TclSetVarUndefined(varPtr);
4456
        TclSetVarScalar(varPtr);
4457
        varPtr++;
4458
    }
4459
}
4460
 
4461
/*
4462
 *----------------------------------------------------------------------
4463
 *
4464
 * DeleteArray --
4465
 *
4466
 *      This procedure is called to free up everything in an array
4467
 *      variable.  It's the caller's responsibility to make sure
4468
 *      that the array is no longer accessible before this procedure
4469
 *      is called.
4470
 *
4471
 * Results:
4472
 *      None.
4473
 *
4474
 * Side effects:
4475
 *      All storage associated with varPtr's array elements is deleted
4476
 *      (including the array's hash table). Deletion trace procedures for
4477
 *      array elements are invoked, then deleted. Any pending traces for
4478
 *      array elements are also deleted.
4479
 *
4480
 *----------------------------------------------------------------------
4481
 */
4482
 
4483
static void
4484
DeleteArray(iPtr, arrayName, varPtr, flags)
4485
    Interp *iPtr;                       /* Interpreter containing array. */
4486
    char *arrayName;                    /* Name of array (used for trace
4487
                                         * callbacks). */
4488
    Var *varPtr;                        /* Pointer to variable structure. */
4489
    int flags;                          /* Flags to pass to CallTraces:
4490
                                         * TCL_TRACE_UNSETS and sometimes
4491
                                         * TCL_INTERP_DESTROYED,
4492
                                         * TCL_NAMESPACE_ONLY, or
4493
                                         * TCL_GLOBAL_ONLY. */
4494
{
4495
    Tcl_HashSearch search;
4496
    register Tcl_HashEntry *hPtr;
4497
    register Var *elPtr;
4498
    ActiveVarTrace *activePtr;
4499
    Tcl_Obj *objPtr;
4500
 
4501
    DeleteSearches(varPtr);
4502
    for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
4503
            hPtr != NULL;  hPtr = Tcl_NextHashEntry(&search)) {
4504
        elPtr = (Var *) Tcl_GetHashValue(hPtr);
4505
        if (TclIsVarScalar(elPtr) && (elPtr->value.objPtr != NULL)) {
4506
            objPtr = elPtr->value.objPtr;
4507
            TclDecrRefCount(objPtr);
4508
            elPtr->value.objPtr = NULL;
4509
        }
4510
        elPtr->hPtr = NULL;
4511
        if (elPtr->tracePtr != NULL) {
4512
            elPtr->flags &= ~VAR_TRACE_ACTIVE;
4513
            (void) CallTraces(iPtr, (Var *) NULL, elPtr, arrayName,
4514
                    Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), flags);
4515
            while (elPtr->tracePtr != NULL) {
4516
                VarTrace *tracePtr = elPtr->tracePtr;
4517
                elPtr->tracePtr = tracePtr->nextPtr;
4518
                ckfree((char *) tracePtr);
4519
            }
4520
            for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
4521
                    activePtr = activePtr->nextPtr) {
4522
                if (activePtr->varPtr == elPtr) {
4523
                    activePtr->nextTracePtr = NULL;
4524
                }
4525
            }
4526
        }
4527
        TclSetVarUndefined(elPtr);
4528
        TclSetVarScalar(elPtr);
4529
        if (elPtr->refCount == 0) {
4530
            ckfree((char *) elPtr); /* element Vars are VAR_IN_HASHTABLE */
4531
        }
4532
    }
4533
    Tcl_DeleteHashTable(varPtr->value.tablePtr);
4534
    ckfree((char *) varPtr->value.tablePtr);
4535
}
4536
 
4537
/*
4538
 *----------------------------------------------------------------------
4539
 *
4540
 * CleanupVar --
4541
 *
4542
 *      This procedure is called when it looks like it may be OK to free up
4543
 *      a variable's storage. If the variable is in a hashtable, its Var
4544
 *      structure and hash table entry will be freed along with those of its
4545
 *      containing array, if any. This procedure is called, for example,
4546
 *      when a trace on a variable deletes a variable.
4547
 *
4548
 * Results:
4549
 *      None.
4550
 *
4551
 * Side effects:
4552
 *      If the variable (or its containing array) really is dead and in a
4553
 *      hashtable, then its Var structure, and possibly its hash table
4554
 *      entry, is freed up.
4555
 *
4556
 *----------------------------------------------------------------------
4557
 */
4558
 
4559
static void
4560
CleanupVar(varPtr, arrayPtr)
4561
    Var *varPtr;                /* Pointer to variable that may be a
4562
                                 * candidate for being expunged. */
4563
    Var *arrayPtr;              /* Array that contains the variable, or
4564
                                 * NULL if this variable isn't an array
4565
                                 * element. */
4566
{
4567
    if (TclIsVarUndefined(varPtr) && (varPtr->refCount == 0)
4568
            && (varPtr->tracePtr == NULL)
4569
            && (varPtr->flags & VAR_IN_HASHTABLE)) {
4570
        if (varPtr->hPtr != NULL) {
4571
            Tcl_DeleteHashEntry(varPtr->hPtr);
4572
        }
4573
        ckfree((char *) varPtr);
4574
    }
4575
    if (arrayPtr != NULL) {
4576
        if (TclIsVarUndefined(arrayPtr) && (arrayPtr->refCount == 0)
4577
                && (arrayPtr->tracePtr == NULL)
4578
                && (arrayPtr->flags & VAR_IN_HASHTABLE)) {
4579
            if (arrayPtr->hPtr != NULL) {
4580
                Tcl_DeleteHashEntry(arrayPtr->hPtr);
4581
            }
4582
            ckfree((char *) arrayPtr);
4583
        }
4584
    }
4585
}
4586
/*
4587
 *----------------------------------------------------------------------
4588
 *
4589
 * VarErrMsg --
4590
 *
4591
 *      Generate a reasonable error message describing why a variable
4592
 *      operation failed.
4593
 *
4594
 * Results:
4595
 *      None.
4596
 *
4597
 * Side effects:
4598
 *      Interp->result is reset to hold a message identifying the
4599
 *      variable given by part1 and part2 and describing why the
4600
 *      variable operation failed.
4601
 *
4602
 *----------------------------------------------------------------------
4603
 */
4604
 
4605
static void
4606
VarErrMsg(interp, part1, part2, operation, reason)
4607
    Tcl_Interp *interp;         /* Interpreter in which to record message. */
4608
    char *part1, *part2;        /* Variable's two-part name. */
4609
    char *operation;            /* String describing operation that failed,
4610
                                 * e.g. "read", "set", or "unset". */
4611
    char *reason;               /* String describing why operation failed. */
4612
{
4613
    Tcl_ResetResult(interp);
4614
    Tcl_AppendResult(interp, "can't ", operation, " \"", part1,
4615
                     (char *) NULL);
4616
    if (part2 != NULL) {
4617
        Tcl_AppendResult(interp, "(", part2, ")", (char *) NULL);
4618
    }
4619
    Tcl_AppendResult(interp, "\": ", reason, (char *) NULL);
4620
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.