tclVar.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:161k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclVar.c --
  3.  *
  4.  * This file contains routines that implement Tcl variables
  5.  * (both scalars and arrays).
  6.  *
  7.  * The implementation of arrays is modelled after an initial
  8.  * implementation by Mark Diekhans and Karl Lehenbauer.
  9.  *
  10.  * Copyright (c) 1987-1994 The Regents of the University of California.
  11.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  12.  * Copyright (c) 1998-1999 by Scriptics Corporation.
  13.  * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
  14.  *
  15.  * See the file "license.terms" for information on usage and redistribution
  16.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  17.  *
  18.  * RCS: @(#) $Id: tclVar.c,v 1.69.2.14 2007/05/10 18:23:58 dgp Exp $
  19.  */
  20. #include "tclInt.h"
  21. #include "tclPort.h"
  22. /*
  23.  * The strings below are used to indicate what went wrong when a
  24.  * variable access is denied.
  25.  */
  26. static CONST char *noSuchVar = "no such variable";
  27. static CONST char *isArray = "variable is array";
  28. static CONST char *needArray = "variable isn't array";
  29. static CONST char *noSuchElement = "no such element in array";
  30. static CONST char *danglingElement =
  31. "upvar refers to element in deleted array";
  32. static CONST char *danglingVar =
  33. "upvar refers to variable in deleted namespace";
  34. static CONST char *badNamespace = "parent namespace doesn't exist";
  35. static CONST char *missingName = "missing variable name";
  36. static CONST char *isArrayElement = "name refers to an element in an array";
  37. /*
  38.  * Forward references to procedures defined later in this file:
  39.  */
  40. static int CallVarTraces _ANSI_ARGS_((Interp *iPtr, Var *arrayPtr,
  41.     Var *varPtr, CONST char *part1, CONST char *part2,
  42.     int flags, CONST int leaveErrMsg));
  43. static void CleanupVar _ANSI_ARGS_((Var *varPtr,
  44.     Var *arrayPtr));
  45. static void DeleteSearches _ANSI_ARGS_((Var *arrayVarPtr));
  46. static void DeleteArray _ANSI_ARGS_((Interp *iPtr,
  47.     CONST char *arrayName, Var *varPtr, int flags));
  48. static void DisposeTraceResult _ANSI_ARGS_((int flags,
  49.     char *result));
  50. static int              ObjMakeUpvar _ANSI_ARGS_((Tcl_Interp *interp, 
  51.                             CallFrame *framePtr, Tcl_Obj *otherP1Ptr, 
  52.                             CONST char *otherP2, CONST int otherFlags,
  53.             CONST char *myName, int myFlags, int index));
  54. static Var * NewVar _ANSI_ARGS_((void));
  55. static ArraySearch * ParseSearchId _ANSI_ARGS_((Tcl_Interp *interp,
  56.     CONST Var *varPtr, CONST char *varName,
  57.     Tcl_Obj *handleObj));
  58. static void VarErrMsg _ANSI_ARGS_((Tcl_Interp *interp,
  59.     CONST char *part1, CONST char *part2,
  60.     CONST char *operation, CONST char *reason));
  61. static int SetArraySearchObj _ANSI_ARGS_((Tcl_Interp *interp,
  62.     Tcl_Obj *objPtr));
  63. static void UnsetVarStruct _ANSI_ARGS_((Var *varPtr, Var *arrayPtr,
  64.     Interp *iPtr, CONST char *part1, CONST char *part2,
  65.     int flags));
  66. /*
  67.  * Functions defined in this file that may be exported in the future
  68.  * for use by the bytecode compiler and engine or to the public interface.
  69.  */
  70. Var * TclLookupSimpleVar _ANSI_ARGS_((Tcl_Interp *interp,
  71.     CONST char *varName, int flags, CONST int create,
  72.     CONST char **errMsgPtr, int *indexPtr));
  73. int TclObjUnsetVar2 _ANSI_ARGS_((Tcl_Interp *interp,
  74.     Tcl_Obj *part1Ptr, CONST char *part2, int flags));
  75. static Tcl_FreeInternalRepProc FreeLocalVarName;
  76. static Tcl_DupInternalRepProc DupLocalVarName;
  77. static Tcl_UpdateStringProc UpdateLocalVarName;
  78. static Tcl_FreeInternalRepProc FreeNsVarName;
  79. static Tcl_DupInternalRepProc DupNsVarName;
  80. static Tcl_FreeInternalRepProc FreeParsedVarName;
  81. static Tcl_DupInternalRepProc DupParsedVarName;
  82. static Tcl_UpdateStringProc UpdateParsedVarName;
  83. /*
  84.  * Types of Tcl_Objs used to cache variable lookups.
  85.  *
  86.  * 
  87.  * localVarName - INTERNALREP DEFINITION:
  88.  *   twoPtrValue.ptr1 = pointer to the corresponding Proc 
  89.  *   twoPtrValue.ptr2 = index into locals table
  90.  *
  91.  * nsVarName - INTERNALREP DEFINITION:
  92.  *   twoPtrValue.ptr1: pointer to the namespace containing the 
  93.  *                     reference
  94.  *   twoPtrValue.ptr2: pointer to the corresponding Var 
  95.  *
  96.  * parsedVarName - INTERNALREP DEFINITION:
  97.  *   twoPtrValue.ptr1 = pointer to the array name Tcl_Obj, 
  98.  *                      or NULL if it is a scalar variable
  99.  *   twoPtrValue.ptr2 = pointer to the element name string
  100.  *                      (owned by this Tcl_Obj), or NULL if 
  101.  *                      it is a scalar variable
  102.  */
  103. static Tcl_ObjType tclLocalVarNameType = {
  104.     "localVarName",
  105.     FreeLocalVarName, DupLocalVarName, UpdateLocalVarName, NULL
  106. };
  107. static Tcl_ObjType tclNsVarNameType = {
  108.     "namespaceVarName",
  109.     FreeNsVarName, DupNsVarName, NULL, NULL
  110. };
  111. static Tcl_ObjType tclParsedVarNameType = {
  112.     "parsedVarName",
  113.     FreeParsedVarName, DupParsedVarName, UpdateParsedVarName, NULL
  114. };
  115. /*
  116.  * Type of Tcl_Objs used to speed up array searches.
  117.  *
  118.  * INTERNALREP DEFINITION:
  119.  *   twoPtrValue.ptr1 = searchIdNumber as offset from (char*)NULL
  120.  *   twoPtrValue.ptr2 = variableNameStartInString as offset from (char*)NULL
  121.  *
  122.  * Note that the value stored in ptr2 is the offset into the string of
  123.  * the start of the variable name and not the address of the variable
  124.  * name itself, as this can be safely copied.
  125.  */
  126. Tcl_ObjType tclArraySearchType = {
  127.     "array search",
  128.     NULL, NULL, NULL, SetArraySearchObj
  129. };
  130. /*
  131.  *----------------------------------------------------------------------
  132.  *
  133.  * TclLookupVar --
  134.  *
  135.  * This procedure is used to locate a variable given its name(s). It
  136.  *      has been mostly superseded by TclObjLookupVar, it is now only used 
  137.  *      by the string-based interfaces. It is kept in tcl8.4 mainly because 
  138.  *      it is in the internal stubs table, so that some extension may be 
  139.  *      calling it. 
  140.  *
  141.  * Results:
  142.  * The return value is a pointer to the variable structure indicated by
  143.  * part1 and part2, or NULL if the variable couldn't be found. If the
  144.  * variable is found, *arrayPtrPtr is filled in with the address of the
  145.  * variable structure for the array that contains the variable (or NULL
  146.  * if the variable is a scalar). If the variable can't be found and
  147.  * either createPart1 or createPart2 are 1, a new as-yet-undefined
  148.  * (VAR_UNDEFINED) variable structure is created, entered into a hash
  149.  * table, and returned.
  150.  *
  151.  * If the variable isn't found and creation wasn't specified, or some
  152.  * other error occurs, NULL is returned and an error message is left in
  153.  * the interp's result if TCL_LEAVE_ERR_MSG is set in flags. 
  154.  *
  155.  * Note: it's possible for the variable returned to be VAR_UNDEFINED
  156.  * even if createPart1 or createPart2 are 1 (these only cause the hash
  157.  * table entry or array to be created). For example, the variable might
  158.  * be a global that has been unset but is still referenced by a
  159.  * procedure, or a variable that has been unset but it only being kept
  160.  * in existence (if VAR_UNDEFINED) by a trace.
  161.  *
  162.  * Side effects:
  163.  * New hashtable entries may be created if createPart1 or createPart2
  164.  * are 1.
  165.  *
  166.  *----------------------------------------------------------------------
  167.  */
  168. Var *
  169. TclLookupVar(interp, part1, part2, flags, msg, createPart1, createPart2,
  170.         arrayPtrPtr)
  171.     Tcl_Interp *interp; /* Interpreter to use for lookup. */
  172.     CONST char *part1;         /* If part2 isn't NULL, this is the name of
  173.  * an array. Otherwise, this
  174.  * is a full variable name that could
  175.  * include a parenthesized array element. */
  176.     CONST char *part2; /* Name of element within array, or NULL. */
  177.     int flags; /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
  178.  * and TCL_LEAVE_ERR_MSG bits matter. */
  179.     CONST char *msg; /* Verb to use in error messages, e.g.
  180.  * "read" or "set". Only needed if
  181.  * TCL_LEAVE_ERR_MSG is set in flags. */
  182.     int createPart1; /* If 1, create hash table entry for part 1
  183.  * of name, if it doesn't already exist. If
  184.  * 0, return error if it doesn't exist. */
  185.     int createPart2; /* If 1, create hash table entry for part 2
  186.  * of name, if it doesn't already exist. If
  187.  * 0, return error if it doesn't exist. */
  188.     Var **arrayPtrPtr; /* If the name refers to an element of an
  189.  * array, *arrayPtrPtr gets filled in with
  190.  * address of array variable. Otherwise
  191.  * this is set to NULL. */
  192. {
  193.     Var *varPtr;
  194.     CONST char *elName; /* Name of array element or NULL; may be
  195.  * same as part2, or may be openParen+1. */
  196.     int openParen, closeParen;
  197.                                 /* If this procedure parses a name into
  198.  * array and index, these are the offsets to 
  199.  * the parens around the index.  Otherwise 
  200.  * they are -1. */
  201.     register CONST char *p;
  202.     CONST char *errMsg = NULL;
  203.     int index;
  204. #define VAR_NAME_BUF_SIZE 26
  205.     char buffer[VAR_NAME_BUF_SIZE];
  206.     char *newVarName = buffer;
  207.     varPtr = NULL;
  208.     *arrayPtrPtr = NULL;
  209.     openParen = closeParen = -1;
  210.     /*
  211.      * Parse part1 into array name and index.
  212.      * Always check if part1 is an array element name and allow it only if
  213.      * part2 is not given.   
  214.      * (if one does not care about creating array elements that can't be used
  215.      *  from tcl, and prefer slightly better performance, one can put
  216.      *  the following in an   if (part2 == NULL) { ... } block and remove
  217.      *  the part2's test and error reporting  or move that code in array set)
  218.      */
  219.     elName = part2;
  220.     for (p = part1; *p ; p++) {
  221. if (*p == '(') {
  222.     openParen = p - part1;
  223.     do {
  224. p++;
  225.     } while (*p != '');
  226.     p--;
  227.     if (*p == ')') {
  228. if (part2 != NULL) {
  229.     if (flags & TCL_LEAVE_ERR_MSG) {
  230. VarErrMsg(interp, part1, part2, msg, needArray);
  231.     }
  232.     return NULL;
  233. }
  234. closeParen = p - part1;
  235.     } else {
  236. openParen = -1;
  237.     }
  238.     break;
  239. }
  240.     }
  241.     if (openParen != -1) {
  242. if (closeParen >= VAR_NAME_BUF_SIZE) {
  243.     newVarName = ckalloc((unsigned int) (closeParen+1));
  244. }
  245. memcpy(newVarName, part1, (unsigned int) closeParen);
  246. newVarName[openParen] = '';
  247. newVarName[closeParen] = '';
  248. part1 = newVarName;
  249. elName = newVarName + openParen + 1;
  250.     }
  251.     varPtr = TclLookupSimpleVar(interp, part1, flags, 
  252.             createPart1, &errMsg, &index);
  253.     if (varPtr == NULL) {
  254. if ((errMsg != NULL) && (flags & TCL_LEAVE_ERR_MSG)) {
  255.     VarErrMsg(interp, part1, elName, msg, errMsg);
  256. }
  257.     } else {
  258. while (TclIsVarLink(varPtr)) {
  259.     varPtr = varPtr->value.linkPtr;
  260. }
  261. if (elName != NULL) {
  262.     *arrayPtrPtr = varPtr;
  263.     varPtr = TclLookupArrayElement(interp, part1, elName, flags, 
  264.     msg, createPart1, createPart2, varPtr);
  265. }
  266.     }
  267.     if (newVarName != buffer) {
  268. ckfree(newVarName);
  269.     }
  270.     return varPtr;
  271. #undef VAR_NAME_BUF_SIZE
  272. }
  273. /*
  274.  *----------------------------------------------------------------------
  275.  *
  276.  * TclObjLookupVar --
  277.  *
  278.  * This procedure is used by virtually all of the variable code to
  279.  * locate a variable given its name(s). The parsing into array/element
  280.  *      components and (if possible) the lookup results are cached in 
  281.  *      part1Ptr, which is converted to one of the varNameTypes.
  282.  *
  283.  * Results:
  284.  * The return value is a pointer to the variable structure indicated by
  285.  * part1Ptr and part2, or NULL if the variable couldn't be found. If 
  286.  *      the variable is found, *arrayPtrPtr is filled with the address of the
  287.  * variable structure for the array that contains the variable (or NULL
  288.  * if the variable is a scalar). If the variable can't be found and
  289.  * either createPart1 or createPart2 are 1, a new as-yet-undefined
  290.  * (VAR_UNDEFINED) variable structure is created, entered into a hash
  291.  * table, and returned.
  292.  *
  293.  * If the variable isn't found and creation wasn't specified, or some
  294.  * other error occurs, NULL is returned and an error message is left in
  295.  * the interp's result if TCL_LEAVE_ERR_MSG is set in flags. 
  296.  *
  297.  * Note: it's possible for the variable returned to be VAR_UNDEFINED
  298.  * even if createPart1 or createPart2 are 1 (these only cause the hash
  299.  * table entry or array to be created). For example, the variable might
  300.  * be a global that has been unset but is still referenced by a
  301.  * procedure, or a variable that has been unset but it only being kept
  302.  * in existence (if VAR_UNDEFINED) by a trace.
  303.  *
  304.  * Side effects:
  305.  * New hashtable entries may be created if createPart1 or createPart2
  306.  * are 1.
  307.  *      The object part1Ptr is converted to one of tclLocalVarNameType, 
  308.  *      tclNsVarNameType or tclParsedVarNameType and caches as much of the
  309.  *      lookup as it can.
  310.  *
  311.  *----------------------------------------------------------------------
  312.  */
  313. Var *
  314. TclObjLookupVar(interp, part1Ptr, part2, flags, msg, createPart1, createPart2,
  315.         arrayPtrPtr)
  316.     Tcl_Interp *interp; /* Interpreter to use for lookup. */
  317.     register Tcl_Obj *part1Ptr; /* If part2 isn't NULL, this is the name 
  318.  * of an array. Otherwise, this is a full 
  319.  * variable name that could include a parenthesized 
  320.  * array element. */
  321.     CONST char *part2; /* Name of element within array, or NULL. */
  322.     int flags;         /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
  323.  * and TCL_LEAVE_ERR_MSG bits matter. */
  324.     CONST char *msg; /* Verb to use in error messages, e.g.
  325.  * "read" or "set". Only needed if
  326.  * TCL_LEAVE_ERR_MSG is set in flags. */
  327.     CONST int createPart1; /* If 1, create hash table entry for part 1
  328.  * of name, if it doesn't already exist. If
  329.  * 0, return error if it doesn't exist. */
  330.     CONST int createPart2; /* If 1, create hash table entry for part 2
  331.  * of name, if it doesn't already exist. If
  332.  * 0, return error if it doesn't exist. */
  333.     Var **arrayPtrPtr; /* If the name refers to an element of an
  334.  * array, *arrayPtrPtr gets filled in with
  335.  * address of array variable. Otherwise
  336.  * this is set to NULL. */
  337. {
  338.     Interp *iPtr = (Interp *) interp;
  339.     register Var *varPtr; /* Points to the variable's in-frame Var
  340.  * structure. */
  341.     char *part1;
  342.     int index, len1, len2;
  343.     int parsed = 0;
  344.     Tcl_Obj *objPtr;
  345.     Tcl_ObjType *typePtr = part1Ptr->typePtr;
  346.     CONST char *errMsg = NULL;
  347.     CallFrame *varFramePtr = iPtr->varFramePtr;
  348.     Namespace *nsPtr;
  349.     /*
  350.      * If part1Ptr is a tclParsedVarNameType, separate it into the 
  351.      * pre-parsed parts.
  352.      */
  353.     *arrayPtrPtr = NULL;
  354.     if (typePtr == &tclParsedVarNameType) {
  355. if (part1Ptr->internalRep.twoPtrValue.ptr1 != NULL) {
  356.     if (part2 != NULL) {
  357. /*
  358.  * ERROR: part1Ptr is already an array element, cannot 
  359.  * specify a part2.
  360.  */
  361. if (flags & TCL_LEAVE_ERR_MSG) {
  362.     part1 = TclGetString(part1Ptr);
  363.     VarErrMsg(interp, part1, part2, msg, needArray);
  364. }
  365. return NULL;
  366.     }
  367.     part2 = (char *) part1Ptr->internalRep.twoPtrValue.ptr2;
  368.     part1Ptr = (Tcl_Obj *) part1Ptr->internalRep.twoPtrValue.ptr1;
  369.     typePtr = part1Ptr->typePtr;
  370. }
  371. parsed = 1;
  372.     }
  373.     part1 = Tcl_GetStringFromObj(part1Ptr, &len1);    
  374.     nsPtr = ((varFramePtr == NULL)? iPtr->globalNsPtr : varFramePtr->nsPtr);
  375.     if (nsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) {
  376. goto doParse;
  377.     }
  378.     
  379.     if (typePtr == &tclLocalVarNameType) {
  380. Proc *procPtr = (Proc *) part1Ptr->internalRep.twoPtrValue.ptr1;
  381. int localIndex = (int) part1Ptr->internalRep.twoPtrValue.ptr2;
  382. int useLocal;
  383. useLocal = ((varFramePtr != NULL) && varFramePtr->isProcCallFrame
  384.         && !(flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)));
  385. if (useLocal && (procPtr == varFramePtr->procPtr)) {
  386.     /*
  387.      * part1Ptr points to an indexed local variable of the
  388.      * correct procedure: use the cached value.
  389.      */
  390.     
  391.     varPtr = &(varFramePtr->compiledLocals[localIndex]);
  392.     goto donePart1;
  393. }
  394. goto doneParsing;
  395.     } else if (typePtr == &tclNsVarNameType) {
  396. Namespace *cachedNsPtr;
  397. int useGlobal, useReference;
  398. varPtr = (Var *) part1Ptr->internalRep.twoPtrValue.ptr2;
  399. cachedNsPtr = (Namespace *) part1Ptr->internalRep.twoPtrValue.ptr1;
  400. useGlobal = (cachedNsPtr == iPtr->globalNsPtr) 
  401.     && ((flags & TCL_GLOBAL_ONLY) 
  402. || ((*part1 == ':') && (*(part1+1) == ':'))
  403. || (varFramePtr == NULL) 
  404. || (!varFramePtr->isProcCallFrame 
  405.     && (nsPtr == iPtr->globalNsPtr)));
  406. useReference = useGlobal || ((cachedNsPtr == nsPtr) 
  407.         && ((flags & TCL_NAMESPACE_ONLY) 
  408.     || (varFramePtr && !varFramePtr->isProcCallFrame 
  409. && !(flags & TCL_GLOBAL_ONLY)
  410. /* careful: an undefined ns variable could
  411.  * be hiding a valid global reference. */
  412. && !(varPtr->flags & VAR_UNDEFINED))));
  413. if (useReference && (varPtr->hPtr != NULL)) {
  414.     /*
  415.      * A straight global or namespace reference, use it. It isn't 
  416.      * so simple to deal with 'implicit' namespace references, i.e., 
  417.      * those where the reference could be to either a namespace 
  418.      * or a global variable. Those we lookup again.
  419.      *
  420.      * If (varPtr->hPtr == NULL), this might be a reference to a
  421.      * variable in a deleted namespace, kept alive by e.g. part1Ptr.
  422.      * We could conceivably be so unlucky that a new namespace was
  423.      * created at the same address as the deleted one, so to be 
  424.      * safe we test for a valid hPtr.
  425.      */
  426.     goto donePart1;
  427. }
  428. goto doneParsing;
  429.     }
  430.     doParse:
  431.     if (!parsed && (*(part1 + len1 - 1) == ')')) {
  432. /*
  433.  * part1Ptr is possibly an unparsed array element.
  434.  */
  435. register int i;
  436. char *newPart2;
  437. len2 = -1;
  438. for (i = 0; i < len1; i++) {
  439.     if (*(part1 + i) == '(') {
  440. if (part2 != NULL) {
  441.     if (flags & TCL_LEAVE_ERR_MSG) {
  442. VarErrMsg(interp, part1, part2, msg, needArray);
  443.     }
  444. }
  445. /*
  446.  * part1Ptr points to an array element; first copy 
  447.  * the element name to a new string part2.
  448.  */
  449. part2 = part1 + i + 1;
  450. len2 = len1 - i - 2;
  451. len1 = i;
  452. newPart2 = ckalloc((unsigned int) (len2+1));
  453. memcpy(newPart2, part2, (unsigned int) len2);
  454. *(newPart2+len2) = '';
  455. part2 = newPart2;
  456. /*
  457.  * Free the internal rep of the original part1Ptr, now
  458.  * renamed objPtr, and set it to tclParsedVarNameType.
  459.  */
  460. objPtr = part1Ptr;
  461. if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
  462.     typePtr->freeIntRepProc(objPtr);
  463. }
  464. objPtr->typePtr = &tclParsedVarNameType;
  465. /*
  466.  * Define a new string object to hold the new part1Ptr, i.e., 
  467.  * the array name. Set the internal rep of objPtr, reset
  468.  * typePtr and part1 to contain the references to the
  469.  * array name.
  470.  */
  471. part1Ptr = Tcl_NewStringObj(part1, len1);
  472. Tcl_IncrRefCount(part1Ptr);
  473. objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) part1Ptr;
  474. objPtr->internalRep.twoPtrValue.ptr2 = (VOID *) part2;
  475. typePtr = part1Ptr->typePtr;
  476. part1 = TclGetString(part1Ptr);
  477. break;
  478.     }
  479. }
  480.     }
  481.     
  482.     doneParsing:
  483.     /*
  484.      * part1Ptr is not an array element; look it up, and convert 
  485.      * it to one of the cached types if possible.
  486.      */
  487.     if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
  488. typePtr->freeIntRepProc(part1Ptr);
  489. part1Ptr->typePtr = NULL;
  490.     }
  491.     varPtr = TclLookupSimpleVar(interp, part1, flags, 
  492.             createPart1, &errMsg, &index);
  493.     if (varPtr == NULL) {
  494. if ((errMsg != NULL) && (flags & TCL_LEAVE_ERR_MSG)) {
  495.     VarErrMsg(interp, part1, part2, msg, errMsg);
  496. }
  497. return NULL;
  498.     }
  499.     /*
  500.      * Cache the newly found variable if possible.
  501.      */
  502.     if (index >= 0) {
  503.         /*
  504.  * An indexed local variable.
  505.  */
  506. Proc *procPtr = ((Interp *) interp)->varFramePtr->procPtr;
  507. part1Ptr->typePtr = &tclLocalVarNameType;
  508. procPtr->refCount++;
  509. part1Ptr->internalRep.twoPtrValue.ptr1 = (VOID *) procPtr;
  510. part1Ptr->internalRep.twoPtrValue.ptr2 = (VOID *) index;
  511. #if 0
  512.     /*
  513.      * TEMPORARYLY DISABLED tclNsVarNameType
  514.      *
  515.      * This optimisation will hopefully be turned back on soon.
  516.      *      Miguel Sofer, 2004-05-22
  517.      */
  518.     } else if (index > -3) {
  519. /*
  520.  * A cacheable namespace or global variable.
  521.  */
  522. Namespace *nsPtr;
  523.     
  524. nsPtr = ((index == -1)? iPtr->globalNsPtr : varFramePtr->nsPtr);
  525. varPtr->refCount++;
  526. part1Ptr->typePtr = &tclNsVarNameType;
  527. part1Ptr->internalRep.twoPtrValue.ptr1 = (VOID *) nsPtr;
  528. part1Ptr->internalRep.twoPtrValue.ptr2 = (VOID *) varPtr;
  529. #endif
  530.     } else {
  531. /*
  532.  * At least mark part1Ptr as already parsed.
  533.  */
  534. part1Ptr->typePtr = &tclParsedVarNameType;
  535. part1Ptr->internalRep.twoPtrValue.ptr1 = NULL;
  536. part1Ptr->internalRep.twoPtrValue.ptr2 = NULL;
  537.     }
  538.     
  539.     donePart1:
  540. #if 0
  541.     if (varPtr == NULL) {
  542. if (flags & TCL_LEAVE_ERR_MSG) {
  543.     part1 = TclGetString(part1Ptr);
  544.     VarErrMsg(interp, part1, part2, msg, 
  545.     "Cached variable reference is NULL.");
  546. }
  547. return NULL;
  548.     }
  549. #endif
  550.     while (TclIsVarLink(varPtr)) {
  551. varPtr = varPtr->value.linkPtr;
  552.     }
  553.     if (part2 != NULL) {
  554. /*
  555.  * Array element sought: look it up.
  556.  */
  557. part1 = TclGetString(part1Ptr);
  558. *arrayPtrPtr = varPtr;
  559. varPtr = TclLookupArrayElement(interp, part1, part2, 
  560.                 flags, msg, createPart1, createPart2, varPtr);
  561.     }
  562.     return varPtr;
  563. }
  564. /*
  565.  * This flag bit should not interfere with TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
  566.  * or TCL_LEAVE_ERR_MSG; it signals that the variable lookup is performed for 
  567.  * upvar (or similar) purposes, with slightly different rules:
  568.  *   - Bug #696893 - variable is either proc-local or in the current
  569.  *     namespace; never follow the second (global) resolution path 
  570.  *   - Bug #631741 - do not use special namespace or interp resolvers
  571.  */
  572. #define LOOKUP_FOR_UPVAR 0x40000
  573. /*
  574.  *----------------------------------------------------------------------
  575.  *
  576.  * TclLookupSimpleVar --
  577.  *
  578.  * This procedure is used by to locate a simple variable (i.e., not
  579.  *      an array element) given its name.
  580.  *
  581.  * Results:
  582.  * The return value is a pointer to the variable structure indicated by
  583.  * varName, or NULL if the variable couldn't be found. If the variable 
  584.  *      can't be found and create is 1, a new as-yet-undefined (VAR_UNDEFINED) 
  585.  *      variable structure is created, entered into a hash table, and returned.
  586.  *
  587.  *      If the current CallFrame corresponds to a proc and the variable found is
  588.  *      one of the compiledLocals, its index is placed in *indexPtr. Otherwise,
  589.  *      *indexPtr will be set to (according to the needs of TclObjLookupVar):
  590.  *               -1 a global reference
  591.  *               -2 a reference to a namespace variable
  592.  *               -3 a non-cachable reference, i.e., one of:
  593.  *                    . non-indexed local var
  594.  *                    . a reference of unknown origin;
  595.  *                    . resolution by a namespace or interp resolver
  596.  *
  597.  * If the variable isn't found and creation wasn't specified, or some
  598.  * other error occurs, NULL is returned and the corresponding error
  599.  * message is left in *errMsgPtr. 
  600.  *
  601.  * Note: it's possible for the variable returned to be VAR_UNDEFINED
  602.  * even if create is 1 (this only causes the hash table entry to be
  603.  * created).  For example, the variable might be a global that has been
  604.  * unset but is still referenced by a procedure, or a variable that has
  605.  * been unset but it only being kept in existence (if VAR_UNDEFINED) by
  606.  * a trace.
  607.  *
  608.  * Side effects:
  609.  * A new hashtable entry may be created if create is 1.
  610.  *
  611.  *----------------------------------------------------------------------
  612.  */
  613. Var *
  614. TclLookupSimpleVar(interp, varName, flags, create, errMsgPtr, indexPtr)
  615.     Tcl_Interp *interp; /* Interpreter to use for lookup. */
  616.     CONST char *varName;        /* This is a simple variable name that could
  617.  * representa scalar or an array. */
  618.     int flags;         /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
  619.  * LOOKUP_FOR_UPVAR and TCL_LEAVE_ERR_MSG bits 
  620.  * matter. */
  621.     CONST int create; /* If 1, create hash table entry for varname,
  622.  * if it doesn't already exist. If 0, return 
  623.  * error if it doesn't exist. */
  624.     CONST char **errMsgPtr;
  625.     int *indexPtr;
  626. {    
  627.     Interp *iPtr = (Interp *) interp;
  628.     CallFrame *varFramePtr = iPtr->varFramePtr;
  629. /* Points to the procedure call frame whose
  630.  * variables are currently in use. Same as
  631.  * the current procedure's frame, if any,
  632.  * unless an "uplevel" is executing. */
  633.     Tcl_HashTable *tablePtr; /* Points to the hashtable, if any, in which
  634.  * to look up the variable. */
  635.     Tcl_Var var;                /* Used to search for global names. */
  636.     Var *varPtr; /* Points to the Var structure returned for
  637.  * the variable. */
  638.     Namespace *varNsPtr, *cxtNsPtr, *dummy1Ptr, *dummy2Ptr;
  639.     ResolverScheme *resPtr;
  640.     Tcl_HashEntry *hPtr;
  641.     int new, i, result;
  642.     varPtr = NULL;
  643.     varNsPtr = NULL; /* set non-NULL if a nonlocal variable */
  644.     *indexPtr = -3;
  645.     if ((flags & TCL_GLOBAL_ONLY) || iPtr->varFramePtr == NULL) {
  646.         cxtNsPtr = iPtr->globalNsPtr;
  647.     } else {
  648.         cxtNsPtr = iPtr->varFramePtr->nsPtr;
  649.     }
  650.     /*
  651.      * If this namespace has a variable resolver, then give it first
  652.      * crack at the variable resolution.  It may return a Tcl_Var
  653.      * value, it may signal to continue onward, or it may signal
  654.      * an error.
  655.      */
  656.     if ((cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) 
  657.     && !(flags & LOOKUP_FOR_UPVAR)) {
  658.         resPtr = iPtr->resolverPtr;
  659.         if (cxtNsPtr->varResProc) {
  660.             result = (*cxtNsPtr->varResProc)(interp, varName,
  661.     (Tcl_Namespace *) cxtNsPtr, flags, &var);
  662.         } else {
  663.             result = TCL_CONTINUE;
  664.         }
  665.         while (result == TCL_CONTINUE && resPtr) {
  666.             if (resPtr->varResProc) {
  667.                 result = (*resPtr->varResProc)(interp, varName,
  668. (Tcl_Namespace *) cxtNsPtr, flags, &var);
  669.             }
  670.             resPtr = resPtr->nextPtr;
  671.         }
  672.         if (result == TCL_OK) {
  673.             varPtr = (Var *) var;
  674.     return varPtr;
  675.         } else if (result != TCL_CONTINUE) {
  676.     return NULL;
  677.         }
  678.     }
  679.     /*
  680.      * Look up varName. Look it up as either a namespace variable or as a
  681.      * local variable in a procedure call frame (varFramePtr).
  682.      * Interpret varName as a namespace variable if:
  683.      *    1) so requested by a TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY flag,
  684.      *    2) there is no active frame (we're at the global :: scope),
  685.      *    3) the active frame was pushed to define the namespace context
  686.      *       for a "namespace eval" or "namespace inscope" command,
  687.      *    4) the name has namespace qualifiers ("::"s).
  688.      * Otherwise, if varName is a local variable, search first in the
  689.      * frame's array of compiler-allocated local variables, then in its
  690.      * hashtable for runtime-created local variables.
  691.      *
  692.      * If create and the variable isn't found, create the variable and,
  693.      * if necessary, create varFramePtr's local var hashtable.
  694.      */
  695.     if (((flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) != 0)
  696.     || (varFramePtr == NULL)
  697.     || !varFramePtr->isProcCallFrame
  698.     || (strstr(varName, "::") != NULL)) {
  699. CONST char *tail;
  700. int lookGlobal;
  701. lookGlobal = (flags & TCL_GLOBAL_ONLY) 
  702.     || (cxtNsPtr == iPtr->globalNsPtr)
  703.     || ((*varName == ':') && (*(varName+1) == ':'));
  704. if (lookGlobal) {
  705.     *indexPtr = -1;
  706.     flags = (flags | TCL_GLOBAL_ONLY) & ~(TCL_NAMESPACE_ONLY|LOOKUP_FOR_UPVAR);
  707. } else {
  708.     if (flags & LOOKUP_FOR_UPVAR) {
  709. flags = (flags | TCL_NAMESPACE_ONLY) & ~LOOKUP_FOR_UPVAR;
  710.     }
  711.     if (flags & TCL_NAMESPACE_ONLY) {
  712. *indexPtr = -2;
  713.     }
  714. /*
  715.  * Don't pass TCL_LEAVE_ERR_MSG, we may yet create the variable,
  716.  * or otherwise generate our own error!
  717.  */
  718. var = Tcl_FindNamespaceVar(interp, varName, (Tcl_Namespace *) cxtNsPtr,
  719. flags & ~TCL_LEAVE_ERR_MSG);
  720. if (var != (Tcl_Var) NULL) {
  721.             varPtr = (Var *) var;
  722.         }
  723. if (varPtr == NULL) {
  724.     if (create) {   /* var wasn't found so create it  */
  725. TclGetNamespaceForQualName(interp, varName, cxtNsPtr,
  726. flags, &varNsPtr, &dummy1Ptr, &dummy2Ptr, &tail);
  727. if (varNsPtr == NULL) {
  728.     *errMsgPtr = badNamespace;
  729.     return NULL;
  730. }
  731. if (tail == NULL) {
  732.     *errMsgPtr = missingName;
  733.     return NULL;
  734. }
  735. hPtr = Tcl_CreateHashEntry(&varNsPtr->varTable, tail, &new);
  736. varPtr = NewVar();
  737. Tcl_SetHashValue(hPtr, varPtr);
  738. varPtr->hPtr = hPtr;
  739. varPtr->nsPtr = varNsPtr;
  740. if ((lookGlobal)  || (varNsPtr == NULL)) {
  741.     /*
  742.      * The variable was created starting from the global
  743.      * namespace: a global reference is returned even if 
  744.      * it wasn't explicitly requested.
  745.      */
  746.     *indexPtr = -1;
  747. } else {
  748.     *indexPtr = -2;
  749. }
  750.     } else { /* var wasn't found and not to create it */
  751. *errMsgPtr = noSuchVar;
  752. return NULL;
  753.     }
  754. }
  755.     } else { /* local var: look in frame varFramePtr */
  756. Proc *procPtr = varFramePtr->procPtr;
  757. int localCt = procPtr->numCompiledLocals;
  758. CompiledLocal *localPtr = procPtr->firstLocalPtr;
  759. Var *localVarPtr = varFramePtr->compiledLocals;
  760. int varNameLen = strlen(varName);
  761. for (i = 0;  i < localCt;  i++) {
  762.     if (!TclIsVarTemporary(localPtr)) {
  763. register char *localName = localVarPtr->name;
  764. if ((varName[0] == localName[0])
  765.         && (varNameLen == localPtr->nameLength)
  766.         && (strcmp(varName, localName) == 0)) {
  767.     *indexPtr = i;
  768.     return localVarPtr;
  769. }
  770.     }
  771.     localVarPtr++;
  772.     localPtr = localPtr->nextPtr;
  773. }
  774. tablePtr = varFramePtr->varTablePtr;
  775. if (create) {
  776.     if (tablePtr == NULL) {
  777. tablePtr = (Tcl_HashTable *)
  778.     ckalloc(sizeof(Tcl_HashTable));
  779. Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS);
  780. varFramePtr->varTablePtr = tablePtr;
  781.     }
  782.     hPtr = Tcl_CreateHashEntry(tablePtr, varName, &new);
  783.     if (new) {
  784. varPtr = NewVar();
  785. Tcl_SetHashValue(hPtr, varPtr);
  786. varPtr->hPtr = hPtr;
  787. varPtr->nsPtr = NULL; /* a local variable */
  788.     } else {
  789. varPtr = (Var *) Tcl_GetHashValue(hPtr);
  790.     }
  791. } else {
  792.     hPtr = NULL;
  793.     if (tablePtr != NULL) {
  794. hPtr = Tcl_FindHashEntry(tablePtr, varName);
  795.     }
  796.     if (hPtr == NULL) {
  797. *errMsgPtr = noSuchVar;
  798. return NULL;
  799.     }
  800.     varPtr = (Var *) Tcl_GetHashValue(hPtr);
  801. }
  802.     }
  803.     return varPtr;
  804. }
  805. /*
  806.  *----------------------------------------------------------------------
  807.  *
  808.  * TclLookupArrayElement --
  809.  *
  810.  * This procedure is used to locate a variable which is in an array's 
  811.  *      hashtable given a pointer to the array's Var structure and the 
  812.  *      element's name.
  813.  *
  814.  * Results:
  815.  * The return value is a pointer to the variable structure , or NULL if 
  816.  *      the variable couldn't be found. 
  817.  *
  818.  *      If arrayPtr points to a variable that isn't an array and createPart1 
  819.  *      is 1, the corresponding variable will be converted to an array. 
  820.  *      Otherwise, NULL is returned and an error message is left in
  821.  * the interp's result if TCL_LEAVE_ERR_MSG is set in flags.
  822.  *
  823.  *      If the variable is not found and createPart2 is 1, the variable is
  824.  *      created. Otherwise, NULL is returned and an error message is left in
  825.  * the interp's result if TCL_LEAVE_ERR_MSG is set in flags.
  826.  *
  827.  * Note: it's possible for the variable returned to be VAR_UNDEFINED
  828.  * even if createPart1 or createPart2 are 1 (these only cause the hash
  829.  * table entry or array to be created). For example, the variable might
  830.  * be a global that has been unset but is still referenced by a
  831.  * procedure, or a variable that has been unset but it only being kept
  832.  * in existence (if VAR_UNDEFINED) by a trace.
  833.  *
  834.  * Side effects:
  835.  *      The variable at arrayPtr may be converted to be an array if 
  836.  *      createPart1 is 1. A new hashtable entry may be created if createPart2 
  837.  *      is 1.
  838.  *
  839.  *----------------------------------------------------------------------
  840.  */
  841. Var *
  842. TclLookupArrayElement(interp, arrayName, elName, flags, msg, createArray, createElem, arrayPtr)
  843.     Tcl_Interp *interp; /* Interpreter to use for lookup. */
  844.     CONST char *arrayName;         /* This is the name of the array. */
  845.     CONST char *elName; /* Name of element within array. */
  846.     CONST int flags; /* Only TCL_LEAVE_ERR_MSG bit matters. */
  847.     CONST char *msg; /* Verb to use in error messages, e.g.
  848.  * "read" or "set". Only needed if
  849.  * TCL_LEAVE_ERR_MSG is set in flags. */
  850.     CONST int createArray; /* If 1, transform arrayName to be an array
  851.  * if it isn't one yet and the transformation 
  852.  * is possible. If 0, return error if it 
  853.  * isn't already an array. */
  854.     CONST int createElem; /* If 1, create hash table entry for the 
  855.  * element, if it doesn't already exist. If
  856.  * 0, return error if it doesn't exist. */
  857.     Var *arrayPtr;         /* Pointer to the array's Var structure. */
  858. {
  859.     Tcl_HashEntry *hPtr;
  860.     int new;
  861.     Var *varPtr;
  862.     /*
  863.      * We're dealing with an array element. Make sure the variable is an
  864.      * array and look up the element (create the element if desired).
  865.      */
  866.     if (TclIsVarUndefined(arrayPtr) && !TclIsVarArrayElement(arrayPtr)) {
  867. if (!createArray) {
  868.     if (flags & TCL_LEAVE_ERR_MSG) {
  869. VarErrMsg(interp, arrayName, elName, msg, noSuchVar);
  870.     }
  871.     return NULL;
  872. }
  873. /*
  874.  * Make sure we are not resurrecting a namespace variable from a
  875.  * deleted namespace!
  876.  */
  877. if ((arrayPtr->flags & VAR_IN_HASHTABLE) && (arrayPtr->hPtr == NULL)) {
  878.     if (flags & TCL_LEAVE_ERR_MSG) {
  879. VarErrMsg(interp, arrayName, elName, msg, danglingVar);
  880.     }
  881.     return NULL;
  882. }
  883. TclSetVarArray(arrayPtr);
  884. TclClearVarUndefined(arrayPtr);
  885. arrayPtr->value.tablePtr =
  886.     (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  887. Tcl_InitHashTable(arrayPtr->value.tablePtr, TCL_STRING_KEYS);
  888.     } else if (!TclIsVarArray(arrayPtr)) {
  889. if (flags & TCL_LEAVE_ERR_MSG) {
  890.     VarErrMsg(interp, arrayName, elName, msg, needArray);
  891. }
  892. return NULL;
  893.     }
  894.     if (createElem) {
  895. hPtr = Tcl_CreateHashEntry(arrayPtr->value.tablePtr, elName, &new);
  896. if (new) {
  897.     if (arrayPtr->searchPtr != NULL) {
  898. DeleteSearches(arrayPtr);
  899.     }
  900.     varPtr = NewVar();
  901.     Tcl_SetHashValue(hPtr, varPtr);
  902.     varPtr->hPtr = hPtr;
  903.     varPtr->nsPtr = arrayPtr->nsPtr;
  904.     TclSetVarArrayElement(varPtr);
  905. }
  906.     } else {
  907. hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr, elName);
  908. if (hPtr == NULL) {
  909.     if (flags & TCL_LEAVE_ERR_MSG) {
  910. VarErrMsg(interp, arrayName, elName, msg, noSuchElement);
  911.     }
  912.     return NULL;
  913. }
  914.     }
  915.     return (Var *) Tcl_GetHashValue(hPtr);
  916. }
  917. /*
  918.  *----------------------------------------------------------------------
  919.  *
  920.  * Tcl_GetVar --
  921.  *
  922.  * Return the value of a Tcl variable as a string.
  923.  *
  924.  * Results:
  925.  * The return value points to the current value of varName as a string.
  926.  * If the variable is not defined or can't be read because of a clash
  927.  * in array usage then a NULL pointer is returned and an error message
  928.  * is left in the interp's result if the TCL_LEAVE_ERR_MSG flag is set.
  929.  * Note: the return value is only valid up until the next change to the
  930.  * variable; if you depend on the value lasting longer than that, then
  931.  * make yourself a private copy.
  932.  *
  933.  * Side effects:
  934.  * None.
  935.  *
  936.  *----------------------------------------------------------------------
  937.  */
  938. CONST char *
  939. Tcl_GetVar(interp, varName, flags)
  940.     Tcl_Interp *interp; /* Command interpreter in which varName is
  941.  * to be looked up. */
  942.     CONST char *varName; /* Name of a variable in interp. */
  943.     int flags; /* OR-ed combination of TCL_GLOBAL_ONLY,
  944.  * TCL_NAMESPACE_ONLY or TCL_LEAVE_ERR_MSG
  945.  * bits. */
  946. {
  947.     return Tcl_GetVar2(interp, varName, (char *) NULL, flags);
  948. }
  949. /*
  950.  *----------------------------------------------------------------------
  951.  *
  952.  * Tcl_GetVar2 --
  953.  *
  954.  * Return the value of a Tcl variable as a string, given a two-part
  955.  * name consisting of array name and element within array.
  956.  *
  957.  * Results:
  958.  * The return value points to the current value of the variable given
  959.  * by part1 and part2 as a string. If the specified variable doesn't
  960.  * exist, or if there is a clash in array usage, then NULL is returned
  961.  * and a message will be left in the interp's result if the
  962.  * TCL_LEAVE_ERR_MSG flag is set. Note: the return value is only valid
  963.  * up until the next change to the variable; if you depend on the value
  964.  * lasting longer than that, then make yourself a private copy.
  965.  *
  966.  * Side effects:
  967.  * None.
  968.  *
  969.  *----------------------------------------------------------------------
  970.  */
  971. CONST char *
  972. Tcl_GetVar2(interp, part1, part2, flags)
  973.     Tcl_Interp *interp; /* Command interpreter in which variable is
  974.  * to be looked up. */
  975.     CONST char *part1; /* Name of an array (if part2 is non-NULL)
  976.  * or the name of a variable. */
  977.     CONST char *part2; /* If non-NULL, gives the name of an element
  978.  * in the array part1. */
  979.     int flags; /* OR-ed combination of TCL_GLOBAL_ONLY,
  980.  * TCL_NAMESPACE_ONLY and TCL_LEAVE_ERR_MSG
  981.                                  * bits. */
  982. {
  983.     Tcl_Obj *objPtr;
  984.     objPtr = Tcl_GetVar2Ex(interp, part1, part2, flags);
  985.     if (objPtr == NULL) {
  986. return NULL;
  987.     }
  988.     return TclGetString(objPtr);
  989. }
  990. /*
  991.  *----------------------------------------------------------------------
  992.  *
  993.  * Tcl_GetVar2Ex --
  994.  *
  995.  * Return the value of a Tcl variable as a Tcl object, given a
  996.  * two-part name consisting of array name and element within array.
  997.  *
  998.  * Results:
  999.  * The return value points to the current object value of the variable
  1000.  * given by part1Ptr and part2Ptr. If the specified variable doesn't
  1001.  * exist, or if there is a clash in array usage, then NULL is returned
  1002.  * and a message will be left in the interpreter's result if the
  1003.  * TCL_LEAVE_ERR_MSG flag is set.
  1004.  *
  1005.  * Side effects:
  1006.  * The ref count for the returned object is _not_ incremented to
  1007.  * reflect the returned reference; if you want to keep a reference to
  1008.  * the object you must increment its ref count yourself.
  1009.  *
  1010.  *----------------------------------------------------------------------
  1011.  */
  1012. Tcl_Obj *
  1013. Tcl_GetVar2Ex(interp, part1, part2, flags)
  1014.     Tcl_Interp *interp; /* Command interpreter in which variable is
  1015.  * to be looked up. */
  1016.     CONST char *part1; /* Name of an array (if part2 is non-NULL)
  1017.  * or the name of a variable. */
  1018.     CONST char *part2; /* If non-NULL, gives the name of an element
  1019.  * in the array part1. */
  1020.     int flags; /* OR-ed combination of TCL_GLOBAL_ONLY,
  1021.  * and TCL_LEAVE_ERR_MSG bits. */
  1022. {
  1023.     Var *varPtr, *arrayPtr;
  1024.     /* Filter to pass through only the flags this interface supports. */
  1025.     flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG);
  1026.     varPtr = TclLookupVar(interp, part1, part2, flags, "read",
  1027.             /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr);
  1028.     if (varPtr == NULL) {
  1029. return NULL;
  1030.     }
  1031.     return TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags);
  1032. }
  1033. /*
  1034.  *----------------------------------------------------------------------
  1035.  *
  1036.  * Tcl_ObjGetVar2 --
  1037.  *
  1038.  * Return the value of a Tcl variable as a Tcl object, given a
  1039.  * two-part name consisting of array name and element within array.
  1040.  *
  1041.  * Results:
  1042.  * The return value points to the current object value of the variable
  1043.  * given by part1Ptr and part2Ptr. If the specified variable doesn't
  1044.  * exist, or if there is a clash in array usage, then NULL is returned
  1045.  * and a message will be left in the interpreter's result if the
  1046.  * TCL_LEAVE_ERR_MSG flag is set.
  1047.  *
  1048.  * Side effects:
  1049.  * The ref count for the returned object is _not_ incremented to
  1050.  * reflect the returned reference; if you want to keep a reference to
  1051.  * the object you must increment its ref count yourself.
  1052.  *
  1053.  *----------------------------------------------------------------------
  1054.  */
  1055. Tcl_Obj *
  1056. Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags)
  1057.     Tcl_Interp *interp; /* Command interpreter in which variable is
  1058.  * to be looked up. */
  1059.     register Tcl_Obj *part1Ptr; /* Points to an object holding the name of
  1060.  * an array (if part2 is non-NULL) or the
  1061.  * name of a variable. */
  1062.     register Tcl_Obj *part2Ptr; /* If non-null, points to an object holding
  1063.  * the name of an element in the array
  1064.  * part1Ptr. */
  1065.     int flags; /* OR-ed combination of TCL_GLOBAL_ONLY and
  1066.  * TCL_LEAVE_ERR_MSG bits. */
  1067. {
  1068.     Var *varPtr, *arrayPtr;
  1069.     char *part1, *part2;
  1070.     part1 = Tcl_GetString(part1Ptr);
  1071.     part2 = ((part2Ptr == NULL) ? NULL : Tcl_GetString(part2Ptr));
  1072.     
  1073.     /* Filter to pass through only the flags this interface supports. */
  1074.     flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG);
  1075.     varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "read",
  1076.             /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr);
  1077.     if (varPtr == NULL) {
  1078. return NULL;
  1079.     }
  1080.     return TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags);
  1081. }
  1082. /*
  1083.  *----------------------------------------------------------------------
  1084.  *
  1085.  * TclPtrGetVar --
  1086.  *
  1087.  * Return the value of a Tcl variable as a Tcl object, given the
  1088.  *      pointers to the variable's (and possibly containing array's) 
  1089.  *      VAR structure.
  1090.  *
  1091.  * Results:
  1092.  * The return value points to the current object value of the variable
  1093.  * given by varPtr. If the specified variable doesn't exist, or if there 
  1094.  *      is a clash in array usage, then NULL is returned and a message will be 
  1095.  *      left in the interpreter's result if the TCL_LEAVE_ERR_MSG flag is set.
  1096.  *
  1097.  * Side effects:
  1098.  * The ref count for the returned object is _not_ incremented to
  1099.  * reflect the returned reference; if you want to keep a reference to
  1100.  * the object you must increment its ref count yourself.
  1101.  *
  1102.  *----------------------------------------------------------------------
  1103.  */
  1104. Tcl_Obj *
  1105. TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags)
  1106.     Tcl_Interp *interp; /* Command interpreter in which variable is
  1107.  * to be looked up. */
  1108.     register Var *varPtr;       /* The variable to be read.*/
  1109.     Var *arrayPtr;              /* NULL for scalar variables, pointer to
  1110.  * the containing array otherwise. */
  1111.     CONST char *part1; /* Name of an array (if part2 is non-NULL)
  1112.  * or the name of a variable. */
  1113.     CONST char *part2; /* If non-NULL, gives the name of an element
  1114.  * in the array part1. */
  1115.     CONST int flags; /* OR-ed combination of TCL_GLOBAL_ONLY,
  1116.  * and TCL_LEAVE_ERR_MSG bits. */
  1117. {
  1118.     Interp *iPtr = (Interp *) interp;
  1119.     CONST char *msg;
  1120.     /*
  1121.      * Invoke any traces that have been set for the variable.
  1122.      */
  1123.     if ((varPtr->tracePtr != NULL)
  1124.     || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
  1125. if (TCL_ERROR == CallVarTraces(iPtr, arrayPtr, varPtr, part1, part2,
  1126. (flags & (TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY))
  1127. | TCL_TRACE_READS, (flags & TCL_LEAVE_ERR_MSG))) {
  1128.     goto errorReturn;
  1129. }
  1130.     }
  1131.     /*
  1132.      * Return the element if it's an existing scalar variable.
  1133.      */
  1134.     
  1135.     if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
  1136. return varPtr->value.objPtr;
  1137.     }
  1138.     
  1139.     if (flags & TCL_LEAVE_ERR_MSG) {
  1140. if (TclIsVarUndefined(varPtr) && (arrayPtr != NULL)
  1141.         && !TclIsVarUndefined(arrayPtr)) {
  1142.     msg = noSuchElement;
  1143. } else if (TclIsVarArray(varPtr)) {
  1144.     msg = isArray;
  1145. } else {
  1146.     msg = noSuchVar;
  1147. }
  1148. VarErrMsg(interp, part1, part2, "read", msg);
  1149.     }
  1150.     /*
  1151.      * An error. If the variable doesn't exist anymore and no-one's using
  1152.      * it, then free up the relevant structures and hash table entries.
  1153.      */
  1154.     errorReturn:
  1155.     if (TclIsVarUndefined(varPtr)) {
  1156. CleanupVar(varPtr, arrayPtr);
  1157.     }
  1158.     return NULL;
  1159. }
  1160. /*
  1161.  *----------------------------------------------------------------------
  1162.  *
  1163.  * Tcl_SetObjCmd --
  1164.  *
  1165.  * This procedure is invoked to process the "set" Tcl command.
  1166.  * See the user documentation for details on what it does.
  1167.  *
  1168.  * Results:
  1169.  * A standard Tcl result value.
  1170.  *
  1171.  * Side effects:
  1172.  * A variable's value may be changed.
  1173.  *
  1174.  *----------------------------------------------------------------------
  1175.  */
  1176. /* ARGSUSED */
  1177. int
  1178. Tcl_SetObjCmd(dummy, interp, objc, objv)
  1179.     ClientData dummy; /* Not used. */
  1180.     register Tcl_Interp *interp; /* Current interpreter. */
  1181.     int objc; /* Number of arguments. */
  1182.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  1183. {
  1184.     Tcl_Obj *varValueObj;
  1185.     if (objc == 2) {
  1186. varValueObj = Tcl_ObjGetVar2(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG);
  1187. if (varValueObj == NULL) {
  1188.     return TCL_ERROR;
  1189. }
  1190. Tcl_SetObjResult(interp, varValueObj);
  1191. return TCL_OK;
  1192.     } else if (objc == 3) {
  1193. varValueObj = Tcl_ObjSetVar2(interp, objv[1], NULL, objv[2],
  1194. TCL_LEAVE_ERR_MSG);
  1195. if (varValueObj == NULL) {
  1196.     return TCL_ERROR;
  1197. }
  1198. Tcl_SetObjResult(interp, varValueObj);
  1199. return TCL_OK;
  1200.     } else {
  1201. Tcl_WrongNumArgs(interp, 1, objv, "varName ?newValue?");
  1202. return TCL_ERROR;
  1203.     }
  1204. }
  1205. /*
  1206.  *----------------------------------------------------------------------
  1207.  *
  1208.  * Tcl_SetVar --
  1209.  *
  1210.  * Change the value of a variable.
  1211.  *
  1212.  * Results:
  1213.  * Returns a pointer to the malloc'ed string which is the character
  1214.  * representation of the variable's new value. The caller must not
  1215.  * modify this string. If the write operation was disallowed then NULL
  1216.  * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then an
  1217.  * explanatory message will be left in the interp's result. Note that the
  1218.  * returned string may not be the same as newValue; this is because
  1219.  * variable traces may modify the variable's value.
  1220.  *
  1221.  * Side effects:
  1222.  * If varName is defined as a local or global variable in interp,
  1223.  * its value is changed to newValue. If varName isn't currently
  1224.  * defined, then a new global variable by that name is created.
  1225.  *
  1226.  *----------------------------------------------------------------------
  1227.  */
  1228. CONST char *
  1229. Tcl_SetVar(interp, varName, newValue, flags)
  1230.     Tcl_Interp *interp; /* Command interpreter in which varName is
  1231.  * to be looked up. */
  1232.     CONST char *varName; /* Name of a variable in interp. */
  1233.     CONST char *newValue; /* New value for varName. */
  1234.     int flags; /* Various flags that tell how to set value:
  1235.  * any of TCL_GLOBAL_ONLY,
  1236.  * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
  1237.  * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG. */
  1238. {
  1239.     return Tcl_SetVar2(interp, varName, (char *) NULL, newValue, flags);
  1240. }
  1241. /*
  1242.  *----------------------------------------------------------------------
  1243.  *
  1244.  * Tcl_SetVar2 --
  1245.  *
  1246.  *      Given a two-part variable name, which may refer either to a
  1247.  *      scalar variable or an element of an array, change the value
  1248.  *      of the variable.  If the named scalar or array or element
  1249.  *      doesn't exist then create one.
  1250.  *
  1251.  * Results:
  1252.  * Returns a pointer to the malloc'ed string which is the character
  1253.  * representation of the variable's new value. The caller must not
  1254.  * modify this string. If the write operation was disallowed because an
  1255.  * array was expected but not found (or vice versa), then NULL is
  1256.  * returned; if the TCL_LEAVE_ERR_MSG flag is set, then an explanatory
  1257.  * message will be left in the interp's result. Note that the returned
  1258.  * string may not be the same as newValue; this is because variable
  1259.  * traces may modify the variable's value.
  1260.  *
  1261.  * Side effects:
  1262.  *      The value of the given variable is set. If either the array
  1263.  *      or the entry didn't exist then a new one is created.
  1264.  *
  1265.  *----------------------------------------------------------------------
  1266.  */
  1267. CONST char *
  1268. Tcl_SetVar2(interp, part1, part2, newValue, flags)
  1269.     Tcl_Interp *interp;         /* Command interpreter in which variable is
  1270.                                  * to be looked up. */
  1271.     CONST char *part1;          /* If part2 is NULL, this is name of scalar
  1272.                                  * variable. Otherwise it is the name of
  1273.                                  * an array. */
  1274.     CONST char *part2; /* Name of an element within an array, or
  1275.  * NULL. */
  1276.     CONST char *newValue;       /* New value for variable. */
  1277.     int flags;                  /* Various flags that tell how to set value:
  1278.  * any of TCL_GLOBAL_ONLY,
  1279.  * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
  1280.  * TCL_LIST_ELEMENT, or TCL_LEAVE_ERR_MSG */
  1281. {
  1282.     register Tcl_Obj *valuePtr;
  1283.     Tcl_Obj *varValuePtr;
  1284.     /*
  1285.      * Create an object holding the variable's new value and use
  1286.      * Tcl_SetVar2Ex to actually set the variable.
  1287.      */
  1288.     valuePtr = Tcl_NewStringObj(newValue, -1);
  1289.     Tcl_IncrRefCount(valuePtr);
  1290.     varValuePtr = Tcl_SetVar2Ex(interp, part1, part2, valuePtr, flags);
  1291.     Tcl_DecrRefCount(valuePtr); /* done with the object */
  1292.     
  1293.     if (varValuePtr == NULL) {
  1294. return NULL;
  1295.     }
  1296.     return TclGetString(varValuePtr);
  1297. }
  1298. /*
  1299.  *----------------------------------------------------------------------
  1300.  *
  1301.  * Tcl_SetVar2Ex --
  1302.  *
  1303.  * Given a two-part variable name, which may refer either to a scalar
  1304.  * variable or an element of an array, change the value of the variable
  1305.  * to a new Tcl object value. If the named scalar or array or element
  1306.  * doesn't exist then create one.
  1307.  *
  1308.  * Results:
  1309.  * Returns a pointer to the Tcl_Obj holding the new value of the
  1310.  * variable. If the write operation was disallowed because an array was
  1311.  * expected but not found (or vice versa), then NULL is returned; if
  1312.  * the TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will
  1313.  * be left in the interpreter's result. Note that the returned object
  1314.  * may not be the same one referenced by newValuePtr; this is because
  1315.  * variable traces may modify the variable's value.
  1316.  *
  1317.  * Side effects:
  1318.  * The value of the given variable is set. If either the array or the
  1319.  * entry didn't exist then a new variable is created.
  1320.  *
  1321.  * The reference count is decremented for any old value of the variable
  1322.  * and incremented for its new value. If the new value for the variable
  1323.  * is not the same one referenced by newValuePtr (perhaps as a result
  1324.  * of a variable trace), then newValuePtr's ref count is left unchanged
  1325.  * by Tcl_SetVar2Ex. newValuePtr's ref count is also left unchanged if
  1326.  * we are appending it as a string value: that is, if "flags" includes
  1327.  * TCL_APPEND_VALUE but not TCL_LIST_ELEMENT.
  1328.  *
  1329.  * The reference count for the returned object is _not_ incremented: if
  1330.  * you want to keep a reference to the object you must increment its
  1331.  * ref count yourself.
  1332.  *
  1333.  *----------------------------------------------------------------------
  1334.  */
  1335. Tcl_Obj *
  1336. Tcl_SetVar2Ex(interp, part1, part2, newValuePtr, flags)
  1337.     Tcl_Interp *interp; /* Command interpreter in which variable is
  1338.  * to be found. */
  1339.     CONST char *part1; /* Name of an array (if part2 is non-NULL)
  1340.  * or the name of a variable. */
  1341.     CONST char *part2; /* If non-NULL, gives the name of an element
  1342.  * in the array part1. */
  1343.     Tcl_Obj *newValuePtr; /* New value for variable. */
  1344.     int flags; /* Various flags that tell how to set value:
  1345.  * any of TCL_GLOBAL_ONLY,
  1346.  * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
  1347.  * TCL_LIST_ELEMENT or TCL_LEAVE_ERR_MSG. */
  1348. {
  1349.     Var *varPtr, *arrayPtr;
  1350.     /* Filter to pass through only the flags this interface supports. */
  1351.     flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG
  1352.     |TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
  1353.     varPtr = TclLookupVar(interp, part1, part2, flags, "set",
  1354.     /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
  1355.     if (varPtr == NULL) {
  1356. return NULL;
  1357.     }
  1358.     return TclPtrSetVar(interp, varPtr, arrayPtr, part1, part2, 
  1359.             newValuePtr, flags);
  1360. }
  1361. /*
  1362.  *----------------------------------------------------------------------
  1363.  *
  1364.  * Tcl_ObjSetVar2 --
  1365.  *
  1366.  * This function is the same as Tcl_SetVar2Ex above, except the
  1367.  * variable names are passed in Tcl object instead of strings.
  1368.  *
  1369.  * Results:
  1370.  * Returns a pointer to the Tcl_Obj holding the new value of the
  1371.  * variable. If the write operation was disallowed because an array was
  1372.  * expected but not found (or vice versa), then NULL is returned; if
  1373.  * the TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will
  1374.  * be left in the interpreter's result. Note that the returned object
  1375.  * may not be the same one referenced by newValuePtr; this is because
  1376.  * variable traces may modify the variable's value.
  1377.  *
  1378.  * Side effects:
  1379.  * The value of the given variable is set. If either the array or the
  1380.  * entry didn't exist then a new variable is created.
  1381.  *
  1382.  *----------------------------------------------------------------------
  1383.  */
  1384. Tcl_Obj *
  1385. Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, newValuePtr, flags)
  1386.     Tcl_Interp *interp; /* Command interpreter in which variable is
  1387.  * to be found. */
  1388.     register Tcl_Obj *part1Ptr; /* Points to an object holding the name of
  1389.  * an array (if part2 is non-NULL) or the
  1390.  * name of a variable. */
  1391.     register Tcl_Obj *part2Ptr; /* If non-null, points to an object holding
  1392.  * the name of an element in the array
  1393.  * part1Ptr. */
  1394.     Tcl_Obj *newValuePtr; /* New value for variable. */
  1395.     int flags; /* Various flags that tell how to set value:
  1396.  * any of TCL_GLOBAL_ONLY,
  1397.  * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
  1398.  * TCL_LIST_ELEMENT, or TCL_LEAVE_ERR_MSG. */
  1399. {
  1400.     Var *varPtr, *arrayPtr;
  1401.     char *part1, *part2;
  1402.     part1 = TclGetString(part1Ptr);
  1403.     part2 = ((part2Ptr == NULL) ? NULL : Tcl_GetString(part2Ptr));    
  1404.     /* Filter to pass through only the flags this interface supports. */
  1405.     flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG
  1406.     |TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
  1407.     varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "set",
  1408.     /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
  1409.     if (varPtr == NULL) {
  1410. return NULL;
  1411.     }
  1412.     return TclPtrSetVar(interp, varPtr, arrayPtr, part1, part2, 
  1413.             newValuePtr, flags);
  1414. }
  1415. /*
  1416.  *----------------------------------------------------------------------
  1417.  *
  1418.  * TclPtrSetVar --
  1419.  *
  1420.  * This function is the same as Tcl_SetVar2Ex above, except that
  1421.  *      it requires pointers to the variable's Var structs in addition
  1422.  * to the variable names.
  1423.  *
  1424.  * Results:
  1425.  * Returns a pointer to the Tcl_Obj holding the new value of the
  1426.  * variable. If the write operation was disallowed because an array was
  1427.  * expected but not found (or vice versa), then NULL is returned; if
  1428.  * the TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will
  1429.  * be left in the interpreter's result. Note that the returned object
  1430.  * may not be the same one referenced by newValuePtr; this is because
  1431.  * variable traces may modify the variable's value.
  1432.  *
  1433.  * Side effects:
  1434.  * The value of the given variable is set. If either the array or the
  1435.  * entry didn't exist then a new variable is created.
  1436.  *
  1437.  *----------------------------------------------------------------------
  1438.  */
  1439. Tcl_Obj *
  1440. TclPtrSetVar(interp, varPtr, arrayPtr, part1, part2, newValuePtr, flags)
  1441.     Tcl_Interp *interp; /* Command interpreter in which variable is
  1442.  * to be looked up. */
  1443.     register Var *varPtr;
  1444.     Var *arrayPtr;
  1445.     CONST char *part1; /* Name of an array (if part2 is non-NULL)
  1446.  * or the name of a variable. */
  1447.     CONST char *part2; /* If non-NULL, gives the name of an element
  1448.  * in the array part1. */
  1449.     Tcl_Obj *newValuePtr; /* New value for variable. */
  1450.     CONST int flags; /* OR-ed combination of TCL_GLOBAL_ONLY,
  1451.  * and TCL_LEAVE_ERR_MSG bits. */
  1452. {
  1453.     Interp *iPtr = (Interp *) interp;
  1454.     Tcl_Obj *oldValuePtr;
  1455.     Tcl_Obj *resultPtr = NULL;
  1456.     int result;
  1457.     /*
  1458.      * If the variable is in a hashtable and its hPtr field is NULL, then we
  1459.      * may have an upvar to an array element where the array was deleted
  1460.      * or an upvar to a namespace variable whose namespace was deleted.
  1461.      * Generate an error (allowing the variable to be reset would screw up
  1462.      * our storage allocation and is meaningless anyway).
  1463.      */
  1464.     if ((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL)) {
  1465. if (flags & TCL_LEAVE_ERR_MSG) {
  1466.     if (TclIsVarArrayElement(varPtr)) {
  1467. VarErrMsg(interp, part1, part2, "set", danglingElement);
  1468.     } else {
  1469. VarErrMsg(interp, part1, part2, "set", danglingVar);
  1470.     }
  1471. }
  1472. return NULL;
  1473.     }
  1474.     /*
  1475.      * It's an error to try to set an array variable itself.
  1476.      */
  1477.     if (TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
  1478. if (flags & TCL_LEAVE_ERR_MSG) {
  1479.     VarErrMsg(interp, part1, part2, "set", isArray);
  1480. }
  1481. return NULL;
  1482.     }
  1483.     /*
  1484.      * Invoke any read traces that have been set for the variable if it
  1485.      * is requested; this is only done in the core by the INST_LAPPEND_*
  1486.      * instructions.
  1487.      */
  1488.     if ((flags & TCL_TRACE_READS) && ((varPtr->tracePtr != NULL) 
  1489.     || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL)))) {
  1490. if (TCL_ERROR == CallVarTraces(iPtr, arrayPtr, varPtr, part1, part2,
  1491. TCL_TRACE_READS, (flags & TCL_LEAVE_ERR_MSG))) {
  1492.     return NULL;
  1493. }
  1494.     }
  1495.     /*
  1496.      * Set the variable's new value. If appending, append the new value to
  1497.      * the variable, either as a list element or as a string. Also, if
  1498.      * appending, then if the variable's old value is unshared we can modify
  1499.      * it directly, otherwise we must create a new copy to modify: this is
  1500.      * "copy on write".
  1501.      */
  1502.     if (flags & TCL_LIST_ELEMENT && !(flags & TCL_APPEND_VALUE)) {
  1503. TclSetVarUndefined(varPtr);
  1504.     }
  1505.     oldValuePtr = varPtr->value.objPtr;
  1506.     if (flags & (TCL_APPEND_VALUE|TCL_LIST_ELEMENT)) {
  1507. if (TclIsVarUndefined(varPtr) && (oldValuePtr != NULL)) {
  1508.     Tcl_DecrRefCount(oldValuePtr);     /* discard old value */
  1509.     varPtr->value.objPtr = NULL;
  1510.     oldValuePtr = NULL;
  1511. }
  1512. if (flags & TCL_LIST_ELEMENT) {        /* append list element */
  1513.     if (oldValuePtr == NULL) {
  1514. TclNewObj(oldValuePtr);
  1515. varPtr->value.objPtr = oldValuePtr;
  1516. Tcl_IncrRefCount(oldValuePtr); /* since var is referenced */
  1517.     } else if (Tcl_IsShared(oldValuePtr)) {
  1518. varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr);
  1519. Tcl_DecrRefCount(oldValuePtr);
  1520. oldValuePtr = varPtr->value.objPtr;
  1521. Tcl_IncrRefCount(oldValuePtr); /* since var is referenced */
  1522.     }
  1523.     result = Tcl_ListObjAppendElement(interp, oldValuePtr,
  1524.     newValuePtr);
  1525.     if (result != TCL_OK) {
  1526. return NULL;
  1527.     }
  1528. } else {                /* append string */
  1529.     /*
  1530.      * We append newValuePtr's bytes but don't change its ref count.
  1531.      */
  1532.     if (oldValuePtr == NULL) {
  1533. varPtr->value.objPtr = newValuePtr;
  1534. Tcl_IncrRefCount(newValuePtr);
  1535.     } else {
  1536. if (Tcl_IsShared(oldValuePtr)) {   /* append to copy */
  1537.     varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr);
  1538.     TclDecrRefCount(oldValuePtr);
  1539.     oldValuePtr = varPtr->value.objPtr;
  1540.     Tcl_IncrRefCount(oldValuePtr); /* since var is ref */
  1541. }
  1542. Tcl_AppendObjToObj(oldValuePtr, newValuePtr);
  1543.     }
  1544. }
  1545.     } else if (newValuePtr != oldValuePtr) {
  1546. /*
  1547.  * In this case we are replacing the value, so we don't need to
  1548.  * do more than swap the objects.
  1549.  */
  1550. varPtr->value.objPtr = newValuePtr;
  1551. Tcl_IncrRefCount(newValuePtr);      /* var is another ref */
  1552. if (oldValuePtr != NULL) {
  1553.     TclDecrRefCount(oldValuePtr);   /* discard old value */
  1554. }
  1555.     }
  1556.     TclSetVarScalar(varPtr);
  1557.     TclClearVarUndefined(varPtr);
  1558.     if (arrayPtr != NULL) {
  1559. TclClearVarUndefined(arrayPtr);
  1560.     }
  1561.     /*
  1562.      * Invoke any write traces for the variable.
  1563.      */
  1564.     if ((varPtr->tracePtr != NULL)
  1565.     || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
  1566. if (TCL_ERROR == CallVarTraces(iPtr, arrayPtr, varPtr, part1, part2,
  1567.         (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY))
  1568. | TCL_TRACE_WRITES, (flags & TCL_LEAVE_ERR_MSG))) {
  1569.     goto cleanup;
  1570. }
  1571.     }
  1572.     /*
  1573.      * Return the variable's value unless the variable was changed in some
  1574.      * gross way by a trace (e.g. it was unset and then recreated as an
  1575.      * array). 
  1576.      */
  1577.     if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
  1578. return varPtr->value.objPtr;
  1579.     }
  1580.     /*
  1581.      * A trace changed the value in some gross way. Return an empty string
  1582.      * object.
  1583.      */
  1584.     
  1585.     resultPtr = iPtr->emptyObjPtr;
  1586.     /*
  1587.      * If the variable doesn't exist anymore and no-one's using it, then
  1588.      * free up the relevant structures and hash table entries.
  1589.      */
  1590.     cleanup:
  1591.     if (TclIsVarUndefined(varPtr)) {
  1592. CleanupVar(varPtr, arrayPtr);
  1593.     }
  1594.     return resultPtr;
  1595. }
  1596. /*
  1597.  *----------------------------------------------------------------------
  1598.  *
  1599.  * TclIncrVar2 --
  1600.  *
  1601.  * Given a two-part variable name, which may refer either to a scalar
  1602.  * variable or an element of an array, increment the Tcl object value
  1603.  * of the variable by a specified amount.
  1604.  *
  1605.  * Results:
  1606.  * Returns a pointer to the Tcl_Obj holding the new value of the
  1607.  * variable. If the specified variable doesn't exist, or there is a
  1608.  * clash in array usage, or an error occurs while executing variable
  1609.  * traces, then NULL is returned and a message will be left in
  1610.  * the interpreter's result.
  1611.  *
  1612.  * Side effects:
  1613.  * The value of the given variable is incremented by the specified
  1614.  * amount. If either the array or the entry didn't exist then a new
  1615.  * variable is created. The ref count for the returned object is _not_
  1616.  * incremented to reflect the returned reference; if you want to keep a
  1617.  * reference to the object you must increment its ref count yourself.
  1618.  *
  1619.  *----------------------------------------------------------------------
  1620.  */
  1621. Tcl_Obj *
  1622. TclIncrVar2(interp, part1Ptr, part2Ptr, incrAmount, flags)
  1623.     Tcl_Interp *interp; /* Command interpreter in which variable is
  1624.  * to be found. */
  1625.     Tcl_Obj *part1Ptr; /* Points to an object holding the name of
  1626.  * an array (if part2 is non-NULL) or the
  1627.  * name of a variable. */
  1628.     Tcl_Obj *part2Ptr; /* If non-null, points to an object holding
  1629.  * the name of an element in the array
  1630.  * part1Ptr. */
  1631.     long incrAmount; /* Amount to be added to variable. */
  1632.     int flags;                  /* Various flags that tell how to incr value:
  1633.  * any of TCL_GLOBAL_ONLY,
  1634.  * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
  1635.  * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG. */
  1636. {
  1637.     Var *varPtr, *arrayPtr;
  1638.     char *part1, *part2;
  1639.     part1 = TclGetString(part1Ptr);
  1640.     part2 = ((part2Ptr == NULL)? NULL : TclGetString(part2Ptr));
  1641.     varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "read",
  1642.     0, 1, &arrayPtr);
  1643.     if (varPtr == NULL) {
  1644. Tcl_AddObjErrorInfo(interp,
  1645. "n    (reading value of variable to increment)", -1);
  1646. return NULL;
  1647.     }
  1648.     return TclPtrIncrVar(interp, varPtr, arrayPtr, part1, part2,
  1649.     incrAmount, flags);
  1650. }
  1651. /*
  1652.  *----------------------------------------------------------------------
  1653.  *
  1654.  * TclPtrIncrVar --
  1655.  *
  1656.  * Given the pointers to a variable and possible containing array, 
  1657.  *      increment the Tcl object value of the variable by a specified 
  1658.  *      amount.
  1659.  *
  1660.  * Results:
  1661.  * Returns a pointer to the Tcl_Obj holding the new value of the
  1662.  * variable. If the specified variable doesn't exist, or there is a
  1663.  * clash in array usage, or an error occurs while executing variable
  1664.  * traces, then NULL is returned and a message will be left in
  1665.  * the interpreter's result.
  1666.  *
  1667.  * Side effects:
  1668.  * The value of the given variable is incremented by the specified
  1669.  * amount. If either the array or the entry didn't exist then a new
  1670.  * variable is created. The ref count for the returned object is _not_
  1671.  * incremented to reflect the returned reference; if you want to keep a
  1672.  * reference to the object you must increment its ref count yourself.
  1673.  *
  1674.  *----------------------------------------------------------------------
  1675.  */
  1676. Tcl_Obj *
  1677. TclPtrIncrVar(interp, varPtr, arrayPtr, part1, part2, incrAmount, flags)
  1678.     Tcl_Interp *interp; /* Command interpreter in which variable is
  1679.  * to be found. */
  1680.     Var *varPtr;
  1681.     Var *arrayPtr;
  1682.     CONST char *part1; /* Points to an object holding the name of
  1683.  * an array (if part2 is non-NULL) or the
  1684.  * name of a variable. */
  1685.     CONST char *part2; /* If non-null, points to an object holding
  1686.  * the name of an element in the array
  1687.  * part1Ptr. */
  1688.     CONST long incrAmount; /* Amount to be added to variable. */
  1689.     CONST int flags;            /* Various flags that tell how to incr value:
  1690.  * any of TCL_GLOBAL_ONLY,
  1691.  * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
  1692.  * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG. */
  1693. {
  1694.     register Tcl_Obj *varValuePtr;
  1695.     int createdNewObj; /* Set 1 if var's value object is shared
  1696.  * so we must increment a copy (i.e. copy
  1697.  * on write). */
  1698.     long i;
  1699.     varValuePtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags);
  1700.     if (varValuePtr == NULL) {
  1701. Tcl_AddObjErrorInfo(interp,
  1702. "n    (reading value of variable to increment)", -1);
  1703. return NULL;
  1704.     }
  1705.     /*
  1706.      * Increment the variable's value. If the object is unshared we can
  1707.      * modify it directly, otherwise we must create a new copy to modify:
  1708.      * this is "copy on write". Then free the variable's old string
  1709.      * representation, if any, since it will no longer be valid.
  1710.      */
  1711.     createdNewObj = 0;
  1712.     if (Tcl_IsShared(varValuePtr)) {
  1713. varValuePtr = Tcl_DuplicateObj(varValuePtr);
  1714. createdNewObj = 1;
  1715.     }
  1716.     if (varValuePtr->typePtr == &tclWideIntType) {
  1717. Tcl_WideInt wide;
  1718. TclGetWide(wide,varValuePtr);
  1719. Tcl_SetWideIntObj(varValuePtr, wide + Tcl_LongAsWide(incrAmount));
  1720.     } else if (varValuePtr->typePtr == &tclIntType) {
  1721. i = varValuePtr->internalRep.longValue;
  1722. Tcl_SetIntObj(varValuePtr, i + incrAmount);
  1723.     } else {
  1724. /*
  1725.  * Not an integer or wide internal-rep...
  1726.  */
  1727. Tcl_WideInt wide;
  1728. if (Tcl_GetWideIntFromObj(interp, varValuePtr, &wide) != TCL_OK) {
  1729.     if (createdNewObj) {
  1730. Tcl_DecrRefCount(varValuePtr); /* free unneeded copy */
  1731.     }
  1732.     return NULL;
  1733. }
  1734. if (wide <= Tcl_LongAsWide(LONG_MAX)
  1735. && wide >= Tcl_LongAsWide(LONG_MIN)) {
  1736.     Tcl_SetLongObj(varValuePtr, Tcl_WideAsLong(wide) + incrAmount);
  1737. } else {
  1738.     Tcl_SetWideIntObj(varValuePtr, wide + Tcl_LongAsWide(incrAmount));
  1739. }
  1740.     }
  1741.     /*
  1742.      * Store the variable's new value and run any write traces.
  1743.      */
  1744.     
  1745.     return TclPtrSetVar(interp, varPtr, arrayPtr, part1, part2,
  1746.     varValuePtr, flags);
  1747. }
  1748. /*
  1749.  *----------------------------------------------------------------------
  1750.  *
  1751.  * Tcl_UnsetVar --
  1752.  *
  1753.  * Delete a variable, so that it may not be accessed anymore.
  1754.  *
  1755.  * Results:
  1756.  * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR
  1757.  * if the variable can't be unset.  In the event of an error,
  1758.  * if the TCL_LEAVE_ERR_MSG flag is set then an error message
  1759.  * is left in the interp's result.
  1760.  *
  1761.  * Side effects:
  1762.  * If varName is defined as a local or global variable in interp,
  1763.  * it is deleted.
  1764.  *
  1765.  *----------------------------------------------------------------------
  1766.  */
  1767. int
  1768. Tcl_UnsetVar(interp, varName, flags)
  1769.     Tcl_Interp *interp; /* Command interpreter in which varName is
  1770.  * to be looked up. */
  1771.     CONST char *varName; /* Name of a variable in interp.  May be
  1772.  * either a scalar name or an array name
  1773.  * or an element in an array. */
  1774.     int flags; /* OR-ed combination of any of
  1775.  * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY or
  1776.  * TCL_LEAVE_ERR_MSG. */
  1777. {
  1778.     return Tcl_UnsetVar2(interp, varName, (char *) NULL, flags);
  1779. }
  1780. /*
  1781.  *----------------------------------------------------------------------
  1782.  *
  1783.  * Tcl_UnsetVar2 --
  1784.  *
  1785.  * Delete a variable, given a 2-part name.
  1786.  *
  1787.  * Results:
  1788.  * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR
  1789.  * if the variable can't be unset.  In the event of an error,
  1790.  * if the TCL_LEAVE_ERR_MSG flag is set then an error message
  1791.  * is left in the interp's result.
  1792.  *
  1793.  * Side effects:
  1794.  * If part1 and part2 indicate a local or global variable in interp,
  1795.  * it is deleted.  If part1 is an array name and part2 is NULL, then
  1796.  * the whole array is deleted.
  1797.  *
  1798.  *----------------------------------------------------------------------
  1799.  */
  1800. int
  1801. Tcl_UnsetVar2(interp, part1, part2, flags)
  1802.     Tcl_Interp *interp; /* Command interpreter in which varName is
  1803.  * to be looked up. */
  1804.     CONST char *part1; /* Name of variable or array. */
  1805.     CONST char *part2; /* Name of element within array or NULL. */
  1806.     int flags; /* OR-ed combination of any of
  1807.  * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
  1808.  * TCL_LEAVE_ERR_MSG. */
  1809. {
  1810.     int result;
  1811.     Tcl_Obj *part1Ptr;
  1812.     part1Ptr = Tcl_NewStringObj(part1, -1);
  1813.     Tcl_IncrRefCount(part1Ptr);
  1814.     /* Filter to pass through only the flags this interface supports. */
  1815.     flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG);
  1816.     result = TclObjUnsetVar2(interp, part1Ptr, part2, flags);
  1817.     TclDecrRefCount(part1Ptr);
  1818.     return result;
  1819. }
  1820. /*
  1821.  *----------------------------------------------------------------------
  1822.  *
  1823.  * TclObjUnsetVar2 --
  1824.  *
  1825.  * Delete a variable, given a 2-object name.
  1826.  *
  1827.  * Results:
  1828.  * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR
  1829.  * if the variable can't be unset.  In the event of an error,
  1830.  * if the TCL_LEAVE_ERR_MSG flag is set then an error message
  1831.  * is left in the interp's result.
  1832.  *
  1833.  * Side effects:
  1834.  * If part1ptr and part2Ptr indicate a local or global variable in interp,
  1835.  * it is deleted.  If part1Ptr is an array name and part2Ptr is NULL, then
  1836.  * the whole array is deleted.
  1837.  *
  1838.  *----------------------------------------------------------------------
  1839.  */
  1840. int
  1841. TclObjUnsetVar2(interp, part1Ptr, part2, flags)
  1842.     Tcl_Interp *interp; /* Command interpreter in which varName is
  1843.  * to be looked up. */
  1844.     Tcl_Obj *part1Ptr; /* Name of variable or array. */
  1845.     CONST char *part2; /* Name of element within array or NULL. */
  1846.     int flags; /* OR-ed combination of any of
  1847.  * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
  1848.  * TCL_LEAVE_ERR_MSG. */
  1849. {
  1850.     Var *varPtr;
  1851.     Interp *iPtr = (Interp *) interp;
  1852.     Var *arrayPtr;
  1853.     int result;
  1854.     char *part1;
  1855.     part1 = TclGetString(part1Ptr);
  1856.     varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "unset",
  1857.     /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
  1858.     if (varPtr == NULL) {
  1859. return TCL_ERROR;
  1860.     }
  1861.  
  1862.     result = (TclIsVarUndefined(varPtr)? TCL_ERROR : TCL_OK);
  1863.     /*
  1864.      * Keep the variable alive until we're done with it. We used to
  1865.      * increase/decrease the refCount for each operation, making it
  1866.      * hard to find [Bug 735335] - caused by unsetting the variable
  1867.      * whose value was the variable's name.
  1868.      */
  1869.     
  1870.     varPtr->refCount++;
  1871.     UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags);
  1872.     /*
  1873.      * It's an error to unset an undefined variable.
  1874.      */
  1875.     if (result != TCL_OK) {
  1876. if (flags & TCL_LEAVE_ERR_MSG) {
  1877.     VarErrMsg(interp, part1, part2, "unset", 
  1878.     ((arrayPtr == NULL) ? noSuchVar : noSuchElement));
  1879. }
  1880.     }
  1881.     /*
  1882.      * Try to avoid keeping the Var struct allocated due to a tclNsVarNameType 
  1883.      * keeping a reference. This removes some additional exteriorisations of
  1884.      * [Bug 736729], but may be a good thing independently of the bug.
  1885.      */
  1886.     if (part1Ptr->typePtr == &tclNsVarNameType) {
  1887. part1Ptr->typePtr->freeIntRepProc(part1Ptr);
  1888. part1Ptr->typePtr = NULL;
  1889.     }
  1890.     /*
  1891.      * Finally, if the variable is truly not in use then free up its Var
  1892.      * structure and remove it from its hash table, if any. The ref count of
  1893.      * its value object, if any, was decremented above.
  1894.      */
  1895.     varPtr->refCount--;
  1896.     CleanupVar(varPtr, arrayPtr);
  1897.     return result;
  1898. }
  1899. /*
  1900.  *----------------------------------------------------------------------
  1901.  *
  1902.  * UnsetVarStruct --
  1903.  *
  1904.  * Unset and delete a variable. This does the internal work for
  1905.  * TclObjUnsetVar2 and TclDeleteNamespaceVars, which call here for each
  1906.  * variable to be unset and deleted.
  1907.  *
  1908.  * Results:
  1909.  * None.
  1910.  *
  1911.  * Side effects:
  1912.  * If the arguments indicate a local or global variable in iPtr, it is
  1913.  *      unset and deleted.   
  1914.  *
  1915.  *----------------------------------------------------------------------
  1916.  */
  1917. static void
  1918. UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags)
  1919.     Var *varPtr;
  1920.     Var *arrayPtr;
  1921.     Interp *iPtr;
  1922.     CONST char *part1;
  1923.     CONST char *part2;
  1924.     int flags;
  1925. {
  1926.     Var dummyVar;
  1927.     Var *dummyVarPtr;
  1928.     ActiveVarTrace *activePtr;
  1929.     if ((arrayPtr != NULL) && (arrayPtr->searchPtr != NULL)) {
  1930. DeleteSearches(arrayPtr);
  1931.     }
  1932.     /*
  1933.      * For global/upvar variables referenced in procedures, decrement
  1934.      * the reference count on the variable referred to, and free
  1935.      * the referenced variable if it's no longer needed. 
  1936.      */
  1937.     if (TclIsVarLink(varPtr)) {
  1938. Var *linkPtr = varPtr->value.linkPtr;
  1939. linkPtr->refCount--;
  1940. if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr)
  1941. && (linkPtr->tracePtr == NULL)
  1942. && (linkPtr->flags & VAR_IN_HASHTABLE)) {
  1943.     if (linkPtr->hPtr != NULL) {
  1944. Tcl_DeleteHashEntry(linkPtr->hPtr);
  1945.     }
  1946.     ckfree((char *) linkPtr);
  1947. }
  1948.     }
  1949.     /*
  1950.      * The code below is tricky, because of the possibility that
  1951.      * a trace procedure might try to access a variable being
  1952.      * deleted. To handle this situation gracefully, do things
  1953.      * in three steps:
  1954.      * 1. Copy the contents of the variable to a dummy variable
  1955.      *    structure, and mark the original Var structure as undefined.
  1956.      * 2. Invoke traces and clean up the variable, using the dummy copy.
  1957.      * 3. If at the end of this the original variable is still
  1958.      *    undefined and has no outstanding references, then delete
  1959.      *   it (but it could have gotten recreated by a trace).
  1960.      */
  1961.     dummyVar = *varPtr;
  1962.     TclSetVarUndefined(varPtr);
  1963.     TclSetVarScalar(varPtr);
  1964.     varPtr->value.objPtr = NULL; /* dummyVar points to any value object */
  1965.     varPtr->tracePtr = NULL;
  1966.     varPtr->searchPtr = NULL;
  1967.     /*
  1968.      * Call trace procedures for the variable being deleted. Then delete
  1969.      * its traces. Be sure to abort any other traces for the variable
  1970.      * that are still pending. Special tricks:
  1971.      * 1. We need to increment varPtr's refCount around this: CallVarTraces
  1972.      *    will use dummyVar so it won't increment varPtr's refCount itself.
  1973.      * 2. Turn off the VAR_TRACE_ACTIVE flag in dummyVar: we want to
  1974.      *    call unset traces even if other traces are pending.
  1975.      */
  1976.     if ((dummyVar.tracePtr != NULL)
  1977.     || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
  1978. dummyVar.flags &= ~VAR_TRACE_ACTIVE;
  1979. CallVarTraces(iPtr, arrayPtr, &dummyVar, part1, part2,
  1980. (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY))
  1981. | TCL_TRACE_UNSETS, /* leaveErrMsg */ 0);
  1982. while (dummyVar.tracePtr != NULL) {
  1983.     VarTrace *tracePtr = dummyVar.tracePtr;
  1984.     dummyVar.tracePtr = tracePtr->nextPtr;
  1985.     Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC);
  1986. }
  1987. for (activePtr = iPtr->activeVarTracePtr;  activePtr != NULL;
  1988.      activePtr = activePtr->nextPtr) {
  1989.     if (activePtr->varPtr == varPtr) {
  1990. activePtr->nextTracePtr = NULL;
  1991.     }
  1992. }
  1993.     }
  1994.     /*
  1995.      * If the variable is an array, delete all of its elements. This must be
  1996.      * done after calling the traces on the array, above (that's the way
  1997.      * traces are defined). If it is a scalar, "discard" its object
  1998.      * (decrement the ref count of its object, if any).
  1999.      */
  2000.     dummyVarPtr = &dummyVar;
  2001.     if (TclIsVarArray(dummyVarPtr) && !TclIsVarUndefined(dummyVarPtr)) {
  2002. DeleteArray(iPtr, part1, dummyVarPtr, (flags
  2003. & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS);
  2004.     }
  2005.     if (TclIsVarScalar(dummyVarPtr)
  2006.     && (dummyVarPtr->value.objPtr != NULL)) {
  2007. Tcl_Obj *objPtr = dummyVarPtr->value.objPtr;
  2008. TclDecrRefCount(objPtr);
  2009. dummyVarPtr->value.objPtr = NULL;
  2010.     }
  2011.     /*
  2012.      * If the variable was a namespace variable, decrement its reference count.
  2013.      */
  2014.     
  2015.     if (varPtr->flags & VAR_NAMESPACE_VAR) {
  2016. varPtr->flags &= ~VAR_NAMESPACE_VAR;
  2017. varPtr->refCount--;
  2018.     }
  2019. }
  2020. /*
  2021.  *----------------------------------------------------------------------
  2022.  *
  2023.  * Tcl_TraceVar --
  2024.  *
  2025.  * Arrange for reads and/or writes to a variable to cause a
  2026.  * procedure to be invoked, which can monitor the operations
  2027.  * and/or change their actions.
  2028.  *
  2029.  * Results:
  2030.  * A standard Tcl return value.
  2031.  *
  2032.  * Side effects:
  2033.  * A trace is set up on the variable given by varName, such that
  2034.  * future references to the variable will be intermediated by
  2035.  * proc.  See the manual entry for complete details on the calling
  2036.  * sequence for proc.
  2037.  *
  2038.  *----------------------------------------------------------------------
  2039.  */
  2040. int
  2041. Tcl_TraceVar(interp, varName, flags, proc, clientData)
  2042.     Tcl_Interp *interp; /* Interpreter in which variable is
  2043.  * to be traced. */
  2044.     CONST char *varName; /* Name of variable;  may end with "(index)"
  2045.  * to signify an array reference. */
  2046.     int flags; /* OR-ed collection of bits, including any
  2047.  * of TCL_TRACE_READS, TCL_TRACE_WRITES,
  2048.  * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY, and
  2049.  * TCL_NAMESPACE_ONLY. */
  2050.     Tcl_VarTraceProc *proc; /* Procedure to call when specified ops are
  2051.  * invoked upon varName. */
  2052.     ClientData clientData; /* Arbitrary argument to pass to proc. */
  2053. {
  2054.     return Tcl_TraceVar2(interp, varName, (char *) NULL, 
  2055.     flags, proc, clientData);
  2056. }
  2057. /*
  2058.  *----------------------------------------------------------------------
  2059.  *
  2060.  * Tcl_TraceVar2 --
  2061.  *
  2062.  * Arrange for reads and/or writes to a variable to cause a
  2063.  * procedure to be invoked, which can monitor the operations
  2064.  * and/or change their actions.
  2065.  *
  2066.  * Results:
  2067.  * A standard Tcl return value.
  2068.  *
  2069.  * Side effects:
  2070.  * A trace is set up on the variable given by part1 and part2, such
  2071.  * that future references to the variable will be intermediated by
  2072.  * proc.  See the manual entry for complete details on the calling
  2073.  * sequence for proc.
  2074.  *
  2075.  *----------------------------------------------------------------------
  2076.  */
  2077. int
  2078. Tcl_TraceVar2(interp, part1, part2, flags, proc, clientData)
  2079.     Tcl_Interp *interp; /* Interpreter in which variable is
  2080.  * to be traced. */
  2081.     CONST char *part1; /* Name of scalar variable or array. */
  2082.     CONST char *part2; /* Name of element within array;  NULL means
  2083.  * trace applies to scalar variable or array
  2084.  * as-a-whole. */
  2085.     int flags; /* OR-ed collection of bits, including any
  2086.  * of TCL_TRACE_READS, TCL_TRACE_WRITES,
  2087.  * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY,
  2088.  * and TCL_NAMESPACE_ONLY. */
  2089.     Tcl_VarTraceProc *proc; /* Procedure to call when specified ops are
  2090.  * invoked upon varName. */
  2091.     ClientData clientData; /* Arbitrary argument to pass to proc. */
  2092. {
  2093.     Var *varPtr, *arrayPtr;
  2094.     register VarTrace *tracePtr;
  2095.     int flagMask;
  2096.     
  2097.     /* 
  2098.      * We strip 'flags' down to just the parts which are relevant to
  2099.      * TclLookupVar, to avoid conflicts between trace flags and
  2100.      * internal namespace flags such as 'FIND_ONLY_NS'.  This can
  2101.      * now occur since we have trace flags with values 0x1000 and higher.
  2102.      */
  2103.     flagMask = TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY;
  2104.     varPtr = TclLookupVar(interp, part1, part2,
  2105.     (flags & flagMask) | TCL_LEAVE_ERR_MSG,
  2106.     "trace", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
  2107.     if (varPtr == NULL) {
  2108. return TCL_ERROR;
  2109.     }
  2110.     /*
  2111.      * Check for a nonsense flag combination.  Note that this is a
  2112.      * panic() because there should be no code path that ever sets
  2113.      * both flags.
  2114.      */
  2115.     if ((flags&TCL_TRACE_RESULT_DYNAMIC) && (flags&TCL_TRACE_RESULT_OBJECT)) {
  2116. panic("bad result flag combination");
  2117.     }
  2118.     /*
  2119.      * Set up trace information.
  2120.      */
  2121.     flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | 
  2122. TCL_TRACE_ARRAY | TCL_TRACE_RESULT_DYNAMIC | TCL_TRACE_RESULT_OBJECT;
  2123. #ifndef TCL_REMOVE_OBSOLETE_TRACES
  2124.     flagMask |= TCL_TRACE_OLD_STYLE;
  2125. #endif
  2126.     tracePtr = (VarTrace *) ckalloc(sizeof(VarTrace));
  2127.     tracePtr->traceProc = proc;
  2128.     tracePtr->clientData = clientData;
  2129.     tracePtr->flags = flags & flagMask;
  2130.     tracePtr->nextPtr = varPtr->tracePtr;
  2131.     varPtr->tracePtr = tracePtr;
  2132.     return TCL_OK;
  2133. }
  2134. /*
  2135.  *----------------------------------------------------------------------
  2136.  *
  2137.  * Tcl_UntraceVar --
  2138.  *
  2139.  * Remove a previously-created trace for a variable.
  2140.  *
  2141.  * Results:
  2142.  * None.
  2143.  *
  2144.  * Side effects:
  2145.  * If there exists a trace for the variable given by varName
  2146.  * with the given flags, proc, and clientData, then that trace
  2147.  * is removed.
  2148.  *
  2149.  *----------------------------------------------------------------------
  2150.  */
  2151. void
  2152. Tcl_UntraceVar(interp, varName, flags, proc, clientData)
  2153.     Tcl_Interp *interp; /* Interpreter containing variable. */
  2154.     CONST char *varName; /* Name of variable; may end with "(index)"
  2155.  * to signify an array reference. */
  2156.     int flags; /* OR-ed collection of bits describing
  2157.  * current trace, including any of
  2158.  * TCL_TRACE_READS, TCL_TRACE_WRITES,
  2159.  * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY
  2160.  * and TCL_NAMESPACE_ONLY. */
  2161.     Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */
  2162.     ClientData clientData; /* Arbitrary argument to pass to proc. */
  2163. {
  2164.     Tcl_UntraceVar2(interp, varName, (char *) NULL, flags, proc, clientData);
  2165. }
  2166. /*
  2167.  *----------------------------------------------------------------------
  2168.  *
  2169.  * Tcl_UntraceVar2 --
  2170.  *
  2171.  * Remove a previously-created trace for a variable.
  2172.  *
  2173.  * Results:
  2174.  * None.
  2175.  *
  2176.  * Side effects:
  2177.  * If there exists a trace for the variable given by part1
  2178.  * and part2 with the given flags, proc, and clientData, then
  2179.  * that trace is removed.
  2180.  *
  2181.  *----------------------------------------------------------------------
  2182.  */
  2183. void
  2184. Tcl_UntraceVar2(interp, part1, part2, flags, proc, clientData)
  2185.     Tcl_Interp *interp; /* Interpreter containing variable. */
  2186.     CONST char *part1; /* Name of variable or array. */
  2187.     CONST char *part2; /* Name of element within array;  NULL means
  2188.  * trace applies to scalar variable or array
  2189.  * as-a-whole. */
  2190.     int flags; /* OR-ed collection of bits describing
  2191.  * current trace, including any of
  2192.  * TCL_TRACE_READS, TCL_TRACE_WRITES,
  2193.  * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY,
  2194.  * and TCL_NAMESPACE_ONLY. */
  2195.     Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */
  2196.     ClientData clientData; /* Arbitrary argument to pass to proc. */
  2197. {
  2198.     register VarTrace *tracePtr;
  2199.     VarTrace *prevPtr;
  2200.     Var *varPtr, *arrayPtr;
  2201.     Interp *iPtr = (Interp *) interp;
  2202.     ActiveVarTrace *activePtr;
  2203.     int flagMask;
  2204.     
  2205.     /*
  2206.      * Set up a mask to mask out the parts of the flags that we are not
  2207.      * interested in now.
  2208.      */
  2209.     flagMask = TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY;
  2210.     varPtr = TclLookupVar(interp, part1, part2, flags & flagMask,
  2211.     /*msg*/ (char *) NULL,
  2212.     /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
  2213.     if (varPtr == NULL) {
  2214. return;
  2215.     }
  2216.     /*
  2217.      * Set up a mask to mask out the parts of the flags that we are not
  2218.      * interested in now.
  2219.      */
  2220.     flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
  2221. TCL_TRACE_ARRAY | TCL_TRACE_RESULT_DYNAMIC | TCL_TRACE_RESULT_OBJECT; 
  2222. #ifndef TCL_REMOVE_OBSOLETE_TRACES
  2223.     flagMask |= TCL_TRACE_OLD_STYLE;
  2224. #endif
  2225.     flags &= flagMask;
  2226.     for (tracePtr = varPtr->tracePtr, prevPtr = NULL;  ;
  2227.  prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) {
  2228. if (tracePtr == NULL) {
  2229.     return;
  2230. }
  2231. if ((tracePtr->traceProc == proc) && (tracePtr->flags == flags)
  2232. && (tracePtr->clientData == clientData)) {
  2233.     break;
  2234. }
  2235.     }
  2236.     /*
  2237.      * The code below makes it possible to delete traces while traces
  2238.      * are active: it makes sure that the deleted trace won't be
  2239.      * processed by CallVarTraces.
  2240.      */
  2241.     for (activePtr = iPtr->activeVarTracePtr;  activePtr != NULL;
  2242.  activePtr = activePtr->nextPtr) {
  2243. if (activePtr->nextTracePtr == tracePtr) {
  2244.     activePtr->nextTracePtr = tracePtr->nextPtr;
  2245. }
  2246.     }
  2247.     if (prevPtr == NULL) {
  2248. varPtr->tracePtr = tracePtr->nextPtr;
  2249.     } else {
  2250. prevPtr->nextPtr = tracePtr->nextPtr;
  2251.     }
  2252.     Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC);
  2253.     /*
  2254.      * If this is the last trace on the variable, and the variable is
  2255.      * unset and unused, then free up the variable.
  2256.      */
  2257.     if (TclIsVarUndefined(varPtr)) {
  2258. CleanupVar(varPtr, (Var *) NULL);
  2259.     }
  2260. }
  2261. /*
  2262.  *----------------------------------------------------------------------
  2263.  *
  2264.  * Tcl_VarTraceInfo --
  2265.  *
  2266.  * Return the clientData value associated with a trace on a
  2267.  * variable.  This procedure can also be used to step through
  2268.  * all of the traces on a particular variable that have the
  2269.  * same trace procedure.
  2270.  *
  2271.  * Results:
  2272.  * The return value is the clientData value associated with
  2273.  * a trace on the given variable.  Information will only be
  2274.  * returned for a trace with proc as trace procedure.  If
  2275.  * the clientData argument is NULL then the first such trace is
  2276.  * returned;  otherwise, the next relevant one after the one
  2277.  * given by clientData will be returned.  If the variable
  2278.  * doesn't exist, or if there are no (more) traces for it,
  2279.  * then NULL is returned.
  2280.  *
  2281.  * Side effects:
  2282.  * None.
  2283.  *
  2284.  *----------------------------------------------------------------------
  2285.  */
  2286. ClientData
  2287. Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData)
  2288.     Tcl_Interp *interp; /* Interpreter containing variable. */
  2289.     CONST char *varName; /* Name of variable;  may end with "(index)"
  2290.  * to signify an array reference. */
  2291.     int flags; /* OR-ed combo or TCL_GLOBAL_ONLY,
  2292.  * TCL_NAMESPACE_ONLY (can be 0). */
  2293.     Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */
  2294.     ClientData prevClientData; /* If non-NULL, gives last value returned
  2295.  * by this procedure, so this call will
  2296.  * return the next trace after that one.
  2297.  * If NULL, this call will return the
  2298.  * first trace. */
  2299. {
  2300.     return Tcl_VarTraceInfo2(interp, varName, (char *) NULL,
  2301.     flags, proc, prevClientData);
  2302. }
  2303. /*
  2304.  *----------------------------------------------------------------------
  2305.  *
  2306.  * Tcl_VarTraceInfo2 --
  2307.  *
  2308.  * Same as Tcl_VarTraceInfo, except takes name in two pieces
  2309.  * instead of one.
  2310.  *
  2311.  * Results:
  2312.  * Same as Tcl_VarTraceInfo.
  2313.  *
  2314.  * Side effects:
  2315.  * None.
  2316.  *
  2317.  *----------------------------------------------------------------------
  2318.  */
  2319. ClientData
  2320. Tcl_VarTraceInfo2(interp, part1, part2, flags, proc, prevClientData)
  2321.     Tcl_Interp *interp; /* Interpreter containing variable. */
  2322.     CONST char *part1; /* Name of variable or array. */
  2323.     CONST char *part2; /* Name of element within array;  NULL means
  2324.  * trace applies to scalar variable or array
  2325.  * as-a-whole. */
  2326.     int flags; /* OR-ed combination of TCL_GLOBAL_ONLY,
  2327.  * TCL_NAMESPACE_ONLY. */
  2328.     Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */
  2329.     ClientData prevClientData; /* If non-NULL, gives last value returned
  2330.  * by this procedure, so this call will
  2331.  * return the next trace after that one.
  2332.  * If NULL, this call will return the
  2333.  * first trace. */
  2334. {
  2335.     register VarTrace *tracePtr;
  2336.     Var *varPtr, *arrayPtr;
  2337.     varPtr = TclLookupVar(interp, part1, part2,
  2338.     flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY),
  2339.     /*msg*/ (char *) NULL,
  2340.     /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
  2341.     if (varPtr == NULL) {
  2342. return NULL;
  2343.     }
  2344.     /*
  2345.      * Find the relevant trace, if any, and return its clientData.
  2346.      */
  2347.     tracePtr = varPtr->tracePtr;
  2348.     if (prevClientData != NULL) {
  2349. for ( ;  tracePtr != NULL;  tracePtr = tracePtr->nextPtr) {
  2350.     if ((tracePtr->clientData == prevClientData)
  2351.     && (tracePtr->traceProc == proc)) {
  2352. tracePtr = tracePtr->nextPtr;
  2353. break;
  2354.     }
  2355. }
  2356.     }
  2357.     for ( ;  tracePtr != NULL;  tracePtr = tracePtr->nextPtr) {
  2358. if (tracePtr->traceProc == proc) {
  2359.     return tracePtr->clientData;
  2360. }
  2361.     }
  2362.     return NULL;
  2363. }
  2364. /*
  2365.  *----------------------------------------------------------------------
  2366.  *
  2367.  * Tcl_UnsetObjCmd --
  2368.  *
  2369.  * This object-based procedure is invoked to process the "unset" Tcl
  2370.  * command. See the user documentation for details on what it does.
  2371.  *
  2372.  * Results:
  2373.  * A standard Tcl object result value.
  2374.  *
  2375.  * Side effects:
  2376.  * See the user documentation.
  2377.  *
  2378.  *----------------------------------------------------------------------
  2379.  */
  2380. /* ARGSUSED */
  2381. int
  2382. Tcl_UnsetObjCmd(dummy, interp, objc, objv)
  2383.     ClientData dummy; /* Not used. */
  2384.     Tcl_Interp *interp; /* Current interpreter. */
  2385.     int objc; /* Number of arguments. */
  2386.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  2387. {
  2388.     register int i, flags = TCL_LEAVE_ERR_MSG;
  2389.     register char *name;
  2390.     if (objc < 1) {
  2391. Tcl_WrongNumArgs(interp, 1, objv,
  2392. "?-nocomplain? ?--? ?varName varName ...?");
  2393. return TCL_ERROR;
  2394.     } else if (objc == 1) {
  2395. /*
  2396.  * Do nothing if no arguments supplied, so as to match
  2397.  * command documentation.
  2398.  */
  2399. return TCL_OK;
  2400.     }
  2401.     /*
  2402.      * Simple, restrictive argument parsing.  The only options are --
  2403.      * and -nocomplain (which must come first and be given exactly to
  2404.      * be an option).
  2405.      */
  2406.     i = 1;
  2407.     name = TclGetString(objv[i]);
  2408.     if (name[0] == '-') {
  2409.   if (strcmp("-nocomplain", name) == 0) {
  2410.     i++;
  2411.       if (i == objc) {
  2412. return TCL_OK;
  2413.     }
  2414.       flags = 0;
  2415.       name = TclGetString(objv[i]);
  2416.   }
  2417.   if (strcmp("--", name) == 0) {
  2418.       i++;
  2419.   }
  2420.     }
  2421.     for (; i < objc;  i++) {
  2422. if ((TclObjUnsetVar2(interp, objv[i], NULL, flags) != TCL_OK)
  2423. && (flags == TCL_LEAVE_ERR_MSG)) {
  2424.     return TCL_ERROR;
  2425. }
  2426.     }
  2427.     return TCL_OK;
  2428. }
  2429. /*
  2430.  *----------------------------------------------------------------------
  2431.  *
  2432.  * Tcl_AppendObjCmd --
  2433.  *
  2434.  * This object-based procedure is invoked to process the "append" 
  2435.  * Tcl command. See the user documentation for details on what it does.
  2436.  *
  2437.  * Results:
  2438.  * A standard Tcl object result value.
  2439.  *
  2440.  * Side effects:
  2441.  * A variable's value may be changed.
  2442.  *
  2443.  *----------------------------------------------------------------------
  2444.  */
  2445. /* ARGSUSED */
  2446. int
  2447. Tcl_AppendObjCmd(dummy, interp, objc, objv)
  2448.     ClientData dummy; /* Not used. */
  2449.     Tcl_Interp *interp; /* Current interpreter. */
  2450.     int objc; /* Number of arguments. */
  2451.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  2452. {
  2453.     Var *varPtr, *arrayPtr;
  2454.     char *part1;
  2455.     register Tcl_Obj *varValuePtr = NULL;