PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/TCL/src/base/Var.cs

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

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