PageRenderTime 107ms CodeModel.GetById 38ms RepoModel.GetById 6ms app.codeStats 1ms

/TCL/src/base/Var.cs

http://github.com/plainprogrammer/csharp-sqlite
C# | 2476 lines | 1298 code | 322 blank | 856 comment | 384 complexity | ec8718890f57b9b9f6bb101cdb5b9eb8 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Var.java
  3. *
  4. * Copyright (c) 1997 Sun Microsystems, Inc.
  5. *
  6. * See the file "license.terms" for information on usage and
  7. * redistribution of this file, and for a DISCLAIMER OF ALL
  8. * WARRANTIES.
  9. *
  10. * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
  11. * $Header$
  12. * RCS @(#) $Id: Var.java,v 1.11 2003/01/09 02:15:39 mdejong Exp $
  13. *
  14. */
  15. using System;
  16. using System.Collections;
  17. using System.Text;
  18. namespace tcl.lang
  19. {
  20. /// <summary> Flag bits for variables. The first three (SCALAR, ARRAY, and
  21. /// LINK) are mutually exclusive and give the "type" of the variable.
  22. /// UNDEFINED is independent of the variable's type.
  23. ///
  24. /// SCALAR - 1 means this is a scalar variable and not
  25. /// an array or link. The value field points
  26. /// to the variable's value, a Tcl object.
  27. /// ARRAY - 1 means this is an array variable rather
  28. /// than a scalar variable or link. The
  29. /// table field points to the array's
  30. /// hashtable for its elements.
  31. /// LINK - 1 means this Var structure contains a
  32. /// reference to another Var structure that
  33. /// either has the real value or is itself
  34. /// another LINK pointer. Variables like
  35. /// this come about through "upvar" and "global"
  36. /// commands, or through references to variables
  37. /// in enclosing namespaces.
  38. /// UNDEFINED - 1 means that the variable is in the process
  39. /// of being deleted. An undefined variable
  40. /// logically does not exist and survives only
  41. /// while it has a trace, or if it is a global
  42. /// variable currently being used by some
  43. /// procedure.
  44. /// IN_HASHTABLE - 1 means this variable is in a hashtable. 0 if
  45. /// a local variable that was assigned a slot
  46. /// in a procedure frame by the compiler so the
  47. /// Var storage is part of the call frame.
  48. /// TRACE_ACTIVE - 1 means that trace processing is currently
  49. /// underway for a read or write access, so
  50. /// new read or write accesses should not cause
  51. /// trace procedures to be called and the
  52. /// variable can't be deleted.
  53. /// ARRAY_ELEMENT - 1 means that this variable is an array
  54. /// element, so it is not legal for it to be
  55. /// an array itself (the ARRAY flag had
  56. /// better not be set).
  57. /// NAMESPACE_VAR - 1 means that this variable was declared
  58. /// as a namespace variable. This flag ensures
  59. /// it persists until its namespace is
  60. /// destroyed or until the variable is unset;
  61. /// it will persist even if it has not been
  62. /// initialized and is marked undefined.
  63. /// The variable's refCount is incremented to
  64. /// reflect the "reference" from its namespace.
  65. ///
  66. /// </summary>
  67. [Flags()]
  68. public enum VarFlags
  69. {
  70. SCALAR = 0x1,
  71. ARRAY = 0x2,
  72. LINK = 0x4,
  73. UNDEFINED = 0x8,
  74. IN_HASHTABLE = 0x10,
  75. TRACE_ACTIVE = 0x20,
  76. ARRAY_ELEMENT = 0x40,
  77. NAMESPACE_VAR = 0x80,
  78. SQLITE3_LINK_INT = 0x100,
  79. SQLITE3_LINK_DOUBLE = 0x200,
  80. SQLITE3_LINK_BOOLEAN = 0x400,
  81. SQLITE3_LINK_STRING = 0x800,
  82. SQLITE3_LINK_WIDE_INT = 0x1000,
  83. SQLITE3_LINK = 0x10000,
  84. SQLITE3_LINK_READ_ONLY = 0x20000,
  85. };
  86. /*
  87. * Implements variables in Tcl. The Var class encapsulates most of the functionality
  88. * of the methods in generic/tclVar.c and the structure TCL.Tcl_Var from the C version.
  89. */
  90. public class Var
  91. {
  92. /// <summary> Used by ArrayCmd to create a unique searchId string. If the
  93. /// sidVec Vector is empty then simply return 1. Else return 1
  94. /// plus the SearchId.index value of the last Object in the vector.
  95. ///
  96. /// </summary>
  97. /// <param name="">None
  98. /// </param>
  99. /// <returns> The int value for unique SearchId string.
  100. /// </returns>
  101. protected internal int NextIndex
  102. {
  103. get
  104. {
  105. lock ( this )
  106. {
  107. if ( sidVec.Count == 0 )
  108. {
  109. return 1;
  110. }
  111. SearchId sid = (SearchId)SupportClass.VectorLastElement( sidVec );
  112. return ( sid.Index + 1 );
  113. }
  114. }
  115. }
  116. // internal const int SCALAR = 0x1;
  117. // internal const int ARRAY = 0x2;
  118. // internal const int LINK = 0x4;
  119. // internal const int UNDEFINED = 0x8;
  120. // internal const int IN_HASHTABLE = 0x10;
  121. // internal const int TRACE_ACTIVE = 0x20;
  122. // internal const int ARRAY_ELEMENT = 0x40;
  123. // internal const int NAMESPACE_VAR = 0x80;
  124. // Methods to read various flag bits of variables.
  125. internal bool isVarScalar()
  126. {
  127. return ( ( flags & VarFlags.SCALAR ) != 0 );
  128. }
  129. internal bool isVarLink()
  130. {
  131. return ( ( flags & VarFlags.LINK ) != 0 );
  132. }
  133. internal bool isVarArray()
  134. {
  135. return ( ( flags & VarFlags.ARRAY ) != 0 );
  136. }
  137. internal bool isVarUndefined()
  138. {
  139. return ( ( flags & VarFlags.UNDEFINED ) != 0 );
  140. }
  141. internal bool isVarArrayElement()
  142. {
  143. return ( ( flags & VarFlags.ARRAY_ELEMENT ) != 0 );
  144. }
  145. // Methods to ensure that various flag bits are set properly for variables.
  146. internal void setVarScalar()
  147. {
  148. flags = ( flags & ~( VarFlags.ARRAY | VarFlags.LINK ) ) | VarFlags.SCALAR;
  149. }
  150. internal void setVarArray()
  151. {
  152. flags = ( flags & ~( VarFlags.SCALAR | VarFlags.LINK ) ) | VarFlags.ARRAY;
  153. }
  154. internal void setVarLink()
  155. {
  156. flags = ( flags & ~( VarFlags.SCALAR | VarFlags.ARRAY ) ) | VarFlags.LINK;
  157. }
  158. internal void setVarArrayElement()
  159. {
  160. flags = ( flags & ~VarFlags.ARRAY ) | VarFlags.ARRAY_ELEMENT;
  161. }
  162. internal void setVarUndefined()
  163. {
  164. flags |= VarFlags.UNDEFINED;
  165. }
  166. internal void clearVarUndefined()
  167. {
  168. flags &= ~VarFlags.UNDEFINED;
  169. }
  170. /// <summary> Stores the "value" of the variable. It stored different information
  171. /// depending on the type of the variable: <ul>
  172. /// <li>Scalar variable - (TclObject) value is the object stored in the
  173. /// variable.
  174. /// <li> Array variable - (Hashtable) value is the hashtable that stores
  175. /// all the elements. <p>
  176. /// <li> Upvar (Link) - (Var) value is the variable associated by this upvar.
  177. /// </ul>
  178. /// </summary>
  179. internal Object value;
  180. /// <summary> Vector that holds the traces that were placed in this Var</summary>
  181. internal ArrayList traces;
  182. internal ArrayList sidVec;
  183. /// <summary> Miscellaneous bits of information about variable.
  184. ///
  185. /// </summary>
  186. /// <seealso cref="Var#SCALAR">
  187. /// </seealso>
  188. /// <seealso cref="Var#ARRAY">
  189. /// </seealso>
  190. /// <seealso cref="Var#LINK">
  191. /// </seealso>
  192. /// <seealso cref="Var#UNDEFINED">
  193. /// </seealso>
  194. /// <seealso cref="Var#IN_HASHTABLE">
  195. /// </seealso>
  196. /// <seealso cref="Var#TRACE_ACTIVE">
  197. /// </seealso>
  198. /// <seealso cref="Var#ARRAY_ELEMENT">
  199. /// </seealso>
  200. /// <seealso cref="Var#NAMESPACE_VAR">
  201. /// </seealso>
  202. internal VarFlags flags;
  203. /// <summary> If variable is in a hashtable, either the
  204. /// hash table entry that refers to this
  205. /// variable or null if the variable has been
  206. /// detached from its hash table (e.g. an
  207. /// array is deleted, but some of its
  208. /// elements are still referred to in
  209. /// upvars). null if the variable is not in a
  210. /// hashtable. This is used to delete an
  211. /// variable from its hashtable if it is no
  212. /// longer needed.
  213. /// </summary>
  214. internal Hashtable table;
  215. /// <summary> The key under which this variable is stored in the hash table.</summary>
  216. internal string hashKey;
  217. /// <summary> Counts number of active uses of this
  218. /// variable, not including its entry in the
  219. /// call frame or the hash table: 1 for each
  220. /// additional variable whose link points
  221. /// here, 1 for each nested trace active on
  222. /// variable, and 1 if the variable is a
  223. /// namespace variable. This record can't be
  224. /// deleted until refCount becomes 0.
  225. /// </summary>
  226. internal int refCount;
  227. /// <summary> Reference to the namespace that contains
  228. /// this variable or null if the variable is
  229. /// a local variable in a Tcl procedure.
  230. /// </summary>
  231. internal NamespaceCmd.Namespace ns;
  232. public class SQLITE3_GETSET
  233. {
  234. string name = "";
  235. int _Integer = 0; // Internal integer value
  236. StringBuilder _StringBuilder = null; // Internal string value
  237. public SQLITE3_GETSET( string name )
  238. {
  239. this._Integer = 0;
  240. this._StringBuilder = new StringBuilder( 500 );
  241. this.name = name;
  242. }
  243. public int iValue
  244. {
  245. get { return _Integer; }
  246. set { _Integer = value; }
  247. }
  248. public string sValue
  249. {
  250. get { return _StringBuilder.ToString(); }
  251. set { _StringBuilder.Length = 0; _StringBuilder.Append( value ); }
  252. }
  253. public void Append( byte[] append )
  254. {
  255. _StringBuilder.Append( Encoding.UTF8.GetString( append ) );
  256. }
  257. public void Append( string append )
  258. {
  259. _StringBuilder.Append( append );
  260. }
  261. public void Trim()
  262. {
  263. _StringBuilder = new StringBuilder( _StringBuilder.ToString().Trim() );
  264. }
  265. public int Length
  266. {
  267. get { return _StringBuilder.Length; }
  268. }
  269. }
  270. /// <summary> Reference to the object the allows getting & setting the sqlite3 linked variable
  271. /// </summary>
  272. internal object sqlite3_get_set;
  273. internal TclObject sqlite3_get()
  274. {
  275. TclObject to;
  276. if ( ( flags & VarFlags.SQLITE3_LINK_READ_ONLY ) != 0 && ( flags & VarFlags.SQLITE3_LINK_INT ) != 0 )
  277. if ( sqlite3_get_set.GetType().Name == "Int32" )
  278. to = TclInteger.newInstance( (Int32)sqlite3_get_set );
  279. else
  280. to = TclInteger.newInstance( ( (SQLITE3_GETSET)sqlite3_get_set ).iValue );
  281. else if ( ( flags & VarFlags.SQLITE3_LINK_INT ) != 0 )
  282. {
  283. if ( sqlite3_get_set.GetType().Name == "Int32" )
  284. to = TclInteger.newInstance( (Int32)sqlite3_get_set );
  285. else
  286. to = TclInteger.newInstance( ( (SQLITE3_GETSET)sqlite3_get_set ).iValue );
  287. }
  288. else to = TclString.newInstance( ( (SQLITE3_GETSET)sqlite3_get_set ).sValue );
  289. to.preserve();
  290. return to;
  291. }
  292. internal void sqlite3_set( TclObject to )
  293. {
  294. if ( ( flags & VarFlags.SQLITE3_LINK_READ_ONLY ) == 0 )
  295. {
  296. if ( ( flags & VarFlags.SQLITE3_LINK_INT ) != 0 )
  297. ( (SQLITE3_GETSET)sqlite3_get_set ).iValue = Convert.ToInt32( to.ToString() );
  298. else
  299. if ( ( flags & VarFlags.SQLITE3_LINK_STRING ) != 0 )
  300. ( (SQLITE3_GETSET)sqlite3_get_set ).sValue = to.ToString();
  301. else
  302. ( (SQLITE3_GETSET)sqlite3_get_set ).sValue = to.ToString();
  303. }
  304. }
  305. internal bool isSQLITE3_Link()
  306. {
  307. return ( ( flags & VarFlags.SQLITE3_LINK ) != 0 );
  308. }
  309. /// <summary> NewVar -> Var
  310. ///
  311. /// Construct a variable and initialize its fields.
  312. /// </summary>
  313. internal Var()
  314. {
  315. value = null;
  316. //name = null; // Like hashKey in Jacl
  317. ns = null;
  318. hashKey = null; // Like hPtr in the C implementation
  319. table = null; // Like hPtr in the C implementation
  320. refCount = 0;
  321. traces = null;
  322. //search = null;
  323. sidVec = null; // Like search in the C implementation
  324. flags = ( VarFlags.SCALAR | VarFlags.UNDEFINED | VarFlags.IN_HASHTABLE );
  325. }
  326. /// <summary> Used to create a String that describes this variable
  327. ///
  328. /// </summary>
  329. public override string ToString()
  330. {
  331. System.Text.StringBuilder sb = new System.Text.StringBuilder();
  332. sb.Append( ns );
  333. if ( sb.Length == 2 )
  334. {
  335. // It is in the global namespace
  336. sb.Append( hashKey );
  337. }
  338. else
  339. {
  340. // It is not in the global namespaces
  341. sb.Append( "::" );
  342. sb.Append( hashKey );
  343. }
  344. return sb.ToString();
  345. }
  346. /// <summary> Find the SearchId that in the sidVec Vector that is equal the
  347. /// unique String s and returns the enumeration associated with
  348. /// that SearchId.
  349. ///
  350. /// </summary>
  351. /// <param name="s">String that ia a unique identifier for a SearchId object
  352. /// </param>
  353. /// <returns> Enumeration if a match is found else null.
  354. /// </returns>
  355. protected internal SearchId getSearch( string s )
  356. {
  357. SearchId sid;
  358. for ( int i = 0 ; i < sidVec.Count ; i++ )
  359. {
  360. sid = (SearchId)sidVec[i];
  361. if ( sid.equals( s ) )
  362. {
  363. return sid;
  364. }
  365. }
  366. return null;
  367. }
  368. /// <summary> Find the SearchId object in the sidVec Vector and remove it.
  369. ///
  370. /// </summary>
  371. /// <param name="sid">String that ia a unique identifier for a SearchId object.
  372. /// </param>
  373. protected internal bool removeSearch( string sid )
  374. {
  375. SearchId curSid;
  376. for ( int i = 0 ; i < sidVec.Count ; i++ )
  377. {
  378. curSid = (SearchId)sidVec[i];
  379. if ( curSid.equals( sid ) )
  380. {
  381. sidVec.RemoveAt( i );
  382. return true;
  383. }
  384. }
  385. return false;
  386. }
  387. // End of the instance method for the Var class, the rest of the methods
  388. // are Var related methods ported from the code in generic/tclVar.c
  389. // The strings below are used to indicate what went wrong when a
  390. // variable access is denied.
  391. internal const string noSuchVar = "no such variable";
  392. internal const string isArray = "variable is array";
  393. internal const string needArray = "variable isn't array";
  394. internal const string noSuchElement = "no such element in array";
  395. internal const string danglingElement = "upvar refers to element in deleted array";
  396. internal const string danglingVar = "upvar refers to variable in deleted namespace";
  397. internal const string badNamespace = "parent namespace doesn't exist";
  398. internal const string missingName = "missing variable name";
  399. /// <summary> TclLookupVar -> lookupVar
  400. ///
  401. /// This procedure is used by virtually all of the variable
  402. /// code to locate a variable given its name(s).
  403. ///
  404. /// </summary>
  405. /// <param name="part1">if part2 isn't NULL, this is the name of an array.
  406. /// Otherwise, this is a full variable name that could include
  407. /// a parenthesized array elemnt or a scalar.
  408. /// </param>
  409. /// <param name="part2">Name of an element within array, or null.
  410. /// </param>
  411. /// <param name="flags">Only the TCL.VarFlag.GLOBAL_ONLY bit matters.
  412. /// </param>
  413. /// <param name="msg">Verb to use in error messages, e.g. "read" or "set".
  414. /// </param>
  415. /// <param name="create">OR'ed combination of CRT_PART1 and CRT_PART2.
  416. /// Tells which entries to create if they don't already exist.
  417. /// </param>
  418. /// <param name="throwException">true if an exception should be throw if the
  419. /// variable cannot be found.
  420. /// </param>
  421. /// <returns> a two element array. a[0] is the variable indicated by
  422. /// part1 and part2, or null if the variable couldn't be
  423. /// found and throwException is false.
  424. /// <p>
  425. /// If the variable is found, a[1] is the array that
  426. /// contains the variable (or null if the variable is a scalar).
  427. /// If the variable can't be found and either createPart1 or
  428. /// createPart2 are true, a new as-yet-undefined (VAR_UNDEFINED)
  429. /// variable instance is created, entered into a hash
  430. /// table, and returned.
  431. /// Note: it's possible that var.value of the returned variable
  432. /// may be null (variable undefined), even if createPart1 or createPart2
  433. /// are true (these only cause the hash table entry or array to be created).
  434. /// For example, the variable might be a global that has been unset but
  435. /// is still referenced by a procedure, or a variable that has been unset
  436. /// but it only being kept in existence by a trace.
  437. /// </returns>
  438. /// <exception cref=""> TclException if the variable cannot be found and
  439. /// throwException is true.
  440. ///
  441. /// </exception>
  442. internal static Var[] lookupVar( Interp interp, string part1, string part2, TCL.VarFlag flags, string msg, bool createPart1, bool createPart2 )
  443. {
  444. CallFrame varFrame = interp.varFrame;
  445. // Reference to the procedure call frame whose
  446. // variables are currently in use. Same as
  447. // the current procedure's frame, if any,
  448. // unless an "uplevel" is executing.
  449. Hashtable table; // to the hashtable, if any, in which
  450. // to look up the variable.
  451. Var var; // Used to search for global names.
  452. string elName; // Name of array element or null.
  453. int openParen;
  454. // If this procedure parses a name into
  455. // array and index, these point to the
  456. // parens around the index. Otherwise they
  457. // are -1. These are needed to restore
  458. // the parens after parsing the name.
  459. NamespaceCmd.Namespace varNs, cxtNs;
  460. int p;
  461. int i, result;
  462. var = null;
  463. openParen = -1;
  464. varNs = null; // set non-null if a nonlocal variable
  465. // Parse part1 into array name and index.
  466. // Always check if part1 is an array element name and allow it only if
  467. // part2 is not given.
  468. // (if one does not care about creating array elements that can't be used
  469. // from tcl, and prefer slightly better performance, one can put
  470. // the following in an if (part2 == null) { ... } block and remove
  471. // the part2's test and error reporting or move that code in array set)
  472. elName = part2;
  473. int len = part1.Length;
  474. for ( p = 0 ; p < len ; p++ )
  475. {
  476. if ( part1[p] == '(' )
  477. {
  478. openParen = p;
  479. p = len - 1;
  480. if ( part1[p] == ')' )
  481. {
  482. if ( (System.Object)part2 != null )
  483. {
  484. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  485. {
  486. throw new TclVarException( interp, part1, part2, msg, needArray );
  487. }
  488. return null;
  489. }
  490. elName = part1.Substring( openParen + 1, ( len - 1 ) - ( openParen + 1 ) );
  491. part2 = elName; // same as elName, only used in error reporting
  492. part1 = part1.Substring( 0, ( openParen ) - ( 0 ) );
  493. }
  494. break;
  495. }
  496. }
  497. // If this namespace has a variable resolver, then give it first
  498. // crack at the variable resolution. It may return a Var
  499. // value, it may signal to continue onward, or it may signal
  500. // an error.
  501. if ( ( ( flags & TCL.VarFlag.GLOBAL_ONLY ) != 0 ) || ( interp.varFrame == null ) )
  502. {
  503. cxtNs = interp.globalNs;
  504. }
  505. else
  506. {
  507. cxtNs = interp.varFrame.ns;
  508. }
  509. if ( cxtNs.resolver != null || interp.resolvers != null )
  510. {
  511. try
  512. {
  513. if ( cxtNs.resolver != null )
  514. {
  515. var = cxtNs.resolver.resolveVar( interp, part1, cxtNs, flags );
  516. }
  517. else
  518. {
  519. var = null;
  520. }
  521. if ( var == null && interp.resolvers != null )
  522. {
  523. IEnumerator enum_Renamed = interp.resolvers.GetEnumerator();
  524. foreach ( Interp.ResolverScheme res in interp.resolvers )
  525. {
  526. var = res.resolver.resolveVar( interp, part1, cxtNs, flags );
  527. if ( var != null )
  528. break;
  529. }
  530. }
  531. }
  532. catch ( TclException e )
  533. {
  534. var = null;
  535. }
  536. }
  537. // Look up part1. Look it up as either a namespace variable or as a
  538. // local variable in a procedure call frame (varFrame).
  539. // Interpret part1 as a namespace variable if:
  540. // 1) so requested by a TCL.VarFlag.GLOBAL_ONLY or TCL.VarFlag.NAMESPACE_ONLY flag,
  541. // 2) there is no active frame (we're at the global :: scope),
  542. // 3) the active frame was pushed to define the namespace context
  543. // for a "namespace eval" or "namespace inscope" command,
  544. // 4) the name has namespace qualifiers ("::"s).
  545. // Otherwise, if part1 is a local variable, search first in the
  546. // frame's array of compiler-allocated local variables, then in its
  547. // hashtable for runtime-created local variables.
  548. //
  549. // If createPart1 and the variable isn't found, create the variable and,
  550. // if necessary, create varFrame's local var hashtable.
  551. if ( ( ( flags & ( TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.NAMESPACE_ONLY ) ) != 0 ) || ( varFrame == null ) || !varFrame.isProcCallFrame || ( part1.IndexOf( "::" ) != -1 ) )
  552. {
  553. string tail;
  554. // Don't pass TCL.VarFlag.LEAVE_ERR_MSG, we may yet create the variable,
  555. // or otherwise generate our own error!
  556. var = NamespaceCmd.findNamespaceVar( interp, part1, null, flags & ~TCL.VarFlag.LEAVE_ERR_MSG );
  557. if ( var == null )
  558. {
  559. if ( createPart1 )
  560. {
  561. // var wasn't found so create it
  562. // Java does not support passing an address so we pass
  563. // an array of size 1 and then assign arr[0] to the value
  564. NamespaceCmd.Namespace[] varNsArr = new NamespaceCmd.Namespace[1];
  565. NamespaceCmd.Namespace[] dummyArr = new NamespaceCmd.Namespace[1];
  566. string[] tailArr = new string[1];
  567. NamespaceCmd.getNamespaceForQualName( interp, part1, null, flags, varNsArr, dummyArr, dummyArr, tailArr );
  568. // Get the values out of the arrays!
  569. varNs = varNsArr[0];
  570. tail = tailArr[0];
  571. if ( varNs == null )
  572. {
  573. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  574. {
  575. throw new TclVarException( interp, part1, part2, msg, badNamespace );
  576. }
  577. return null;
  578. }
  579. if ( (System.Object)tail == null )
  580. {
  581. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  582. {
  583. throw new TclVarException( interp, part1, part2, msg, missingName );
  584. }
  585. return null;
  586. }
  587. var = new Var();
  588. varNs.varTable.Add( tail, var );
  589. // There is no hPtr member in Jacl, The hPtr combines the table
  590. // and the key used in a table lookup.
  591. var.hashKey = tail;
  592. var.table = varNs.varTable;
  593. var.ns = varNs;
  594. }
  595. else
  596. {
  597. // var wasn't found and not to create it
  598. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  599. {
  600. throw new TclVarException( interp, part1, part2, msg, noSuchVar );
  601. }
  602. return null;
  603. }
  604. }
  605. }
  606. else
  607. {
  608. // local var: look in frame varFrame
  609. // removed code block that searches for local compiled vars
  610. if ( var == null )
  611. {
  612. // look in the frame's var hash table
  613. table = varFrame.varTable;
  614. if ( createPart1 )
  615. {
  616. if ( table == null )
  617. {
  618. table = new Hashtable();
  619. varFrame.varTable = table;
  620. }
  621. var = (Var)table[part1];
  622. if ( var == null )
  623. {
  624. // we are adding a new entry
  625. var = new Var();
  626. SupportClass.PutElement( table, part1, var );
  627. // There is no hPtr member in Jacl, The hPtr combines
  628. // the table and the key used in a table lookup.
  629. var.hashKey = part1;
  630. var.table = table;
  631. var.ns = null; // a local variable
  632. }
  633. }
  634. else
  635. {
  636. if ( table != null )
  637. {
  638. var = (Var)table[part1];
  639. }
  640. if ( var == null )
  641. {
  642. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  643. {
  644. throw new TclVarException( interp, part1, part2, msg, noSuchVar );
  645. }
  646. return null;
  647. }
  648. }
  649. }
  650. }
  651. // If var is a link variable, we have a reference to some variable
  652. // that was created through an "upvar" or "global" command. Traverse
  653. // through any links until we find the referenced variable.
  654. while ( var.isVarLink() )
  655. {
  656. var = (Var)var.value;
  657. }
  658. // If we're not dealing with an array element, return var.
  659. if ( (System.Object)elName == null )
  660. {
  661. Var[] ret = new Var[2];
  662. ret[0] = var;
  663. ret[1] = null;
  664. return ret;
  665. }
  666. // We're dealing with an array element. Make sure the variable is an
  667. // array and look up the element (create the element if desired).
  668. if ( var.isVarUndefined() && !var.isVarArrayElement() )
  669. {
  670. if ( !createPart1 )
  671. {
  672. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  673. {
  674. throw new TclVarException( interp, part1, part2, msg, noSuchVar );
  675. }
  676. return null;
  677. }
  678. // Make sure we are not resurrecting a namespace variable from a
  679. // deleted namespace!
  680. if ( ( ( var.flags & VarFlags.IN_HASHTABLE ) != 0 ) && ( var.table == null ) )
  681. {
  682. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  683. {
  684. throw new TclVarException( interp, part1, part2, msg, danglingVar );
  685. }
  686. return null;
  687. }
  688. var.setVarArray();
  689. var.clearVarUndefined();
  690. var.value = new Hashtable();
  691. }
  692. else if ( !var.isVarArray() )
  693. {
  694. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  695. {
  696. throw new TclVarException( interp, part1, part2, msg, needArray );
  697. }
  698. return null;
  699. }
  700. Var arrayVar = var;
  701. Hashtable arrayTable = (Hashtable)var.value;
  702. if ( createPart2 )
  703. {
  704. Var searchvar = (Var)arrayTable[elName];
  705. if ( searchvar == null )
  706. {
  707. // new entry
  708. if ( var.sidVec != null )
  709. {
  710. deleteSearches( var );
  711. }
  712. var = new Var();
  713. SupportClass.PutElement( arrayTable, elName, var );
  714. // There is no hPtr member in Jacl, The hPtr combines the table
  715. // and the key used in a table lookup.
  716. var.hashKey = elName;
  717. var.table = arrayTable;
  718. var.ns = varNs;
  719. var.setVarArrayElement();
  720. }
  721. else
  722. {
  723. var = searchvar;
  724. }
  725. }
  726. else
  727. {
  728. var = (Var)arrayTable[elName];
  729. if ( var == null )
  730. {
  731. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  732. {
  733. throw new TclVarException( interp, part1, part2, msg, noSuchElement );
  734. }
  735. return null;
  736. }
  737. }
  738. Var[] ret2 = new Var[2];
  739. ret2[0] = var; // The Var in the array
  740. ret2[1] = arrayVar; // The array (Hashtable) Var
  741. return ret2;
  742. }
  743. /// <summary> Query the value of a variable whose name is stored in a Tcl object.
  744. ///
  745. /// </summary>
  746. /// <param name="interp">the interp that holds the variable
  747. /// </param>
  748. /// <param name="nameObj">name of the variable.
  749. /// </param>
  750. /// <param name="flags">misc flags that control the actions of this method.
  751. /// </param>
  752. /// <returns> the value of the variable.
  753. /// </returns>
  754. internal static TclObject getVar( Interp interp, TclObject nameObj, TCL.VarFlag flags )
  755. {
  756. return getVar( interp, nameObj.ToString(), null, flags );
  757. }
  758. /// <summary> Query the value of a variable.
  759. ///
  760. /// </summary>
  761. /// <param name="interp">the interp that holds the variable
  762. /// </param>
  763. /// <param name="name">name of the variable.
  764. /// </param>
  765. /// <param name="flags">misc flags that control the actions of this method.
  766. /// </param>
  767. /// <returns> the value of the variable.
  768. /// </returns>
  769. internal static TclObject getVar( Interp interp, string name, TCL.VarFlag flags )
  770. {
  771. return getVar( interp, name, null, flags );
  772. }
  773. /// <summary> Tcl_ObjGetVar2 -> getVar
  774. ///
  775. /// Query the value of a variable.
  776. ///
  777. /// </summary>
  778. /// <param name="interp">the interp that holds the variable
  779. /// </param>
  780. /// <param name="part1">1st part of the variable name.
  781. /// </param>
  782. /// <param name="part2">2nd part of the variable name.
  783. /// </param>
  784. /// <param name="flags">misc flags that control the actions of this method.
  785. /// </param>
  786. /// <returns> the value of the variable.
  787. /// </returns>
  788. internal static TclObject getVar( Interp interp, TclObject part1Obj, TclObject part2Obj, TCL.VarFlag flags )
  789. {
  790. string part1, part2;
  791. part1 = part1Obj.ToString();
  792. if ( part2Obj != null )
  793. {
  794. part2 = part2Obj.ToString();
  795. }
  796. else
  797. {
  798. part2 = null;
  799. }
  800. return getVar( interp, part1, part2, flags );
  801. }
  802. /// <summary> TCL.Tcl_GetVar2Ex -> getVar
  803. ///
  804. /// Query the value of a variable, given a two-part name consisting
  805. /// of array name and element within array.
  806. ///
  807. /// </summary>
  808. /// <param name="interp">the interp that holds the variable
  809. /// </param>
  810. /// <param name="part1">1st part of the variable name.
  811. /// </param>
  812. /// <param name="part2">2nd part of the variable name.
  813. /// </param>
  814. /// <param name="flags">misc flags that control the actions of this method.
  815. /// </param>
  816. /// <returns> the value of the variable.
  817. /// </returns>
  818. internal static TclObject getVar( Interp interp, string part1, string part2, TCL.VarFlag flags )
  819. {
  820. Var[] result = lookupVar( interp, part1, part2, flags, "read", false, true );
  821. if ( result == null )
  822. {
  823. // lookupVar() returns null only if TCL.VarFlag.LEAVE_ERR_MSG is
  824. // not part of the flags argument, return null in this case.
  825. return null;
  826. }
  827. Var var = result[0];
  828. Var array = result[1];
  829. try
  830. {
  831. // Invoke any traces that have been set for the variable.
  832. if ( ( var.traces != null ) || ( ( array != null ) && ( array.traces != null ) ) )
  833. {
  834. string msg = callTraces( interp, array, var, part1, part2, ( flags & ( TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.GLOBAL_ONLY ) ) | TCL.VarFlag.TRACE_READS );
  835. if ( (System.Object)msg != null )
  836. {
  837. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  838. {
  839. throw new TclVarException( interp, part1, part2, "read", msg );
  840. }
  841. return null;
  842. }
  843. }
  844. if ( var.isVarScalar() && !var.isVarUndefined() )
  845. {
  846. return (TclObject)var.value;
  847. }
  848. if ( var.isSQLITE3_Link() ) return var.sqlite3_get();
  849. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  850. {
  851. string msg;
  852. if ( var.isVarUndefined() && ( array != null ) && !array.isVarUndefined() )
  853. {
  854. msg = noSuchElement;
  855. }
  856. else if ( var.isVarArray() )
  857. {
  858. msg = isArray;
  859. }
  860. else
  861. {
  862. msg = noSuchVar;
  863. }
  864. throw new TclVarException( interp, part1, part2, "read", msg );
  865. }
  866. }
  867. finally
  868. {
  869. // If the variable doesn't exist anymore and no-one's using it,
  870. // then free up the relevant structures and hash table entries.
  871. if ( var.isVarUndefined() )
  872. {
  873. cleanupVar( var, array );
  874. }
  875. }
  876. return null;
  877. }
  878. /// <summary> Set a variable whose name is stored in a Tcl object.
  879. ///
  880. /// </summary>
  881. /// <param name="interp">the interp that holds the variable
  882. /// </param>
  883. /// <param name="nameObj">name of the variable.
  884. /// </param>
  885. /// <param name="value">the new value for the variable
  886. /// </param>
  887. /// <param name="flags">misc flags that control the actions of this method.
  888. /// </param>
  889. internal static TclObject setVar( Interp interp, TclObject nameObj, TclObject value, TCL.VarFlag flags )
  890. {
  891. return setVar( interp, nameObj.ToString(), null, value, flags );
  892. }
  893. /// <summary> Set a variable.
  894. ///
  895. /// </summary>
  896. /// <param name="interp">the interp that holds the variable
  897. /// </param>
  898. /// <param name="name">name of the variable.
  899. /// </param>
  900. /// <param name="value">the new value for the variable
  901. /// </param>
  902. /// <param name="flags">misc flags that control the actions of this method
  903. /// </param>
  904. internal static TclObject setVar( Interp interp, string name, TclObject value, TCL.VarFlag flags )
  905. {
  906. return setVar( interp, name, null, value, flags );
  907. }
  908. /// <summary> Tcl_ObjSetVar2 -> setVar
  909. ///
  910. /// Set the value of a variable.
  911. ///
  912. /// </summary>
  913. /// <param name="interp">the interp that holds the variable
  914. /// </param>
  915. /// <param name="part1">1st part of the variable name.
  916. /// </param>
  917. /// <param name="part2">2nd part of the variable name.
  918. /// </param>
  919. /// <param name="newValue">the new value for the variable
  920. /// </param>
  921. /// <param name="flags">misc flags that control the actions of this method
  922. /// </param>
  923. internal static TclObject setVar( Interp interp, TclObject part1Obj, TclObject part2Obj, TclObject newValue, TCL.VarFlag flags )
  924. {
  925. string part1, part2;
  926. part1 = part1Obj.ToString();
  927. if ( part2Obj != null )
  928. {
  929. part2 = part2Obj.ToString();
  930. }
  931. else
  932. {
  933. part2 = null;
  934. }
  935. return setVar( interp, part1, part2, newValue, flags );
  936. }
  937. /// <summary> TCL.Tcl_SetVar2Ex -> setVar
  938. ///
  939. /// Given a two-part variable name, which may refer either to a scalar
  940. /// variable or an element of an array, change the value of the variable
  941. /// to a new Tcl object value. If the named scalar or array or element
  942. /// doesn't exist then create one.
  943. ///
  944. /// </summary>
  945. /// <param name="interp">the interp that holds the variable
  946. /// </param>
  947. /// <param name="part1">1st part of the variable name.
  948. /// </param>
  949. /// <param name="part2">2nd part of the variable name.
  950. /// </param>
  951. /// <param name="newValue">the new value for the variable
  952. /// </param>
  953. /// <param name="flags">misc flags that control the actions of this method
  954. ///
  955. /// Returns a pointer to the TclObject holding the new value of the
  956. /// variable. If the write operation was disallowed because an array was
  957. /// expected but not found (or vice versa), then null is returned; if
  958. /// the TCL.VarFlag.LEAVE_ERR_MSG flag is set, then an exception will be raised.
  959. /// Note that the returned object may not be the same one referenced
  960. /// by newValue because variable traces may modify the variable's value.
  961. /// The value of the given variable is set. If either the array or the
  962. /// entry didn't exist then a new variable is created.
  963. ///
  964. /// The reference count is decremented for any old value of the variable
  965. /// and incremented for its new value. If the new value for the variable
  966. /// is not the same one referenced by newValue (perhaps as a result
  967. /// of a variable trace), then newValue's ref count is left unchanged
  968. /// by TCL.Tcl_SetVar2Ex. newValue's ref count is also left unchanged if
  969. /// we are appending it as a string value: that is, if "flags" includes
  970. /// TCL.VarFlag.APPEND_VALUE but not TCL.VarFlag.LIST_ELEMENT.
  971. ///
  972. /// The reference count for the returned object is _not_ incremented: if
  973. /// you want to keep a reference to the object you must increment its
  974. /// ref count yourself.
  975. /// </param>
  976. internal static TclObject setVar( Interp interp, string part1, string part2, TclObject newValue, TCL.VarFlag flags )
  977. {
  978. Var var;
  979. Var array;
  980. TclObject oldValue;
  981. string bytes;
  982. Var[] result = lookupVar( interp, part1, part2, flags, "set", true, true );
  983. if ( result == null )
  984. {
  985. return null;
  986. }
  987. var = result[0];
  988. array = result[1];
  989. // If the variable is in a hashtable and its table field is null, then we
  990. // may have an upvar to an array element where the array was deleted
  991. // or an upvar to a namespace variable whose namespace was deleted.
  992. // Generate an error (allowing the variable to be reset would screw up
  993. // our storage allocation and is meaningless anyway).
  994. if ( ( ( var.flags & VarFlags.IN_HASHTABLE ) != 0 ) && ( var.table == null ) )
  995. {
  996. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  997. {
  998. if ( var.isVarArrayElement() )
  999. {
  1000. throw new TclVarException( interp, part1, part2, "set", danglingElement );
  1001. }
  1002. else
  1003. {
  1004. throw new TclVarException( interp, part1, part2, "set", danglingVar );
  1005. }
  1006. }
  1007. return null;
  1008. }
  1009. // It's an error to try to set an array variable itself.
  1010. if ( var.isVarArray() && !var.isVarUndefined() )
  1011. {
  1012. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  1013. {
  1014. throw new TclVarException( interp, part1, part2, "set", isArray );
  1015. }
  1016. return null;
  1017. }
  1018. // At this point, if we were appending, we used to call read traces: we
  1019. // treated append as a read-modify-write. However, it seemed unlikely to
  1020. // us that a real program would be interested in such reads being done
  1021. // during a set operation.
  1022. // Set the variable's new value. If appending, append the new value to
  1023. // the variable, either as a list element or as a string. Also, if
  1024. // appending, then if the variable's old value is unshared we can modify
  1025. // it directly, otherwise we must create a new copy to modify: this is
  1026. // "copy on write".
  1027. try
  1028. {
  1029. if ( var.isSQLITE3_Link() )
  1030. {
  1031. var.sqlite3_set( newValue );
  1032. return var.sqlite3_get();
  1033. }
  1034. else
  1035. {
  1036. oldValue = (TclObject)
  1037. var.value;
  1038. if ( ( flags & TCL.VarFlag.APPEND_VALUE ) != 0 )
  1039. {
  1040. if ( var.isVarUndefined() && ( oldValue != null ) )
  1041. {
  1042. oldValue.release(); // discard old value
  1043. var.value = null;
  1044. oldValue = null;
  1045. }
  1046. if ( ( flags & TCL.VarFlag.LIST_ELEMENT ) != 0 )
  1047. {
  1048. // append list element
  1049. if ( oldValue == null )
  1050. {
  1051. oldValue = TclList.newInstance();
  1052. var.value = oldValue;
  1053. oldValue.preserve(); // since var is referenced
  1054. }
  1055. else if ( oldValue.Shared )
  1056. {
  1057. // append to copy
  1058. var.value = oldValue.duplicate();
  1059. oldValue.release();
  1060. oldValue = (TclObject)var.value;
  1061. oldValue.preserve(); // since var is referenced
  1062. }
  1063. TclList.append( interp, oldValue, newValue );
  1064. }
  1065. else
  1066. {
  1067. // append string
  1068. // We append newValuePtr's bytes but don't change its ref count.
  1069. bytes = newValue.ToString();
  1070. if ( oldValue == null )
  1071. {
  1072. var.value = TclString.newInstance( bytes );
  1073. ( (TclObject)var.value ).preserve();
  1074. }
  1075. else
  1076. {
  1077. if ( oldValue.Shared )
  1078. {
  1079. // append to copy
  1080. var.value = oldValue.duplicate();
  1081. oldValue.release();
  1082. oldValue = (TclObject)var.value;
  1083. oldValue.preserve(); // since var is referenced
  1084. }
  1085. TclString.append( oldValue, newValue );
  1086. }
  1087. }
  1088. }
  1089. else
  1090. {
  1091. if ( ( flags & TCL.VarFlag.LIST_ELEMENT ) != 0 )
  1092. {
  1093. // set var to list element
  1094. int listFlags;
  1095. // We set the variable to the result of converting newValue's
  1096. // string rep to a list element. We do not change newValue's
  1097. // ref count.
  1098. if ( oldValue != null )
  1099. {
  1100. oldValue.release(); // discard old value
  1101. }
  1102. bytes = newValue.ToString();
  1103. listFlags = Util.scanElement( interp, bytes );
  1104. oldValue = TclString.newInstance( Util.convertElement( bytes, listFlags ) );
  1105. var.value = oldValue;
  1106. ( (TclObject)var.value ).preserve();
  1107. }
  1108. else if ( newValue != oldValue )
  1109. {
  1110. var.value = newValue.duplicate();
  1111. ( (TclObject)var.value ).preserve(); // var is another ref
  1112. if ( oldValue != null )
  1113. {
  1114. oldValue.release(); // discard old value
  1115. }
  1116. }
  1117. }
  1118. var.setVarScalar();
  1119. var.clearVarUndefined();
  1120. if ( array != null )
  1121. {
  1122. array.clearVarUndefined();
  1123. }
  1124. // Invoke any write traces for the variable.
  1125. if ( ( var.traces != null ) || ( ( array != null ) && ( array.traces != null ) ) )
  1126. {
  1127. string msg = callTraces( interp, array, var, part1, part2, ( flags & ( TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.NAMESPACE_ONLY ) ) | TCL.VarFlag.TRACE_WRITES );
  1128. if ( (System.Object)msg != null )
  1129. {
  1130. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  1131. {
  1132. throw new TclVarException( interp, part1, part2, "set", msg );
  1133. }
  1134. return null; // Same as "goto cleanup" in C verison
  1135. }
  1136. }
  1137. // Return the variable's value unless the variable was changed in some
  1138. // gross way by a trace (e.g. it was unset and then recreated as an
  1139. // array).
  1140. if ( var.isVarScalar() && !var.isVarUndefined() )
  1141. {
  1142. return (TclObject)var.value;
  1143. }
  1144. // A trace changed the value in some gross way. Return an empty string
  1145. // object.
  1146. return TclString.newInstance( "" );
  1147. }
  1148. }
  1149. finally
  1150. {
  1151. // If the variable doesn't exist anymore and no-one's using it,
  1152. // then free up the relevant structures and hash table entries.
  1153. if ( var.isVarUndefined() )
  1154. {
  1155. cleanupVar( var, array );
  1156. }
  1157. }
  1158. }
  1159. /// <summary> TclIncrVar2 -> incrVar
  1160. ///
  1161. /// Given a two-part variable name, which may refer either to a scalar
  1162. /// variable or an element of an array, increment the Tcl object value
  1163. /// of the variable by a specified amount.
  1164. ///
  1165. /// </summary>
  1166. /// <param name="part1">1st part of the variable name.
  1167. /// </param>
  1168. /// <param name="part2">2nd part of the variable name.
  1169. /// </param>
  1170. /// <param name="incrAmount">Amount to be added to variable.
  1171. /// </param>
  1172. /// <param name="flags">misc flags that control the actions of this method
  1173. ///
  1174. /// Results:
  1175. /// Returns a reference to the TclObject holding the new value of the
  1176. /// variable. If the specified variable doesn't exist, or there is a
  1177. /// clash in array usage, or an error occurs while executing variable
  1178. /// traces, then a TclException will be raised.
  1179. ///
  1180. /// Side effects:
  1181. /// The value of the given variable is incremented by the specified
  1182. /// amount. If either the array or the entry didn't exist then a new
  1183. /// variable is created. The ref count for the returned object is _not_
  1184. /// incremented to reflect the returned reference; if you want to keep a
  1185. /// reference to the object you must increment its ref count yourself.
  1186. ///
  1187. /// ----------------------------------------------------------------------
  1188. /// </param>
  1189. internal static TclObject incrVar( Interp interp, TclObject part1, TclObject part2, int incrAmount, TCL.VarFlag flags )
  1190. {
  1191. TclObject varValue = null;
  1192. bool createdNewObj; // Set to true if var's value object is shared
  1193. // so we must increment a copy (i.e. copy
  1194. // on write).
  1195. int i;
  1196. bool err;
  1197. // There are two possible error conditions that depend on the setting of
  1198. // TCL.VarFlag.LEAVE_ERR_MSG. an exception could be raised or null could be returned
  1199. err = false;
  1200. try
  1201. {
  1202. varValue = getVar( interp, part1, part2, flags );
  1203. }
  1204. catch ( TclException e )
  1205. {
  1206. err = true;
  1207. throw;
  1208. }
  1209. finally
  1210. {
  1211. // FIXME : is this the correct way to catch the error?
  1212. if ( err || varValue == null )
  1213. interp.addErrorInfo( "\n (reading value of variable to increment)" );
  1214. }
  1215. // Increment the variable's value. If the object is unshared we can
  1216. // modify it directly, otherwise we must create a new copy to modify:
  1217. // this is "copy on write". Then free the variable's old string
  1218. // representation, if any, since it will no longer be valid.
  1219. createdNewObj = false;
  1220. if ( varValue.Shared )
  1221. {
  1222. varValue = varValue.duplicate();
  1223. createdNewObj = true;
  1224. }
  1225. try
  1226. {
  1227. i = TclInteger.get( interp, varValue );
  1228. }
  1229. catch ( TclException e )
  1230. {
  1231. if ( createdNewObj )
  1232. {
  1233. varValue.release(); // free unneeded copy
  1234. }
  1235. throw;
  1236. }
  1237. TclInteger.set( varValue, ( i + incrAmount ) );
  1238. // Store the variable's new value and run any write traces.
  1239. return setVar( interp, part1, part2, varValue, flags );
  1240. }
  1241. /// <summary> Unset a variable whose name is stored in a Tcl object.
  1242. ///
  1243. /// </summary>
  1244. /// <param name="nameObj">name of the variable.
  1245. /// </param>
  1246. /// <param name="flags">misc flags that control the actions of this method.
  1247. /// </param>
  1248. internal static void unsetVar( Interp interp, TclObject nameObj, TCL.VarFlag flags )
  1249. {
  1250. unsetVar( interp, nameObj.ToString(), null, flags );
  1251. }
  1252. /// <summary> Unset a variable.
  1253. ///
  1254. /// </summary>
  1255. /// <param name="name">name of the variable.
  1256. /// </param>
  1257. /// <param name="flags">misc flags that control the actions of this method.
  1258. /// </param>
  1259. internal static void unsetVar( Interp interp, string name, TCL.VarFlag flags )
  1260. {
  1261. unsetVar( interp, name, null, flags );
  1262. }
  1263. /// <summary> TCL.Tcl_UnsetVar2 -> unsetVar
  1264. ///
  1265. /// Unset a variable, given a two-part name consisting of array
  1266. /// name and element within array.
  1267. ///
  1268. /// </summary>
  1269. /// <param name="part1">1st part of the variable name.
  1270. /// </param>
  1271. /// <param name="part2">2nd part of the variable name.
  1272. /// </param>
  1273. /// <param name="flags">misc flags that control the actions of this method.
  1274. ///
  1275. /// If part1 and part2 indicate a local or global variable in interp,
  1276. /// it is deleted. If part1 is an array name and part2 is null, then
  1277. /// the whole array is deleted.
  1278. ///
  1279. /// </param>
  1280. internal static void unsetVar( Interp interp, string part1, string part2, TCL.VarFlag flags )
  1281. {
  1282. Var dummyVar;
  1283. Var var;
  1284. Var array;
  1285. //ActiveVarTrace active;
  1286. TclObject obj;
  1287. TCL.CompletionCode result;
  1288. // FIXME : what about the null return vs exception thing here?
  1289. Var[] lookup_result = lookupVar( interp, part1, part2, flags, "unset", false, false );
  1290. if ( lookup_result == null )
  1291. {
  1292. if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
  1293. throw new TclRuntimeError( "unexpected null reference" );
  1294. else
  1295. return;
  1296. }
  1297. var = lookup_result[0];
  1298. array = lookup_result[1];
  1299. result = ( var.isVarUndefined() ? TCL.CompletionCode.ERROR : TCL.CompletionCode.OK );
  1300. if ( ( array != null ) && ( array.sidVec != null ) )
  1301. {
  1302. deleteSearches( array );
  1303. }
  1304. // The code below is tricky, because of the possibility that
  1305. // a trace procedure might try to access a variable being
  1306. // deleted. To handle this situation gracefully, do things
  1307. // in three steps:
  1308. // 1. Copy the contents of the variable to a dummy variable
  1309. // structure, and mark the original Var structure as undefined.
  1310. // 2. Invoke traces and clean up the variable, using the dummy copy.
  1311. // 3. If at the end of this the original variable is still
  1312. // undefined and has no outstanding references, then delete
  1313. // it (but it could have gotten recreated by a trace).
  1314. dummyVar = new Var();
  1315. //FIXME: Var class really should implement clone to make a bit copy.
  1316. dummyVar.value = var.value;
  1317. dummyVar.traces = var.traces;
  1318. dummyVar.flags = var.flags;
  1319. dummyVar.hashKey = var.hashKey;
  1320. dummyVar.table = var.table;
  1321. dummyVar.refCount = var.refCount;
  1322. dummyVar.ns = var.ns;
  1323. var.setVarUndefined();
  1324. var.setVarScalar();
  1325. var.value = null; // dummyVar points to any value object
  1326. var.traces = null;
  1327. var.sidVec = null;
  1328. // Call trace procedures for the variable being deleted. Then delete
  1329. // its traces. Be sure to abort any other traces for the variable
  1330. // that are still pending. Special tricks:
  1331. // 1. We need to increment var's refCount around this: CallTraces
  1332. // will use dummyVar so it won't increment var's refCount itself.
  1333. // 2. Turn off the TRACE_ACTIVE flag in dummyVar: we want to
  1334. // call unset traces even if other traces are pending.
  1335. if ( ( dummyVar.traces != null ) || ( ( array != null ) && ( array.traces != null ) ) )
  1336. {
  1337. var.refCount++;
  1338. dummyVar.flags &= ~VarFlags.TRACE_ACTIVE;
  1339. callTraces( interp, arra

Large files files are truncated, but you can click here to view the full file