tclVar.cGo to the documentation of this file.00001 /* 00002 * tclVar.c -- 00003 * 00004 * This file contains routines that implement Tcl variables (both scalars 00005 * and arrays). 00006 * 00007 * The implementation of arrays is modelled after an initial 00008 * implementation by Mark Diekhans and Karl Lehenbauer. 00009 * 00010 * Copyright (c) 1987-1994 The Regents of the University of California. 00011 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 00012 * Copyright (c) 1998-1999 by Scriptics Corporation. 00013 * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. 00014 * Copyright (c) 2007 Miguel Sofer 00015 * 00016 * See the file "license.terms" for information on usage and redistribution of 00017 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00018 * 00019 * RCS: @(#) $Id: tclVar.c,v 1.159 2007/12/13 15:23:21 dgp Exp $ 00020 */ 00021 00022 #include "tclInt.h" 00023 00024 /* 00025 * Prototypes for the variable hash key methods. 00026 */ 00027 00028 static Tcl_HashEntry * AllocVarEntry(Tcl_HashTable *tablePtr, void *keyPtr); 00029 static void FreeVarEntry(Tcl_HashEntry *hPtr); 00030 static int CompareVarKeys(void *keyPtr, Tcl_HashEntry *hPtr); 00031 static unsigned int HashVarKey(Tcl_HashTable *tablePtr, void *keyPtr); 00032 00033 static Tcl_HashKeyType tclVarHashKeyType = { 00034 TCL_HASH_KEY_TYPE_VERSION, /* version */ 00035 0, /* flags */ 00036 HashVarKey, /* hashKeyProc */ 00037 CompareVarKeys, /* compareKeysProc */ 00038 AllocVarEntry, /* allocEntryProc */ 00039 FreeVarEntry /* freeEntryProc */ 00040 }; 00041 00042 static inline Var * VarHashCreateVar(TclVarHashTable *tablePtr, 00043 Tcl_Obj *key, int *newPtr); 00044 static inline Var * VarHashFirstVar(TclVarHashTable *tablePtr, 00045 Tcl_HashSearch *searchPtr); 00046 static inline Var * VarHashNextVar(Tcl_HashSearch *searchPtr); 00047 static inline void CleanupVar(Var *varPtr, Var *arrayPtr); 00048 00049 #define VarHashGetValue(hPtr) \ 00050 ((Var *) ((char *)hPtr - TclOffset(VarInHash, entry))) 00051 00052 static inline Var * 00053 VarHashCreateVar( 00054 TclVarHashTable *tablePtr, 00055 Tcl_Obj *key, 00056 int *newPtr) 00057 { 00058 Tcl_HashEntry *hPtr = Tcl_CreateHashEntry((Tcl_HashTable *) tablePtr, 00059 (char *) key, newPtr); 00060 00061 if (hPtr) { 00062 return VarHashGetValue(hPtr); 00063 } else { 00064 return NULL; 00065 } 00066 } 00067 00068 #define VarHashFindVar(tablePtr, key) \ 00069 VarHashCreateVar((tablePtr), (key), NULL) 00070 00071 #define VarHashInvalidateEntry(varPtr) \ 00072 ((varPtr)->flags |= VAR_DEAD_HASH) 00073 00074 #define VarHashDeleteEntry(varPtr) \ 00075 Tcl_DeleteHashEntry(&(((VarInHash *) varPtr)->entry)) 00076 00077 #define VarHashFirstEntry(tablePtr, searchPtr) \ 00078 Tcl_FirstHashEntry((Tcl_HashTable *) (tablePtr), (searchPtr)) 00079 00080 #define VarHashNextEntry(searchPtr) \ 00081 Tcl_NextHashEntry((searchPtr)) 00082 00083 static inline Var * 00084 VarHashFirstVar( 00085 TclVarHashTable *tablePtr, 00086 Tcl_HashSearch *searchPtr) 00087 { 00088 Tcl_HashEntry *hPtr = VarHashFirstEntry(tablePtr, searchPtr); 00089 00090 if (hPtr) { 00091 return VarHashGetValue(hPtr); 00092 } else { 00093 return NULL; 00094 } 00095 } 00096 00097 static inline Var * 00098 VarHashNextVar( 00099 Tcl_HashSearch *searchPtr) 00100 { 00101 Tcl_HashEntry *hPtr = VarHashNextEntry(searchPtr); 00102 00103 if (hPtr) { 00104 return VarHashGetValue(hPtr); 00105 } else { 00106 return NULL; 00107 } 00108 } 00109 00110 #define VarHashGetKey(varPtr) \ 00111 (((VarInHash *)(varPtr))->entry.key.objPtr) 00112 00113 #define VarHashDeleteTable(tablePtr) \ 00114 Tcl_DeleteHashTable((Tcl_HashTable *) (tablePtr)) 00115 00116 /* 00117 * The strings below are used to indicate what went wrong when a variable 00118 * access is denied. 00119 */ 00120 00121 static const char *noSuchVar = "no such variable"; 00122 static const char *isArray = "variable is array"; 00123 static const char *needArray = "variable isn't array"; 00124 static const char *noSuchElement = "no such element in array"; 00125 static const char *danglingElement = 00126 "upvar refers to element in deleted array"; 00127 static const char *danglingVar = 00128 "upvar refers to variable in deleted namespace"; 00129 static const char *badNamespace = "parent namespace doesn't exist"; 00130 static const char *missingName = "missing variable name"; 00131 static const char *isArrayElement = 00132 "name refers to an element in an array"; 00133 00134 /* 00135 * A test to see if we are in a call frame that has local variables. This is 00136 * true if we are inside a procedure body. 00137 */ 00138 00139 #define HasLocalVars(framePtr) ((framePtr)->isProcCallFrame & FRAME_IS_PROC) 00140 00141 /* 00142 * Forward references to functions defined later in this file: 00143 */ 00144 00145 static void AppendLocals(Tcl_Interp *interp, Tcl_Obj *listPtr, 00146 Tcl_Obj *patternPtr, int includeLinks); 00147 static void DeleteSearches(Interp *iPtr, Var *arrayVarPtr); 00148 static void DeleteArray(Interp *iPtr, Tcl_Obj *arrayNamePtr, 00149 Var *varPtr, int flags); 00150 static Tcl_Var ObjFindNamespaceVar(Tcl_Interp *interp, 00151 Tcl_Obj *namePtr, Tcl_Namespace *contextNsPtr, 00152 int flags); 00153 static int ObjMakeUpvar(Tcl_Interp *interp, 00154 CallFrame *framePtr, Tcl_Obj *otherP1Ptr, 00155 const char *otherP2, const int otherFlags, 00156 Tcl_Obj *myNamePtr, int myFlags, int index); 00157 static ArraySearch * ParseSearchId(Tcl_Interp *interp, const Var *varPtr, 00158 Tcl_Obj *varNamePtr, Tcl_Obj *handleObj); 00159 static void UnsetVarStruct(Var *varPtr, Var *arrayPtr, 00160 Interp *iPtr, Tcl_Obj *part1Ptr, 00161 Tcl_Obj *part2Ptr, int flags); 00162 static int SetArraySearchObj(Tcl_Interp *interp, 00163 Tcl_Obj *objPtr); 00164 00165 /* 00166 * Functions defined in this file that may be exported in the future for use 00167 * by the bytecode compiler and engine or to the public interface. 00168 */ 00169 00170 MODULE_SCOPE Var * TclLookupSimpleVar(Tcl_Interp *interp, 00171 Tcl_Obj *varNamePtr, int flags, const int create, 00172 const char **errMsgPtr, int *indexPtr); 00173 00174 static Tcl_DupInternalRepProc DupLocalVarName; 00175 static Tcl_FreeInternalRepProc FreeLocalVarName; 00176 static Tcl_UpdateStringProc PanicOnUpdateVarName; 00177 00178 static Tcl_FreeInternalRepProc FreeParsedVarName; 00179 static Tcl_DupInternalRepProc DupParsedVarName; 00180 static Tcl_UpdateStringProc UpdateParsedVarName; 00181 00182 static Tcl_UpdateStringProc PanicOnUpdateVarName; 00183 static Tcl_SetFromAnyProc PanicOnSetVarName; 00184 00185 /* 00186 * Types of Tcl_Objs used to cache variable lookups. 00187 * 00188 * localVarName - INTERNALREP DEFINITION: 00189 * ptrAndLongRep.ptr: pointer to name obj in varFramePtr->localCache 00190 * or NULL if it is this same obj 00191 * ptrAndLongRep.value: index into locals table 00192 * 00193 * nsVarName - INTERNALREP DEFINITION: 00194 * twoPtrValue.ptr1: pointer to the namespace containing the reference 00195 * twoPtrValue.ptr2: pointer to the corresponding Var 00196 * 00197 * parsedVarName - INTERNALREP DEFINITION: 00198 * twoPtrValue.ptr1: pointer to the array name Tcl_Obj, or NULL if it is a 00199 * scalar variable 00200 * twoPtrValue.ptr2: pointer to the element name string (owned by this 00201 * Tcl_Obj), or NULL if it is a scalar variable 00202 */ 00203 00204 static Tcl_ObjType localVarNameType = { 00205 "localVarName", 00206 FreeLocalVarName, DupLocalVarName, PanicOnUpdateVarName, PanicOnSetVarName 00207 }; 00208 00209 /* 00210 * Caching of namespace variables disabled: no simple way was found to avoid 00211 * interfering with the resolver's idea of variable existence. A cached 00212 * varName may keep a variable's name in the namespace's hash table, which is 00213 * the resolver's criterion for existence (see test namespace-17.10). 00214 */ 00215 00216 #define ENABLE_NS_VARNAME_CACHING 0 00217 00218 #if ENABLE_NS_VARNAME_CACHING 00219 static Tcl_FreeInternalRepProc FreeNsVarName; 00220 static Tcl_DupInternalRepProc DupNsVarName; 00221 00222 static Tcl_ObjType tclNsVarNameType = { 00223 "namespaceVarName", 00224 FreeNsVarName, DupNsVarName, PanicOnUpdateVarName, PanicOnSetVarName 00225 }; 00226 #endif 00227 00228 static Tcl_ObjType tclParsedVarNameType = { 00229 "parsedVarName", 00230 FreeParsedVarName, DupParsedVarName, UpdateParsedVarName, PanicOnSetVarName 00231 }; 00232 00233 /* 00234 * Type of Tcl_Objs used to speed up array searches. 00235 * 00236 * INTERNALREP DEFINITION: 00237 * twoPtrValue.ptr1: searchIdNumber (cast to pointer) 00238 * twoPtrValue.ptr2: variableNameStartInString (cast to pointer) 00239 * 00240 * Note that the value stored in ptr2 is the offset into the string of the 00241 * start of the variable name and not the address of the variable name itself, 00242 * as this can be safely copied. 00243 */ 00244 00245 Tcl_ObjType tclArraySearchType = { 00246 "array search", 00247 NULL, NULL, NULL, SetArraySearchObj 00248 }; 00249 00250 Var * 00251 TclVarHashCreateVar( 00252 TclVarHashTable *tablePtr, 00253 const char *key, 00254 int *newPtr) 00255 { 00256 Tcl_Obj *keyPtr; 00257 Var *varPtr; 00258 00259 keyPtr = Tcl_NewStringObj(key, -1); 00260 Tcl_IncrRefCount(keyPtr); 00261 varPtr = VarHashCreateVar(tablePtr, keyPtr, newPtr); 00262 Tcl_DecrRefCount(keyPtr); 00263 00264 return varPtr; 00265 } 00266 00267 /* 00268 *---------------------------------------------------------------------- 00269 * 00270 * TclCleanupVar -- 00271 * 00272 * This function is called when it looks like it may be OK to free up a 00273 * variable's storage. If the variable is in a hashtable, its Var 00274 * structure and hash table entry will be freed along with those of its 00275 * containing array, if any. This function is called, for example, when 00276 * a trace on a variable deletes a variable. 00277 * 00278 * Results: 00279 * None. 00280 * 00281 * Side effects: 00282 * If the variable (or its containing array) really is dead and in a 00283 * hashtable, then its Var structure, and possibly its hash table entry, 00284 * is freed up. 00285 * 00286 *---------------------------------------------------------------------- 00287 */ 00288 00289 static inline void 00290 CleanupVar( 00291 Var *varPtr, /* Pointer to variable that may be a candidate 00292 * for being expunged. */ 00293 Var *arrayPtr) /* Array that contains the variable, or NULL 00294 * if this variable isn't an array element. */ 00295 { 00296 if (TclIsVarUndefined(varPtr) && TclIsVarInHash(varPtr) 00297 && !TclIsVarTraced(varPtr) 00298 && (VarHashRefCount(varPtr) == !TclIsVarDeadHash(varPtr))) { 00299 if (VarHashRefCount(varPtr) == 0) { 00300 ckfree((char *) varPtr); 00301 } else { 00302 VarHashDeleteEntry(varPtr); 00303 } 00304 } 00305 if (arrayPtr != NULL && TclIsVarUndefined(arrayPtr) && 00306 TclIsVarInHash(arrayPtr) && !TclIsVarTraced(arrayPtr) && 00307 (VarHashRefCount(arrayPtr) == !TclIsVarDeadHash(arrayPtr))) { 00308 if (VarHashRefCount(arrayPtr) == 0) { 00309 ckfree((char *) arrayPtr); 00310 } else { 00311 VarHashDeleteEntry(arrayPtr); 00312 } 00313 } 00314 } 00315 00316 void 00317 TclCleanupVar( 00318 Var *varPtr, /* Pointer to variable that may be a candidate 00319 * for being expunged. */ 00320 Var *arrayPtr) /* Array that contains the variable, or NULL 00321 * if this variable isn't an array element. */ 00322 { 00323 CleanupVar(varPtr, arrayPtr); 00324 } 00325 00326 /* 00327 *---------------------------------------------------------------------- 00328 * 00329 * TclLookupVar -- 00330 * 00331 * This function is used to locate a variable given its name(s). It has 00332 * been mostly superseded by TclObjLookupVar, it is now only used by the 00333 * trace code. It is kept in tcl8.5 mainly because it is in the internal 00334 * stubs table, so that some extension may be calling it. 00335 * 00336 * Results: 00337 * The return value is a pointer to the variable structure indicated by 00338 * part1 and part2, or NULL if the variable couldn't be found. If the 00339 * variable is found, *arrayPtrPtr is filled in with the address of the 00340 * variable structure for the array that contains the variable (or NULL 00341 * if the variable is a scalar). If the variable can't be found and 00342 * either createPart1 or createPart2 are 1, a new as-yet-undefined 00343 * (VAR_UNDEFINED) variable structure is created, entered into a hash 00344 * table, and returned. 00345 * 00346 * If the variable isn't found and creation wasn't specified, or some 00347 * other error occurs, NULL is returned and an error message is left in 00348 * the interp's result if TCL_LEAVE_ERR_MSG is set in flags. 00349 * 00350 * Note: it's possible for the variable returned to be VAR_UNDEFINED even 00351 * if createPart1 or createPart2 are 1 (these only cause the hash table 00352 * entry or array to be created). For example, the variable might be a 00353 * global that has been unset but is still referenced by a procedure, or 00354 * a variable that has been unset but it only being kept in existence (if 00355 * VAR_UNDEFINED) by a trace. 00356 * 00357 * Side effects: 00358 * New hashtable entries may be created if createPart1 or createPart2 00359 * are 1. 00360 * 00361 *---------------------------------------------------------------------- 00362 */ 00363 00364 Var * 00365 TclLookupVar( 00366 Tcl_Interp *interp, /* Interpreter to use for lookup. */ 00367 const char *part1, /* If part2 isn't NULL, this is the name of an 00368 * array. Otherwise, this is a full variable 00369 * name that could include a parenthesized 00370 * array element. */ 00371 const char *part2, /* Name of element within array, or NULL. */ 00372 int flags, /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 00373 * and TCL_LEAVE_ERR_MSG bits matter. */ 00374 const char *msg, /* Verb to use in error messages, e.g. "read" 00375 * or "set". Only needed if TCL_LEAVE_ERR_MSG 00376 * is set in flags. */ 00377 int createPart1, /* If 1, create hash table entry for part 1 of 00378 * name, if it doesn't already exist. If 0, 00379 * return error if it doesn't exist. */ 00380 int createPart2, /* If 1, create hash table entry for part 2 of 00381 * name, if it doesn't already exist. If 0, 00382 * return error if it doesn't exist. */ 00383 Var **arrayPtrPtr) /* If the name refers to an element of an 00384 * array, *arrayPtrPtr gets filled in with 00385 * address of array variable. Otherwise this 00386 * is set to NULL. */ 00387 { 00388 Tcl_Obj *part1Ptr; 00389 Var *varPtr; 00390 00391 part1Ptr = Tcl_NewStringObj(part1, -1); 00392 Tcl_IncrRefCount(part1Ptr); 00393 00394 varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, msg, 00395 createPart1, createPart2, arrayPtrPtr); 00396 00397 TclDecrRefCount(part1Ptr); 00398 return varPtr; 00399 } 00400 00401 /* 00402 *---------------------------------------------------------------------- 00403 * 00404 * TclObjLookupVar, TclObjLookupVarEx -- 00405 * 00406 * This function is used by virtually all of the variable code to locate 00407 * a variable given its name(s). The parsing into array/element 00408 * components and (if possible) the lookup results are cached in 00409 * part1Ptr, which is converted to one of the varNameTypes. 00410 * 00411 * Results: 00412 * The return value is a pointer to the variable structure indicated by 00413 * part1Ptr and part2, or NULL if the variable couldn't be found. If * 00414 * the variable is found, *arrayPtrPtr is filled with the address of the 00415 * variable structure for the array that contains the variable (or NULL 00416 * if the variable is a scalar). If the variable can't be found and 00417 * either createPart1 or createPart2 are 1, a new as-yet-undefined 00418 * (VAR_UNDEFINED) variable structure is created, entered into a hash 00419 * table, and returned. 00420 * 00421 * If the variable isn't found and creation wasn't specified, or some 00422 * other error occurs, NULL is returned and an error message is left in 00423 * the interp's result if TCL_LEAVE_ERR_MSG is set in flags. 00424 * 00425 * Note: it's possible for the variable returned to be VAR_UNDEFINED even 00426 * if createPart1 or createPart2 are 1 (these only cause the hash table 00427 * entry or array to be created). For example, the variable might be a 00428 * global that has been unset but is still referenced by a procedure, or 00429 * a variable that has been unset but it only being kept in existence (if 00430 * VAR_UNDEFINED) by a trace. 00431 * 00432 * Side effects: 00433 * New hashtable entries may be created if createPart1 or createPart2 00434 * are 1. The object part1Ptr is converted to one of localVarNameType, 00435 * tclNsVarNameType or tclParsedVarNameType and caches as much of the 00436 * lookup as it can. 00437 * 00438 *---------------------------------------------------------------------- 00439 */ 00440 00441 Var * 00442 TclObjLookupVar( 00443 Tcl_Interp *interp, /* Interpreter to use for lookup. */ 00444 register Tcl_Obj *part1Ptr, /* If part2 isn't NULL, this is the name of an 00445 * array. Otherwise, this is a full variable 00446 * name that could include a parenthesized 00447 * array element. */ 00448 const char *part2, /* Name of element within array, or NULL. */ 00449 int flags, /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 00450 * and TCL_LEAVE_ERR_MSG bits matter. */ 00451 const char *msg, /* Verb to use in error messages, e.g. "read" 00452 * or "set". Only needed if TCL_LEAVE_ERR_MSG 00453 * is set in flags. */ 00454 const int createPart1, /* If 1, create hash table entry for part 1 of 00455 * name, if it doesn't already exist. If 0, 00456 * return error if it doesn't exist. */ 00457 const int createPart2, /* If 1, create hash table entry for part 2 of 00458 * name, if it doesn't already exist. If 0, 00459 * return error if it doesn't exist. */ 00460 Var **arrayPtrPtr) /* If the name refers to an element of an 00461 * array, *arrayPtrPtr gets filled in with 00462 * address of array variable. Otherwise this 00463 * is set to NULL. */ 00464 { 00465 Tcl_Obj *part2Ptr; 00466 Var *resPtr; 00467 00468 if (part2) { 00469 part2Ptr = Tcl_NewStringObj(part2, -1); 00470 Tcl_IncrRefCount(part2Ptr); 00471 } else { 00472 part2Ptr = NULL; 00473 } 00474 00475 resPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, 00476 flags, msg, createPart1, createPart2, arrayPtrPtr); 00477 00478 if (part2Ptr) { 00479 Tcl_DecrRefCount(part2Ptr); 00480 } 00481 00482 return resPtr; 00483 } 00484 00485 Var * 00486 TclObjLookupVarEx( 00487 Tcl_Interp *interp, /* Interpreter to use for lookup. */ 00488 Tcl_Obj *part1Ptr, /* If part2Ptr isn't NULL, this is the name of 00489 * an array. Otherwise, this is a full 00490 * variable name that could include a 00491 * parenthesized array element. */ 00492 Tcl_Obj *part2Ptr, /* Name of element within array, or NULL. */ 00493 int flags, /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 00494 * and TCL_LEAVE_ERR_MSG bits matter. */ 00495 const char *msg, /* Verb to use in error messages, e.g. "read" 00496 * or "set". Only needed if TCL_LEAVE_ERR_MSG 00497 * is set in flags. */ 00498 const int createPart1, /* If 1, create hash table entry for part 1 of 00499 * name, if it doesn't already exist. If 0, 00500 * return error if it doesn't exist. */ 00501 const int createPart2, /* If 1, create hash table entry for part 2 of 00502 * name, if it doesn't already exist. If 0, 00503 * return error if it doesn't exist. */ 00504 Var **arrayPtrPtr) /* If the name refers to an element of an 00505 * array, *arrayPtrPtr gets filled in with 00506 * address of array variable. Otherwise this 00507 * is set to NULL. */ 00508 { 00509 Interp *iPtr = (Interp *) interp; 00510 register Var *varPtr; /* Points to the variable's in-frame Var 00511 * structure. */ 00512 char *part1; 00513 int index, len1, len2; 00514 int parsed = 0; 00515 Tcl_Obj *objPtr; 00516 const Tcl_ObjType *typePtr = part1Ptr->typePtr; 00517 const char *errMsg = NULL; 00518 CallFrame *varFramePtr = iPtr->varFramePtr; 00519 Namespace *nsPtr; 00520 char *part2 = part2Ptr? TclGetString(part2Ptr):NULL; 00521 char *newPart2 = NULL; 00522 00523 *arrayPtrPtr = NULL; 00524 00525 if (varFramePtr) { 00526 nsPtr = varFramePtr->nsPtr; 00527 } else { 00528 /* 00529 * Some variables in the global ns have to be initialized before the 00530 * root call frame is in place. 00531 */ 00532 00533 nsPtr = NULL; 00534 } 00535 00536 if (typePtr == &localVarNameType) { 00537 int localIndex; 00538 00539 localVarNameTypeHandling: 00540 localIndex = (int) part1Ptr->internalRep.ptrAndLongRep.value; 00541 if (HasLocalVars(varFramePtr) 00542 && !(flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) 00543 && (localIndex < varFramePtr->numCompiledLocals)) { 00544 /* 00545 * Use the cached index if the names coincide. 00546 */ 00547 00548 Tcl_Obj *namePtr = (Tcl_Obj *) 00549 part1Ptr->internalRep.ptrAndLongRep.ptr; 00550 Tcl_Obj *checkNamePtr = localName(iPtr->varFramePtr, localIndex); 00551 00552 if ((!namePtr && (checkNamePtr == part1Ptr)) || 00553 (namePtr && (checkNamePtr == namePtr))) { 00554 varPtr = (Var *) &(varFramePtr->compiledLocals[localIndex]); 00555 goto donePart1; 00556 } 00557 } 00558 goto doneParsing; 00559 #if ENABLE_NS_VARNAME_CACHING 00560 } else if (typePtr == &tclNsVarNameType) { 00561 int useGlobal, useReference; 00562 Namespace *cachedNsPtr = part1Ptr->internalRep.twoPtrValue.ptr1; 00563 varPtr = part1Ptr->internalRep.twoPtrValue.ptr2; 00564 00565 useGlobal = (cachedNsPtr == iPtr->globalNsPtr) && ( 00566 (flags & TCL_GLOBAL_ONLY) || 00567 (part1[0]==':' && part1[1]==':') || 00568 (!HasLocalVars(varFramePtr) && (nsPtr==iPtr->globalNsPtr))); 00569 00570 useReference = useGlobal || ((cachedNsPtr == nsPtr) && ( 00571 (flags & TCL_NAMESPACE_ONLY) || 00572 (!HasLocalVars(varFramePtr) && !(flags & TCL_GLOBAL_ONLY) && 00573 /* 00574 * Careful: an undefined ns variable could be hiding a valid 00575 * global reference. 00576 */ 00577 !TclIsVarUndefined(varPtr)))); 00578 00579 if (useReference && !TclIsVarDeadHash(varPtr)) { 00580 /* 00581 * A straight global or namespace reference, use it. It isn't so 00582 * simple to deal with 'implicit' namespace references, i.e., 00583 * those where the reference could be to either a namespace or a 00584 * global variable. Those we lookup again. 00585 * 00586 * If TclIsVarDeadHash(varPtr), this might be a reference to a 00587 * variable in a deleted namespace, kept alive by e.g. part1Ptr. 00588 * We could conceivably be so unlucky that a new namespace was 00589 * created at the same address as the deleted one, so to be safe 00590 * we test for a valid hPtr. 00591 */ 00592 00593 goto donePart1; 00594 } 00595 goto doneParsing; 00596 #endif 00597 } 00598 00599 /* 00600 * If part1Ptr is a tclParsedVarNameType, separate it into the pre-parsed 00601 * parts. 00602 */ 00603 00604 if (typePtr == &tclParsedVarNameType) { 00605 if (part1Ptr->internalRep.twoPtrValue.ptr1 != NULL) { 00606 if (part2Ptr != NULL) { 00607 /* 00608 * ERROR: part1Ptr is already an array element, cannot specify 00609 * a part2. 00610 */ 00611 00612 if (flags & TCL_LEAVE_ERR_MSG) { 00613 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, msg, 00614 noSuchVar, -1); 00615 } 00616 return NULL; 00617 } 00618 part2 = newPart2 = part1Ptr->internalRep.twoPtrValue.ptr2; 00619 if (newPart2) { 00620 part2Ptr = Tcl_NewStringObj(newPart2, -1); 00621 Tcl_IncrRefCount(part2Ptr); 00622 } 00623 part1Ptr = part1Ptr->internalRep.twoPtrValue.ptr1; 00624 typePtr = part1Ptr->typePtr; 00625 if (typePtr == &localVarNameType) { 00626 goto localVarNameTypeHandling; 00627 } 00628 } 00629 parsed = 1; 00630 } 00631 part1 = TclGetStringFromObj(part1Ptr, &len1); 00632 00633 if (!parsed && (*(part1 + len1 - 1) == ')')) { 00634 /* 00635 * part1Ptr is possibly an unparsed array element. 00636 */ 00637 00638 register int i; 00639 00640 len2 = -1; 00641 for (i = 0; i < len1; i++) { 00642 if (*(part1 + i) == '(') { 00643 if (part2Ptr != NULL) { 00644 if (flags & TCL_LEAVE_ERR_MSG) { 00645 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, msg, 00646 needArray, -1); 00647 } 00648 return NULL; 00649 } 00650 00651 /* 00652 * part1Ptr points to an array element; first copy the element 00653 * name to a new string part2. 00654 */ 00655 00656 part2 = part1 + i + 1; 00657 len2 = len1 - i - 2; 00658 len1 = i; 00659 00660 newPart2 = ckalloc((unsigned int) (len2+1)); 00661 memcpy(newPart2, part2, (unsigned int) len2); 00662 *(newPart2+len2) = '\0'; 00663 part2 = newPart2; 00664 part2Ptr = Tcl_NewStringObj(newPart2, -1); 00665 Tcl_IncrRefCount(part2Ptr); 00666 00667 /* 00668 * Free the internal rep of the original part1Ptr, now renamed 00669 * objPtr, and set it to tclParsedVarNameType. 00670 */ 00671 00672 objPtr = part1Ptr; 00673 TclFreeIntRep(objPtr); 00674 objPtr->typePtr = &tclParsedVarNameType; 00675 00676 /* 00677 * Define a new string object to hold the new part1Ptr, i.e., 00678 * the array name. Set the internal rep of objPtr, reset 00679 * typePtr and part1 to contain the references to the array 00680 * name. 00681 */ 00682 00683 TclNewStringObj(part1Ptr, part1, len1); 00684 Tcl_IncrRefCount(part1Ptr); 00685 00686 objPtr->internalRep.twoPtrValue.ptr1 = part1Ptr; 00687 objPtr->internalRep.twoPtrValue.ptr2 = (void *) part2; 00688 00689 typePtr = part1Ptr->typePtr; 00690 part1 = TclGetString(part1Ptr); 00691 break; 00692 } 00693 } 00694 } 00695 00696 doneParsing: 00697 /* 00698 * part1Ptr is not an array element; look it up, and convert it to one of 00699 * the cached types if possible. 00700 */ 00701 00702 TclFreeIntRep(part1Ptr); 00703 part1Ptr->typePtr = NULL; 00704 00705 varPtr = TclLookupSimpleVar(interp, part1Ptr, flags, createPart1, 00706 &errMsg, &index); 00707 if (varPtr == NULL) { 00708 if ((errMsg != NULL) && (flags & TCL_LEAVE_ERR_MSG)) { 00709 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, msg, errMsg, -1); 00710 } 00711 if (newPart2) { 00712 Tcl_DecrRefCount(part2Ptr); 00713 } 00714 return NULL; 00715 } 00716 00717 /* 00718 * Cache the newly found variable if possible. 00719 */ 00720 00721 if (index >= 0) { 00722 /* 00723 * An indexed local variable. 00724 */ 00725 00726 part1Ptr->typePtr = &localVarNameType; 00727 if (part1Ptr != localName(iPtr->varFramePtr, index)) { 00728 part1Ptr->internalRep.ptrAndLongRep.ptr = 00729 localName(iPtr->varFramePtr, index); 00730 Tcl_IncrRefCount((Tcl_Obj *) 00731 part1Ptr->internalRep.ptrAndLongRep.ptr); 00732 } else { 00733 part1Ptr->internalRep.ptrAndLongRep.ptr = NULL; 00734 } 00735 part1Ptr->internalRep.ptrAndLongRep.value = (long) index; 00736 #if ENABLE_NS_VARNAME_CACHING 00737 } else if (index > -3) { 00738 /* 00739 * A cacheable namespace or global variable. 00740 */ 00741 00742 Namespace *nsPtr; 00743 00744 nsPtr = ((index == -1) ? iPtr->globalNsPtr : varFramePtr->nsPtr); 00745 varPtr->refCount++; 00746 part1Ptr->typePtr = &tclNsVarNameType; 00747 part1Ptr->internalRep.twoPtrValue.ptr1 = nsPtr; 00748 part1Ptr->internalRep.twoPtrValue.ptr2 = varPtr; 00749 #endif 00750 } else { 00751 /* 00752 * At least mark part1Ptr as already parsed. 00753 */ 00754 00755 part1Ptr->typePtr = &tclParsedVarNameType; 00756 part1Ptr->internalRep.twoPtrValue.ptr1 = NULL; 00757 part1Ptr->internalRep.twoPtrValue.ptr2 = NULL; 00758 } 00759 00760 donePart1: 00761 #if 0 00762 if (varPtr == NULL) { 00763 if (flags & TCL_LEAVE_ERR_MSG) { 00764 part1 = TclGetString(part1Ptr); 00765 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, msg, 00766 "Cached variable reference is NULL.", -1); 00767 } 00768 return NULL; 00769 } 00770 #endif 00771 while (TclIsVarLink(varPtr)) { 00772 varPtr = varPtr->value.linkPtr; 00773 } 00774 00775 if (part2Ptr != NULL) { 00776 /* 00777 * Array element sought: look it up. 00778 */ 00779 00780 *arrayPtrPtr = varPtr; 00781 varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr, flags, msg, 00782 createPart1, createPart2, varPtr, -1); 00783 if (newPart2) { 00784 Tcl_DecrRefCount(part2Ptr); 00785 } 00786 } 00787 return varPtr; 00788 } 00789 00790 /* 00791 * This flag bit should not interfere with TCL_GLOBAL_ONLY, 00792 * TCL_NAMESPACE_ONLY, or TCL_LEAVE_ERR_MSG; it signals that the variable 00793 * lookup is performed for upvar (or similar) purposes, with slightly 00794 * different rules: 00795 * - Bug #696893 - variable is either proc-local or in the current 00796 * namespace; never follow the second (global) resolution path 00797 * - Bug #631741 - do not use special namespace or interp resolvers 00798 * 00799 * It should also not collide with the (deprecated) TCL_PARSE_PART1 flag 00800 * (Bug #835020) 00801 */ 00802 00803 #define AVOID_RESOLVERS 0x40000 00804 00805 /* 00806 *---------------------------------------------------------------------- 00807 * 00808 * TclLookupSimpleVar -- 00809 * 00810 * This function is used by to locate a simple variable (i.e., not an 00811 * array element) given its name. 00812 * 00813 * Results: 00814 * The return value is a pointer to the variable structure indicated by 00815 * varName, or NULL if the variable couldn't be found. If the variable 00816 * can't be found and create is 1, a new as-yet-undefined (VAR_UNDEFINED) 00817 * variable structure is created, entered into a hash table, and 00818 * returned. 00819 * 00820 * If the current CallFrame corresponds to a proc and the variable found 00821 * is one of the compiledLocals, its index is placed in *indexPtr. 00822 * Otherwise, *indexPtr will be set to (according to the needs of 00823 * TclObjLookupVar): 00824 * -1 a global reference 00825 * -2 a reference to a namespace variable 00826 * -3 a non-cachable reference, i.e., one of: 00827 * . non-indexed local var 00828 * . a reference of unknown origin; 00829 * . resolution by a namespace or interp resolver 00830 * 00831 * If the variable isn't found and creation wasn't specified, or some 00832 * other error occurs, NULL is returned and the corresponding error 00833 * message is left in *errMsgPtr. 00834 * 00835 * Note: it's possible for the variable returned to be VAR_UNDEFINED even 00836 * if create is 1 (this only causes the hash table entry to be created). 00837 * For example, the variable might be a global that has been unset but is 00838 * still referenced by a procedure, or a variable that has been unset but 00839 * it only being kept in existence (if VAR_UNDEFINED) by a trace. 00840 * 00841 * Side effects: 00842 * A new hashtable entry may be created if create is 1. 00843 * 00844 *---------------------------------------------------------------------- 00845 */ 00846 00847 Var * 00848 TclLookupSimpleVar( 00849 Tcl_Interp *interp, /* Interpreter to use for lookup. */ 00850 Tcl_Obj *varNamePtr, /* This is a simple variable name that could 00851 * represent a scalar or an array. */ 00852 int flags, /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 00853 * AVOID_RESOLVERS and TCL_LEAVE_ERR_MSG bits 00854 * matter. */ 00855 const int create, /* If 1, create hash table entry for varname, 00856 * if it doesn't already exist. If 0, return 00857 * error if it doesn't exist. */ 00858 const char **errMsgPtr, 00859 int *indexPtr) 00860 { 00861 Interp *iPtr = (Interp *) interp; 00862 CallFrame *varFramePtr = iPtr->varFramePtr; 00863 /* Points to the procedure call frame whose 00864 * variables are currently in use. Same as the 00865 * current procedure's frame, if any, unless 00866 * an "uplevel" is executing. */ 00867 TclVarHashTable *tablePtr; /* Points to the hashtable, if any, in which 00868 * to look up the variable. */ 00869 Tcl_Var var; /* Used to search for global names. */ 00870 Var *varPtr; /* Points to the Var structure returned for 00871 * the variable. */ 00872 Namespace *varNsPtr, *cxtNsPtr, *dummy1Ptr, *dummy2Ptr; 00873 ResolverScheme *resPtr; 00874 int isNew, i, result; 00875 const char *varName = TclGetString(varNamePtr); 00876 00877 varPtr = NULL; 00878 varNsPtr = NULL; /* Set non-NULL if a nonlocal variable. */ 00879 *indexPtr = -3; 00880 00881 if (flags & TCL_GLOBAL_ONLY) { 00882 cxtNsPtr = iPtr->globalNsPtr; 00883 } else { 00884 cxtNsPtr = iPtr->varFramePtr->nsPtr; 00885 } 00886 00887 /* 00888 * If this namespace has a variable resolver, then give it first crack at 00889 * the variable resolution. It may return a Tcl_Var value, it may signal 00890 * to continue onward, or it may signal an error. 00891 */ 00892 00893 if ((cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) 00894 && !(flags & AVOID_RESOLVERS)) { 00895 resPtr = iPtr->resolverPtr; 00896 if (cxtNsPtr->varResProc) { 00897 result = (*cxtNsPtr->varResProc)(interp, varName, 00898 (Tcl_Namespace *) cxtNsPtr, flags, &var); 00899 } else { 00900 result = TCL_CONTINUE; 00901 } 00902 00903 while (result == TCL_CONTINUE && resPtr) { 00904 if (resPtr->varResProc) { 00905 result = (*resPtr->varResProc)(interp, varName, 00906 (Tcl_Namespace *) cxtNsPtr, flags, &var); 00907 } 00908 resPtr = resPtr->nextPtr; 00909 } 00910 00911 if (result == TCL_OK) { 00912 return (Var *) var; 00913 } else if (result != TCL_CONTINUE) { 00914 return NULL; 00915 } 00916 } 00917 00918 /* 00919 * Look up varName. Look it up as either a namespace variable or as a 00920 * local variable in a procedure call frame (varFramePtr). Interpret 00921 * varName as a namespace variable if: 00922 * 1) so requested by a TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY flag, 00923 * 2) there is no active frame (we're at the global :: scope), 00924 * 3) the active frame was pushed to define the namespace context for a 00925 * "namespace eval" or "namespace inscope" command, 00926 * 4) the name has namespace qualifiers ("::"s). 00927 * Otherwise, if varName is a local variable, search first in the frame's 00928 * array of compiler-allocated local variables, then in its hashtable for 00929 * runtime-created local variables. 00930 * 00931 * If create and the variable isn't found, create the variable and, if 00932 * necessary, create varFramePtr's local var hashtable. 00933 */ 00934 00935 if (((flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) != 0) 00936 || !HasLocalVars(varFramePtr) 00937 || (strstr(varName, "::") != NULL)) { 00938 const char *tail; 00939 int lookGlobal = (flags & TCL_GLOBAL_ONLY) 00940 || (cxtNsPtr == iPtr->globalNsPtr) 00941 || ((*varName == ':') && (*(varName+1) == ':')); 00942 00943 if (lookGlobal) { 00944 *indexPtr = -1; 00945 flags = (flags | TCL_GLOBAL_ONLY) & ~TCL_NAMESPACE_ONLY; 00946 } else { 00947 if (flags & AVOID_RESOLVERS) { 00948 flags = (flags | TCL_NAMESPACE_ONLY); 00949 } 00950 if (flags & TCL_NAMESPACE_ONLY) { 00951 *indexPtr = -2; 00952 } 00953 } 00954 00955 /* 00956 * Don't pass TCL_LEAVE_ERR_MSG, we may yet create the variable, or 00957 * otherwise generate our own error! 00958 */ 00959 00960 varPtr = (Var *) ObjFindNamespaceVar(interp, varNamePtr, 00961 (Tcl_Namespace *) cxtNsPtr, 00962 (flags | AVOID_RESOLVERS) & ~TCL_LEAVE_ERR_MSG); 00963 if (varPtr == NULL) { 00964 Tcl_Obj *tailPtr; 00965 00966 if (create) { /* Var wasn't found so create it. */ 00967 TclGetNamespaceForQualName(interp, varName, cxtNsPtr, 00968 flags, &varNsPtr, &dummy1Ptr, &dummy2Ptr, &tail); 00969 if (varNsPtr == NULL) { 00970 *errMsgPtr = badNamespace; 00971 return NULL; 00972 } else if (tail == NULL) { 00973 *errMsgPtr = missingName; 00974 return NULL; 00975 } 00976 if (tail != varName) { 00977 tailPtr = Tcl_NewStringObj(tail, -1); 00978 } else { 00979 tailPtr = varNamePtr; 00980 } 00981 varPtr = VarHashCreateVar(&varNsPtr->varTable, tailPtr, 00982 &isNew); 00983 if (lookGlobal) { 00984 /* 00985 * The variable was created starting from the global 00986 * namespace: a global reference is returned even if it 00987 * wasn't explicitly requested. 00988 */ 00989 00990 *indexPtr = -1; 00991 } else { 00992 *indexPtr = -2; 00993 } 00994 } else { /* Var wasn't found and not to create it. */ 00995 *errMsgPtr = noSuchVar; 00996 return NULL; 00997 } 00998 } 00999 } else { /* Local var: look in frame varFramePtr. */ 01000 Proc *procPtr = varFramePtr->procPtr; 01001 int localCt = procPtr->numCompiledLocals; 01002 Tcl_Obj **objPtrPtr = &varFramePtr->localCachePtr->varName0; 01003 01004 for (i=0 ; i<localCt ; i++, objPtrPtr++) { 01005 register Tcl_Obj *objPtr = *objPtrPtr; 01006 01007 if (objPtr) { 01008 char *localName = TclGetString(objPtr); 01009 01010 if ((varName[0] == localName[0]) 01011 && (strcmp(varName, localName) == 0)) { 01012 *indexPtr = i; 01013 return (Var *) &varFramePtr->compiledLocals[i]; 01014 } 01015 } 01016 } 01017 tablePtr = varFramePtr->varTablePtr; 01018 if (create) { 01019 if (tablePtr == NULL) { 01020 tablePtr = (TclVarHashTable *) 01021 ckalloc(sizeof(TclVarHashTable)); 01022 TclInitVarHashTable(tablePtr, NULL); 01023 varFramePtr->varTablePtr = tablePtr; 01024 } 01025 varPtr = VarHashCreateVar(tablePtr, varNamePtr, &isNew); 01026 } else { 01027 varPtr = NULL; 01028 if (tablePtr != NULL) { 01029 varPtr = VarHashFindVar(tablePtr, varNamePtr); 01030 } 01031 if (varPtr == NULL) { 01032 *errMsgPtr = noSuchVar; 01033 } 01034 } 01035 } 01036 return varPtr; 01037 } 01038 01039 /* 01040 *---------------------------------------------------------------------- 01041 * 01042 * TclLookupArrayElement -- 01043 * 01044 * This function is used to locate a variable which is in an array's 01045 * hashtable given a pointer to the array's Var structure and the 01046 * element's name. 01047 * 01048 * Results: 01049 * The return value is a pointer to the variable structure , or NULL if 01050 * the variable couldn't be found. 01051 * 01052 * If arrayPtr points to a variable that isn't an array and createPart1 01053 * is 1, the corresponding variable will be converted to an array. 01054 * Otherwise, NULL is returned and an error message is left in the 01055 * interp's result if TCL_LEAVE_ERR_MSG is set in flags. 01056 * 01057 * If the variable is not found and createPart2 is 1, the variable is 01058 * created. Otherwise, NULL is returned and an error message is left in 01059 * the interp's result if TCL_LEAVE_ERR_MSG is set in flags. 01060 * 01061 * Note: it's possible for the variable returned to be VAR_UNDEFINED even 01062 * if createPart1 or createPart2 are 1 (these only cause the hash table 01063 * entry or array to be created). For example, the variable might be a 01064 * global that has been unset but is still referenced by a procedure, or 01065 * a variable that has been unset but it only being kept in existence (if 01066 * VAR_UNDEFINED) by a trace. 01067 * 01068 * Side effects: 01069 * The variable at arrayPtr may be converted to be an array if 01070 * createPart1 is 1. A new hashtable entry may be created if createPart2 01071 * is 1. 01072 * 01073 *---------------------------------------------------------------------- 01074 */ 01075 01076 Var * 01077 TclLookupArrayElement( 01078 Tcl_Interp *interp, /* Interpreter to use for lookup. */ 01079 Tcl_Obj *arrayNamePtr, /* This is the name of the array, or NULL if 01080 * index>= 0. */ 01081 Tcl_Obj *elNamePtr, /* Name of element within array. */ 01082 const int flags, /* Only TCL_LEAVE_ERR_MSG bit matters. */ 01083 const char *msg, /* Verb to use in error messages, e.g. "read" 01084 * or "set". Only needed if TCL_LEAVE_ERR_MSG 01085 * is set in flags. */ 01086 const int createArray, /* If 1, transform arrayName to be an array if 01087 * it isn't one yet and the transformation is 01088 * possible. If 0, return error if it isn't 01089 * already an array. */ 01090 const int createElem, /* If 1, create hash table entry for the 01091 * element, if it doesn't already exist. If 0, 01092 * return error if it doesn't exist. */ 01093 Var *arrayPtr, /* Pointer to the array's Var structure. */ 01094 int index) /* If >=0, the index of the local array. */ 01095 { 01096 int isNew; 01097 Var *varPtr; 01098 TclVarHashTable *tablePtr; 01099 Namespace *nsPtr; 01100 01101 /* 01102 * We're dealing with an array element. Make sure the variable is an array 01103 * and look up the element (create the element if desired). 01104 */ 01105 01106 if (TclIsVarUndefined(arrayPtr) && !TclIsVarArrayElement(arrayPtr)) { 01107 if (!createArray) { 01108 if (flags & TCL_LEAVE_ERR_MSG) { 01109 TclObjVarErrMsg(interp, arrayNamePtr, elNamePtr, msg, 01110 noSuchVar, index); 01111 } 01112 return NULL; 01113 } 01114 01115 /* 01116 * Make sure we are not resurrecting a namespace variable from a 01117 * deleted namespace! 01118 */ 01119 01120 if (TclIsVarDeadHash(arrayPtr)) { 01121 if (flags & TCL_LEAVE_ERR_MSG) { 01122 TclObjVarErrMsg(interp, arrayNamePtr, elNamePtr, msg, 01123 danglingVar, index); 01124 } 01125 return NULL; 01126 } 01127 01128 TclSetVarArray(arrayPtr); 01129 tablePtr = (TclVarHashTable *) ckalloc(sizeof(TclVarHashTable)); 01130 arrayPtr->value.tablePtr = tablePtr; 01131 01132 if (TclIsVarInHash(arrayPtr) && TclGetVarNsPtr(arrayPtr)) { 01133 nsPtr = TclGetVarNsPtr(arrayPtr); 01134 } else { 01135 nsPtr = NULL; 01136 } 01137 TclInitVarHashTable(arrayPtr->value.tablePtr, nsPtr); 01138 } else if (!TclIsVarArray(arrayPtr)) { 01139 if (flags & TCL_LEAVE_ERR_MSG) { 01140 TclObjVarErrMsg(interp, arrayNamePtr, elNamePtr, msg, needArray, 01141 index); 01142 } 01143 return NULL; 01144 } 01145 01146 if (createElem) { 01147 varPtr = VarHashCreateVar(arrayPtr->value.tablePtr, elNamePtr, 01148 &isNew); 01149 if (isNew) { 01150 if (arrayPtr->flags & VAR_SEARCH_ACTIVE) { 01151 DeleteSearches((Interp *) interp, arrayPtr); 01152 } 01153 TclSetVarArrayElement(varPtr); 01154 } 01155 } else { 01156 varPtr = VarHashFindVar(arrayPtr->value.tablePtr, elNamePtr); 01157 if (varPtr == NULL) { 01158 if (flags & TCL_LEAVE_ERR_MSG) { 01159 TclObjVarErrMsg(interp, arrayNamePtr, elNamePtr, msg, 01160 noSuchElement, index); 01161 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ELEMENT", 01162 TclGetString(elNamePtr), NULL); 01163 } 01164 } 01165 } 01166 return varPtr; 01167 } 01168 01169 /* 01170 *---------------------------------------------------------------------- 01171 * 01172 * Tcl_GetVar -- 01173 * 01174 * Return the value of a Tcl variable as a string. 01175 * 01176 * Results: 01177 * The return value points to the current value of varName as a string. 01178 * If the variable is not defined or can't be read because of a clash in 01179 * array usage then a NULL pointer is returned and an error message is 01180 * left in the interp's result if the TCL_LEAVE_ERR_MSG flag is set. 01181 * Note: the return value is only valid up until the next change to the 01182 * variable; if you depend on the value lasting longer than that, then 01183 * make yourself a private copy. 01184 * 01185 * Side effects: 01186 * None. 01187 * 01188 *---------------------------------------------------------------------- 01189 */ 01190 01191 const char * 01192 Tcl_GetVar( 01193 Tcl_Interp *interp, /* Command interpreter in which varName is to 01194 * be looked up. */ 01195 const char *varName, /* Name of a variable in interp. */ 01196 int flags) /* OR-ed combination of TCL_GLOBAL_ONLY, 01197 * TCL_NAMESPACE_ONLY or TCL_LEAVE_ERR_MSG 01198 * bits. */ 01199 { 01200 return Tcl_GetVar2(interp, varName, NULL, flags); 01201 } 01202 01203 /* 01204 *---------------------------------------------------------------------- 01205 * 01206 * Tcl_GetVar2 -- 01207 * 01208 * Return the value of a Tcl variable as a string, given a two-part name 01209 * consisting of array name and element within array. 01210 * 01211 * Results: 01212 * The return value points to the current value of the variable given by 01213 * part1 and part2 as a string. If the specified variable doesn't exist, 01214 * or if there is a clash in array usage, then NULL is returned and a 01215 * message will be left in the interp's result if the TCL_LEAVE_ERR_MSG 01216 * flag is set. Note: the return value is only valid up until the next 01217 * change to the variable; if you depend on the value lasting longer than 01218 * that, then make yourself a private copy. 01219 * 01220 * Side effects: 01221 * None. 01222 * 01223 *---------------------------------------------------------------------- 01224 */ 01225 01226 const char * 01227 Tcl_GetVar2( 01228 Tcl_Interp *interp, /* Command interpreter in which variable is to 01229 * be looked up. */ 01230 const char *part1, /* Name of an array (if part2 is non-NULL) or 01231 * the name of a variable. */ 01232 const char *part2, /* If non-NULL, gives the name of an element 01233 * in the array part1. */ 01234 int flags) /* OR-ed combination of TCL_GLOBAL_ONLY, 01235 * TCL_NAMESPACE_ONLY and TCL_LEAVE_ERR_MSG * 01236 * bits. */ 01237 { 01238 Tcl_Obj *objPtr; 01239 01240 objPtr = Tcl_GetVar2Ex(interp, part1, part2, flags); 01241 if (objPtr == NULL) { 01242 return NULL; 01243 } 01244 return TclGetString(objPtr); 01245 } 01246 01247 /* 01248 *---------------------------------------------------------------------- 01249 * 01250 * Tcl_GetVar2Ex -- 01251 * 01252 * Return the value of a Tcl variable as a Tcl object, given a two-part 01253 * name consisting of array name and element within array. 01254 * 01255 * Results: 01256 * The return value points to the current object value of the variable 01257 * given by part1Ptr and part2Ptr. If the specified variable doesn't 01258 * exist, or if there is a clash in array usage, then NULL is returned 01259 * and a message will be left in the interpreter's result if the 01260 * TCL_LEAVE_ERR_MSG flag is set. 01261 * 01262 * Side effects: 01263 * The ref count for the returned object is _not_ incremented to reflect 01264 * the returned reference; if you want to keep a reference to the object 01265 * you must increment its ref count yourself. 01266 * 01267 *---------------------------------------------------------------------- 01268 */ 01269 01270 Tcl_Obj * 01271 Tcl_GetVar2Ex( 01272 Tcl_Interp *interp, /* Command interpreter in which variable is to 01273 * be looked up. */ 01274 const char *part1, /* Name of an array (if part2 is non-NULL) or 01275 * the name of a variable. */ 01276 const char *part2, /* If non-NULL, gives the name of an element 01277 * in the array part1. */ 01278 int flags) /* OR-ed combination of TCL_GLOBAL_ONLY, and 01279 * TCL_LEAVE_ERR_MSG bits. */ 01280 { 01281 Tcl_Obj *part1Ptr, *part2Ptr, *resPtr; 01282 01283 part1Ptr = Tcl_NewStringObj(part1, -1); 01284 Tcl_IncrRefCount(part1Ptr); 01285 if (part2) { 01286 part2Ptr = Tcl_NewStringObj(part2, -1); 01287 Tcl_IncrRefCount(part2Ptr); 01288 } else { 01289 part2Ptr = NULL; 01290 } 01291 01292 resPtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags); 01293 01294 Tcl_DecrRefCount(part1Ptr); 01295 if (part2Ptr) { 01296 Tcl_DecrRefCount(part2Ptr); 01297 } 01298 01299 return resPtr; 01300 } 01301 01302 /* 01303 *---------------------------------------------------------------------- 01304 * 01305 * Tcl_ObjGetVar2 -- 01306 * 01307 * Return the value of a Tcl variable as a Tcl object, given a two-part 01308 * name consisting of array name and element within array. 01309 * 01310 * Results: 01311 * The return value points to the current object value of the variable 01312 * given by part1Ptr and part2Ptr. If the specified variable doesn't 01313 * exist, or if there is a clash in array usage, then NULL is returned 01314 * and a message will be left in the interpreter's result if the 01315 * TCL_LEAVE_ERR_MSG flag is set. 01316 * 01317 * Side effects: 01318 * The ref count for the returned object is _not_ incremented to reflect 01319 * the returned reference; if you want to keep a reference to the object 01320 * you must increment its ref count yourself. 01321 * 01322 *---------------------------------------------------------------------- 01323 */ 01324 01325 Tcl_Obj * 01326 Tcl_ObjGetVar2( 01327 Tcl_Interp *interp, /* Command interpreter in which variable is to 01328 * be looked up. */ 01329 register Tcl_Obj *part1Ptr, /* Points to an object holding the name of an 01330 * array (if part2 is non-NULL) or the name of 01331 * a variable. */ 01332 register Tcl_Obj *part2Ptr, /* If non-null, points to an object holding 01333 * the name of an element in the array 01334 * part1Ptr. */ 01335 int flags) /* OR-ed combination of TCL_GLOBAL_ONLY and 01336 * TCL_LEAVE_ERR_MSG bits. */ 01337 { 01338 Var *varPtr, *arrayPtr; 01339 01340 /* 01341 * Filter to pass through only the flags this interface supports. 01342 */ 01343 01344 flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); 01345 varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, flags, "read", 01346 /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr); 01347 if (varPtr == NULL) { 01348 return NULL; 01349 } 01350 01351 return TclPtrGetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, 01352 flags, -1); 01353 } 01354 01355 /* 01356 *---------------------------------------------------------------------- 01357 * 01358 * TclPtrGetVar -- 01359 * 01360 * Return the value of a Tcl variable as a Tcl object, given the pointers 01361 * to the variable's (and possibly containing array's) VAR structure. 01362 * 01363 * Results: 01364 * The return value points to the current object value of the variable 01365 * given by varPtr. If the specified variable doesn't exist, or if there 01366 * is a clash in array usage, then NULL is returned and a message will be 01367 * left in the interpreter's result if the TCL_LEAVE_ERR_MSG flag is set. 01368 * 01369 * Side effects: 01370 * The ref count for the returned object is _not_ incremented to reflect 01371 * the returned reference; if you want to keep a reference to the object 01372 * you must increment its ref count yourself. 01373 * 01374 *---------------------------------------------------------------------- 01375 */ 01376 01377 Tcl_Obj * 01378 TclPtrGetVar( 01379 Tcl_Interp *interp, /* Command interpreter in which variable is to 01380 * be looked up. */ 01381 register Var *varPtr, /* The variable to be read.*/ 01382 Var *arrayPtr, /* NULL for scalar variables, pointer to the 01383 * containing array otherwise. */ 01384 Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or 01385 * the name of a variable. */ 01386 Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element 01387 * in the array part1. */ 01388 const int flags, /* OR-ed combination of TCL_GLOBAL_ONLY, and 01389 * TCL_LEAVE_ERR_MSG bits. */ 01390 int index) /* Index into the local variable table of the 01391 * variable, or -1. Only used when part1Ptr is 01392 * NULL. */ 01393 { 01394 Interp *iPtr = (Interp *) interp; 01395 const char *msg; 01396 01397 /* 01398 * Invoke any read traces that have been set for the variable. 01399 */ 01400 01401 if ((varPtr->flags & VAR_TRACED_READ) 01402 || (arrayPtr && (arrayPtr->flags & VAR_TRACED_READ))) { 01403 if (TCL_ERROR == TclObjCallVarTraces(iPtr, arrayPtr, varPtr, 01404 part1Ptr, part2Ptr, 01405 (flags & (TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY)) 01406 | TCL_TRACE_READS, (flags & TCL_LEAVE_ERR_MSG), index)) { 01407 goto errorReturn; 01408 } 01409 } 01410 01411 /* 01412 * Return the element if it's an existing scalar variable. 01413 */ 01414 01415 if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) { 01416 return varPtr->value.objPtr; 01417 } 01418 01419 if (flags & TCL_LEAVE_ERR_MSG) { 01420 if (TclIsVarUndefined(varPtr) && arrayPtr 01421 && !TclIsVarUndefined(arrayPtr)) { 01422 msg = noSuchElement; 01423 } else if (TclIsVarArray(varPtr)) { 01424 msg = isArray; 01425 } else { 01426 msg = noSuchVar; 01427 } 01428 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, "read", msg, index); 01429 } 01430 01431 /* 01432 * An error. If the variable doesn't exist anymore and no-one's using it, 01433 * then free up the relevant structures and hash table entries. 01434 */ 01435 01436 errorReturn: 01437 if (TclIsVarUndefined(varPtr)) { 01438 TclCleanupVar(varPtr, arrayPtr); 01439 } 01440 return NULL; 01441 } 01442 01443 /* 01444 *---------------------------------------------------------------------- 01445 * 01446 * Tcl_SetObjCmd -- 01447 * 01448 * This function is invoked to process the "set" Tcl command. See the 01449 * user documentation for details on what it does. 01450 * 01451 * Results: 01452 * A standard Tcl result value. 01453 * 01454 * Side effects: 01455 * A variable's value may be changed. 01456 * 01457 *---------------------------------------------------------------------- 01458 */ 01459 01460 /* ARGSUSED */ 01461 int 01462 Tcl_SetObjCmd( 01463 ClientData dummy, /* Not used. */ 01464 register Tcl_Interp *interp,/* Current interpreter. */ 01465 int objc, /* Number of arguments. */ 01466 Tcl_Obj *const objv[]) /* Argument objects. */ 01467 { 01468 Tcl_Obj *varValueObj; 01469 01470 if (objc == 2) { 01471 varValueObj = Tcl_ObjGetVar2(interp, objv[1], NULL,TCL_LEAVE_ERR_MSG); 01472 if (varValueObj == NULL) { 01473 return TCL_ERROR; 01474 } 01475 Tcl_SetObjResult(interp, varValueObj); 01476 return TCL_OK; 01477 } else if (objc == 3) { 01478 varValueObj = Tcl_ObjSetVar2(interp, objv[1], NULL, objv[2], 01479 TCL_LEAVE_ERR_MSG); 01480 if (varValueObj == NULL) { 01481 return TCL_ERROR; 01482 } 01483 Tcl_SetObjResult(interp, varValueObj); 01484 return TCL_OK; 01485 } else { 01486 Tcl_WrongNumArgs(interp, 1, objv, "varName ?newValue?"); 01487 return TCL_ERROR; 01488 } 01489 } 01490 01491 /* 01492 *---------------------------------------------------------------------- 01493 * 01494 * Tcl_SetVar -- 01495 * 01496 * Change the value of a variable. 01497 * 01498 * Results: 01499 * Returns a pointer to the malloc'ed string which is the character 01500 * representation of the variable's new value. The caller must not modify 01501 * this string. If the write operation was disallowed then NULL is 01502 * returned; if the TCL_LEAVE_ERR_MSG flag is set, then an explanatory 01503 * message will be left in the interp's result. Note that the returned 01504 * string may not be the same as newValue; this is because variable 01505 * traces may modify the variable's value. 01506 * 01507 * Side effects: 01508 * If varName is defined as a local or global variable in interp, its 01509 * value is changed to newValue. If varName isn't currently defined, then 01510 * a new global variable by that name is created. 01511 * 01512 *---------------------------------------------------------------------- 01513 */ 01514 01515 const char * 01516 Tcl_SetVar( 01517 Tcl_Interp *interp, /* Command interpreter in which varName is to 01518 * be looked up. */ 01519 const char *varName, /* Name of a variable in interp. */ 01520 const char *newValue, /* New value for varName. */ 01521 int flags) /* Various flags that tell how to set value: 01522 * any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 01523 * TCL_APPEND_VALUE, TCL_LIST_ELEMENT, 01524 * TCL_LEAVE_ERR_MSG. */ 01525 { 01526 return Tcl_SetVar2(interp, varName, NULL, newValue, flags); 01527 } 01528 01529 /* 01530 *---------------------------------------------------------------------- 01531 * 01532 * Tcl_SetVar2 -- 01533 * 01534 * Given a two-part variable name, which may refer either to a scalar 01535 * variable or an element of an array, change the value of the variable. 01536 * If the named scalar or array or element doesn't exist then create one. 01537 * 01538 * Results: 01539 * Returns a pointer to the malloc'ed string which is the character 01540 * representation of the variable's new value. The caller must not modify 01541 * this string. If the write operation was disallowed because an array 01542 * was expected but not found (or vice versa), then NULL is returned; if 01543 * the TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will be 01544 * left in the interp's result. Note that the returned string may not be 01545 * the same as newValue; this is because variable traces may modify the 01546 * variable's value. 01547 * 01548 * Side effects: 01549 * The value of the given variable is set. If either the array or the 01550 * entry didn't exist then a new one is created. 01551 * 01552 *---------------------------------------------------------------------- 01553 */ 01554 01555 const char * 01556 Tcl_SetVar2( 01557 Tcl_Interp *interp, /* Command interpreter in which variable is to 01558 * be looked up. */ 01559 const char *part1, /* If part2 is NULL, this is name of scalar 01560 * variable. Otherwise it is the name of an 01561 * array. */ 01562 const char *part2, /* Name of an element within an array, or 01563 * NULL. */ 01564 const char *newValue, /* New value for variable. */ 01565 int flags) /* Various flags that tell how to set value: 01566 * any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 01567 * TCL_APPEND_VALUE, TCL_LIST_ELEMENT, or 01568 * TCL_LEAVE_ERR_MSG. */ 01569 { 01570 register Tcl_Obj *valuePtr; 01571 Tcl_Obj *varValuePtr; 01572 01573 /* 01574 * Create an object holding the variable's new value and use Tcl_SetVar2Ex 01575 * to actually set the variable. 01576 */ 01577 01578 valuePtr = Tcl_NewStringObj(newValue, -1); 01579 Tcl_IncrRefCount(valuePtr); 01580 varValuePtr = Tcl_SetVar2Ex(interp, part1, part2, valuePtr, flags); 01581 Tcl_DecrRefCount(valuePtr); 01582 01583 if (varValuePtr == NULL) { 01584 return NULL; 01585 } 01586 return TclGetString(varValuePtr); 01587 } 01588 01589 /* 01590 *---------------------------------------------------------------------- 01591 * 01592 * Tcl_SetVar2Ex -- 01593 * 01594 * Given a two-part variable name, which may refer either to a scalar 01595 * variable or an element of an array, change the value of the variable 01596 * to a new Tcl object value. If the named scalar or array or element 01597 * doesn't exist then create one. 01598 * 01599 * Results: 01600 * Returns a pointer to the Tcl_Obj holding the new value of the 01601 * variable. If the write operation was disallowed because an array was 01602 * expected but not found (or vice versa), then NULL is returned; if the 01603 * TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will be 01604 * left in the interpreter's result. Note that the returned object may 01605 * not be the same one referenced by newValuePtr; this is because 01606 * variable traces may modify the variable's value. 01607 * 01608 * Side effects: 01609 * The value of the given variable is set. If either the array or the 01610 * entry didn't exist then a new variable is created. 01611 * 01612 * The reference count is decremented for any old value of the variable 01613 * and incremented for its new value. If the new value for the variable 01614 * is not the same one referenced by newValuePtr (perhaps as a result of 01615 * a variable trace), then newValuePtr's ref count is left unchanged by 01616 * Tcl_SetVar2Ex. newValuePtr's ref count is also left unchanged if we 01617 * are appending it as a string value: that is, if "flags" includes 01618 * TCL_APPEND_VALUE but not TCL_LIST_ELEMENT. 01619 * 01620 * The reference count for the returned object is _not_ incremented: if 01621 * you want to keep a reference to the object you must increment its ref 01622 * count yourself. 01623 * 01624 *---------------------------------------------------------------------- 01625 */ 01626 01627 Tcl_Obj * 01628 Tcl_SetVar2Ex( 01629 Tcl_Interp *interp, /* Command interpreter in which variable is to 01630 * be found. */ 01631 const char *part1, /* Name of an array (if part2 is non-NULL) or 01632 * the name of a variable. */ 01633 const char *part2, /* If non-NULL, gives the name of an element 01634 * in the array part1. */ 01635 Tcl_Obj *newValuePtr, /* New value for variable. */ 01636 int flags) /* Various flags that tell how to set value: 01637 * any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 01638 * TCL_APPEND_VALUE, TCL_LIST_ELEMENT or 01639 * TCL_LEAVE_ERR_MSG. */ 01640 { 01641 Tcl_Obj *part1Ptr, *part2Ptr, *resPtr; 01642 01643 part1Ptr = Tcl_NewStringObj(part1, -1); 01644 Tcl_IncrRefCount(part1Ptr); 01645 if (part2) { 01646 part2Ptr = Tcl_NewStringObj(part2, -1); 01647 Tcl_IncrRefCount(part2Ptr); 01648 } else { 01649 part2Ptr = NULL; 01650 } 01651 01652 resPtr = Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, newValuePtr, flags); 01653 01654 Tcl_DecrRefCount(part1Ptr); 01655 if (part2Ptr) { 01656 Tcl_DecrRefCount(part2Ptr); 01657 } 01658 01659 return resPtr; 01660 } 01661 01662 /* 01663 *---------------------------------------------------------------------- 01664 * 01665 * Tcl_ObjSetVar2 -- 01666 * 01667 * This function is the same as Tcl_SetVar2Ex above, except the variable 01668 * names are passed in Tcl object instead of strings. 01669 * 01670 * Results: 01671 * Returns a pointer to the Tcl_Obj holding the new value of the 01672 * variable. If the write operation was disallowed because an array was 01673 * expected but not found (or vice versa), then NULL is returned; if the 01674 * TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will be 01675 * left in the interpreter's result. Note that the returned object may 01676 * not be the same one referenced by newValuePtr; this is because 01677 * variable traces may modify the variable's value. 01678 * 01679 * Side effects: 01680 * The value of the given variable is set. If either the array or the 01681 * entry didn't exist then a new variable is created. 01682 * 01683 *---------------------------------------------------------------------- 01684 */ 01685 01686 Tcl_Obj * 01687 Tcl_ObjSetVar2( 01688 Tcl_Interp *interp, /* Command interpreter in which variable is to 01689 * be found. */ 01690 register Tcl_Obj *part1Ptr, /* Points to an object holding the name of an 01691 * array (if part2 is non-NULL) or the name of 01692 * a variable. */ 01693 register Tcl_Obj *part2Ptr, /* If non-NULL, points to an object holding 01694 * the name of an element in the array 01695 * part1Ptr. */ 01696 Tcl_Obj *newValuePtr, /* New value for variable. */ 01697 int flags) /* Various flags that tell how to set value: 01698 * any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 01699 * TCL_APPEND_VALUE, TCL_LIST_ELEMENT, or 01700 * TCL_LEAVE_ERR_MSG. */ 01701 { 01702 Var *varPtr, *arrayPtr; 01703 01704 /* 01705 * Filter to pass through only the flags this interface supports. 01706 */ 01707 01708 flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG 01709 |TCL_APPEND_VALUE|TCL_LIST_ELEMENT); 01710 varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, flags, "set", 01711 /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); 01712 if (varPtr == NULL) { 01713 if (newValuePtr->refCount == 0) { 01714 Tcl_DecrRefCount(newValuePtr); 01715 } 01716 return NULL; 01717 } 01718 01719 return TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, 01720 newValuePtr, flags, -1); 01721 } 01722 01723 /* 01724 *---------------------------------------------------------------------- 01725 * 01726 * TclPtrSetVar -- 01727 * 01728 * This function is the same as Tcl_SetVar2Ex above, except that it 01729 * requires pointers to the variable's Var structs in addition to the 01730 * variable names. 01731 * 01732 * Results: 01733 * Returns a pointer to the Tcl_Obj holding the new value of the 01734 * variable. If the write operation was disallowed because an array was 01735 * expected but not found (or vice versa), then NULL is returned; if the 01736 * TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will be 01737 * left in the interpreter's result. Note that the returned object may 01738 * not be the same one referenced by newValuePtr; this is because 01739 * variable traces may modify the variable's value. 01740 * 01741 * Side effects: 01742 * The value of the given variable is set. If either the array or the 01743 * entry didn't exist then a new variable is created. 01744 * 01745 *---------------------------------------------------------------------- 01746 */ 01747 01748 Tcl_Obj * 01749 TclPtrSetVar( 01750 Tcl_Interp *interp, /* Command interpreter in which variable is to 01751 * be looked up. */ 01752 register Var *varPtr, /* Reference to the variable to set. */ 01753 Var *arrayPtr, /* Reference to the array containing the 01754 * variable, or NULL if the variable is a 01755 * scalar. */ 01756 Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or 01757 * the name of a variable. NULL if the 'index' 01758 * parameter is >= 0 */ 01759 Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element 01760 * in the array part1. */ 01761 Tcl_Obj *newValuePtr, /* New value for variable. */ 01762 const int flags, /* OR-ed combination of TCL_GLOBAL_ONLY, and 01763 * TCL_LEAVE_ERR_MSG bits. */ 01764 int index) /* Index of local var where part1 is to be 01765 * found. */ 01766 { 01767 Interp *iPtr = (Interp *) interp; 01768 Tcl_Obj *oldValuePtr; 01769 Tcl_Obj *resultPtr = NULL; 01770 int result; 01771 01772 /* 01773 * If the variable is in a hashtable and its hPtr field is NULL, then we 01774 * may have an upvar to an array element where the array was deleted or an 01775 * upvar to a namespace variable whose namespace was deleted. Generate an 01776 * error (allowing the variable to be reset would screw up our storage 01777 * allocation and is meaningless anyway). 01778 */ 01779 01780 if (TclIsVarDeadHash(varPtr)) { 01781 if (flags & TCL_LEAVE_ERR_MSG) { 01782 if (TclIsVarArrayElement(varPtr)) { 01783 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, "set", 01784 danglingElement, index); 01785 } else { 01786 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, "set", 01787 danglingVar, index); 01788 } 01789 } 01790 goto earlyError; 01791 } 01792 01793 /* 01794 * It's an error to try to set an array variable itself. 01795 */ 01796 01797 if (TclIsVarArray(varPtr)) { 01798 if (flags & TCL_LEAVE_ERR_MSG) { 01799 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, "set", isArray,index); 01800 } 01801 goto earlyError; 01802 } 01803 01804 /* 01805 * Invoke any read traces that have been set for the variable if it is 01806 * requested; this is only done in the core by the INST_LAPPEND_* 01807 * instructions. 01808 */ 01809 01810 if ((flags & TCL_TRACE_READS) && ((varPtr->flags & VAR_TRACED_READ) 01811 || (arrayPtr && (arrayPtr->flags & VAR_TRACED_READ)))) { 01812 if (TCL_ERROR == TclObjCallVarTraces(iPtr, arrayPtr, varPtr, 01813 part1Ptr, part2Ptr, 01814 TCL_TRACE_READS, (flags & TCL_LEAVE_ERR_MSG), index)) { 01815 goto earlyError; 01816 } 01817 } 01818 01819 /* 01820 * Set the variable's new value. If appending, append the new value to the 01821 * variable, either as a list element or as a string. Also, if appending, 01822 * then if the variable's old value is unshared we can modify it directly, 01823 * otherwise we must create a new copy to modify: this is "copy on write". 01824 */ 01825 01826 oldValuePtr = varPtr->value.objPtr; 01827 if (flags & TCL_LIST_ELEMENT && !(flags & TCL_APPEND_VALUE)) { 01828 varPtr->value.objPtr = NULL; 01829 } 01830 if (flags & (TCL_APPEND_VALUE|TCL_LIST_ELEMENT)) { 01831 #if 0 01832 /* 01833 * Can't happen now! 01834 */ 01835 01836 if (TclIsVarUndefined(varPtr) && (oldValuePtr != NULL)) { 01837 TclDecrRefCount(oldValuePtr); /* Discard old value. */ 01838 varPtr->value.objPtr = NULL; 01839 oldValuePtr = NULL; 01840 } 01841 #endif 01842 if (flags & TCL_LIST_ELEMENT) { /* Append list element. */ 01843 if (oldValuePtr == NULL) { 01844 TclNewObj(oldValuePtr); 01845 varPtr->value.objPtr = oldValuePtr; 01846 Tcl_IncrRefCount(oldValuePtr); /* Since var is referenced. */ 01847 } else if (Tcl_IsShared(oldValuePtr)) { 01848 varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr); 01849 TclDecrRefCount(oldValuePtr); 01850 oldValuePtr = varPtr->value.objPtr; 01851 Tcl_IncrRefCount(oldValuePtr); /* Since var is referenced. */ 01852 } 01853 result = Tcl_ListObjAppendElement(interp, oldValuePtr, 01854 newValuePtr); 01855 if (result != TCL_OK) { 01856 goto earlyError; 01857 } 01858 } else { /* Append string. */ 01859 /* 01860 * We append newValuePtr's bytes but don't change its ref count. 01861 */ 01862 01863 if (oldValuePtr == NULL) { 01864 varPtr->value.objPtr = newValuePtr; 01865 Tcl_IncrRefCount(newValuePtr); 01866 } else { 01867 if (Tcl_IsShared(oldValuePtr)) { /* Append to copy. */ 01868 varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr); 01869 TclDecrRefCount(oldValuePtr); 01870 oldValuePtr = varPtr->value.objPtr; 01871 Tcl_IncrRefCount(oldValuePtr); /* Since var is ref */ 01872 } 01873 Tcl_AppendObjToObj(oldValuePtr, newValuePtr); 01874 } 01875 } 01876 } else if (newValuePtr != oldValuePtr) { 01877 /* 01878 * In this case we are replacing the value, so we don't need to do 01879 * more than swap the objects. 01880 */ 01881 01882 varPtr->value.objPtr = newValuePtr; 01883 Tcl_IncrRefCount(newValuePtr); /* Var is another ref. */ 01884 if (oldValuePtr != NULL) { 01885 TclDecrRefCount(oldValuePtr); /* Discard old value. */ 01886 } 01887 } 01888 01889 /* 01890 * Invoke any write traces for the variable. 01891 */ 01892 01893 if ((varPtr->flags & VAR_TRACED_WRITE) 01894 || (arrayPtr && (arrayPtr->flags & VAR_TRACED_WRITE))) { 01895 if (TCL_ERROR == TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr, 01896 part2Ptr, (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) 01897 | TCL_TRACE_WRITES, (flags & TCL_LEAVE_ERR_MSG), index)) { 01898 goto cleanup; 01899 } 01900 } 01901 01902 /* 01903 * Return the variable's value unless the variable was changed in some 01904 * gross way by a trace (e.g. it was unset and then recreated as an 01905 * array). 01906 */ 01907 01908 if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) { 01909 return varPtr->value.objPtr; 01910 } 01911 01912 /* 01913 * A trace changed the value in some gross way. Return an empty string 01914 * object. 01915 */ 01916 01917 resultPtr = iPtr->emptyObjPtr; 01918 01919 /* 01920 * If the variable doesn't exist anymore and no-one's using it, then free 01921 * up the relevant structures and hash table entries. 01922 */ 01923 01924 cleanup: 01925 if (TclIsVarUndefined(varPtr)) { 01926 TclCleanupVar(varPtr, arrayPtr); 01927 } 01928 return resultPtr; 01929 01930 earlyError: 01931 if (newValuePtr->refCount == 0) { 01932 Tcl_DecrRefCount(newValuePtr); 01933 } 01934 goto cleanup; 01935 } 01936 01937 /* 01938 *---------------------------------------------------------------------- 01939 * 01940 * TclIncrObjVar2 -- 01941 * 01942 * Given a two-part variable name, which may refer either to a scalar 01943 * variable or an element of an array, increment the Tcl object value of 01944 * the variable by a specified Tcl_Obj increment value. 01945 * 01946 * Results: 01947 * Returns a pointer to the Tcl_Obj holding the new value of the 01948 * variable. If the specified variable doesn't exist, or there is a clash 01949 * in array usage, or an error occurs while executing variable traces, 01950 * then NULL is returned and a message will be left in the interpreter's 01951 * result. 01952 * 01953 * Side effects: 01954 * The value of the given variable is incremented by the specified 01955 * amount. If either the array or the entry didn't exist then a new 01956 * variable is created. The ref count for the returned object is _not_ 01957 * incremented to reflect the returned reference; if you want to keep a 01958 * reference to the object you must increment its ref count yourself. 01959 * 01960 *---------------------------------------------------------------------- 01961 */ 01962 01963 Tcl_Obj * 01964 TclIncrObjVar2( 01965 Tcl_Interp *interp, /* Command interpreter in which variable is to 01966 * be found. */ 01967 Tcl_Obj *part1Ptr, /* Points to an object holding the name of an 01968 * array (if part2 is non-NULL) or the name of 01969 * a variable. */ 01970 Tcl_Obj *part2Ptr, /* If non-null, points to an object holding 01971 * the name of an element in the array 01972 * part1Ptr. */ 01973 Tcl_Obj *incrPtr, /* Amount to be added to variable. */ 01974 int flags) /* Various flags that tell how to incr value: 01975 * any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 01976 * TCL_APPEND_VALUE, TCL_LIST_ELEMENT, 01977 * TCL_LEAVE_ERR_MSG. */ 01978 { 01979 Var *varPtr, *arrayPtr; 01980 01981 varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, flags, "read", 01982 1, 1, &arrayPtr); 01983 if (varPtr == NULL) { 01984 Tcl_AddObjErrorInfo(interp, 01985 "\n (reading value of variable to increment)", -1); 01986 return NULL; 01987 } 01988 return TclPtrIncrObjVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, 01989 incrPtr, flags, -1); 01990 } 01991 01992 /* 01993 *---------------------------------------------------------------------- 01994 * 01995 * TclPtrIncrObjVar -- 01996 * 01997 * Given the pointers to a variable and possible containing array, 01998 * increment the Tcl object value of the variable by a Tcl_Obj increment. 01999 * 02000 * Results: 02001 * Returns a pointer to the Tcl_Obj holding the new value of the 02002 * variable. If the specified variable doesn't exist, or there is a clash 02003 * in array usage, or an error occurs while executing variable traces, 02004 * then NULL is returned and a message will be left in the interpreter's 02005 * result. 02006 * 02007 * Side effects: 02008 * The value of the given variable is incremented by the specified 02009 * amount. If either the array or the entry didn't exist then a new 02010 * variable is created. The ref count for the returned object is _not_ 02011 * incremented to reflect the returned reference; if you want to keep a 02012 * reference to the object you must increment its ref count yourself. 02013 * 02014 *---------------------------------------------------------------------- 02015 */ 02016 02017 Tcl_Obj * 02018 TclPtrIncrObjVar( 02019 Tcl_Interp *interp, /* Command interpreter in which variable is to 02020 * be found. */ 02021 Var *varPtr, /* Reference to the variable to set. */ 02022 Var *arrayPtr, /* Reference to the array containing the 02023 * variable, or NULL if the variable is a 02024 * scalar. */ 02025 Tcl_Obj *part1Ptr, /* Points to an object holding the name of an 02026 * array (if part2 is non-NULL) or the name of 02027 * a variable. */ 02028 Tcl_Obj *part2Ptr, /* If non-null, points to an object holding 02029 * the name of an element in the array 02030 * part1Ptr. */ 02031 Tcl_Obj *incrPtr, /* Increment value. */ 02032 /* TODO: Which of these flag values really make sense? */ 02033 const int flags, /* Various flags that tell how to incr value: 02034 * any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 02035 * TCL_APPEND_VALUE, TCL_LIST_ELEMENT, 02036 * TCL_LEAVE_ERR_MSG. */ 02037 int index) /* Index into the local variable table of the 02038 * variable, or -1. Only used when part1Ptr is 02039 * NULL. */ 02040 { 02041 register Tcl_Obj *varValuePtr, *newValuePtr = NULL; 02042 int duplicated, code; 02043 02044 if (TclIsVarInHash(varPtr)) { 02045 VarHashRefCount(varPtr)++; 02046 } 02047 varValuePtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, 02048 flags, index); 02049 if (TclIsVarInHash(varPtr)) { 02050 VarHashRefCount(varPtr)--; 02051 } 02052 if (varValuePtr == NULL) { 02053 varValuePtr = Tcl_NewIntObj(0); 02054 } 02055 if (Tcl_IsShared(varValuePtr)) { 02056 duplicated = 1; 02057 varValuePtr = Tcl_DuplicateObj(varValuePtr); 02058 } else { 02059 duplicated = 0; 02060 } 02061 code = TclIncrObj(interp, varValuePtr, incrPtr); 02062 if (code == TCL_OK) { 02063 newValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr, 02064 part2Ptr, varValuePtr, flags, index); 02065 } else if (duplicated) { 02066 Tcl_DecrRefCount(varValuePtr); 02067 } 02068 return newValuePtr; 02069 } 02070 02071 /* 02072 *---------------------------------------------------------------------- 02073 * 02074 * Tcl_UnsetVar -- 02075 * 02076 * Delete a variable, so that it may not be accessed anymore. 02077 * 02078 * Results: 02079 * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR if 02080 * the variable can't be unset. In the event of an error, if the 02081 * TCL_LEAVE_ERR_MSG flag is set then an error message is left in the 02082 * interp's result. 02083 * 02084 * Side effects: 02085 * If varName is defined as a local or global variable in interp, it is 02086 * deleted. 02087 * 02088 *---------------------------------------------------------------------- 02089 */ 02090 02091 int 02092 Tcl_UnsetVar( 02093 Tcl_Interp *interp, /* Command interpreter in which varName is to 02094 * be looked up. */ 02095 const char *varName, /* Name of a variable in interp. May be either 02096 * a scalar name or an array name or an 02097 * element in an array. */ 02098 int flags) /* OR-ed combination of any of 02099 * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY or 02100 * TCL_LEAVE_ERR_MSG. */ 02101 { 02102 return Tcl_UnsetVar2(interp, varName, NULL, flags); 02103 } 02104 02105 /* 02106 *---------------------------------------------------------------------- 02107 * 02108 * Tcl_UnsetVar2 -- 02109 * 02110 * Delete a variable, given a 2-part name. 02111 * 02112 * Results: 02113 * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR if 02114 * the variable can't be unset. In the event of an error, if the 02115 * TCL_LEAVE_ERR_MSG flag is set then an error message is left in the 02116 * interp's result. 02117 * 02118 * Side effects: 02119 * If part1 and part2 indicate a local or global variable in interp, it 02120 * is deleted. If part1 is an array name and part2 is NULL, then the 02121 * whole array is deleted. 02122 * 02123 *---------------------------------------------------------------------- 02124 */ 02125 02126 int 02127 Tcl_UnsetVar2( 02128 Tcl_Interp *interp, /* Command interpreter in which varName is to 02129 * be looked up. */ 02130 const char *part1, /* Name of variable or array. */ 02131 const char *part2, /* Name of element within array or NULL. */ 02132 int flags) /* OR-ed combination of any of 02133 * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 02134 * TCL_LEAVE_ERR_MSG. */ 02135 { 02136 int result; 02137 Tcl_Obj *part1Ptr, *part2Ptr = NULL; 02138 02139 part1Ptr = Tcl_NewStringObj(part1, -1); 02140 Tcl_IncrRefCount(part1Ptr); 02141 if (part2) { 02142 part2Ptr = Tcl_NewStringObj(part2, -1); 02143 Tcl_IncrRefCount(part2Ptr); 02144 } 02145 02146 /* 02147 * Filter to pass through only the flags this interface supports. 02148 */ 02149 02150 flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); 02151 result = TclObjUnsetVar2(interp, part1Ptr, part2Ptr, flags); 02152 02153 Tcl_DecrRefCount(part1Ptr); 02154 if (part2Ptr) { 02155 Tcl_DecrRefCount(part2Ptr); 02156 } 02157 return result; 02158 } 02159 02160 /* 02161 *---------------------------------------------------------------------- 02162 * 02163 * TclObjUnsetVar2 -- 02164 * 02165 * Delete a variable, given a 2-object name. 02166 * 02167 * Results: 02168 * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR if 02169 * the variable can't be unset. In the event of an error, if the 02170 * TCL_LEAVE_ERR_MSG flag is set then an error message is left in the 02171 * interp's result. 02172 * 02173 * Side effects: 02174 * If part1ptr and part2Ptr indicate a local or global variable in 02175 * interp, it is deleted. If part1Ptr is an array name and part2Ptr is 02176 * NULL, then the whole array is deleted. 02177 * 02178 *---------------------------------------------------------------------- 02179 */ 02180 02181 int 02182 TclObjUnsetVar2( 02183 Tcl_Interp *interp, /* Command interpreter in which varName is to 02184 * be looked up. */ 02185 Tcl_Obj *part1Ptr, /* Name of variable or array. */ 02186 Tcl_Obj *part2Ptr, /* Name of element within array or NULL. */ 02187 int flags) /* OR-ed combination of any of 02188 * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, 02189 * TCL_LEAVE_ERR_MSG. */ 02190 { 02191 Var *varPtr; 02192 Interp *iPtr = (Interp *) interp; 02193 Var *arrayPtr; 02194 int result; 02195 02196 varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, flags, "unset", 02197 /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr); 02198 if (varPtr == NULL) { 02199 return TCL_ERROR; 02200 } 02201 02202 result = (TclIsVarUndefined(varPtr)? TCL_ERROR : TCL_OK); 02203 02204 /* 02205 * Keep the variable alive until we're done with it. We used to 02206 * increase/decrease the refCount for each operation, making it hard to 02207 * find [Bug 735335] - caused by unsetting the variable whose value was 02208 * the variable's name. 02209 */ 02210 02211 if (TclIsVarInHash(varPtr)) { 02212 VarHashRefCount(varPtr)++; 02213 } 02214 02215 UnsetVarStruct(varPtr, arrayPtr, iPtr, part1Ptr, part2Ptr, flags); 02216 02217 /* 02218 * It's an error to unset an undefined variable. 02219 */ 02220 02221 if (result != TCL_OK) { 02222 if (flags & TCL_LEAVE_ERR_MSG) { 02223 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, "unset", 02224 ((arrayPtr == NULL) ? noSuchVar : noSuchElement), -1); 02225 } 02226 } 02227 02228 #if ENABLE_NS_VARNAME_CACHING 02229 /* 02230 * Try to avoid keeping the Var struct allocated due to a tclNsVarNameType 02231 * keeping a reference. This removes some additional exteriorisations of 02232 * [Bug 736729], but may be a good thing independently of the bug. 02233 */ 02234 02235 if (part1Ptr->typePtr == &tclNsVarNameType) { 02236 TclFreeIntRep(part1Ptr); 02237 part1Ptr->typePtr = NULL; 02238 } 02239 #endif 02240 02241 /* 02242 * Finally, if the variable is truly not in use then free up its Var 02243 * structure and remove it from its hash table, if any. The ref count of 02244 * its value object, if any, was decremented above. 02245 */ 02246 02247 if (TclIsVarInHash(varPtr)) { 02248 VarHashRefCount(varPtr)--; 02249 CleanupVar(varPtr, arrayPtr); 02250 } 02251 return result; 02252 } 02253 02254 /* 02255 *---------------------------------------------------------------------- 02256 * 02257 * UnsetVarStruct -- 02258 * 02259 * Unset and delete a variable. This does the internal work for 02260 * TclObjUnsetVar2 and TclDeleteNamespaceVars, which call here for each 02261 * variable to be unset and deleted. 02262 * 02263 * Results: 02264 * None. 02265 * 02266 * Side effects: 02267 * If the arguments indicate a local or global variable in iPtr, it is 02268 * unset and deleted. 02269 * 02270 *---------------------------------------------------------------------- 02271 */ 02272 02273 static void 02274 UnsetVarStruct( 02275 Var *varPtr, 02276 Var *arrayPtr, 02277 Interp *iPtr, 02278 Tcl_Obj *part1Ptr, 02279 Tcl_Obj *part2Ptr, 02280 int flags) 02281 { 02282 Var dummyVar; 02283 int traced = TclIsVarTraced(varPtr) 02284 || (arrayPtr && (arrayPtr->flags & VAR_TRACED_UNSET)); 02285 02286 if (arrayPtr && (arrayPtr->flags & VAR_SEARCH_ACTIVE)) { 02287 DeleteSearches(iPtr, arrayPtr); 02288 } else if (varPtr->flags & VAR_SEARCH_ACTIVE) { 02289 DeleteSearches(iPtr, varPtr); 02290 } 02291 02292 /* 02293 * The code below is tricky, because of the possibility that a trace 02294 * function might try to access a variable being deleted. To handle this 02295 * situation gracefully, do things in three steps: 02296 * 1. Copy the contents of the variable to a dummy variable structure, and 02297 * mark the original Var structure as undefined. 02298 * 2. Invoke traces and clean up the variable, using the dummy copy. 02299 * 3. If at the end of this the original variable is still undefined and 02300 * has no outstanding references, then delete it (but it could have 02301 * gotten recreated by a trace). 02302 */ 02303 02304 dummyVar = *varPtr; 02305 dummyVar.flags &= ~VAR_ALL_HASH; 02306 TclSetVarUndefined(varPtr); 02307 02308 /* 02309 * Call trace functions for the variable being deleted. Then delete its 02310 * traces. Be sure to abort any other traces for the variable that are 02311 * still pending. Special tricks: 02312 * 1. We need to increment varPtr's refCount around this: TclCallVarTraces 02313 * will use dummyVar so it won't increment varPtr's refCount itself. 02314 * 2. Turn off the VAR_TRACE_ACTIVE flag in dummyVar: we want to call 02315 * unset traces even if other traces are pending. 02316 */ 02317 02318 if (traced) { 02319 VarTrace *tracePtr = NULL; 02320 Tcl_HashEntry *tPtr = NULL; 02321 02322 if (TclIsVarTraced(&dummyVar)) { 02323 /* 02324 * Transfer any existing traces on var, IF there are unset traces. 02325 * Otherwise just delete them. 02326 */ 02327 02328 int isNew; 02329 Tcl_HashEntry *tPtr = 02330 Tcl_FindHashEntry(&iPtr->varTraces, (char *) varPtr); 02331 02332 tracePtr = Tcl_GetHashValue(tPtr); 02333 varPtr->flags &= ~VAR_ALL_TRACES; 02334 Tcl_DeleteHashEntry(tPtr); 02335 if (dummyVar.flags & VAR_TRACED_UNSET) { 02336 tPtr = Tcl_CreateHashEntry(&iPtr->varTraces, 02337 (char *) &dummyVar, &isNew); 02338 Tcl_SetHashValue(tPtr, tracePtr); 02339 } else { 02340 tPtr = NULL; 02341 } 02342 } 02343 02344 if ((dummyVar.flags & VAR_TRACED_UNSET) 02345 || (arrayPtr && (arrayPtr->flags & VAR_TRACED_UNSET))) { 02346 dummyVar.flags &= ~VAR_TRACE_ACTIVE; 02347 TclObjCallVarTraces(iPtr, arrayPtr, (Var *) &dummyVar, 02348 part1Ptr, part2Ptr, 02349 (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) 02350 | TCL_TRACE_UNSETS, 02351 /* leaveErrMsg */ 0, -1); 02352 if (tPtr) { 02353 Tcl_DeleteHashEntry(tPtr); 02354 } 02355 } 02356 02357 if (tracePtr) { 02358 ActiveVarTrace *activePtr; 02359 02360 while (tracePtr) { 02361 VarTrace *prevPtr = tracePtr; 02362 02363 tracePtr = tracePtr->nextPtr; 02364 Tcl_EventuallyFree((ClientData) prevPtr, TCL_DYNAMIC); 02365 } 02366 for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; 02367 activePtr = activePtr->nextPtr) { 02368 if (activePtr->varPtr == varPtr) { 02369 activePtr->nextTracePtr = NULL; 02370 } 02371 } 02372 dummyVar.flags &= ~VAR_ALL_TRACES; 02373 } 02374 } 02375 02376 if (TclIsVarScalar(&dummyVar) && (dummyVar.value.objPtr != NULL)) { 02377 /* 02378 * Decrement the ref count of the var's value. 02379 */ 02380 02381 Tcl_Obj *objPtr = dummyVar.value.objPtr; 02382 02383 TclDecrRefCount(objPtr); 02384 } else if (TclIsVarArray(&dummyVar)) { 02385 /* 02386 * If the variable is an array, delete all of its elements. This must 02387 * be done after calling and deleting the traces on the array, above 02388 * (that's the way traces are defined). If the array name is not 02389 * present and is required for a trace on some element, it will be 02390 * computed at DeleteArray. 02391 */ 02392 02393 DeleteArray(iPtr, part1Ptr, (Var *) &dummyVar, (flags 02394 & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS); 02395 } else if (TclIsVarLink(&dummyVar)) { 02396 /* 02397 * For global/upvar variables referenced in procedures, decrement the 02398 * reference count on the variable referred to, and free the 02399 * referenced variable if it's no longer needed. 02400 */ 02401 02402 Var *linkPtr = dummyVar.value.linkPtr; 02403 02404 if (TclIsVarInHash(linkPtr)) { 02405 VarHashRefCount(linkPtr)--; 02406 CleanupVar(linkPtr, NULL); 02407 } 02408 } 02409 02410 /* 02411 * If the variable was a namespace variable, decrement its reference 02412 * count. 02413 */ 02414 02415 TclClearVarNamespaceVar(varPtr); 02416 } 02417 02418 /* 02419 *---------------------------------------------------------------------- 02420 * 02421 * Tcl_UnsetObjCmd -- 02422 * 02423 * This object-based function is invoked to process the "unset" Tcl 02424 * command. See the user documentation for details on what it does. 02425 * 02426 * Results: 02427 * A standard Tcl object result value. 02428 * 02429 * Side effects: 02430 * See the user documentation. 02431 * 02432 *---------------------------------------------------------------------- 02433 */ 02434 02435 /* ARGSUSED */ 02436 int 02437 Tcl_UnsetObjCmd( 02438 ClientData dummy, /* Not used. */ 02439 Tcl_Interp *interp, /* Current interpreter. */ 02440 int objc, /* Number of arguments. */ 02441 Tcl_Obj *const objv[]) /* Argument objects. */ 02442 { 02443 register int i, flags = TCL_LEAVE_ERR_MSG; 02444 register char *name; 02445 02446 if (objc == 1) { 02447 /* 02448 * Do nothing if no arguments supplied, so as to match command 02449 * documentation. 02450 */ 02451 02452 return TCL_OK; 02453 } 02454 02455 /* 02456 * Simple, restrictive argument parsing. The only options are -- and 02457 * -nocomplain (which must come first and be given exactly to be an 02458 * option). 02459 */ 02460 02461 i = 1; 02462 name = TclGetString(objv[i]); 02463 if (name[0] == '-') { 02464 if (strcmp("-nocomplain", name) == 0) { 02465 i++; 02466 if (i == objc) { 02467 return TCL_OK; 02468 } 02469 flags = 0; 02470 name = TclGetString(objv[i]); 02471 } 02472 if (strcmp("--", name) == 0) { 02473 i++; 02474 } 02475 } 02476 02477 for (; i < objc; i++) { 02478 if ((TclObjUnsetVar2(interp, objv[i], NULL, flags) != TCL_OK) 02479 && (flags == TCL_LEAVE_ERR_MSG)) { 02480 return TCL_ERROR; 02481 } 02482 } 02483 return TCL_OK; 02484 } 02485 02486 /* 02487 *---------------------------------------------------------------------- 02488 * 02489 * Tcl_AppendObjCmd -- 02490 * 02491 * This object-based function is invoked to process the "append" Tcl 02492 * command. See the user documentation for details on what it does. 02493 * 02494 * Results: 02495 * A standard Tcl object result value. 02496 * 02497 * Side effects: 02498 * A variable's value may be changed. 02499 * 02500 *---------------------------------------------------------------------- 02501 */ 02502 02503 /* ARGSUSED */ 02504 int 02505 Tcl_AppendObjCmd( 02506 ClientData dummy, /* Not used. */ 02507 Tcl_Interp *interp, /* Current interpreter. */ 02508 int objc, /* Number of arguments. */ 02509 Tcl_Obj *const objv[]) /* Argument objects. */ 02510 { 02511 Var *varPtr, *arrayPtr; 02512 register Tcl_Obj *varValuePtr = NULL; 02513 /* Initialized to avoid compiler warning. */ 02514 int i; 02515 02516 if (objc < 2) { 02517 Tcl_WrongNumArgs(interp, 1, objv, "varName ?value value ...?"); 02518 return TCL_ERROR; 02519 } 02520 02521 if (objc == 2) { 02522 varValuePtr = Tcl_ObjGetVar2(interp, objv[1], NULL,TCL_LEAVE_ERR_MSG); 02523 if (varValuePtr == NULL) { 02524 return TCL_ERROR; 02525 } 02526 } else { 02527 varPtr = TclObjLookupVarEx(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG, 02528 "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); 02529 if (varPtr == NULL) { 02530 return TCL_ERROR; 02531 } 02532 for (i=2 ; i<objc ; i++) { 02533 /* 02534 * Note that we do not need to increase the refCount of the Var 02535 * pointers: should a trace delete the variable, the return value 02536 * of TclPtrSetVar will be NULL, and we will not access the 02537 * variable again. 02538 */ 02539 02540 varValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, objv[1], 02541 NULL, objv[i], TCL_APPEND_VALUE|TCL_LEAVE_ERR_MSG, -1); 02542 if (varValuePtr == NULL) { 02543 return TCL_ERROR; 02544 } 02545 } 02546 } 02547 Tcl_SetObjResult(interp, varValuePtr); 02548 return TCL_OK; 02549 } 02550 02551 /* 02552 *---------------------------------------------------------------------- 02553 * 02554 * Tcl_LappendObjCmd -- 02555 * 02556 * This object-based function is invoked to process the "lappend" Tcl 02557 * command. See the user documentation for details on what it does. 02558 * 02559 * Results: 02560 * A standard Tcl object result value. 02561 * 02562 * Side effects: 02563 * A variable's value may be changed. 02564 * 02565 *---------------------------------------------------------------------- 02566 */ 02567 02568 /* ARGSUSED */ 02569 int 02570 Tcl_LappendObjCmd( 02571 ClientData dummy, /* Not used. */ 02572 Tcl_Interp *interp, /* Current interpreter. */ 02573 int objc, /* Number of arguments. */ 02574 Tcl_Obj *const objv[]) /* Argument objects. */ 02575 { 02576 Tcl_Obj *varValuePtr, *newValuePtr; 02577 int numElems, createdNewObj; 02578 Var *varPtr, *arrayPtr; 02579 int result; 02580 02581 if (objc < 2) { 02582 Tcl_WrongNumArgs(interp, 1, objv, "varName ?value value ...?"); 02583 return TCL_ERROR; 02584 } 02585 if (objc == 2) { 02586 newValuePtr = Tcl_ObjGetVar2(interp, objv[1], NULL, 0); 02587 if (newValuePtr == NULL) { 02588 /* 02589 * The variable doesn't exist yet. Just create it with an empty 02590 * initial value. 02591 */ 02592 02593 TclNewObj(varValuePtr); 02594 newValuePtr = Tcl_ObjSetVar2(interp, objv[1], NULL, varValuePtr, 02595 TCL_LEAVE_ERR_MSG); 02596 if (newValuePtr == NULL) { 02597 return TCL_ERROR; 02598 } 02599 } else { 02600 result = TclListObjLength(interp, newValuePtr, &numElems); 02601 if (result != TCL_OK) { 02602 return result; 02603 } 02604 } 02605 } else { 02606 /* 02607 * We have arguments to append. We used to call Tcl_SetVar2 to append 02608 * each argument one at a time to ensure that traces were run for each 02609 * append step. We now append the arguments all at once because it's 02610 * faster. Note that a read trace and a write trace for the variable 02611 * will now each only be called once. Also, if the variable's old 02612 * value is unshared we modify it directly, otherwise we create a new 02613 * copy to modify: this is "copy on write". 02614 */ 02615 02616 createdNewObj = 0; 02617 02618 /* 02619 * Protect the variable pointers around the TclPtrGetVar call 02620 * to insure that they remain valid even if the variable was undefined 02621 * and unused. 02622 */ 02623 02624 varPtr = TclObjLookupVarEx(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG, 02625 "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); 02626 if (varPtr == NULL) { 02627 return TCL_ERROR; 02628 } 02629 if (TclIsVarInHash(varPtr)) { 02630 VarHashRefCount(varPtr)++; 02631 } 02632 if (arrayPtr && TclIsVarInHash(arrayPtr)) { 02633 VarHashRefCount(arrayPtr)++; 02634 } 02635 varValuePtr = TclPtrGetVar(interp, varPtr, arrayPtr, objv[1], NULL, 02636 TCL_LEAVE_ERR_MSG, -1); 02637 if (TclIsVarInHash(varPtr)) { 02638 VarHashRefCount(varPtr)--; 02639 } 02640 if (arrayPtr && TclIsVarInHash(arrayPtr)) { 02641 VarHashRefCount(arrayPtr)--; 02642 } 02643 02644 if (varValuePtr == NULL) { 02645 /* 02646 * We couldn't read the old value: either the var doesn't yet 02647 * exist or it's an array element. If it's new, we will try to 02648 * create it with Tcl_ObjSetVar2 below. 02649 */ 02650 02651 TclNewObj(varValuePtr); 02652 createdNewObj = 1; 02653 } else if (Tcl_IsShared(varValuePtr)) { 02654 varValuePtr = Tcl_DuplicateObj(varValuePtr); 02655 createdNewObj = 1; 02656 } 02657 02658 result = TclListObjLength(interp, varValuePtr, &numElems); 02659 if (result == TCL_OK) { 02660 result = Tcl_ListObjReplace(interp, varValuePtr, numElems, 0, 02661 (objc-2), (objv+2)); 02662 } 02663 if (result != TCL_OK) { 02664 if (createdNewObj) { 02665 TclDecrRefCount(varValuePtr); /* Free unneeded obj. */ 02666 } 02667 return result; 02668 } 02669 02670 /* 02671 * Now store the list object back into the variable. If there is an 02672 * error setting the new value, decrement its ref count if it was new 02673 * and we didn't create the variable. 02674 */ 02675 02676 newValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, objv[1], NULL, 02677 varValuePtr, TCL_LEAVE_ERR_MSG, -1); 02678 if (newValuePtr == NULL) { 02679 return TCL_ERROR; 02680 } 02681 } 02682 02683 /* 02684 * Set the interpreter's object result to refer to the variable's value 02685 * object. 02686 */ 02687 02688 Tcl_SetObjResult(interp, newValuePtr); 02689 return TCL_OK; 02690 } 02691 02692 /* 02693 *---------------------------------------------------------------------- 02694 * 02695 * Tcl_ArrayObjCmd -- 02696 * 02697 * This object-based function is invoked to process the "array" Tcl 02698 * command. See the user documentation for details on what it does. 02699 * 02700 * Results: 02701 * A standard Tcl result object. 02702 * 02703 * Side effects: 02704 * See the user documentation. 02705 * 02706 *---------------------------------------------------------------------- 02707 */ 02708 02709 /* ARGSUSED */ 02710 int 02711 Tcl_ArrayObjCmd( 02712 ClientData dummy, /* Not used. */ 02713 Tcl_Interp *interp, /* Current interpreter. */ 02714 int objc, /* Number of arguments. */ 02715 Tcl_Obj *const objv[]) /* Argument objects. */ 02716 { 02717 /* 02718 * The list of constants below should match the arrayOptions string array 02719 * below. 02720 */ 02721 02722 enum { 02723 ARRAY_ANYMORE, ARRAY_DONESEARCH, ARRAY_EXISTS, ARRAY_GET, 02724 ARRAY_NAMES, ARRAY_NEXTELEMENT, ARRAY_SET, ARRAY_SIZE, 02725 ARRAY_STARTSEARCH, ARRAY_STATISTICS, ARRAY_UNSET 02726 }; 02727 static const char *arrayOptions[] = { 02728 "anymore", "donesearch", "exists", "get", "names", "nextelement", 02729 "set", "size", "startsearch", "statistics", "unset", NULL 02730 }; 02731 02732 Interp *iPtr = (Interp *) interp; 02733 Var *varPtr, *arrayPtr; 02734 Tcl_HashEntry *hPtr; 02735 Tcl_Obj *varNamePtr; 02736 int notArray; 02737 int index, result; 02738 02739 if (objc < 3) { 02740 Tcl_WrongNumArgs(interp, 1, objv, "option arrayName ?arg ...?"); 02741 return TCL_ERROR; 02742 } 02743 02744 if (Tcl_GetIndexFromObj(interp, objv[1], arrayOptions, "option", 02745 0, &index) != TCL_OK) { 02746 return TCL_ERROR; 02747 } 02748 02749 /* 02750 * Locate the array variable 02751 */ 02752 02753 varNamePtr = objv[2]; 02754 varPtr = TclObjLookupVarEx(interp, varNamePtr, NULL, /*flags*/ 0, 02755 /*msg*/ 0, /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr); 02756 02757 /* 02758 * Special array trace used to keep the env array in sync for array names, 02759 * array get, etc. 02760 */ 02761 02762 if (varPtr && (varPtr->flags & VAR_TRACED_ARRAY) 02763 && (TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr))) { 02764 if (TclObjCallVarTraces(iPtr, arrayPtr, varPtr, varNamePtr, NULL, 02765 (TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY| 02766 TCL_TRACE_ARRAY), /* leaveErrMsg */ 1, -1) == TCL_ERROR) { 02767 return TCL_ERROR; 02768 } 02769 } 02770 02771 /* 02772 * Verify that it is indeed an array variable. This test comes after the 02773 * traces - the variable may actually become an array as an effect of said 02774 * traces. 02775 */ 02776 02777 notArray = 0; 02778 if ((varPtr == NULL) || !TclIsVarArray(varPtr) 02779 || TclIsVarUndefined(varPtr)) { 02780 notArray = 1; 02781 } 02782 02783 switch (index) { 02784 case ARRAY_ANYMORE: { 02785 ArraySearch *searchPtr; 02786 02787 if (objc != 4) { 02788 Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId"); 02789 return TCL_ERROR; 02790 } 02791 if (notArray) { 02792 goto error; 02793 } 02794 searchPtr = ParseSearchId(interp, varPtr, varNamePtr, objv[3]); 02795 if (searchPtr == NULL) { 02796 return TCL_ERROR; 02797 } 02798 while (1) { 02799 Var *varPtr2; 02800 02801 if (searchPtr->nextEntry != NULL) { 02802 varPtr2 = VarHashGetValue(searchPtr->nextEntry); 02803 if (!TclIsVarUndefined(varPtr2)) { 02804 break; 02805 } 02806 } 02807 searchPtr->nextEntry = Tcl_NextHashEntry(&searchPtr->search); 02808 if (searchPtr->nextEntry == NULL) { 02809 Tcl_SetObjResult(interp, iPtr->execEnvPtr->constants[0]); 02810 return TCL_OK; 02811 } 02812 } 02813 Tcl_SetObjResult(interp, iPtr->execEnvPtr->constants[1]); 02814 break; 02815 } 02816 case ARRAY_DONESEARCH: { 02817 ArraySearch *searchPtr, *prevPtr; 02818 02819 if (objc != 4) { 02820 Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId"); 02821 return TCL_ERROR; 02822 } 02823 if (notArray) { 02824 goto error; 02825 } 02826 searchPtr = ParseSearchId(interp, varPtr, varNamePtr, objv[3]); 02827 if (searchPtr == NULL) { 02828 return TCL_ERROR; 02829 } 02830 hPtr = Tcl_FindHashEntry(&iPtr->varSearches,(char *) varPtr); 02831 if (searchPtr == Tcl_GetHashValue(hPtr)) { 02832 if (searchPtr->nextPtr) { 02833 Tcl_SetHashValue(hPtr, searchPtr->nextPtr); 02834 } else { 02835 varPtr->flags &= ~VAR_SEARCH_ACTIVE; 02836 Tcl_DeleteHashEntry(hPtr); 02837 } 02838 } else { 02839 for (prevPtr=Tcl_GetHashValue(hPtr) ;; prevPtr=prevPtr->nextPtr) { 02840 if (prevPtr->nextPtr == searchPtr) { 02841 prevPtr->nextPtr = searchPtr->nextPtr; 02842 break; 02843 } 02844 } 02845 } 02846 ckfree((char *) searchPtr); 02847 break; 02848 } 02849 case ARRAY_NEXTELEMENT: { 02850 ArraySearch *searchPtr; 02851 Tcl_HashEntry *hPtr; 02852 Var *varPtr2; 02853 02854 if (objc != 4) { 02855 Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId"); 02856 return TCL_ERROR; 02857 } 02858 if (notArray) { 02859 goto error; 02860 } 02861 searchPtr = ParseSearchId(interp, varPtr, varNamePtr, objv[3]); 02862 if (searchPtr == NULL) { 02863 return TCL_ERROR; 02864 } 02865 while (1) { 02866 hPtr = searchPtr->nextEntry; 02867 if (hPtr == NULL) { 02868 hPtr = Tcl_NextHashEntry(&searchPtr->search); 02869 if (hPtr == NULL) { 02870 return TCL_OK; 02871 } 02872 } else { 02873 searchPtr->nextEntry = NULL; 02874 } 02875 varPtr2 = VarHashGetValue(hPtr); 02876 if (!TclIsVarUndefined(varPtr2)) { 02877 break; 02878 } 02879 } 02880 Tcl_SetObjResult(interp, VarHashGetKey(varPtr2)); 02881 break; 02882 } 02883 case ARRAY_STARTSEARCH: { 02884 ArraySearch *searchPtr; 02885 int isNew; 02886 char *varName = TclGetString(varNamePtr); 02887 02888 if (objc != 3) { 02889 Tcl_WrongNumArgs(interp, 2, objv, "arrayName"); 02890 return TCL_ERROR; 02891 } 02892 if (notArray) { 02893 goto error; 02894 } 02895 searchPtr = (ArraySearch *) ckalloc(sizeof(ArraySearch)); 02896 hPtr = Tcl_CreateHashEntry(&iPtr->varSearches, 02897 (char *) varPtr, &isNew); 02898 if (isNew) { 02899 searchPtr->id = 1; 02900 Tcl_AppendResult(interp, "s-1-", varName, NULL); 02901 varPtr->flags |= VAR_SEARCH_ACTIVE; 02902 searchPtr->nextPtr = NULL; 02903 } else { 02904 char string[TCL_INTEGER_SPACE]; 02905 02906 searchPtr->id = ((ArraySearch *) Tcl_GetHashValue(hPtr))->id + 1; 02907 TclFormatInt(string, searchPtr->id); 02908 Tcl_AppendResult(interp, "s-", string, "-", varName, NULL); 02909 searchPtr->nextPtr = Tcl_GetHashValue(hPtr); 02910 } 02911 searchPtr->varPtr = varPtr; 02912 searchPtr->nextEntry = VarHashFirstEntry(varPtr->value.tablePtr, 02913 &searchPtr->search); 02914 Tcl_SetHashValue(hPtr, searchPtr); 02915 break; 02916 } 02917 02918 case ARRAY_EXISTS: 02919 if (objc != 3) { 02920 Tcl_WrongNumArgs(interp, 2, objv, "arrayName"); 02921 return TCL_ERROR; 02922 } 02923 Tcl_SetObjResult(interp, iPtr->execEnvPtr->constants[!notArray]); 02924 break; 02925 case ARRAY_GET: { 02926 Tcl_HashSearch search; 02927 Var *varPtr2; 02928 char *pattern = NULL; 02929 char *name; 02930 Tcl_Obj *namePtr, *valuePtr, *nameLstPtr, *tmpResPtr, **namePtrPtr; 02931 int i, count; 02932 02933 if ((objc != 3) && (objc != 4)) { 02934 Tcl_WrongNumArgs(interp, 2, objv, "arrayName ?pattern?"); 02935 return TCL_ERROR; 02936 } 02937 if (notArray) { 02938 return TCL_OK; 02939 } 02940 if (objc == 4) { 02941 pattern = TclGetString(objv[3]); 02942 } 02943 02944 /* 02945 * Store the array names in a new object. 02946 */ 02947 02948 TclNewObj(nameLstPtr); 02949 Tcl_IncrRefCount(nameLstPtr); 02950 if ((pattern != NULL) && TclMatchIsTrivial(pattern)) { 02951 varPtr2 = VarHashFindVar(varPtr->value.tablePtr, objv[3]); 02952 if (varPtr2 == NULL) { 02953 goto searchDone; 02954 } 02955 if (TclIsVarUndefined(varPtr2)) { 02956 goto searchDone; 02957 } 02958 result = Tcl_ListObjAppendElement(interp, nameLstPtr, 02959 VarHashGetKey(varPtr2)); 02960 if (result != TCL_OK) { 02961 TclDecrRefCount(nameLstPtr); 02962 return result; 02963 } 02964 goto searchDone; 02965 } 02966 for (varPtr2 = VarHashFirstVar(varPtr->value.tablePtr, &search); 02967 varPtr2; varPtr2 = VarHashNextVar(&search)) { 02968 if (TclIsVarUndefined(varPtr2)) { 02969 continue; 02970 } 02971 namePtr = VarHashGetKey(varPtr2); 02972 name = TclGetString(namePtr); 02973 if ((objc == 4) && !Tcl_StringMatch(name, pattern)) { 02974 continue; /* Element name doesn't match pattern. */ 02975 } 02976 02977 result = Tcl_ListObjAppendElement(interp, nameLstPtr, namePtr); 02978 if (result != TCL_OK) { 02979 TclDecrRefCount(nameLstPtr); 02980 return result; 02981 } 02982 } 02983 02984 searchDone: 02985 /* 02986 * Make sure the Var structure of the array is not removed by a trace 02987 * while we're working. 02988 */ 02989 02990 if (TclIsVarInHash(varPtr)) { 02991 VarHashRefCount(varPtr)++; 02992 } 02993 02994 /* 02995 * Get the array values corresponding to each element name. 02996 */ 02997 02998 TclNewObj(tmpResPtr); 02999 result = Tcl_ListObjGetElements(interp, nameLstPtr, &count, 03000 &namePtrPtr); 03001 if (result != TCL_OK) { 03002 goto errorInArrayGet; 03003 } 03004 03005 for (i=0 ; i<count ; i++) { 03006 namePtr = *namePtrPtr++; 03007 valuePtr = Tcl_ObjGetVar2(interp, objv[2], namePtr, 03008 TCL_LEAVE_ERR_MSG); 03009 if (valuePtr == NULL) { 03010 /* 03011 * Some trace played a trick on us; we need to diagnose to 03012 * adapt our behaviour: was the array element unset, or did 03013 * the modification modify the complete array? 03014 */ 03015 03016 if (TclIsVarArray(varPtr)) { 03017 /* 03018 * The array itself looks OK, the variable was undefined: 03019 * forget it. 03020 */ 03021 03022 continue; 03023 } else { 03024 result = TCL_ERROR; 03025 goto errorInArrayGet; 03026 } 03027 } 03028 result = Tcl_DictObjPut(interp, tmpResPtr, namePtr, valuePtr); 03029 if (result != TCL_OK) { 03030 goto errorInArrayGet; 03031 } 03032 } 03033 if (TclIsVarInHash(varPtr)) { 03034 VarHashRefCount(varPtr)--; 03035 } 03036 Tcl_SetObjResult(interp, tmpResPtr); 03037 TclDecrRefCount(nameLstPtr); 03038 break; 03039 03040 errorInArrayGet: 03041 if (TclIsVarInHash(varPtr)) { 03042 VarHashRefCount(varPtr)--; 03043 } 03044 TclDecrRefCount(nameLstPtr); 03045 TclDecrRefCount(tmpResPtr); /* Free unneeded temp result. */ 03046 return result; 03047 } 03048 case ARRAY_NAMES: { 03049 Tcl_HashSearch search; 03050 Var *varPtr2; 03051 char *pattern; 03052 char *name; 03053 Tcl_Obj *namePtr, *resultPtr, *patternPtr; 03054 int mode, matched = 0; 03055 static const char *options[] = { 03056 "-exact", "-glob", "-regexp", NULL 03057 }; 03058 enum options { OPT_EXACT, OPT_GLOB, OPT_REGEXP }; 03059 03060 mode = OPT_GLOB; 03061 03062 if ((objc < 3) || (objc > 5)) { 03063 Tcl_WrongNumArgs(interp, 2,objv, "arrayName ?mode? ?pattern?"); 03064 return TCL_ERROR; 03065 } 03066 if (notArray) { 03067 return TCL_OK; 03068 } 03069 if (objc == 4) { 03070 patternPtr = objv[3]; 03071 pattern = TclGetString(patternPtr); 03072 } else if (objc == 5) { 03073 patternPtr = objv[4]; 03074 pattern = TclGetString(patternPtr); 03075 if (Tcl_GetIndexFromObj(interp, objv[3], options, "option", 0, 03076 &mode) != TCL_OK) { 03077 return TCL_ERROR; 03078 } 03079 } else { 03080 patternPtr = NULL; 03081 pattern = NULL; 03082 } 03083 TclNewObj(resultPtr); 03084 if (((enum options) mode)==OPT_GLOB && pattern!=NULL && 03085 TclMatchIsTrivial(pattern)) { 03086 varPtr2 = VarHashFindVar(varPtr->value.tablePtr, patternPtr); 03087 if ((varPtr2 != NULL) && !TclIsVarUndefined(varPtr2)) { 03088 result = Tcl_ListObjAppendElement(interp, resultPtr, 03089 VarHashGetKey(varPtr2)); 03090 if (result != TCL_OK) { 03091 TclDecrRefCount(resultPtr); 03092 return result; 03093 } 03094 } 03095 Tcl_SetObjResult(interp, resultPtr); 03096 return TCL_OK; 03097 } 03098 for (varPtr2=VarHashFirstVar(varPtr->value.tablePtr, &search); 03099 varPtr2!=NULL ; varPtr2=VarHashNextVar(&search)) { 03100 if (TclIsVarUndefined(varPtr2)) { 03101 continue; 03102 } 03103 namePtr = VarHashGetKey(varPtr2); 03104 name = TclGetString(namePtr); 03105 if (objc > 3) { 03106 switch ((enum options) mode) { 03107 case OPT_EXACT: 03108 matched = (strcmp(name, pattern) == 0); 03109 break; 03110 case OPT_GLOB: 03111 matched = Tcl_StringMatch(name, pattern); 03112 break; 03113 case OPT_REGEXP: 03114 matched = Tcl_RegExpMatch(interp, name, pattern); 03115 if (matched < 0) { 03116 TclDecrRefCount(resultPtr); 03117 return TCL_ERROR; 03118 } 03119 break; 03120 } 03121 if (matched == 0) { 03122 continue; 03123 } 03124 } 03125 03126 result = Tcl_ListObjAppendElement(interp, resultPtr, namePtr); 03127 if (result != TCL_OK) { 03128 TclDecrRefCount(namePtr); /* Free unneeded name obj. */ 03129 return result; 03130 } 03131 } 03132 Tcl_SetObjResult(interp, resultPtr); 03133 break; 03134 } 03135 case ARRAY_SET: 03136 if (objc != 4) { 03137 Tcl_WrongNumArgs(interp, 2, objv, "arrayName list"); 03138 return TCL_ERROR; 03139 } 03140 return TclArraySet(interp, objv[2], objv[3]); 03141 case ARRAY_UNSET: { 03142 Tcl_HashSearch search; 03143 Var *varPtr2; 03144 char *pattern = NULL; 03145 03146 if ((objc != 3) && (objc != 4)) { 03147 Tcl_WrongNumArgs(interp, 2, objv, "arrayName ?pattern?"); 03148 return TCL_ERROR; 03149 } 03150 if (notArray) { 03151 return TCL_OK; 03152 } 03153 if (objc == 3) { 03154 /* 03155 * When no pattern is given, just unset the whole array. 03156 */ 03157 03158 if (TclObjUnsetVar2(interp, varNamePtr, NULL, 0) != TCL_OK) { 03159 return TCL_ERROR; 03160 } 03161 } else { 03162 pattern = TclGetString(objv[3]); 03163 if (TclMatchIsTrivial(pattern)) { 03164 varPtr2 = VarHashFindVar(varPtr->value.tablePtr, objv[3]); 03165 if (varPtr2 != NULL && !TclIsVarUndefined(varPtr2)) { 03166 return TclObjUnsetVar2(interp, varNamePtr, objv[3], 0); 03167 } 03168 return TCL_OK; 03169 } 03170 for (varPtr2=VarHashFirstVar(varPtr->value.tablePtr, &search); 03171 varPtr2!=NULL ; varPtr2=VarHashNextVar(&search)) { 03172 Tcl_Obj *namePtr; 03173 03174 if (TclIsVarUndefined(varPtr2)) { 03175 continue; 03176 } 03177 namePtr = VarHashGetKey(varPtr2); 03178 if (Tcl_StringMatch(TclGetString(namePtr), pattern) && 03179 TclObjUnsetVar2(interp, varNamePtr, namePtr, 03180 0) != TCL_OK) { 03181 return TCL_ERROR; 03182 } 03183 } 03184 } 03185 break; 03186 } 03187 03188 case ARRAY_SIZE: { 03189 Tcl_HashSearch search; 03190 Var *varPtr2; 03191 int size; 03192 03193 if (objc != 3) { 03194 Tcl_WrongNumArgs(interp, 2, objv, "arrayName"); 03195 return TCL_ERROR; 03196 } 03197 size = 0; 03198 03199 /* 03200 * Must iterate in order to get chance to check for present but 03201 * "undefined" entries. 03202 */ 03203 03204 if (!notArray) { 03205 for (varPtr2=VarHashFirstVar(varPtr->value.tablePtr, &search); 03206 varPtr2!=NULL ; varPtr2=VarHashNextVar(&search)) { 03207 if (TclIsVarUndefined(varPtr2)) { 03208 continue; 03209 } 03210 size++; 03211 } 03212 } 03213 Tcl_SetObjResult(interp, Tcl_NewIntObj(size)); 03214 break; 03215 } 03216 03217 case ARRAY_STATISTICS: { 03218 const char *stats; 03219 03220 if (notArray) { 03221 goto error; 03222 } 03223 03224 stats = Tcl_HashStats((Tcl_HashTable *) varPtr->value.tablePtr); 03225 if (stats != NULL) { 03226 Tcl_SetObjResult(interp, Tcl_NewStringObj(stats, -1)); 03227 ckfree((void *)stats); 03228 } else { 03229 Tcl_SetResult(interp,"error reading array statistics",TCL_STATIC); 03230 return TCL_ERROR; 03231 } 03232 break; 03233 } 03234 } 03235 return TCL_OK; 03236 03237 error: 03238 Tcl_AppendResult(interp, "\"", TclGetString(varNamePtr), 03239 "\" isn't an array", NULL); 03240 return TCL_ERROR; 03241 } 03242 03243 /* 03244 *---------------------------------------------------------------------- 03245 * 03246 * TclArraySet -- 03247 * 03248 * Set the elements of an array. If there are no elements to set, create 03249 * an empty array. This routine is used by the Tcl_ArrayObjCmd and by the 03250 * TclSetupEnv routine. 03251 * 03252 * Results: 03253 * A standard Tcl result object. 03254 * 03255 * Side effects: 03256 * A variable will be created if one does not already exist. 03257 * 03258 *---------------------------------------------------------------------- 03259 */ 03260 03261 int 03262 TclArraySet( 03263 Tcl_Interp *interp, /* Current interpreter. */ 03264 Tcl_Obj *arrayNameObj, /* The array name. */ 03265 Tcl_Obj *arrayElemObj) /* The array elements list or dict. If this is 03266 * NULL, create an empty array. */ 03267 { 03268 Var *varPtr, *arrayPtr; 03269 int result, i; 03270 03271 varPtr = TclObjLookupVarEx(interp, arrayNameObj, NULL, 03272 /*flags*/ TCL_LEAVE_ERR_MSG, /*msg*/ "set", /*createPart1*/ 1, 03273 /*createPart2*/ 1, &arrayPtr); 03274 if (varPtr == NULL) { 03275 return TCL_ERROR; 03276 } 03277 if (arrayPtr) { 03278 CleanupVar(varPtr, arrayPtr); 03279 TclObjVarErrMsg(interp, arrayNameObj, NULL, "set", needArray, -1); 03280 return TCL_ERROR; 03281 } 03282 03283 if (arrayElemObj == NULL) { 03284 goto ensureArray; 03285 } 03286 03287 /* 03288 * Install the contents of the dictionary or list into the array. 03289 */ 03290 03291 if (arrayElemObj->typePtr == &tclDictType) { 03292 Tcl_Obj *keyPtr, *valuePtr; 03293 Tcl_DictSearch search; 03294 int done; 03295 03296 if (Tcl_DictObjSize(interp, arrayElemObj, &done) != TCL_OK) { 03297 return TCL_ERROR; 03298 } 03299 if (done == 0) { 03300 /* 03301 * Empty, so we'll just force the array to be properly existing 03302 * instead. 03303 */ 03304 03305 goto ensureArray; 03306 } 03307 03308 /* 03309 * Don't need to look at result of Tcl_DictObjFirst as we've just 03310 * successfully used a dictionary operation on the same object. 03311 */ 03312 03313 for (Tcl_DictObjFirst(interp, arrayElemObj, &search, 03314 &keyPtr, &valuePtr, &done) ; !done ; 03315 Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done)) { 03316 /* 03317 * At this point, it would be nice if the key was directly usable 03318 * by the array. This isn't the case though. 03319 */ 03320 03321 Var *elemVarPtr = TclLookupArrayElement(interp, arrayNameObj, 03322 keyPtr, TCL_LEAVE_ERR_MSG, "set", 1, 1, varPtr, -1); 03323 03324 if ((elemVarPtr == NULL) || 03325 (TclPtrSetVar(interp, elemVarPtr, varPtr, arrayNameObj, 03326 keyPtr, valuePtr, TCL_LEAVE_ERR_MSG, -1) == NULL)) { 03327 Tcl_DictObjDone(&search); 03328 return TCL_ERROR; 03329 } 03330 } 03331 return TCL_OK; 03332 } else { 03333 /* 03334 * Not a dictionary, so assume (and convert to, for backward- 03335 * -compatability reasons) a list. 03336 */ 03337 03338 int elemLen; 03339 Tcl_Obj **elemPtrs, *copyListObj; 03340 03341 result = TclListObjGetElements(interp, arrayElemObj, 03342 &elemLen, &elemPtrs); 03343 if (result != TCL_OK) { 03344 return result; 03345 } 03346 if (elemLen & 1) { 03347 Tcl_SetObjResult(interp, Tcl_NewStringObj( 03348 "list must have an even number of elements", -1)); 03349 return TCL_ERROR; 03350 } 03351 if (elemLen == 0) { 03352 goto ensureArray; 03353 } 03354 03355 /* 03356 * We needn't worry about traces invalidating arrayPtr: should that be 03357 * the case, TclPtrSetVar will return NULL so that we break out of the 03358 * loop and return an error. 03359 */ 03360 03361 copyListObj = TclListObjCopy(NULL, arrayElemObj); 03362 for (i=0 ; i<elemLen ; i+=2) { 03363 Var *elemVarPtr = TclLookupArrayElement(interp, arrayNameObj, 03364 elemPtrs[i], TCL_LEAVE_ERR_MSG, "set", 1, 1, varPtr, -1); 03365 03366 if ((elemVarPtr == NULL) || 03367 (TclPtrSetVar(interp, elemVarPtr, varPtr, arrayNameObj, 03368 elemPtrs[i],elemPtrs[i+1],TCL_LEAVE_ERR_MSG,-1) == NULL)){ 03369 result = TCL_ERROR; 03370 break; 03371 } 03372 } 03373 Tcl_DecrRefCount(copyListObj); 03374 return result; 03375 } 03376 03377 /* 03378 * The list is empty make sure we have an array, or create one if 03379 * necessary. 03380 */ 03381 03382 ensureArray: 03383 if (varPtr != NULL) { 03384 if (TclIsVarArray(varPtr)) { 03385 /* 03386 * Already an array, done. 03387 */ 03388 03389 return TCL_OK; 03390 } 03391 if (TclIsVarArrayElement(varPtr) || !TclIsVarUndefined(varPtr)) { 03392 /* 03393 * Either an array element, or a scalar: lose! 03394 */ 03395 03396 TclObjVarErrMsg(interp, arrayNameObj, NULL, "array set", 03397 needArray, -1); 03398 return TCL_ERROR; 03399 } 03400 } 03401 TclSetVarArray(varPtr); 03402 varPtr->value.tablePtr = (TclVarHashTable *) 03403 ckalloc(sizeof(TclVarHashTable)); 03404 TclInitVarHashTable(varPtr->value.tablePtr, TclGetVarNsPtr(varPtr)); 03405 return TCL_OK; 03406 } 03407 03408 /* 03409 *---------------------------------------------------------------------- 03410 * 03411 * ObjMakeUpvar -- 03412 * 03413 * This function does all of the work of the "global" and "upvar" 03414 * commands. 03415 * 03416 * Results: 03417 * A standard Tcl completion code. If an error occurs then an error 03418 * message is left in iPtr->result. 03419 * 03420 * Side effects: 03421 * The variable given by myName is linked to the variable in framePtr 03422 * given by otherP1 and otherP2, so that references to myName are 03423 * redirected to the other variable like a symbolic link. 03424 * 03425 *---------------------------------------------------------------------- 03426 */ 03427 03428 static int 03429 ObjMakeUpvar( 03430 Tcl_Interp *interp, /* Interpreter containing variables. Used for 03431 * error messages, too. */ 03432 CallFrame *framePtr, /* Call frame containing "other" variable. 03433 * NULL means use global :: context. */ 03434 Tcl_Obj *otherP1Ptr, 03435 const char *otherP2, /* Two-part name of variable in framePtr. */ 03436 const int otherFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: 03437 * indicates scope of "other" variable. */ 03438 Tcl_Obj *myNamePtr, /* Name of variable which will refer to 03439 * otherP1/otherP2. Must be a scalar. */ 03440 int myFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: 03441 * indicates scope of myName. */ 03442 int index) /* If the variable to be linked is an indexed 03443 * scalar, this is its index. Otherwise, -1 */ 03444 { 03445 Interp *iPtr = (Interp *) interp; 03446 Var *otherPtr, *arrayPtr; 03447 CallFrame *varFramePtr; 03448 03449 /* 03450 * Find "other" in "framePtr". If not looking up other in just the current 03451 * namespace, temporarily replace the current var frame pointer in the 03452 * interpreter in order to use TclObjLookupVar. 03453 */ 03454 03455 if (framePtr == NULL) { 03456 framePtr = iPtr->rootFramePtr; 03457 } 03458 03459 varFramePtr = iPtr->varFramePtr; 03460 if (!(otherFlags & TCL_NAMESPACE_ONLY)) { 03461 iPtr->varFramePtr = framePtr; 03462 } 03463 otherPtr = TclObjLookupVar(interp, otherP1Ptr, otherP2, 03464 (otherFlags | TCL_LEAVE_ERR_MSG), "access", 03465 /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); 03466 if (!(otherFlags & TCL_NAMESPACE_ONLY)) { 03467 iPtr->varFramePtr = varFramePtr; 03468 } 03469 if (otherPtr == NULL) { 03470 return TCL_ERROR; 03471 } 03472 03473 /* 03474 * Check that we are not trying to create a namespace var linked to a 03475 * local variable in a procedure. If we allowed this, the local 03476 * variable in the shorter-lived procedure frame could go away leaving 03477 * the namespace var's reference invalid. 03478 */ 03479 03480 if (index < 0) { 03481 if (!(arrayPtr != NULL 03482 ? (TclIsVarInHash(arrayPtr) && TclGetVarNsPtr(arrayPtr)) 03483 : (TclIsVarInHash(otherPtr) && TclGetVarNsPtr(otherPtr))) 03484 && ((myFlags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) 03485 || (varFramePtr == NULL) 03486 || !HasLocalVars(varFramePtr) 03487 || (strstr(TclGetString(myNamePtr), "::") != NULL))) { 03488 Tcl_AppendResult((Tcl_Interp *) iPtr, "bad variable name \"", 03489 TclGetString(myNamePtr), "\": upvar won't create " 03490 "namespace variable that refers to procedure variable", 03491 NULL); 03492 return TCL_ERROR; 03493 } 03494 } 03495 03496 return TclPtrObjMakeUpvar(interp, otherPtr, myNamePtr, myFlags, index); 03497 } 03498 03499 /* 03500 *---------------------------------------------------------------------- 03501 * 03502 * TclPtrMakeUpvar -- 03503 * 03504 * This procedure does all of the work of the "global" and "upvar" 03505 * commands. 03506 * 03507 * Results: 03508 * A standard Tcl completion code. If an error occurs then an error 03509 * message is left in iPtr->result. 03510 * 03511 * Side effects: 03512 * The variable given by myName is linked to the variable in framePtr 03513 * given by otherP1 and otherP2, so that references to myName are 03514 * redirected to the other variable like a symbolic link. 03515 * 03516 *---------------------------------------------------------------------- 03517 */ 03518 03519 int 03520 TclPtrMakeUpvar( 03521 Tcl_Interp *interp, /* Interpreter containing variables. Used for 03522 * error messages, too. */ 03523 Var *otherPtr, /* Pointer to the variable being linked-to. */ 03524 const char *myName, /* Name of variable which will refer to 03525 * otherP1/otherP2. Must be a scalar. */ 03526 int myFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: 03527 * indicates scope of myName. */ 03528 int index) /* If the variable to be linked is an indexed 03529 * scalar, this is its index. Otherwise, -1 */ 03530 { 03531 Tcl_Obj *myNamePtr; 03532 int result; 03533 03534 if (myName) { 03535 myNamePtr = Tcl_NewStringObj(myName, -1); 03536 Tcl_IncrRefCount(myNamePtr); 03537 } else { 03538 myNamePtr = NULL; 03539 } 03540 result = TclPtrObjMakeUpvar(interp, otherPtr, myNamePtr, myFlags, index); 03541 if (myNamePtr) { 03542 Tcl_DecrRefCount(myNamePtr); 03543 } 03544 return result; 03545 } 03546 03547 int 03548 TclPtrObjMakeUpvar( 03549 Tcl_Interp *interp, /* Interpreter containing variables. Used for 03550 * error messages, too. */ 03551 Var *otherPtr, /* Pointer to the variable being linked-to. */ 03552 Tcl_Obj *myNamePtr, /* Name of variable which will refer to 03553 * otherP1/otherP2. Must be a scalar. */ 03554 int myFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: 03555 * indicates scope of myName. */ 03556 int index) /* If the variable to be linked is an indexed 03557 * scalar, this is its index. Otherwise, -1 */ 03558 { 03559 Interp *iPtr = (Interp *) interp; 03560 CallFrame *varFramePtr = iPtr->varFramePtr; 03561 const char *errMsg, *p, *myName; 03562 Var *varPtr; 03563 03564 if (index >= 0) { 03565 if (!HasLocalVars(varFramePtr)) { 03566 Tcl_Panic("ObjMakeUpvar called with an index outside from a proc"); 03567 } 03568 varPtr = (Var *) &(varFramePtr->compiledLocals[index]); 03569 myNamePtr = localName(iPtr->varFramePtr, index); 03570 myName = myNamePtr? TclGetString(myNamePtr) : NULL; 03571 } else { 03572 /* 03573 * Do not permit the new variable to look like an array reference, as 03574 * it will not be reachable in that case [Bug 600812, TIP 184]. The 03575 * "definition" of what "looks like an array reference" is consistent 03576 * (and must remain consistent) with the code in TclObjLookupVar(). 03577 */ 03578 03579 myName = TclGetString(myNamePtr); 03580 p = strstr(myName, "("); 03581 if (p != NULL) { 03582 p += strlen(p)-1; 03583 if (*p == ')') { 03584 /* 03585 * myName looks like an array reference. 03586 */ 03587 03588 Tcl_AppendResult((Tcl_Interp *) iPtr, "bad variable name \"", 03589 myName, "\": upvar won't create a scalar variable " 03590 "that looks like an array element", NULL); 03591 return TCL_ERROR; 03592 } 03593 } 03594 03595 /* 03596 * Lookup and eventually create the new variable. Set the flag bit 03597 * AVOID_RESOLVERS to indicate the special resolution rules for upvar 03598 * purposes: 03599 * - Bug #696893 - variable is either proc-local or in the current 03600 * namespace; never follow the second (global) resolution path. 03601 * - Bug #631741 - do not use special namespace or interp resolvers. 03602 */ 03603 03604 varPtr = TclLookupSimpleVar(interp, myNamePtr, 03605 myFlags|AVOID_RESOLVERS, /* create */ 1, &errMsg, &index); 03606 if (varPtr == NULL) { 03607 TclObjVarErrMsg(interp, myNamePtr, NULL, "create", errMsg, -1); 03608 return TCL_ERROR; 03609 } 03610 } 03611 03612 if (varPtr == otherPtr) { 03613 Tcl_SetResult((Tcl_Interp *) iPtr, 03614 "can't upvar from variable to itself", TCL_STATIC); 03615 return TCL_ERROR; 03616 } 03617 03618 if (TclIsVarTraced(varPtr)) { 03619 Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName, 03620 "\" has traces: can't use for upvar", NULL); 03621 return TCL_ERROR; 03622 } else if (!TclIsVarUndefined(varPtr)) { 03623 /* 03624 * The variable already existed. Make sure this variable "varPtr" 03625 * isn't the same as "otherPtr" (avoid circular links). Also, if it's 03626 * not an upvar then it's an error. If it is an upvar, then just 03627 * disconnect it from the thing it currently refers to. 03628 */ 03629 03630 if (TclIsVarLink(varPtr)) { 03631 Var *linkPtr = varPtr->value.linkPtr; 03632 if (linkPtr == otherPtr) { 03633 return TCL_OK; 03634 } 03635 if (TclIsVarInHash(linkPtr)) { 03636 VarHashRefCount(linkPtr)--; 03637 if (TclIsVarUndefined(linkPtr)) { 03638 CleanupVar(linkPtr, NULL); 03639 } 03640 } 03641 } else { 03642 Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName, 03643 "\" already exists", NULL); 03644 return TCL_ERROR; 03645 } 03646 } 03647 TclSetVarLink(varPtr); 03648 varPtr->value.linkPtr = otherPtr; 03649 if (TclIsVarInHash(otherPtr)) { 03650 VarHashRefCount(otherPtr)++; 03651 } 03652 return TCL_OK; 03653 } 03654 03655 /* 03656 *---------------------------------------------------------------------- 03657 * 03658 * Tcl_UpVar -- 03659 * 03660 * This function links one variable to another, just like the "upvar" 03661 * command. 03662 * 03663 * Results: 03664 * A standard Tcl completion code. If an error occurs then an error 03665 * message is left in the interp's result. 03666 * 03667 * Side effects: 03668 * The variable in frameName whose name is given by varName becomes 03669 * accessible under the name localName, so that references to localName 03670 * are redirected to the other variable like a symbolic link. 03671 * 03672 *---------------------------------------------------------------------- 03673 */ 03674 03675 int 03676 Tcl_UpVar( 03677 Tcl_Interp *interp, /* Command interpreter in which varName is to 03678 * be looked up. */ 03679 const char *frameName, /* Name of the frame containing the source 03680 * variable, such as "1" or "#0". */ 03681 const char *varName, /* Name of a variable in interp to link to. 03682 * May be either a scalar name or an element 03683 * in an array. */ 03684 const char *localName, /* Name of link variable. */ 03685 int flags) /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: 03686 * indicates scope of localName. */ 03687 { 03688 return Tcl_UpVar2(interp, frameName, varName, NULL, localName, flags); 03689 } 03690 03691 /* 03692 *---------------------------------------------------------------------- 03693 * 03694 * Tcl_UpVar2 -- 03695 * 03696 * This function links one variable to another, just like the "upvar" 03697 * command. 03698 * 03699 * Results: 03700 * A standard Tcl completion code. If an error occurs then an error 03701 * message is left in the interp's result. 03702 * 03703 * Side effects: 03704 * The variable in frameName whose name is given by part1 and part2 03705 * becomes accessible under the name localName, so that references to 03706 * localName are redirected to the other variable like a symbolic link. 03707 * 03708 *---------------------------------------------------------------------- 03709 */ 03710 03711 int 03712 Tcl_UpVar2( 03713 Tcl_Interp *interp, /* Interpreter containing variables. Used for 03714 * error messages too. */ 03715 const char *frameName, /* Name of the frame containing the source 03716 * variable, such as "1" or "#0". */ 03717 const char *part1, 03718 const char *part2, /* Two parts of source variable name to link 03719 * to. */ 03720 const char *localName, /* Name of link variable. */ 03721 int flags) /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: 03722 * indicates scope of localName. */ 03723 { 03724 int result; 03725 CallFrame *framePtr; 03726 Tcl_Obj *part1Ptr, *localNamePtr; 03727 03728 if (TclGetFrame(interp, frameName, &framePtr) == -1) { 03729 return TCL_ERROR; 03730 } 03731 03732 part1Ptr = Tcl_NewStringObj(part1, -1); 03733 Tcl_IncrRefCount(part1Ptr); 03734 localNamePtr = Tcl_NewStringObj(localName, -1); 03735 Tcl_IncrRefCount(localNamePtr); 03736 03737 result = ObjMakeUpvar(interp, framePtr, part1Ptr, part2, 0, 03738 localNamePtr, flags, -1); 03739 Tcl_DecrRefCount(part1Ptr); 03740 Tcl_DecrRefCount(localNamePtr); 03741 return result; 03742 } 03743 03744 /* 03745 *---------------------------------------------------------------------- 03746 * 03747 * Tcl_GetVariableFullName -- 03748 * 03749 * Given a Tcl_Var token returned by Tcl_FindNamespaceVar, this function 03750 * appends to an object the namespace variable's full name, qualified by 03751 * a sequence of parent namespace names. 03752 * 03753 * Results: 03754 * None. 03755 * 03756 * Side effects: 03757 * The variable's fully-qualified name is appended to the string 03758 * representation of objPtr. 03759 * 03760 *---------------------------------------------------------------------- 03761 */ 03762 03763 void 03764 Tcl_GetVariableFullName( 03765 Tcl_Interp *interp, /* Interpreter containing the variable. */ 03766 Tcl_Var variable, /* Token for the variable returned by a 03767 * previous call to Tcl_FindNamespaceVar. */ 03768 Tcl_Obj *objPtr) /* Points to the object onto which the 03769 * variable's full name is appended. */ 03770 { 03771 Interp *iPtr = (Interp *) interp; 03772 register Var *varPtr = (Var *) variable; 03773 Tcl_Obj *namePtr; 03774 Namespace *nsPtr; 03775 03776 /* 03777 * Add the full name of the containing namespace (if any), followed by the 03778 * "::" separator, then the variable name. 03779 */ 03780 03781 if (varPtr) { 03782 if (!TclIsVarArrayElement(varPtr)) { 03783 nsPtr = TclGetVarNsPtr(varPtr); 03784 if (nsPtr) { 03785 Tcl_AppendToObj(objPtr, nsPtr->fullName, -1); 03786 if (nsPtr != iPtr->globalNsPtr) { 03787 Tcl_AppendToObj(objPtr, "::", 2); 03788 } 03789 } 03790 if (TclIsVarInHash(varPtr)) { 03791 if (!TclIsVarDeadHash(varPtr)) { 03792 namePtr = VarHashGetKey(varPtr); 03793 Tcl_AppendObjToObj(objPtr, namePtr); 03794 } 03795 } else if (iPtr->varFramePtr->procPtr) { 03796 int index = varPtr - iPtr->varFramePtr->compiledLocals; 03797 03798 if (index < iPtr->varFramePtr->numCompiledLocals) { 03799 namePtr = localName(iPtr->varFramePtr, index); 03800 Tcl_AppendObjToObj(objPtr, namePtr); 03801 } 03802 } 03803 } 03804 } 03805 } 03806 03807 /* 03808 *---------------------------------------------------------------------- 03809 * 03810 * Tcl_GlobalObjCmd -- 03811 * 03812 * This object-based function is invoked to process the "global" Tcl 03813 * command. See the user documentation for details on what it does. 03814 * 03815 * Results: 03816 * A standard Tcl object result value. 03817 * 03818 * Side effects: 03819 * See the user documentation. 03820 * 03821 *---------------------------------------------------------------------- 03822 */ 03823 03824 int 03825 Tcl_GlobalObjCmd( 03826 ClientData dummy, /* Not used. */ 03827 Tcl_Interp *interp, /* Current interpreter. */ 03828 int objc, /* Number of arguments. */ 03829 Tcl_Obj *const objv[]) /* Argument objects. */ 03830 { 03831 Interp *iPtr = (Interp *) interp; 03832 register Tcl_Obj *objPtr, *tailPtr; 03833 char *varName; 03834 register char *tail; 03835 int result, i; 03836 03837 if (objc < 2) { 03838 Tcl_WrongNumArgs(interp, 1, objv, "varName ?varName ...?"); 03839 return TCL_ERROR; 03840 } 03841 03842 /* 03843 * If we are not executing inside a Tcl procedure, just return. 03844 */ 03845 03846 if (!HasLocalVars(iPtr->varFramePtr)) { 03847 return TCL_OK; 03848 } 03849 03850 for (i=1 ; i<objc ; i++) { 03851 /* 03852 * Make a local variable linked to its counterpart in the global :: 03853 * namespace. 03854 */ 03855 03856 objPtr = objv[i]; 03857 varName = TclGetString(objPtr); 03858 03859 /* 03860 * The variable name might have a scope qualifier, but the name for 03861 * the local "link" variable must be the simple name at the tail. 03862 */ 03863 03864 for (tail=varName ; *tail!='\0' ; tail++) { 03865 /* empty body */ 03866 } 03867 while ((tail > varName) && ((*tail != ':') || (*(tail-1) != ':'))) { 03868 tail--; 03869 } 03870 if ((*tail == ':') && (tail > varName)) { 03871 tail++; 03872 } 03873 03874 if (tail == varName) { 03875 tailPtr = objPtr; 03876 } else { 03877 tailPtr = Tcl_NewStringObj(tail, -1); 03878 Tcl_IncrRefCount(tailPtr); 03879 } 03880 03881 /* 03882 * Link to the variable "varName" in the global :: namespace. 03883 */ 03884 03885 result = ObjMakeUpvar(interp, NULL, objPtr, NULL, 03886 TCL_GLOBAL_ONLY, /*myName*/ tailPtr, /*myFlags*/ 0, -1); 03887 03888 if (tail != varName) { 03889 Tcl_DecrRefCount(tailPtr); 03890 } 03891 03892 if (result != TCL_OK) { 03893 return result; 03894 } 03895 } 03896 return TCL_OK; 03897 } 03898 03899 /* 03900 *---------------------------------------------------------------------- 03901 * 03902 * Tcl_VariableObjCmd -- 03903 * 03904 * Invoked to implement the "variable" command that creates one or more 03905 * global variables. Handles the following syntax: 03906 * 03907 * variable ?name value...? name ?value? 03908 * 03909 * One or more variables can be created. The variables are initialized 03910 * with the specified values. The value for the last variable is 03911 * optional. 03912 * 03913 * If the variable does not exist, it is created and given the optional 03914 * value. If it already exists, it is simply set to the optional value. 03915 * Normally, "name" is an unqualified name, so it is created in the 03916 * current namespace. If it includes namespace qualifiers, it can be 03917 * created in another namespace. 03918 * 03919 * If the variable command is executed inside a Tcl procedure, it creates 03920 * a local variable linked to the newly-created namespace variable. 03921 * 03922 * Results: 03923 * Returns TCL_OK if the variable is found or created. Returns TCL_ERROR 03924 * if anything goes wrong. 03925 * 03926 * Side effects: 03927 * If anything goes wrong, this function returns an error message as the 03928 * result in the interpreter's result object. 03929 * 03930 *---------------------------------------------------------------------- 03931 */ 03932 03933 int 03934 Tcl_VariableObjCmd( 03935 ClientData dummy, /* Not used. */ 03936 Tcl_Interp *interp, /* Current interpreter. */ 03937 int objc, /* Number of arguments. */ 03938 Tcl_Obj *const objv[]) /* Argument objects. */ 03939 { 03940 Interp *iPtr = (Interp *) interp; 03941 char *varName, *tail, *cp; 03942 Var *varPtr, *arrayPtr; 03943 Tcl_Obj *varValuePtr; 03944 int i, result; 03945 Tcl_Obj *varNamePtr, *tailPtr; 03946 03947 if (objc < 2) { 03948 Tcl_WrongNumArgs(interp, 1, objv, "?name value...? name ?value?"); 03949 return TCL_ERROR; 03950 } 03951 03952 for (i=1 ; i<objc ; i+=2) { 03953 /* 03954 * Look up each variable in the current namespace context, creating it 03955 * if necessary. 03956 */ 03957 03958 varNamePtr = objv[i]; 03959 varName = TclGetString(varNamePtr); 03960 varPtr = TclObjLookupVarEx(interp, varNamePtr, NULL, 03961 (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "define", 03962 /*createPart1*/ 1, /*createPart2*/ 0, &arrayPtr); 03963 03964 if (arrayPtr != NULL) { 03965 /* 03966 * Variable cannot be an element in an array. If arrayPtr is 03967 * non-NULL, it is, so throw up an error and return. 03968 */ 03969 03970 TclObjVarErrMsg(interp, varNamePtr, NULL, "define", 03971 isArrayElement, -1); 03972 return TCL_ERROR; 03973 } 03974 03975 if (varPtr == NULL) { 03976 return TCL_ERROR; 03977 } 03978 03979 /* 03980 * Mark the variable as a namespace variable and increment its 03981 * reference count so that it will persist until its namespace is 03982 * destroyed or until the variable is unset. 03983 */ 03984 03985 TclSetVarNamespaceVar(varPtr); 03986 03987 /* 03988 * If a value was specified, set the variable to that value. 03989 * Otherwise, if the variable is new, leave it undefined. (If the 03990 * variable already exists and no value was specified, leave its value 03991 * unchanged; just create the local link if we're in a Tcl procedure). 03992 */ 03993 03994 if (i+1 < objc) { /* A value was specified. */ 03995 varValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, varNamePtr, 03996 NULL, objv[i+1], TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG,-1); 03997 if (varValuePtr == NULL) { 03998 return TCL_ERROR; 03999 } 04000 } 04001 04002 /* 04003 * If we are executing inside a Tcl procedure, create a local variable 04004 * linked to the new namespace variable "varName". 04005 */ 04006 04007 if (HasLocalVars(iPtr->varFramePtr)) { 04008 /* 04009 * varName might have a scope qualifier, but the name for the 04010 * local "link" variable must be the simple name at the tail. 04011 * 04012 * Locate tail in one pass: drop any prefix after two *or more* 04013 * consecutive ":" characters). 04014 */ 04015 04016 for (tail=cp=varName ; *cp!='\0' ;) { 04017 if (*cp++ == ':') { 04018 while (*cp == ':') { 04019 tail = ++cp; 04020 } 04021 } 04022 } 04023 04024 /* 04025 * Create a local link "tail" to the variable "varName" in the 04026 * current namespace. 04027 */ 04028 04029 if (tail == varName) { 04030 tailPtr = varNamePtr; 04031 } else { 04032 tailPtr = Tcl_NewStringObj(tail, -1); 04033 Tcl_IncrRefCount(tailPtr); 04034 } 04035 04036 result = ObjMakeUpvar(interp, NULL, varNamePtr, /*otherP2*/ NULL, 04037 /*otherFlags*/ TCL_NAMESPACE_ONLY, 04038 /*myName*/ tailPtr, /*myFlags*/ 0, -1); 04039 04040 if (tail != varName) { 04041 Tcl_DecrRefCount(tailPtr); 04042 } 04043 04044 if (result != TCL_OK) { 04045 return result; 04046 } 04047 } 04048 } 04049 return TCL_OK; 04050 } 04051 04052 /* 04053 *---------------------------------------------------------------------- 04054 * 04055 * Tcl_UpvarObjCmd -- 04056 * 04057 * This object-based function is invoked to process the "upvar" Tcl 04058 * command. See the user documentation for details on what it does. 04059 * 04060 * Results: 04061 * A standard Tcl object result value. 04062 * 04063 * Side effects: 04064 * See the user documentation. 04065 * 04066 *---------------------------------------------------------------------- 04067 */ 04068 04069 /* ARGSUSED */ 04070 int 04071 Tcl_UpvarObjCmd( 04072 ClientData dummy, /* Not used. */ 04073 Tcl_Interp *interp, /* Current interpreter. */ 04074 int objc, /* Number of arguments. */ 04075 Tcl_Obj *const objv[]) /* Argument objects. */ 04076 { 04077 CallFrame *framePtr; 04078 int result; 04079 04080 if (objc < 3) { 04081 upvarSyntax: 04082 Tcl_WrongNumArgs(interp, 1, objv, 04083 "?level? otherVar localVar ?otherVar localVar ...?"); 04084 return TCL_ERROR; 04085 } 04086 04087 /* 04088 * Find the call frame containing each of the "other variables" to be 04089 * linked to. 04090 */ 04091 04092 result = TclObjGetFrame(interp, objv[1], &framePtr); 04093 if (result == -1) { 04094 return TCL_ERROR; 04095 } 04096 objc -= result+1; 04097 if ((objc & 1) != 0) { 04098 goto upvarSyntax; 04099 } 04100 objv += result+1; 04101 04102 /* 04103 * Iterate over each (other variable, local variable) pair. Divide the 04104 * other variable name into two parts, then call MakeUpvar to do all the 04105 * work of linking it to the local variable. 04106 */ 04107 04108 for (; objc>0 ; objc-=2, objv+=2) { 04109 result = ObjMakeUpvar(interp, framePtr, /* othervarName */ objv[0], 04110 NULL, 0, /* myVarName */ objv[1], /*flags*/ 0, -1); 04111 if (result != TCL_OK) { 04112 return TCL_ERROR; 04113 } 04114 } 04115 return TCL_OK; 04116 } 04117 04118 /* 04119 *---------------------------------------------------------------------- 04120 * 04121 * SetArraySearchObj -- 04122 * 04123 * This function converts the given tcl object into one that has the 04124 * "array search" internal type. 04125 * 04126 * Results: 04127 * TCL_OK if the conversion succeeded, and TCL_ERROR if it failed (when 04128 * an error message will be placed in the interpreter's result.) 04129 * 04130 * Side effects: 04131 * Updates the internal type and representation of the object to make 04132 * this an array-search object. See the tclArraySearchType declaration 04133 * above for details of the internal representation. 04134 * 04135 *---------------------------------------------------------------------- 04136 */ 04137 04138 static int 04139 SetArraySearchObj( 04140 Tcl_Interp *interp, 04141 Tcl_Obj *objPtr) 04142 { 04143 char *string; 04144 char *end; 04145 int id; 04146 size_t offset; 04147 04148 /* 04149 * Get the string representation. Make it up-to-date if necessary. 04150 */ 04151 04152 string = TclGetString(objPtr); 04153 04154 /* 04155 * Parse the id into the three parts separated by dashes. 04156 */ 04157 04158 if ((string[0] != 's') || (string[1] != '-')) { 04159 goto syntax; 04160 } 04161 id = strtoul(string+2, &end, 10); 04162 if ((end == (string+2)) || (*end != '-')) { 04163 goto syntax; 04164 } 04165 04166 /* 04167 * Can't perform value check in this context, so place reference to place 04168 * in string to use for the check in the object instead. 04169 */ 04170 04171 end++; 04172 offset = end - string; 04173 04174 TclFreeIntRep(objPtr); 04175 objPtr->typePtr = &tclArraySearchType; 04176 objPtr->internalRep.twoPtrValue.ptr1 = INT2PTR(id); 04177 objPtr->internalRep.twoPtrValue.ptr2 = INT2PTR(offset); 04178 return TCL_OK; 04179 04180 syntax: 04181 Tcl_AppendResult(interp, "illegal search identifier \"",string,"\"",NULL); 04182 return TCL_ERROR; 04183 } 04184 04185 /* 04186 *---------------------------------------------------------------------- 04187 * 04188 * ParseSearchId -- 04189 * 04190 * This function translates from a tcl object to a pointer to an active 04191 * array search (if there is one that matches the string). 04192 * 04193 * Results: 04194 * The return value is a pointer to the array search indicated by string, 04195 * or NULL if there isn't one. If NULL is returned, the interp's result 04196 * contains an error message. 04197 * 04198 * Side effects: 04199 * The tcl object might have its internal type and representation 04200 * modified. 04201 * 04202 *---------------------------------------------------------------------- 04203 */ 04204 04205 static ArraySearch * 04206 ParseSearchId( 04207 Tcl_Interp *interp, /* Interpreter containing variable. */ 04208 const Var *varPtr, /* Array variable search is for. */ 04209 Tcl_Obj *varNamePtr, /* Name of array variable that search is 04210 * supposed to be for. */ 04211 Tcl_Obj *handleObj) /* Object containing id of search. Must have 04212 * form "search-num-var" where "num" is a 04213 * decimal number and "var" is a variable 04214 * name. */ 04215 { 04216 Interp *iPtr = (Interp *) interp; 04217 register char *string; 04218 register size_t offset; 04219 int id; 04220 ArraySearch *searchPtr; 04221 char *varName = TclGetString(varNamePtr); 04222 04223 /* 04224 * Parse the id. 04225 */ 04226 04227 if (Tcl_ConvertToType(interp, handleObj, &tclArraySearchType) != TCL_OK) { 04228 return NULL; 04229 } 04230 04231 /* 04232 * Extract the information out of the Tcl_Obj. 04233 */ 04234 04235 #if 1 04236 id = PTR2INT(handleObj->internalRep.twoPtrValue.ptr1); 04237 string = TclGetString(handleObj); 04238 offset = PTR2INT(handleObj->internalRep.twoPtrValue.ptr2); 04239 #else 04240 id = (int)(((char *) handleObj->internalRep.twoPtrValue.ptr1) - 04241 ((char *) NULL)); 04242 string = TclGetString(handleObj); 04243 offset = (((char *) handleObj->internalRep.twoPtrValue.ptr2) - 04244 ((char *) NULL)); 04245 #endif 04246 04247 /* 04248 * This test cannot be placed inside the Tcl_Obj machinery, since it is 04249 * dependent on the variable context. 04250 */ 04251 04252 if (strcmp(string+offset, varName) != 0) { 04253 Tcl_AppendResult(interp, "search identifier \"", string, 04254 "\" isn't for variable \"", varName, "\"", NULL); 04255 goto badLookup; 04256 } 04257 04258 /* 04259 * Search through the list of active searches on the interpreter to see if 04260 * the desired one exists. 04261 * 04262 * Note that we cannot store the searchPtr directly in the Tcl_Obj as that 04263 * would run into trouble when DeleteSearches() was called so we must scan 04264 * this list every time. 04265 */ 04266 04267 if (varPtr->flags & VAR_SEARCH_ACTIVE) { 04268 Tcl_HashEntry *hPtr = 04269 Tcl_FindHashEntry(&iPtr->varSearches, (char *) varPtr); 04270 04271 for (searchPtr = (ArraySearch *) Tcl_GetHashValue(hPtr); 04272 searchPtr != NULL; searchPtr = searchPtr->nextPtr) { 04273 if (searchPtr->id == id) { 04274 return searchPtr; 04275 } 04276 } 04277 } 04278 Tcl_AppendResult(interp, "couldn't find search \"", string, "\"", NULL); 04279 badLookup: 04280 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAYSEARCH", string, NULL); 04281 return NULL; 04282 } 04283 04284 /* 04285 *---------------------------------------------------------------------- 04286 * 04287 * DeleteSearches -- 04288 * 04289 * This function is called to free up all of the searches associated 04290 * with an array variable. 04291 * 04292 * Results: 04293 * None. 04294 * 04295 * Side effects: 04296 * Memory is released to the storage allocator. 04297 * 04298 *---------------------------------------------------------------------- 04299 */ 04300 04301 static void 04302 DeleteSearches( 04303 Interp *iPtr, 04304 register Var *arrayVarPtr) /* Variable whose searches are to be 04305 * deleted. */ 04306 { 04307 ArraySearch *searchPtr, *nextPtr; 04308 Tcl_HashEntry *sPtr; 04309 04310 if (arrayVarPtr->flags & VAR_SEARCH_ACTIVE) { 04311 sPtr = Tcl_FindHashEntry(&iPtr->varSearches, (char *) arrayVarPtr); 04312 for (searchPtr = (ArraySearch *) Tcl_GetHashValue(sPtr); 04313 searchPtr != NULL; searchPtr = nextPtr) { 04314 nextPtr = searchPtr->nextPtr; 04315 ckfree((char *) searchPtr); 04316 } 04317 arrayVarPtr->flags &= ~VAR_SEARCH_ACTIVE; 04318 Tcl_DeleteHashEntry(sPtr); 04319 } 04320 } 04321 04322 /* 04323 *---------------------------------------------------------------------- 04324 * 04325 * TclDeleteNamespaceVars -- 04326 * 04327 * This function is called to recycle all the storage space associated 04328 * with a namespace's table of variables. 04329 * 04330 * Results: 04331 * None. 04332 * 04333 * Side effects: 04334 * Variables are deleted and trace functions are invoked, if any are 04335 * declared. 04336 * 04337 *---------------------------------------------------------------------- 04338 */ 04339 04340 void 04341 TclDeleteNamespaceVars( 04342 Namespace *nsPtr) 04343 { 04344 TclVarHashTable *tablePtr = &nsPtr->varTable; 04345 Tcl_Interp *interp = nsPtr->interp; 04346 Interp *iPtr = (Interp *)interp; 04347 Tcl_HashSearch search; 04348 int flags = 0; 04349 Var *varPtr; 04350 04351 /* 04352 * Determine what flags to pass to the trace callback functions. 04353 */ 04354 04355 if (nsPtr == iPtr->globalNsPtr) { 04356 flags = TCL_GLOBAL_ONLY; 04357 } else if (nsPtr == (Namespace *) TclGetCurrentNamespace(interp)) { 04358 flags = TCL_NAMESPACE_ONLY; 04359 } 04360 04361 for (varPtr = VarHashFirstVar(tablePtr, &search); varPtr != NULL; 04362 varPtr = VarHashFirstVar(tablePtr, &search)) { 04363 VarHashRefCount(varPtr)++; /* Make sure we get to remove from 04364 * hash. */ 04365 UnsetVarStruct(varPtr, NULL, iPtr, /* part1 */ VarHashGetKey(varPtr), 04366 NULL, flags); 04367 04368 /* 04369 * Remove the variable from the table and force it undefined in case 04370 * an unset trace brought it back from the dead. 04371 */ 04372 04373 if (TclIsVarTraced(varPtr)) { 04374 Tcl_HashEntry *tPtr = Tcl_FindHashEntry(&iPtr->varTraces, 04375 (char *) varPtr); 04376 VarTrace *tracePtr = (VarTrace *) Tcl_GetHashValue(tPtr); 04377 04378 while (tracePtr) { 04379 VarTrace *prevPtr = tracePtr; 04380 04381 tracePtr = tracePtr->nextPtr; 04382 Tcl_EventuallyFree((ClientData) prevPtr, TCL_DYNAMIC); 04383 } 04384 Tcl_DeleteHashEntry(tPtr); 04385 varPtr->flags &= ~VAR_ALL_TRACES; 04386 } 04387 VarHashRefCount(varPtr)--; 04388 VarHashDeleteEntry(varPtr); 04389 } 04390 VarHashDeleteTable(tablePtr); 04391 } 04392 04393 /* 04394 *---------------------------------------------------------------------- 04395 * 04396 * TclDeleteVars -- 04397 * 04398 * This function is called to recycle all the storage space associated 04399 * with a table of variables. For this function to work correctly, it 04400 * must not be possible for any of the variables in the table to be 04401 * accessed from Tcl commands (e.g. from trace functions). 04402 * 04403 * Results: 04404 * None. 04405 * 04406 * Side effects: 04407 * Variables are deleted and trace functions are invoked, if any are 04408 * declared. 04409 * 04410 *---------------------------------------------------------------------- 04411 */ 04412 04413 void 04414 TclDeleteVars( 04415 Interp *iPtr, /* Interpreter to which variables belong. */ 04416 TclVarHashTable *tablePtr) /* Hash table containing variables to 04417 * delete. */ 04418 { 04419 Tcl_Interp *interp = (Tcl_Interp *) iPtr; 04420 Tcl_HashSearch search; 04421 register Var *varPtr; 04422 int flags; 04423 Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp); 04424 04425 /* 04426 * Determine what flags to pass to the trace callback functions. 04427 */ 04428 04429 flags = TCL_TRACE_UNSETS; 04430 if (tablePtr == &iPtr->globalNsPtr->varTable) { 04431 flags |= TCL_GLOBAL_ONLY; 04432 } else if (tablePtr == &currNsPtr->varTable) { 04433 flags |= TCL_NAMESPACE_ONLY; 04434 } 04435 04436 for (varPtr = VarHashFirstVar(tablePtr, &search); varPtr != NULL; 04437 varPtr = VarHashNextVar(&search)) { 04438 /* 04439 * Lie about the validity of the hashtable entry. In this way the 04440 * variables will be deleted by VarHashDeleteTable. 04441 */ 04442 04443 VarHashInvalidateEntry(varPtr); 04444 UnsetVarStruct(varPtr, NULL, iPtr, VarHashGetKey(varPtr), NULL, flags); 04445 } 04446 VarHashDeleteTable(tablePtr); 04447 } 04448 04449 /* 04450 *---------------------------------------------------------------------- 04451 * 04452 * TclDeleteCompiledLocalVars -- 04453 * 04454 * This function is called to recycle storage space associated with the 04455 * compiler-allocated array of local variables in a procedure call frame. 04456 * This function resembles TclDeleteVars above except that each variable 04457 * is stored in a call frame and not a hash table. For this function to 04458 * work correctly, it must not be possible for any of the variable in the 04459 * table to be accessed from Tcl commands (e.g. from trace functions). 04460 * 04461 * Results: 04462 * None. 04463 * 04464 * Side effects: 04465 * Variables are deleted and trace functions are invoked, if any are 04466 * declared. 04467 * 04468 *---------------------------------------------------------------------- 04469 */ 04470 04471 void 04472 TclDeleteCompiledLocalVars( 04473 Interp *iPtr, /* Interpreter to which variables belong. */ 04474 CallFrame *framePtr) /* Procedure call frame containing compiler- 04475 * assigned local variables to delete. */ 04476 { 04477 register Var *varPtr; 04478 int numLocals, i; 04479 Tcl_Obj **namePtrPtr; 04480 04481 numLocals = framePtr->numCompiledLocals; 04482 varPtr = framePtr->compiledLocals; 04483 namePtrPtr = &localName(framePtr, 0); 04484 for (i=0 ; i<numLocals ; i++, namePtrPtr++, varPtr++) { 04485 UnsetVarStruct(varPtr, NULL, iPtr, *namePtrPtr, NULL, 04486 TCL_TRACE_UNSETS); 04487 } 04488 } 04489 04490 /* 04491 *---------------------------------------------------------------------- 04492 * 04493 * DeleteArray -- 04494 * 04495 * This function is called to free up everything in an array variable. 04496 * It's the caller's responsibility to make sure that the array is no 04497 * longer accessible before this function is called. 04498 * 04499 * Results: 04500 * None. 04501 * 04502 * Side effects: 04503 * All storage associated with varPtr's array elements is deleted 04504 * (including the array's hash table). Deletion trace functions for 04505 * array elements are invoked, then deleted. Any pending traces for array 04506 * elements are also deleted. 04507 * 04508 *---------------------------------------------------------------------- 04509 */ 04510 04511 static void 04512 DeleteArray( 04513 Interp *iPtr, /* Interpreter containing array. */ 04514 Tcl_Obj *arrayNamePtr, /* Name of array (used for trace callbacks), 04515 * or NULL if it is to be computed on 04516 * demand. */ 04517 Var *varPtr, /* Pointer to variable structure. */ 04518 int flags) /* Flags to pass to TclCallVarTraces: 04519 * TCL_TRACE_UNSETS and sometimes 04520 * TCL_NAMESPACE_ONLY or TCL_GLOBAL_ONLY. */ 04521 { 04522 Tcl_HashSearch search; 04523 Tcl_HashEntry *tPtr; 04524 register Var *elPtr; 04525 ActiveVarTrace *activePtr; 04526 Tcl_Obj *objPtr; 04527 VarTrace *tracePtr; 04528 04529 if (varPtr->flags & VAR_SEARCH_ACTIVE) { 04530 DeleteSearches(iPtr, varPtr); 04531 } 04532 for (elPtr = VarHashFirstVar(varPtr->value.tablePtr, &search); 04533 elPtr != NULL; elPtr = VarHashNextVar(&search)) { 04534 if (TclIsVarScalar(elPtr) && (elPtr->value.objPtr != NULL)) { 04535 objPtr = elPtr->value.objPtr; 04536 TclDecrRefCount(objPtr); 04537 elPtr->value.objPtr = NULL; 04538 } 04539 04540 /* 04541 * Lie about the validity of the hashtable entry. In this way the 04542 * variables will be deleted by VarHashDeleteTable. 04543 */ 04544 04545 VarHashInvalidateEntry(elPtr); 04546 if (TclIsVarTraced(elPtr)) { 04547 /* 04548 * Compute the array name if it was not supplied. 04549 */ 04550 04551 if (elPtr->flags & VAR_TRACED_UNSET) { 04552 Tcl_Obj *elNamePtr = VarHashGetKey(elPtr); 04553 04554 elPtr->flags &= ~VAR_TRACE_ACTIVE; 04555 TclObjCallVarTraces(iPtr, NULL, elPtr, arrayNamePtr, 04556 elNamePtr, flags,/* leaveErrMsg */ 0, -1); 04557 } 04558 tPtr = Tcl_FindHashEntry(&iPtr->varTraces, (char *) elPtr); 04559 tracePtr = (VarTrace *) Tcl_GetHashValue(tPtr); 04560 while (tracePtr) { 04561 VarTrace *prevPtr = tracePtr; 04562 04563 tracePtr = tracePtr->nextPtr; 04564 Tcl_EventuallyFree((ClientData) prevPtr, TCL_DYNAMIC); 04565 } 04566 Tcl_DeleteHashEntry(tPtr); 04567 elPtr->flags &= ~VAR_ALL_TRACES; 04568 for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; 04569 activePtr = activePtr->nextPtr) { 04570 if (activePtr->varPtr == elPtr) { 04571 activePtr->nextTracePtr = NULL; 04572 } 04573 } 04574 } 04575 TclSetVarUndefined(elPtr); 04576 04577 /* 04578 * Even though array elements are not supposed to be namespace 04579 * variables, some combinations of [upvar] and [variable] may create 04580 * such beasts - see [Bug 604239]. This is necessary to avoid leaking 04581 * the corresponding Var struct, and is otherwise harmless. 04582 */ 04583 04584 TclClearVarNamespaceVar(elPtr); 04585 } 04586 VarHashDeleteTable(varPtr->value.tablePtr); 04587 ckfree((char *) varPtr->value.tablePtr); 04588 } 04589 04590 /* 04591 *---------------------------------------------------------------------- 04592 * 04593 * TclTclObjVarErrMsg -- 04594 * 04595 * Generate a reasonable error message describing why a variable 04596 * operation failed. 04597 * 04598 * Results: 04599 * None. 04600 * 04601 * Side effects: 04602 * The interp's result is set to hold a message identifying the variable 04603 * given by part1 and part2 and describing why the variable operation 04604 * failed. 04605 * 04606 *---------------------------------------------------------------------- 04607 */ 04608 04609 void 04610 TclVarErrMsg( 04611 Tcl_Interp *interp, /* Interpreter in which to record message. */ 04612 const char *part1, 04613 const char *part2, /* Variable's two-part name. */ 04614 const char *operation, /* String describing operation that failed, 04615 * e.g. "read", "set", or "unset". */ 04616 const char *reason) /* String describing why operation failed. */ 04617 { 04618 Tcl_Obj *part1Ptr = NULL, *part2Ptr = NULL; 04619 04620 part1Ptr = Tcl_NewStringObj(part1, -1); 04621 Tcl_IncrRefCount(part1Ptr); 04622 if (part2) { 04623 part2Ptr = Tcl_NewStringObj(part2, -1); 04624 Tcl_IncrRefCount(part2Ptr); 04625 } else { 04626 part2 = NULL; 04627 } 04628 04629 TclObjVarErrMsg(interp, part1Ptr, part2Ptr, operation, reason, -1); 04630 04631 Tcl_DecrRefCount(part1Ptr); 04632 if (part2Ptr) { 04633 Tcl_DecrRefCount(part2Ptr); 04634 } 04635 } 04636 04637 void 04638 TclObjVarErrMsg( 04639 Tcl_Interp *interp, /* Interpreter in which to record message. */ 04640 Tcl_Obj *part1Ptr, /* (may be NULL, if index >= 0) */ 04641 Tcl_Obj *part2Ptr, /* Variable's two-part name. */ 04642 const char *operation, /* String describing operation that failed, 04643 * e.g. "read", "set", or "unset". */ 04644 const char *reason, /* String describing why operation failed. */ 04645 int index) /* Index into the local variable table of the 04646 * variable, or -1. Only used when part1Ptr is 04647 * NULL. */ 04648 { 04649 Tcl_ResetResult(interp); 04650 if (!part1Ptr) { 04651 part1Ptr = localName(((Interp *)interp)->varFramePtr, index); 04652 } 04653 Tcl_AppendResult(interp, "can't ", operation, " \"", 04654 TclGetString(part1Ptr), NULL); 04655 if (part2Ptr) { 04656 Tcl_AppendResult(interp, "(", TclGetString(part2Ptr), ")", NULL); 04657 } 04658 Tcl_AppendResult(interp, "\": ", reason, NULL); 04659 } 04660 04661 /* 04662 *---------------------------------------------------------------------- 04663 * 04664 * Internal functions for variable name object types -- 04665 * 04666 *---------------------------------------------------------------------- 04667 */ 04668 04669 /* 04670 * Panic functions that should never be called in normal operation. 04671 */ 04672 04673 static void 04674 PanicOnUpdateVarName( 04675 Tcl_Obj *objPtr) 04676 { 04677 Tcl_Panic("%s of type %s should not be called", "updateStringProc", 04678 objPtr->typePtr->name); 04679 } 04680 04681 static int 04682 PanicOnSetVarName( 04683 Tcl_Interp *interp, 04684 Tcl_Obj *objPtr) 04685 { 04686 Tcl_Panic("%s of type %s should not be called", "setFromAnyProc", 04687 objPtr->typePtr->name); 04688 return TCL_ERROR; 04689 } 04690 04691 /* 04692 * localVarName - 04693 * 04694 * INTERNALREP DEFINITION: 04695 * ptrAndLongRep.ptr: pointer to name obj in varFramePtr->localCache 04696 * or NULL if it is this same obj 04697 * ptrAndLongRep.value: index into locals table 04698 */ 04699 04700 static void 04701 FreeLocalVarName( 04702 Tcl_Obj *objPtr) 04703 { 04704 Tcl_Obj *namePtr = (Tcl_Obj *) objPtr->internalRep.ptrAndLongRep.ptr; 04705 if (namePtr) { 04706 Tcl_DecrRefCount(namePtr); 04707 } 04708 } 04709 04710 static void 04711 DupLocalVarName( 04712 Tcl_Obj *srcPtr, 04713 Tcl_Obj *dupPtr) 04714 { 04715 Tcl_Obj *namePtr = srcPtr->internalRep.ptrAndLongRep.ptr; 04716 04717 if (!namePtr) { 04718 namePtr = srcPtr; 04719 } 04720 dupPtr->internalRep.ptrAndLongRep.ptr = namePtr; 04721 Tcl_IncrRefCount(namePtr); 04722 04723 dupPtr->internalRep.ptrAndLongRep.value = 04724 srcPtr->internalRep.ptrAndLongRep.value; 04725 dupPtr->typePtr = &localVarNameType; 04726 } 04727 04728 #if ENABLE_NS_VARNAME_CACHING 04729 /* 04730 * nsVarName - 04731 * 04732 * INTERNALREP DEFINITION: 04733 * twoPtrValue.ptr1: pointer to the namespace containing the reference. 04734 * twoPtrValue.ptr2: pointer to the corresponding Var 04735 */ 04736 04737 static void 04738 FreeNsVarName( 04739 Tcl_Obj *objPtr) 04740 { 04741 register Var *varPtr = objPtr->internalRep.twoPtrValue.ptr2; 04742 04743 if (TclIsVarInHash(varPtr)) { 04744 varPtr->refCount--; 04745 if (TclIsVarUndefined(varPtr) && (varPtr->refCount == 0)) { 04746 CleanupVar(varPtr, NULL); 04747 } 04748 } 04749 } 04750 04751 static void 04752 DupNsVarName( 04753 Tcl_Obj *srcPtr, 04754 Tcl_Obj *dupPtr) 04755 { 04756 Namespace *nsPtr = srcPtr->internalRep.twoPtrValue.ptr1; 04757 register Var *varPtr = srcPtr->internalRep.twoPtrValue.ptr2; 04758 04759 dupPtr->internalRep.twoPtrValue.ptr1 = nsPtr; 04760 dupPtr->internalRep.twoPtrValue.ptr2 = varPtr; 04761 if (TclIsVarInHash(varPtr)) { 04762 varPtr->refCount++; 04763 } 04764 dupPtr->typePtr = &tclNsVarNameType; 04765 } 04766 #endif 04767 04768 /* 04769 * parsedVarName - 04770 * 04771 * INTERNALREP DEFINITION: 04772 * twoPtrValue.ptr1 = pointer to the array name Tcl_Obj (NULL if scalar) 04773 * twoPtrValue.ptr2 = pointer to the element name string (owned by this 04774 * Tcl_Obj), or NULL if it is a scalar variable 04775 */ 04776 04777 static void 04778 FreeParsedVarName( 04779 Tcl_Obj *objPtr) 04780 { 04781 register Tcl_Obj *arrayPtr = objPtr->internalRep.twoPtrValue.ptr1; 04782 register char *elem = objPtr->internalRep.twoPtrValue.ptr2; 04783 04784 if (arrayPtr != NULL) { 04785 TclDecrRefCount(arrayPtr); 04786 ckfree(elem); 04787 } 04788 } 04789 04790 static void 04791 DupParsedVarName( 04792 Tcl_Obj *srcPtr, 04793 Tcl_Obj *dupPtr) 04794 { 04795 register Tcl_Obj *arrayPtr = srcPtr->internalRep.twoPtrValue.ptr1; 04796 register char *elem = srcPtr->internalRep.twoPtrValue.ptr2; 04797 char *elemCopy; 04798 unsigned int elemLen; 04799 04800 if (arrayPtr != NULL) { 04801 Tcl_IncrRefCount(arrayPtr); 04802 elemLen = strlen(elem); 04803 elemCopy = ckalloc(elemLen+1); 04804 memcpy(elemCopy, elem, elemLen); 04805 *(elemCopy + elemLen) = '\0'; 04806 elem = elemCopy; 04807 } 04808 04809 dupPtr->internalRep.twoPtrValue.ptr1 = arrayPtr; 04810 dupPtr->internalRep.twoPtrValue.ptr2 = elem; 04811 dupPtr->typePtr = &tclParsedVarNameType; 04812 } 04813 04814 static void 04815 UpdateParsedVarName( 04816 Tcl_Obj *objPtr) 04817 { 04818 Tcl_Obj *arrayPtr = objPtr->internalRep.twoPtrValue.ptr1; 04819 char *part2 = objPtr->internalRep.twoPtrValue.ptr2; 04820 char *part1, *p; 04821 int len1, len2, totalLen; 04822 04823 if (arrayPtr == NULL) { 04824 /* 04825 * This is a parsed scalar name: what is it doing here? 04826 */ 04827 04828 Tcl_Panic("scalar parsedVarName without a string rep"); 04829 } 04830 04831 part1 = TclGetStringFromObj(arrayPtr, &len1); 04832 len2 = strlen(part2); 04833 04834 totalLen = len1 + len2 + 2; 04835 p = ckalloc((unsigned int) totalLen + 1); 04836 objPtr->bytes = p; 04837 objPtr->length = totalLen; 04838 04839 memcpy(p, part1, (unsigned int) len1); 04840 p += len1; 04841 *p++ = '('; 04842 memcpy(p, part2, (unsigned int) len2); 04843 p += len2; 04844 *p++ = ')'; 04845 *p = '\0'; 04846 } 04847 04848 /* 04849 *---------------------------------------------------------------------- 04850 * 04851 * Tcl_FindNamespaceVar -- MOVED OVER from tclNamesp.c 04852 * 04853 * Searches for a namespace variable, a variable not local to a 04854 * procedure. The variable can be either a scalar or an array, but may 04855 * not be an element of an array. 04856 * 04857 * Results: 04858 * Returns a token for the variable if it is found. Otherwise, if it 04859 * can't be found or there is an error, returns NULL and leaves an error 04860 * message in the interpreter's result object if "flags" contains 04861 * TCL_LEAVE_ERR_MSG. 04862 * 04863 * Side effects: 04864 * None. 04865 * 04866 *---------------------------------------------------------------------- 04867 */ 04868 04869 Tcl_Var 04870 Tcl_FindNamespaceVar( 04871 Tcl_Interp *interp, /* The interpreter in which to find the 04872 * variable. */ 04873 const char *name, /* Variable's name. If it starts with "::", 04874 * will be looked up in global namespace. 04875 * Else, looked up first in contextNsPtr 04876 * (current namespace if contextNsPtr is 04877 * NULL), then in global namespace. */ 04878 Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag set. 04879 * Otherwise, points to namespace in which to 04880 * resolve name. If NULL, look up name in the 04881 * current namespace. */ 04882 int flags) /* An OR'd combination of: AVOID_RESOLVERS, 04883 * TCL_GLOBAL_ONLY (look up name only in 04884 * global namespace), TCL_NAMESPACE_ONLY (look 04885 * up only in contextNsPtr, or the current 04886 * namespace if contextNsPtr is NULL), and 04887 * TCL_LEAVE_ERR_MSG. If both TCL_GLOBAL_ONLY 04888 * and TCL_NAMESPACE_ONLY are given, 04889 * TCL_GLOBAL_ONLY is ignored. */ 04890 { 04891 Tcl_Obj *namePtr = Tcl_NewStringObj(name, -1); 04892 Tcl_Var var; 04893 04894 Tcl_IncrRefCount(namePtr); 04895 var = ObjFindNamespaceVar(interp, namePtr, contextNsPtr, flags); 04896 Tcl_DecrRefCount(namePtr); 04897 return var; 04898 } 04899 04900 static Tcl_Var 04901 ObjFindNamespaceVar( 04902 Tcl_Interp *interp, /* The interpreter in which to find the 04903 * variable. */ 04904 Tcl_Obj *namePtr, /* Variable's name. If it starts with "::", 04905 * will be looked up in global namespace. 04906 * Else, looked up first in contextNsPtr 04907 * (current namespace if contextNsPtr is 04908 * NULL), then in global namespace. */ 04909 Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag set. 04910 * Otherwise, points to namespace in which to 04911 * resolve name. If NULL, look up name in the 04912 * current namespace. */ 04913 int flags) /* An OR'd combination of: AVOID_RESOLVERS, 04914 * TCL_GLOBAL_ONLY (look up name only in 04915 * global namespace), TCL_NAMESPACE_ONLY (look 04916 * up only in contextNsPtr, or the current 04917 * namespace if contextNsPtr is NULL), and 04918 * TCL_LEAVE_ERR_MSG. If both TCL_GLOBAL_ONLY 04919 * and TCL_NAMESPACE_ONLY are given, 04920 * TCL_GLOBAL_ONLY is ignored. */ 04921 { 04922 Interp *iPtr = (Interp *) interp; 04923 ResolverScheme *resPtr; 04924 Namespace *nsPtr[2], *cxtNsPtr; 04925 const char *simpleName; 04926 Var *varPtr; 04927 register int search; 04928 int result; 04929 Tcl_Var var; 04930 Tcl_Obj *simpleNamePtr; 04931 char *name = TclGetString(namePtr); 04932 04933 /* 04934 * If this namespace has a variable resolver, then give it first crack at 04935 * the variable resolution. It may return a Tcl_Var value, it may signal 04936 * to continue onward, or it may signal an error. 04937 */ 04938 04939 if ((flags & TCL_GLOBAL_ONLY) != 0) { 04940 cxtNsPtr = (Namespace *) TclGetGlobalNamespace(interp); 04941 } else if (contextNsPtr != NULL) { 04942 cxtNsPtr = (Namespace *) contextNsPtr; 04943 } else { 04944 cxtNsPtr = (Namespace *) TclGetCurrentNamespace(interp); 04945 } 04946 04947 if (!(flags & AVOID_RESOLVERS) && 04948 (cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL)) { 04949 resPtr = iPtr->resolverPtr; 04950 04951 if (cxtNsPtr->varResProc) { 04952 result = (*cxtNsPtr->varResProc)(interp, name, 04953 (Tcl_Namespace *) cxtNsPtr, flags, &var); 04954 } else { 04955 result = TCL_CONTINUE; 04956 } 04957 04958 while (result == TCL_CONTINUE && resPtr) { 04959 if (resPtr->varResProc) { 04960 result = (*resPtr->varResProc)(interp, name, 04961 (Tcl_Namespace *) cxtNsPtr, flags, &var); 04962 } 04963 resPtr = resPtr->nextPtr; 04964 } 04965 04966 if (result == TCL_OK) { 04967 return var; 04968 } else if (result != TCL_CONTINUE) { 04969 return (Tcl_Var) NULL; 04970 } 04971 } 04972 04973 /* 04974 * Find the namespace(s) that contain the variable. 04975 */ 04976 04977 TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr, 04978 flags, &nsPtr[0], &nsPtr[1], &cxtNsPtr, &simpleName); 04979 04980 /* 04981 * Look for the variable in the variable table of its namespace. Be sure 04982 * to check both possible search paths: from the specified namespace 04983 * context and from the global namespace. 04984 */ 04985 04986 varPtr = NULL; 04987 if (simpleName != name) { 04988 simpleNamePtr = Tcl_NewStringObj(simpleName, -1); 04989 Tcl_IncrRefCount(simpleNamePtr); 04990 } else { 04991 simpleNamePtr = namePtr; 04992 } 04993 04994 for (search = 0; (search < 2) && (varPtr == NULL); search++) { 04995 if ((nsPtr[search] != NULL) && (simpleName != NULL)) { 04996 varPtr = VarHashFindVar(&nsPtr[search]->varTable, simpleNamePtr); 04997 } 04998 } 04999 if (simpleName != name) { 05000 Tcl_DecrRefCount(simpleNamePtr); 05001 } 05002 if ((varPtr == NULL) && (flags & TCL_LEAVE_ERR_MSG)) { 05003 Tcl_ResetResult(interp); 05004 Tcl_AppendResult(interp, "unknown variable \"", name, "\"", NULL); 05005 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARIABLE", name, NULL); 05006 } 05007 return (Tcl_Var) varPtr; 05008 } 05009 05010 /* 05011 *---------------------------------------------------------------------- 05012 * 05013 * InfoVarsCmd -- (moved over from tclCmdIL.c) 05014 * 05015 * Called to implement the "info vars" command that returns the list of 05016 * variables in the interpreter that match an optional pattern. The 05017 * pattern, if any, consists of an optional sequence of namespace names 05018 * separated by "::" qualifiers, which is followed by a glob-style 05019 * pattern that restricts which variables are returned. Handles the 05020 * following syntax: 05021 * 05022 * info vars ?pattern? 05023 * 05024 * Results: 05025 * Returns TCL_OK if successful and TCL_ERROR if there is an error. 05026 * 05027 * Side effects: 05028 * Returns a result in the interpreter's result object. If there is an 05029 * error, the result is an error message. 05030 * 05031 *---------------------------------------------------------------------- 05032 */ 05033 05034 int 05035 TclInfoVarsCmd( 05036 ClientData dummy, /* Not used. */ 05037 Tcl_Interp *interp, /* Current interpreter. */ 05038 int objc, /* Number of arguments. */ 05039 Tcl_Obj *const objv[]) /* Argument objects. */ 05040 { 05041 Interp *iPtr = (Interp *) interp; 05042 char *varName, *pattern; 05043 const char *simplePattern; 05044 Tcl_HashSearch search; 05045 Var *varPtr; 05046 Namespace *nsPtr; 05047 Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); 05048 Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); 05049 Tcl_Obj *listPtr, *elemObjPtr; 05050 int specificNsInPattern = 0;/* Init. to avoid compiler warning. */ 05051 Tcl_Obj *simplePatternPtr = NULL, *varNamePtr; 05052 05053 /* 05054 * Get the pattern and find the "effective namespace" in which to list 05055 * variables. We only use this effective namespace if there's no active 05056 * Tcl procedure frame. 05057 */ 05058 05059 if (objc == 1) { 05060 simplePattern = NULL; 05061 nsPtr = currNsPtr; 05062 specificNsInPattern = 0; 05063 } else if (objc == 2) { 05064 /* 05065 * From the pattern, get the effective namespace and the simple 05066 * pattern (no namespace qualifiers or ::'s) at the end. If an error 05067 * was found while parsing the pattern, return it. Otherwise, if the 05068 * namespace wasn't found, just leave nsPtr NULL: we will return an 05069 * empty list since no variables there can be found. 05070 */ 05071 05072 Namespace *dummy1NsPtr, *dummy2NsPtr; 05073 05074 pattern = TclGetString(objv[1]); 05075 TclGetNamespaceForQualName(interp, pattern, (Namespace *) NULL, 05076 /*flags*/ 0, &nsPtr, &dummy1NsPtr, &dummy2NsPtr, 05077 &simplePattern); 05078 05079 if (nsPtr != NULL) { /* We successfully found the pattern's ns. */ 05080 specificNsInPattern = (strcmp(simplePattern, pattern) != 0); 05081 if (simplePattern == pattern) { 05082 simplePatternPtr = objv[1]; 05083 } else { 05084 simplePatternPtr = Tcl_NewStringObj(simplePattern, -1); 05085 } 05086 Tcl_IncrRefCount(simplePatternPtr); 05087 } 05088 } else { 05089 Tcl_WrongNumArgs(interp, 1, objv, "?pattern?"); 05090 return TCL_ERROR; 05091 } 05092 05093 /* 05094 * If the namespace specified in the pattern wasn't found, just return. 05095 */ 05096 05097 if (nsPtr == NULL) { 05098 return TCL_OK; 05099 } 05100 05101 listPtr = Tcl_NewListObj(0, NULL); 05102 05103 if (!(iPtr->varFramePtr->isProcCallFrame & FRAME_IS_PROC) 05104 || specificNsInPattern) { 05105 /* 05106 * There is no frame pointer, the frame pointer was pushed only to 05107 * activate a namespace, or we are in a procedure call frame but a 05108 * specific namespace was specified. Create a list containing only the 05109 * variables in the effective namespace's variable table. 05110 */ 05111 05112 if (simplePattern && TclMatchIsTrivial(simplePattern)) { 05113 /* 05114 * If we can just do hash lookups, that simplifies things a lot. 05115 */ 05116 05117 varPtr = VarHashFindVar(&nsPtr->varTable, simplePatternPtr); 05118 if (varPtr) { 05119 if (!TclIsVarUndefined(varPtr) 05120 || TclIsVarNamespaceVar(varPtr)) { 05121 if (specificNsInPattern) { 05122 elemObjPtr = Tcl_NewObj(); 05123 Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, 05124 elemObjPtr); 05125 } else { 05126 elemObjPtr = VarHashGetKey(varPtr); 05127 } 05128 Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); 05129 } 05130 } else if ((nsPtr != globalNsPtr) && !specificNsInPattern) { 05131 varPtr = VarHashFindVar(&globalNsPtr->varTable, 05132 simplePatternPtr); 05133 if (varPtr) { 05134 if (!TclIsVarUndefined(varPtr) 05135 || TclIsVarNamespaceVar(varPtr)) { 05136 Tcl_ListObjAppendElement(interp, listPtr, 05137 VarHashGetKey(varPtr)); 05138 } 05139 } 05140 } 05141 } else { 05142 /* 05143 * Have to scan the tables of variables. 05144 */ 05145 05146 varPtr = VarHashFirstVar(&nsPtr->varTable, &search); 05147 while (varPtr) { 05148 if (!TclIsVarUndefined(varPtr) 05149 || TclIsVarNamespaceVar(varPtr)) { 05150 varNamePtr = VarHashGetKey(varPtr); 05151 varName = TclGetString(varNamePtr); 05152 if ((simplePattern == NULL) 05153 || Tcl_StringMatch(varName, simplePattern)) { 05154 if (specificNsInPattern) { 05155 elemObjPtr = Tcl_NewObj(); 05156 Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, 05157 elemObjPtr); 05158 } else { 05159 elemObjPtr = varNamePtr; 05160 } 05161 Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); 05162 } 05163 } 05164 varPtr = VarHashNextVar(&search); 05165 } 05166 05167 /* 05168 * If the effective namespace isn't the global :: namespace, and a 05169 * specific namespace wasn't requested in the pattern (i.e., the 05170 * pattern only specifies variable names), then add in all global 05171 * :: variables that match the simple pattern. Of course, add in 05172 * only those variables that aren't hidden by a variable in the 05173 * effective namespace. 05174 */ 05175 05176 if ((nsPtr != globalNsPtr) && !specificNsInPattern) { 05177 varPtr = VarHashFirstVar(&globalNsPtr->varTable,&search); 05178 while (varPtr) { 05179 if (!TclIsVarUndefined(varPtr) 05180 || TclIsVarNamespaceVar(varPtr)) { 05181 varNamePtr = VarHashGetKey(varPtr); 05182 varName = TclGetString(varNamePtr); 05183 if ((simplePattern == NULL) 05184 || Tcl_StringMatch(varName, simplePattern)) { 05185 if (VarHashFindVar(&nsPtr->varTable, 05186 varNamePtr) == NULL) { 05187 Tcl_ListObjAppendElement(interp, listPtr, 05188 varNamePtr); 05189 } 05190 } 05191 } 05192 varPtr = VarHashNextVar(&search); 05193 } 05194 } 05195 } 05196 } else if (((Interp *)interp)->varFramePtr->procPtr != NULL) { 05197 AppendLocals(interp, listPtr, simplePatternPtr, 1); 05198 } 05199 05200 if (simplePatternPtr) { 05201 Tcl_DecrRefCount(simplePatternPtr); 05202 } 05203 Tcl_SetObjResult(interp, listPtr); 05204 return TCL_OK; 05205 } 05206 05207 /* 05208 *---------------------------------------------------------------------- 05209 * 05210 * InfoGlobalsCmd -- (moved over from tclCmdIL.c) 05211 * 05212 * Called to implement the "info globals" command that returns the list 05213 * of global variables matching an optional pattern. Handles the 05214 * following syntax: 05215 * 05216 * info globals ?pattern? 05217 * 05218 * Results: 05219 * Returns TCL_OK if successful and TCL_ERROR if there is an error. 05220 * 05221 * Side effects: 05222 * Returns a result in the interpreter's result object. If there is an 05223 * error, the result is an error message. 05224 * 05225 *---------------------------------------------------------------------- 05226 */ 05227 05228 int 05229 TclInfoGlobalsCmd( 05230 ClientData dummy, /* Not used. */ 05231 Tcl_Interp *interp, /* Current interpreter. */ 05232 int objc, /* Number of arguments. */ 05233 Tcl_Obj *const objv[]) /* Argument objects. */ 05234 { 05235 char *varName, *pattern; 05236 Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); 05237 Tcl_HashSearch search; 05238 Var *varPtr; 05239 Tcl_Obj *listPtr, *varNamePtr, *patternPtr; 05240 05241 if (objc == 1) { 05242 pattern = NULL; 05243 } else if (objc == 2) { 05244 pattern = TclGetString(objv[1]); 05245 05246 /* 05247 * Strip leading global-namespace qualifiers. [Bug 1057461] 05248 */ 05249 05250 if (pattern[0] == ':' && pattern[1] == ':') { 05251 while (*pattern == ':') { 05252 pattern++; 05253 } 05254 } 05255 } else { 05256 Tcl_WrongNumArgs(interp, 1, objv, "?pattern?"); 05257 return TCL_ERROR; 05258 } 05259 05260 /* 05261 * Scan through the global :: namespace's variable table and create a list 05262 * of all global variables that match the pattern. 05263 */ 05264 05265 listPtr = Tcl_NewListObj(0, NULL); 05266 if (pattern != NULL && TclMatchIsTrivial(pattern)) { 05267 if (pattern == TclGetString(objv[1])) { 05268 patternPtr = objv[1]; 05269 } else { 05270 patternPtr = Tcl_NewStringObj(pattern, -1); 05271 } 05272 Tcl_IncrRefCount(patternPtr); 05273 05274 varPtr = VarHashFindVar(&globalNsPtr->varTable, patternPtr); 05275 if (varPtr) { 05276 if (!TclIsVarUndefined(varPtr)) { 05277 Tcl_ListObjAppendElement(interp, listPtr, 05278 VarHashGetKey(varPtr)); 05279 } 05280 } 05281 Tcl_DecrRefCount(patternPtr); 05282 } else { 05283 for (varPtr = VarHashFirstVar(&globalNsPtr->varTable, &search); 05284 varPtr != NULL; 05285 varPtr = VarHashNextVar(&search)) { 05286 if (TclIsVarUndefined(varPtr)) { 05287 continue; 05288 } 05289 varNamePtr = VarHashGetKey(varPtr); 05290 varName = TclGetString(varNamePtr); 05291 if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { 05292 Tcl_ListObjAppendElement(interp, listPtr, varNamePtr); 05293 } 05294 } 05295 } 05296 Tcl_SetObjResult(interp, listPtr); 05297 return TCL_OK; 05298 } 05299 05300 /* 05301 *---------------------------------------------------------------------- 05302 * 05303 * TclInfoLocalsCmd -- (moved over from tclCmdIl.c) 05304 * 05305 * Called to implement the "info locals" command to return a list of 05306 * local variables that match an optional pattern. Handles the following 05307 * syntax: 05308 * 05309 * info locals ?pattern? 05310 * 05311 * Results: 05312 * Returns TCL_OK if successful and TCL_ERROR if there is an error. 05313 * 05314 * Side effects: 05315 * Returns a result in the interpreter's result object. If there is an 05316 * error, the result is an error message. 05317 * 05318 *---------------------------------------------------------------------- 05319 */ 05320 05321 int 05322 TclInfoLocalsCmd( 05323 ClientData dummy, /* Not used. */ 05324 Tcl_Interp *interp, /* Current interpreter. */ 05325 int objc, /* Number of arguments. */ 05326 Tcl_Obj *const objv[]) /* Argument objects. */ 05327 { 05328 Interp *iPtr = (Interp *) interp; 05329 Tcl_Obj *patternPtr; 05330 Tcl_Obj *listPtr; 05331 05332 if (objc == 1) { 05333 patternPtr = NULL; 05334 } else if (objc == 2) { 05335 patternPtr = objv[1]; 05336 } else { 05337 Tcl_WrongNumArgs(interp, 1, objv, "?pattern?"); 05338 return TCL_ERROR; 05339 } 05340 05341 if (!(iPtr->varFramePtr->isProcCallFrame & FRAME_IS_PROC )) { 05342 return TCL_OK; 05343 } 05344 05345 /* 05346 * Return a list containing names of first the compiled locals (i.e. the 05347 * ones stored in the call frame), then the variables in the local hash 05348 * table (if one exists). 05349 */ 05350 05351 listPtr = Tcl_NewListObj(0, NULL); 05352 AppendLocals(interp, listPtr, patternPtr, 0); 05353 Tcl_SetObjResult(interp, listPtr); 05354 return TCL_OK; 05355 } 05356 05357 /* 05358 *---------------------------------------------------------------------- 05359 * 05360 * AppendLocals -- 05361 * 05362 * Append the local variables for the current frame to the specified list 05363 * object. 05364 * 05365 * Results: 05366 * None. 05367 * 05368 * Side effects: 05369 * None. 05370 * 05371 *---------------------------------------------------------------------- 05372 */ 05373 05374 static void 05375 AppendLocals( 05376 Tcl_Interp *interp, /* Current interpreter. */ 05377 Tcl_Obj *listPtr, /* List object to append names to. */ 05378 Tcl_Obj *patternPtr, /* Pattern to match against. */ 05379 int includeLinks) /* 1 if upvars should be included, else 0. */ 05380 { 05381 Interp *iPtr = (Interp *) interp; 05382 Var *varPtr; 05383 int i, localVarCt; 05384 Tcl_Obj **varNamePtr; 05385 char *varName; 05386 TclVarHashTable *localVarTablePtr; 05387 Tcl_HashSearch search; 05388 const char *pattern = patternPtr? TclGetString(patternPtr) : NULL; 05389 Tcl_Obj *objNamePtr; 05390 05391 localVarCt = iPtr->varFramePtr->numCompiledLocals; 05392 varPtr = iPtr->varFramePtr->compiledLocals; 05393 localVarTablePtr = iPtr->varFramePtr->varTablePtr; 05394 varNamePtr = &iPtr->varFramePtr->localCachePtr->varName0; 05395 05396 for (i = 0; i < localVarCt; i++, varNamePtr++) { 05397 /* 05398 * Skip nameless (temporary) variables and undefined variables. 05399 */ 05400 05401 if (*varNamePtr && !TclIsVarUndefined(varPtr) 05402 && (includeLinks || !TclIsVarLink(varPtr))) { 05403 varName = TclGetString(*varNamePtr); 05404 if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { 05405 Tcl_ListObjAppendElement(interp, listPtr, *varNamePtr); 05406 } 05407 } 05408 varPtr++; 05409 } 05410 05411 /* 05412 * Do nothing if no local variables. 05413 */ 05414 05415 if (localVarTablePtr == NULL) { 05416 return; 05417 } 05418 05419 /* 05420 * Check for the simple and fast case. 05421 */ 05422 05423 if ((pattern != NULL) && TclMatchIsTrivial(pattern)) { 05424 varPtr = VarHashFindVar(localVarTablePtr, patternPtr); 05425 if (varPtr != NULL) { 05426 if (!TclIsVarUndefined(varPtr) 05427 && (includeLinks || !TclIsVarLink(varPtr))) { 05428 Tcl_ListObjAppendElement(interp, listPtr, 05429 VarHashGetKey(varPtr)); 05430 } 05431 } 05432 return; 05433 } 05434 05435 /* 05436 * Scan over and process all local variables. 05437 */ 05438 05439 for (varPtr = VarHashFirstVar(localVarTablePtr, &search); 05440 varPtr != NULL; 05441 varPtr = VarHashNextVar(&search)) { 05442 if (!TclIsVarUndefined(varPtr) 05443 && (includeLinks || !TclIsVarLink(varPtr))) { 05444 objNamePtr = VarHashGetKey(varPtr); 05445 varName = TclGetString(objNamePtr); 05446 if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { 05447 Tcl_ListObjAppendElement(interp, listPtr, objNamePtr); 05448 } 05449 } 05450 } 05451 } 05452 05453 /* 05454 * Hash table implementation - first, just copy and adapt the obj key stuff 05455 */ 05456 05457 void 05458 TclInitVarHashTable( 05459 TclVarHashTable *tablePtr, 05460 Namespace *nsPtr) 05461 { 05462 Tcl_InitCustomHashTable(&tablePtr->table, 05463 TCL_CUSTOM_TYPE_KEYS, &tclVarHashKeyType); 05464 tablePtr->nsPtr = nsPtr; 05465 } 05466 05467 static Tcl_HashEntry * 05468 AllocVarEntry( 05469 Tcl_HashTable *tablePtr, /* Hash table. */ 05470 void *keyPtr) /* Key to store in the hash table entry. */ 05471 { 05472 Tcl_Obj *objPtr = (Tcl_Obj *) keyPtr; 05473 Tcl_HashEntry *hPtr; 05474 Var *varPtr; 05475 05476 varPtr = (Var *) ckalloc(sizeof(VarInHash)); 05477 varPtr->flags = VAR_IN_HASHTABLE; 05478 varPtr->value.objPtr = NULL; 05479 VarHashRefCount(varPtr) = 1; 05480 05481 hPtr = &(((VarInHash *)varPtr)->entry); 05482 Tcl_SetHashValue(hPtr, varPtr); 05483 hPtr->key.objPtr = objPtr; 05484 Tcl_IncrRefCount(objPtr); 05485 05486 return hPtr; 05487 } 05488 05489 static void 05490 FreeVarEntry( 05491 Tcl_HashEntry *hPtr) 05492 { 05493 Var *varPtr = VarHashGetValue(hPtr); 05494 Tcl_Obj *objPtr = hPtr->key.objPtr; 05495 05496 if (TclIsVarUndefined(varPtr) && !TclIsVarTraced(varPtr) 05497 && (VarHashRefCount(varPtr) == 1)) { 05498 ckfree((char *) varPtr); 05499 } else { 05500 VarHashInvalidateEntry(varPtr); 05501 TclSetVarUndefined(varPtr); 05502 VarHashRefCount(varPtr)--; 05503 } 05504 Tcl_DecrRefCount(objPtr); 05505 } 05506 05507 static int 05508 CompareVarKeys( 05509 void *keyPtr, /* New key to compare. */ 05510 Tcl_HashEntry *hPtr) /* Existing key to compare. */ 05511 { 05512 Tcl_Obj *objPtr1 = (Tcl_Obj *) keyPtr; 05513 Tcl_Obj *objPtr2 = hPtr->key.objPtr; 05514 register const char *p1, *p2; 05515 register int l1, l2; 05516 05517 /* 05518 * If the object pointers are the same then they match. 05519 */ 05520 05521 if (objPtr1 == objPtr2) { 05522 return 1; 05523 } 05524 05525 /* 05526 * Don't use Tcl_GetStringFromObj as it would prevent l1 and l2 being in a 05527 * register. 05528 */ 05529 05530 p1 = TclGetString(objPtr1); 05531 l1 = objPtr1->length; 05532 p2 = TclGetString(objPtr2); 05533 l2 = objPtr2->length; 05534 05535 /* 05536 * Only compare if the string representations are of the same length. 05537 */ 05538 05539 if (l1 == l2) { 05540 for (;; p1++, p2++, l1--) { 05541 if (*p1 != *p2) { 05542 break; 05543 } 05544 if (l1 == 0) { 05545 return 1; 05546 } 05547 } 05548 } 05549 05550 return 0; 05551 } 05552 05553 static unsigned int 05554 HashVarKey( 05555 Tcl_HashTable *tablePtr, /* Hash table. */ 05556 void *keyPtr) /* Key from which to compute hash value. */ 05557 { 05558 Tcl_Obj *objPtr = (Tcl_Obj *) keyPtr; 05559 const char *string = TclGetString(objPtr); 05560 int length = objPtr->length; 05561 unsigned int result = 0; 05562 int i; 05563 05564 /* 05565 * I tried a zillion different hash functions and asked many other people 05566 * for advice. Many people had their own favorite functions, all 05567 * different, but no-one had much idea why they were good ones. I chose 05568 * the one below (multiply by 9 and add new character) because of the 05569 * following reasons: 05570 * 05571 * 1. Multiplying by 10 is perfect for keys that are decimal strings, and 05572 * multiplying by 9 is just about as good. 05573 * 2. Times-9 is (shift-left-3) plus (old). This means that each 05574 * character's bits hang around in the low-order bits of the hash value 05575 * for ever, plus they spread fairly rapidly up to the high-order bits 05576 * to fill out the hash value. This seems works well both for decimal 05577 * and non-decimal strings. 05578 */ 05579 05580 for (i=0 ; i<length ; i++) { 05581 result += (result << 3) + string[i]; 05582 } 05583 return result; 05584 } 05585 05586 /* 05587 * Local Variables: 05588 * mode: c 05589 * c-basic-offset: 4 05590 * fill-column: 78 05591 * End: 05592 */
Generated on Wed Mar 12 12:18:24 2008 by 1.5.1 |