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