PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/TCL/src/base/Interp.cs

https://bitbucket.org/eumario/csharp-sqlite
C# | 2609 lines | 1582 code | 408 blank | 619 comment | 246 complexity | 87d7548632eba221c0971ec69b21f156 MD5 | raw file

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

  1. #undef DEBUG
  2. /*
  3. * Interp.java --
  4. *
  5. * Implements the core Tcl interpreter.
  6. *
  7. * Copyright (c) 1997 Cornell University.
  8. * Copyright (c) 1997-1998 Sun Microsystems, Inc.
  9. *
  10. * See the file "license.terms" for information on usage and
  11. * redistribution of this file, and for a DISCLAIMER OF ALL
  12. * WARRANTIES.
  13. *
  14. * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
  15. *
  16. * RCS @(#) $Id: Interp.java,v 1.44 2003/07/25 16:38:35 mdejong Exp $
  17. *
  18. */
  19. using System;
  20. using System.Collections;
  21. using System.IO;
  22. using System.Text;
  23. namespace tcl.lang
  24. {
  25. /// <summary> The Tcl interpreter class.</summary>
  26. public class Interp : EventuallyFreed
  27. {
  28. private void InitBlock()
  29. {
  30. reflectObjTable = new Hashtable();
  31. reflectConflictTable = new Hashtable();
  32. importTable = new Hashtable[] { new Hashtable(), new Hashtable() };
  33. }
  34. /// <summary> Returns the name of the script file currently under execution.
  35. ///
  36. /// </summary>
  37. /// <returns> the name of the script file currently under execution.
  38. /// </returns>
  39. internal string ScriptFile
  40. {
  41. get
  42. {
  43. return dbg.fileName;
  44. }
  45. }
  46. // The following three variables are used to maintain a translation
  47. // table between ReflectObject's and their string names. These
  48. // variables are accessed by the ReflectObject class, they
  49. // are defined here be cause we need them to be per interp data.
  50. // Translates Object to ReflectObject. This makes sure we have only
  51. // one ReflectObject internalRep for the same Object -- this
  52. // way Object identity can be done by string comparison.
  53. internal Hashtable reflectObjTable;
  54. // Number of reflect objects created so far inside this Interp
  55. // (including those that have be freed)
  56. internal long reflectObjCount = 0;
  57. // Table used to store reflect hash index conflicts, see
  58. // ReflectObject implementation for more details
  59. internal Hashtable reflectConflictTable;
  60. // The number of chars to copy from an offending command into error
  61. // message.
  62. private const int MAX_ERR_LENGTH = 200;
  63. // We pretend this is Tcl 8.0, patch level 0.
  64. internal const string TCL_VERSION = "8.0";
  65. internal const string TCL_PATCH_LEVEL = "8.0";
  66. // Total number of times a command procedure
  67. // has been called for this interpreter.
  68. protected internal int cmdCount;
  69. // FIXME : remove later
  70. // Table of commands for this interpreter.
  71. //Hashtable cmdTable;
  72. // Table of channels currently registered in this interp.
  73. internal Hashtable interpChanTable;
  74. // The Notifier associated with this Interp.
  75. private Notifier notifier;
  76. // Hash table for associating data with this interpreter. Cleaned up
  77. // when this interpreter is deleted.
  78. internal Hashtable assocData;
  79. // Current working directory.
  80. private FileInfo workingDir;
  81. // Points to top-most in stack of all nested procedure
  82. // invocations. null means there are no active procedures.
  83. internal CallFrame frame;
  84. // Points to the call frame whose variables are currently in use
  85. // (same as frame unless an "uplevel" command is being
  86. // executed). null means no procedure is active or "uplevel 0" is
  87. // being exec'ed.
  88. internal CallFrame varFrame;
  89. // The interpreter's global namespace.
  90. internal NamespaceCmd.Namespace globalNs;
  91. // Hash table used to keep track of hidden commands on a per-interp basis.
  92. internal Hashtable hiddenCmdTable;
  93. // Information used by InterpCmd.java to keep
  94. // track of master/slave interps on a per-interp basis.
  95. // Keeps track of all interps for which this interp is the Master.
  96. // First, slaveTable (a hashtable) maps from names of commands to
  97. // slave interpreters. This hashtable is used to store information
  98. // about slave interpreters of this interpreter, to map over all slaves, etc.
  99. internal Hashtable slaveTable;
  100. // Hash table for Target Records. Contains all Target records which denote
  101. // aliases from slaves or sibling interpreters that direct to commands in
  102. // this interpreter. This table is used to remove dangling pointers
  103. // from the slave (or sibling) interpreters when this interpreter is deleted.
  104. internal Hashtable targetTable;
  105. // Information necessary for this interp to function as a slave.
  106. internal InterpSlaveCmd slave;
  107. // Table which maps from names of commands in slave interpreter to
  108. // InterpAliasCmd objects.
  109. internal Hashtable aliasTable;
  110. // FIXME : does globalFrame need to be replaced by globalNs?
  111. // Points to the global variable frame.
  112. //CallFrame globalFrame;
  113. // The script file currently under execution. Can be null if the
  114. // interpreter is not evaluating any script file.
  115. internal string scriptFile;
  116. // Number of times the interp.eval() routine has been recursively
  117. // invoked.
  118. internal int nestLevel;
  119. // Used to catch infinite loops in Parser.eval2.
  120. internal int maxNestingDepth;
  121. // Flags used when evaluating a command.
  122. internal int evalFlags;
  123. // Flags used when evaluating a command.
  124. public int flags;
  125. // Is this interpreted marked as safe?
  126. internal bool isSafe;
  127. // Offset of character just after last one compiled or executed
  128. // by Parser.eval2().
  129. internal int termOffset;
  130. // List of name resolution schemes added to this interpreter.
  131. // Schemes are added/removed by calling addInterpResolver and
  132. // removeInterpResolver.
  133. internal ArrayList resolvers;
  134. // The expression parser for this interp.
  135. internal Expression expr;
  136. // Used by the Expression class. If it is equal to zero, then the
  137. // parser will evaluate commands and retrieve variable values from
  138. // the interp.
  139. internal int noEval;
  140. // Used in the Expression.java file for the
  141. // SrandFunction.class and RandFunction.class.
  142. // Set to true if a seed has been set.
  143. internal bool randSeedInit;
  144. // Used in the Expression.java file for the SrandFunction.class and
  145. // RandFunction.class. Stores the value of the seed.
  146. internal long randSeed;
  147. // If returnCode is TCL.CompletionCode.ERROR, stores the errorInfo.
  148. internal string errorInfo;
  149. // If returnCode is TCL.CompletionCode.ERROR, stores the errorCode.
  150. internal string errorCode;
  151. // Completion code to return if current procedure exits with a
  152. // TCL_RETURN code.
  153. protected internal TCL.CompletionCode returnCode;
  154. // True means the interpreter has been deleted: don't process any
  155. // more commands for it, and destroy the structure as soon as all
  156. // nested invocations of eval() are done.
  157. protected internal bool deleted;
  158. // True means an error unwind is already in progress. False
  159. // means a command proc has been invoked since last error occurred.
  160. protected internal bool errInProgress;
  161. // True means information has already been logged in $errorInfo
  162. // for the current eval() instance, so eval() needn't log it
  163. // (used to implement the "error" command).
  164. protected internal bool errAlreadyLogged;
  165. // True means that addErrorInfo has been called to record
  166. // information for the current error. False means Interp.eval
  167. // must clear the errorCode variable if an error is returned.
  168. protected internal bool errCodeSet;
  169. // When TCL_ERROR is returned, this gives the line number within
  170. // the command where the error occurred (1 means first line).
  171. internal int errorLine;
  172. // Stores the current result in the interpreter.
  173. private TclObject m_result;
  174. // Value m_result is set to when resetResult() is called.
  175. private TclObject m_nullResult;
  176. // Used ONLY by PackageCmd.
  177. internal Hashtable packageTable;
  178. internal string packageUnknown;
  179. // Used ONLY by the Parser.
  180. internal TclObject[][][] parserObjv;
  181. internal int[] parserObjvUsed;
  182. internal TclToken[] parserTokens;
  183. internal int parserTokensUsed;
  184. // Used ONLY by JavaImportCmd
  185. internal Hashtable[] importTable;
  186. // List of unsafe commands:
  187. internal static readonly string[] unsafeCmds = new string[] { "encoding", "exit", "load", "cd", "fconfigure", "file", "glob", "open", "pwd", "socket", "beep", "echo", "ls", "resource", "source", "exec", "source" };
  188. // Flags controlling the call of invoke.
  189. internal const int INVOKE_HIDDEN = 1;
  190. internal const int INVOKE_NO_UNKNOWN = 2;
  191. internal const int INVOKE_NO_TRACEBACK = 4;
  192. public Interp()
  193. {
  194. InitBlock();
  195. //freeProc = null;
  196. errorLine = 0;
  197. // An empty result is used pretty often. We will use a shared
  198. // TclObject instance to represent the empty result so that we
  199. // don't need to create a new TclObject instance every time the
  200. // interpreter result is set to empty.
  201. m_nullResult = TclString.newInstance( "" );
  202. m_nullResult.preserve(); // Increment refCount to 1
  203. m_nullResult.preserve(); // Increment refCount to 2 (shared)
  204. m_result = TclString.newInstance( "" ); //m_nullResult; // correcponds to iPtr->objResultPtr
  205. m_result.preserve();
  206. expr = new Expression();
  207. nestLevel = 0;
  208. maxNestingDepth = 1000;
  209. frame = null;
  210. varFrame = null;
  211. returnCode = TCL.CompletionCode.OK;
  212. errorInfo = null;
  213. errorCode = null;
  214. packageTable = new Hashtable();
  215. packageUnknown = null;
  216. cmdCount = 0;
  217. termOffset = 0;
  218. resolvers = null;
  219. evalFlags = 0;
  220. scriptFile = null;
  221. flags = 0;
  222. isSafe = false;
  223. assocData = null;
  224. globalNs = null; // force creation of global ns below
  225. globalNs = NamespaceCmd.createNamespace( this, null, null );
  226. if ( globalNs == null )
  227. {
  228. throw new TclRuntimeError( "Interp(): can't create global namespace" );
  229. }
  230. // Init things that are specific to the Jacl implementation
  231. workingDir = new FileInfo( System.Environment.CurrentDirectory );
  232. noEval = 0;
  233. notifier = Notifier.getNotifierForThread( System.Threading.Thread.CurrentThread );
  234. notifier.preserve();
  235. randSeedInit = false;
  236. deleted = false;
  237. errInProgress = false;
  238. errAlreadyLogged = false;
  239. errCodeSet = false;
  240. dbg = initDebugInfo();
  241. slaveTable = new Hashtable();
  242. targetTable = new Hashtable();
  243. aliasTable = new Hashtable();
  244. // init parser variables
  245. Parser.init( this );
  246. TclParse.init( this );
  247. // Initialize the Global (static) channel table and the local
  248. // interp channel table.
  249. interpChanTable = TclIO.getInterpChanTable( this );
  250. // Sets up the variable trace for tcl_precision.
  251. Util.setupPrecisionTrace( this );
  252. // Create the built-in commands.
  253. createCommands();
  254. try
  255. {
  256. // Set up tcl_platform, tcl_version, tcl_library and other
  257. // global variables.
  258. setVar( "tcl_platform", "platform", "windows", TCL.VarFlag.GLOBAL_ONLY );
  259. setVar( "tcl_platform", "byteOrder", "bigEndian", TCL.VarFlag.GLOBAL_ONLY );
  260. setVar( "tcl_platform", "os", Environment.OSVersion.Platform.ToString(), TCL.VarFlag.GLOBAL_ONLY );
  261. setVar( "tcl_platform", "osVersion", Environment.OSVersion.Version.ToString(), TCL.VarFlag.GLOBAL_ONLY );
  262. setVar( "tcl_platform", "machine", Util.tryGetSystemProperty( "os.arch", "?" ), TCL.VarFlag.GLOBAL_ONLY );
  263. setVar( "tcl_version", TCL_VERSION, TCL.VarFlag.GLOBAL_ONLY );
  264. setVar( "tcl_patchLevel", TCL_PATCH_LEVEL, TCL.VarFlag.GLOBAL_ONLY );
  265. setVar( "tcl_library", "resource:/tcl/lang/library", TCL.VarFlag.GLOBAL_ONLY );
  266. if ( Util.Windows )
  267. {
  268. setVar( "tcl_platform", "host_platform", "windows", TCL.VarFlag.GLOBAL_ONLY );
  269. }
  270. else if ( Util.Mac )
  271. {
  272. setVar( "tcl_platform", "host_platform", "macintosh", TCL.VarFlag.GLOBAL_ONLY );
  273. }
  274. else
  275. {
  276. setVar( "tcl_platform", "host_platform", "unix", TCL.VarFlag.GLOBAL_ONLY );
  277. }
  278. // Create the env array an populated it with proper
  279. // values.
  280. Env.initialize( this );
  281. // Register Tcl's version number. Note: This MUST be
  282. // done before the call to evalResource, otherwise
  283. // calls to "package require tcl" will fail.
  284. pkgProvide( "Tcl", TCL_VERSION );
  285. // Source the init.tcl script to initialize auto-loading.
  286. evalResource( "/tcl/lang/library/init.tcl" );
  287. }
  288. catch ( TclException e )
  289. {
  290. System.Diagnostics.Debug.WriteLine( getResult().ToString() );
  291. SupportClass.WriteStackTrace( e, Console.Error );
  292. throw new TclRuntimeError( "unexpected TclException: " + e.Message, e );
  293. }
  294. }
  295. public override void eventuallyDispose()
  296. {
  297. if ( deleted )
  298. {
  299. return;
  300. }
  301. deleted = true;
  302. if ( nestLevel > 0 )
  303. {
  304. //-- TODO -- Determine why this is an error throw new TclRuntimeError("dispose() called with active evals");
  305. }
  306. // Remove our association with the notifer (if we had one).
  307. if ( notifier != null )
  308. {
  309. notifier.release();
  310. notifier = null;
  311. }
  312. // Dismantle everything in the global namespace except for the
  313. // "errorInfo" and "errorCode" variables. These might be needed
  314. // later on if errors occur while deleting commands. We are careful
  315. // to destroy and recreate the "errorInfo" and "errorCode"
  316. // variables, in case they had any traces on them.
  317. //
  318. // Dismantle the namespace here, before we clear the assocData. If any
  319. // background errors occur here, they will be deleted below.
  320. // FIXME : check impl of TclTeardownNamespace
  321. NamespaceCmd.teardownNamespace( globalNs );
  322. // Delete all variables.
  323. TclObject errorInfoObj = null, errorCodeObj = null;
  324. try
  325. {
  326. errorInfoObj = getVar( "errorInfo", null, TCL.VarFlag.GLOBAL_ONLY );
  327. }
  328. catch ( TclException e )
  329. {
  330. // Do nothing when var does not exist.
  331. }
  332. if ( errorInfoObj != null )
  333. {
  334. errorInfoObj.preserve();
  335. }
  336. try
  337. {
  338. errorCodeObj = getVar( "errorCode", null, TCL.VarFlag.GLOBAL_ONLY );
  339. }
  340. catch ( TclException e )
  341. {
  342. // Do nothing when var does not exist.
  343. }
  344. if ( errorCodeObj != null )
  345. {
  346. errorCodeObj.preserve();
  347. }
  348. frame = null;
  349. varFrame = null;
  350. try
  351. {
  352. if ( errorInfoObj != null )
  353. {
  354. setVar( "errorInfo", null, errorInfoObj, TCL.VarFlag.GLOBAL_ONLY );
  355. errorInfoObj.release();
  356. }
  357. if ( errorCodeObj != null )
  358. {
  359. setVar( "errorCode", null, errorCodeObj, TCL.VarFlag.GLOBAL_ONLY );
  360. errorCodeObj.release();
  361. }
  362. }
  363. catch ( TclException e )
  364. {
  365. // Ignore it -- same behavior as Tcl 8.0.
  366. }
  367. // Tear down the math function table.
  368. expr = null;
  369. // Remove all the assoc data tied to this interp and invoke
  370. // deletion callbacks; note that a callback can create new
  371. // callbacks, so we iterate.
  372. // ATK The java code was somethink strong
  373. if ( assocData != null )
  374. {
  375. foreach ( AssocData data in assocData.Values )
  376. {
  377. data.disposeAssocData( this );
  378. }
  379. assocData.Clear();
  380. }
  381. // Close any remaining channels
  382. for ( IDictionaryEnumerator e = interpChanTable.GetEnumerator(); e.MoveNext(); )
  383. {
  384. Object key = e.Key;
  385. Channel chan = (Channel)e.Value;
  386. try
  387. {
  388. chan.close();
  389. }
  390. catch ( IOException ex )
  391. {
  392. // Ignore any IO errors
  393. }
  394. }
  395. // Finish deleting the global namespace.
  396. // FIXME : check impl of Tcl_DeleteNamespace
  397. NamespaceCmd.deleteNamespace( globalNs );
  398. globalNs = null;
  399. // Free up the result *after* deleting variables, since variable
  400. // deletion could have transferred ownership of the result string
  401. // to Tcl.
  402. frame = null;
  403. varFrame = null;
  404. resolvers = null;
  405. resetResult();
  406. }
  407. ~Interp()
  408. {
  409. dispose();
  410. }
  411. protected internal void createCommands()
  412. {
  413. Extension.loadOnDemand( this, "after", "tcl.lang.AfterCmd" );
  414. Extension.loadOnDemand( this, "append", "tcl.lang.AppendCmd" );
  415. Extension.loadOnDemand( this, "array", "tcl.lang.ArrayCmd" );
  416. Extension.loadOnDemand( this, "binary", "tcl.lang.BinaryCmd" );
  417. Extension.loadOnDemand( this, "break", "tcl.lang.BreakCmd" );
  418. Extension.loadOnDemand( this, "case", "tcl.lang.CaseCmd" );
  419. Extension.loadOnDemand( this, "catch", "tcl.lang.CatchCmd" );
  420. Extension.loadOnDemand( this, "cd", "tcl.lang.CdCmd" );
  421. Extension.loadOnDemand( this, "clock", "tcl.lang.ClockCmd" );
  422. Extension.loadOnDemand( this, "close", "tcl.lang.CloseCmd" );
  423. Extension.loadOnDemand( this, "continue", "tcl.lang.ContinueCmd" );
  424. Extension.loadOnDemand( this, "concat", "tcl.lang.ConcatCmd" );
  425. Extension.loadOnDemand( this, "encoding", "tcl.lang.EncodingCmd" );
  426. Extension.loadOnDemand( this, "eof", "tcl.lang.EofCmd" );
  427. Extension.loadOnDemand( this, "eval", "tcl.lang.EvalCmd" );
  428. Extension.loadOnDemand( this, "error", "tcl.lang.ErrorCmd" );
  429. if ( !Util.Mac )
  430. {
  431. Extension.loadOnDemand( this, "exec", "tcl.lang.ExecCmd" );
  432. }
  433. Extension.loadOnDemand( this, "exit", "tcl.lang.ExitCmd" );
  434. Extension.loadOnDemand( this, "expr", "tcl.lang.ExprCmd" );
  435. Extension.loadOnDemand( this, "fblocked", "tcl.lang.FblockedCmd" );
  436. Extension.loadOnDemand( this, "fconfigure", "tcl.lang.FconfigureCmd" );
  437. Extension.loadOnDemand( this, "file", "tcl.lang.FileCmd" );
  438. Extension.loadOnDemand( this, "flush", "tcl.lang.FlushCmd" );
  439. Extension.loadOnDemand( this, "for", "tcl.lang.ForCmd" );
  440. Extension.loadOnDemand( this, "foreach", "tcl.lang.ForeachCmd" );
  441. Extension.loadOnDemand( this, "format", "tcl.lang.FormatCmd" );
  442. Extension.loadOnDemand( this, "gets", "tcl.lang.GetsCmd" );
  443. Extension.loadOnDemand( this, "global", "tcl.lang.GlobalCmd" );
  444. Extension.loadOnDemand( this, "glob", "tcl.lang.GlobCmd" );
  445. Extension.loadOnDemand( this, "if", "tcl.lang.IfCmd" );
  446. Extension.loadOnDemand( this, "incr", "tcl.lang.IncrCmd" );
  447. Extension.loadOnDemand( this, "info", "tcl.lang.InfoCmd" );
  448. Extension.loadOnDemand( this, "interp", "tcl.lang.InterpCmd" );
  449. Extension.loadOnDemand( this, "list", "tcl.lang.ListCmd" );
  450. Extension.loadOnDemand( this, "join", "tcl.lang.JoinCmd" );
  451. Extension.loadOnDemand( this, "lappend", "tcl.lang.LappendCmd" );
  452. Extension.loadOnDemand( this, "lindex", "tcl.lang.LindexCmd" );
  453. Extension.loadOnDemand( this, "linsert", "tcl.lang.LinsertCmd" );
  454. Extension.loadOnDemand( this, "llength", "tcl.lang.LlengthCmd" );
  455. Extension.loadOnDemand( this, "lrange", "tcl.lang.LrangeCmd" );
  456. Extension.loadOnDemand( this, "lreplace", "tcl.lang.LreplaceCmd" );
  457. Extension.loadOnDemand( this, "lsearch", "tcl.lang.LsearchCmd" );
  458. Extension.loadOnDemand( this, "lset", "tcl.lang.LsetCmd" );
  459. Extension.loadOnDemand( this, "lsort", "tcl.lang.LsortCmd" );
  460. Extension.loadOnDemand( this, "namespace", "tcl.lang.NamespaceCmd" );
  461. Extension.loadOnDemand( this, "open", "tcl.lang.OpenCmd" );
  462. Extension.loadOnDemand( this, "package", "tcl.lang.PackageCmd" );
  463. Extension.loadOnDemand( this, "proc", "tcl.lang.ProcCmd" );
  464. Extension.loadOnDemand( this, "puts", "tcl.lang.PutsCmd" );
  465. Extension.loadOnDemand( this, "pwd", "tcl.lang.PwdCmd" );
  466. Extension.loadOnDemand( this, "read", "tcl.lang.ReadCmd" );
  467. Extension.loadOnDemand( this, "regsub", "tcl.lang.RegsubCmd" );
  468. Extension.loadOnDemand( this, "rename", "tcl.lang.RenameCmd" );
  469. Extension.loadOnDemand( this, "return", "tcl.lang.ReturnCmd" );
  470. Extension.loadOnDemand( this, "scan", "tcl.lang.ScanCmd" );
  471. Extension.loadOnDemand( this, "seek", "tcl.lang.SeekCmd" );
  472. Extension.loadOnDemand( this, "set", "tcl.lang.SetCmd" );
  473. Extension.loadOnDemand( this, "socket", "tcl.lang.SocketCmd" );
  474. Extension.loadOnDemand( this, "source", "tcl.lang.SourceCmd" );
  475. Extension.loadOnDemand( this, "split", "tcl.lang.SplitCmd" );
  476. Extension.loadOnDemand( this, "string", "tcl.lang.StringCmd" );
  477. Extension.loadOnDemand( this, "subst", "tcl.lang.SubstCmd" );
  478. Extension.loadOnDemand( this, "switch", "tcl.lang.SwitchCmd" );
  479. Extension.loadOnDemand( this, "tell", "tcl.lang.TellCmd" );
  480. Extension.loadOnDemand( this, "time", "tcl.lang.TimeCmd" );
  481. Extension.loadOnDemand( this, "trace", "tcl.lang.TraceCmd" );
  482. Extension.loadOnDemand( this, "unset", "tcl.lang.UnsetCmd" );
  483. Extension.loadOnDemand( this, "update", "tcl.lang.UpdateCmd" );
  484. Extension.loadOnDemand( this, "uplevel", "tcl.lang.UplevelCmd" );
  485. Extension.loadOnDemand( this, "upvar", "tcl.lang.UpvarCmd" );
  486. Extension.loadOnDemand( this, "variable", "tcl.lang.VariableCmd" );
  487. Extension.loadOnDemand( this, "vwait", "tcl.lang.VwaitCmd" );
  488. Extension.loadOnDemand( this, "while", "tcl.lang.WhileCmd" );
  489. // Add "regexp" and related commands to this interp.
  490. RegexpCmd.init( this );
  491. // The Java package is only loaded when the user does a
  492. // "package require java" in the interp. We need to create a small
  493. // command that will load when "package require java" is called.
  494. Extension.loadOnDemand( this, "jaclloadjava", "tcl.lang.JaclLoadJavaCmd" );
  495. try
  496. {
  497. eval( "package ifneeded java 1.3.1 jaclloadjava" );
  498. }
  499. catch ( TclException e )
  500. {
  501. System.Diagnostics.Debug.WriteLine( getResult().ToString() );
  502. SupportClass.WriteStackTrace( e, Console.Error );
  503. throw new TclRuntimeError( "unexpected TclException: " + e.Message, e );
  504. }
  505. }
  506. public void setAssocData( string name, AssocData data )
  507. // Object associated with the name.
  508. {
  509. if ( assocData == null )
  510. {
  511. assocData = new Hashtable();
  512. }
  513. SupportClass.PutElement( assocData, name, data );
  514. }
  515. public void deleteAssocData( string name )
  516. // Name of association.
  517. {
  518. if ( assocData == null )
  519. {
  520. return;
  521. }
  522. SupportClass.HashtableRemove( assocData, name );
  523. }
  524. public AssocData getAssocData( string name )
  525. // Name of association.
  526. {
  527. if ( assocData == null )
  528. {
  529. return null;
  530. }
  531. else
  532. {
  533. return (AssocData)assocData[name];
  534. }
  535. }
  536. public void backgroundError()
  537. {
  538. BgErrorMgr mgr = (BgErrorMgr)getAssocData( "tclBgError" );
  539. if ( mgr == null )
  540. {
  541. mgr = new BgErrorMgr( this );
  542. setAssocData( "tclBgError", mgr );
  543. }
  544. mgr.addBgError();
  545. }
  546. /*-----------------------------------------------------------------
  547. *
  548. * VARIABLES
  549. *
  550. *-----------------------------------------------------------------
  551. */
  552. public TclObject setVar( TclObject nameObj, TclObject value, TCL.VarFlag flags )
  553. {
  554. return Var.setVar( this, nameObj, value, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  555. }
  556. public TclObject setVar( string name, TclObject value, TCL.VarFlag flags )
  557. {
  558. return Var.setVar( this, name, value, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  559. }
  560. public TclObject setVar( string name1, string name2, TclObject value, TCL.VarFlag flags )
  561. {
  562. return Var.setVar( this, name1, name2, value, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  563. }
  564. public void setVar( string name, string strValue, TCL.VarFlag flags )
  565. {
  566. Var.setVar( this, name, TclString.newInstance( strValue ), ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  567. }
  568. public void setVar( string name1, string name2, string strValue, TCL.VarFlag flags )
  569. {
  570. Var.setVar( this, name1, name2, TclString.newInstance( strValue ), ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  571. }
  572. public TclObject getVar( TclObject nameObj, TCL.VarFlag flags )
  573. {
  574. return Var.getVar( this, nameObj, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  575. }
  576. public TclObject getVar( string name, TCL.VarFlag flags )
  577. {
  578. return Var.getVar( this, name, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  579. }
  580. public TclObject getVar( string name1, string name2, TCL.VarFlag flags )
  581. {
  582. return Var.getVar( this, name1, name2, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  583. }
  584. public void unsetVar( TclObject nameObj, TCL.VarFlag flags )
  585. {
  586. Var.unsetVar( this, nameObj, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  587. }
  588. public void unsetVar( string name, TCL.VarFlag flags )
  589. {
  590. Var.unsetVar( this, name, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  591. }
  592. public void unsetVar( string name1, string name2, TCL.VarFlag flags )
  593. {
  594. Var.unsetVar( this, name1, name2, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ) );
  595. }
  596. public void traceVar( TclObject nameObj, VarTrace trace, TCL.VarFlag flags )
  597. {
  598. Var.traceVar( this, nameObj, flags, trace );
  599. }
  600. public void traceVar( string name, VarTrace trace, TCL.VarFlag flags )
  601. {
  602. Var.traceVar( this, name, flags, trace );
  603. }
  604. public void traceVar( string part1, string part2, VarTrace trace, TCL.VarFlag flags )
  605. {
  606. Var.traceVar( this, part1, part2, flags, trace );
  607. }
  608. public void untraceVar( TclObject nameObj, VarTrace trace, TCL.VarFlag flags )
  609. // OR-ed collection of bits describing current
  610. // trace, including any of TCL.VarFlag.TRACE_READS,
  611. // TCL.VarFlag.TRACE_WRITES, TCL.VarFlag.TRACE_UNSETS,
  612. // TCL.VarFlag.GLOBAL_ONLY and TCL.VarFlag.NAMESPACE_ONLY.
  613. {
  614. Var.untraceVar( this, nameObj, flags, trace );
  615. }
  616. public void untraceVar( string name, VarTrace trace, TCL.VarFlag flags )
  617. // OR-ed collection of bits describing current
  618. // trace, including any of TCL.VarFlag.TRACE_READS,
  619. // TCL.VarFlag.TRACE_WRITES, TCL.VarFlag.TRACE_UNSETS,
  620. // TCL.VarFlag.GLOBAL_ONLY and TCL.VarFlag.NAMESPACE_ONLY.
  621. {
  622. Var.untraceVar( this, name, flags, trace );
  623. }
  624. public void untraceVar( string part1, string part2, VarTrace trace, TCL.VarFlag flags )
  625. // OR-ed collection of bits describing current
  626. // trace, including any of TCL.VarFlag.TRACE_READS,
  627. // TCL.VarFlag.TRACE_WRITES, TCL.VarFlag.TRACE_UNSETS,
  628. // TCL.VarFlag.GLOBAL_ONLY and TCL.VarFlag.NAMESPACE_ONLY.
  629. {
  630. Var.untraceVar( this, part1, part2, flags, trace );
  631. }
  632. public void createCommand( string cmdName, Command cmdImpl )
  633. // Command object to associate with
  634. // cmdName.
  635. {
  636. ImportRef oldRef = null;
  637. NamespaceCmd.Namespace ns;
  638. WrappedCommand cmd, refCmd;
  639. string tail;
  640. ImportedCmdData data;
  641. if ( deleted )
  642. {
  643. // The interpreter is being deleted. Don't create any new
  644. // commands; it's not safe to muck with the interpreter anymore.
  645. return;
  646. }
  647. // Determine where the command should reside. If its name contains
  648. // namespace qualifiers, we put it in the specified namespace;
  649. // otherwise, we always put it in the global namespace.
  650. if ( cmdName.IndexOf( "::" ) != -1 )
  651. {
  652. // Java does not support passing an address so we pass
  653. // an array of size 1 and then assign arr[0] to the value
  654. NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1];
  655. NamespaceCmd.Namespace[] dummyArr = new NamespaceCmd.Namespace[1];
  656. string[] tailArr = new string[1];
  657. NamespaceCmd.getNamespaceForQualName( this, cmdName, null, TCL.VarFlag.CREATE_NS_IF_UNKNOWN, nsArr, dummyArr, dummyArr, tailArr );
  658. ns = nsArr[0];
  659. tail = tailArr[0];
  660. if ( ( ns == null ) || ( (System.Object)tail == null ) )
  661. {
  662. return;
  663. }
  664. }
  665. else
  666. {
  667. ns = globalNs;
  668. tail = cmdName;
  669. }
  670. cmd = (WrappedCommand)ns.cmdTable[tail];
  671. if ( cmd != null )
  672. {
  673. // Command already exists. Delete the old one.
  674. // Be careful to preserve any existing import links so we can
  675. // restore them down below. That way, you can redefine a
  676. // command and its import status will remain intact.
  677. oldRef = cmd.importRef;
  678. cmd.importRef = null;
  679. deleteCommandFromToken( cmd );
  680. // FIXME : create a test case for this condition!
  681. cmd = (WrappedCommand)ns.cmdTable[tail];
  682. if ( cmd != null )
  683. {
  684. // If the deletion callback recreated the command, just throw
  685. // away the new command (if we try to delete it again, we
  686. // could get stuck in an infinite loop).
  687. SupportClass.HashtableRemove( cmd.table, cmd.hashKey );
  688. }
  689. }
  690. cmd = new WrappedCommand();
  691. ns.cmdTable.Add( tail, cmd );
  692. cmd.table = ns.cmdTable;
  693. cmd.hashKey = tail;
  694. cmd.ns = ns;
  695. cmd.cmd = cmdImpl;
  696. cmd.deleted = false;
  697. // FIXME : import feature not implemented
  698. //cmd.importRef = null;
  699. // Plug in any existing import references found above. Be sure
  700. // to update all of these references to point to the new command.
  701. if ( oldRef != null )
  702. {
  703. cmd.importRef = oldRef;
  704. while ( oldRef != null )
  705. {
  706. refCmd = oldRef.importedCmd;
  707. data = (ImportedCmdData)refCmd.cmd;
  708. data.realCmd = cmd;
  709. oldRef = oldRef.next;
  710. }
  711. }
  712. // There are no shadowed commands in Jacl because they are only
  713. // used in the 8.0 compiler
  714. return;
  715. }
  716. /*
  717. *----------------------------------------------------------------------
  718. *
  719. * Tcl_CreateObjCommand --
  720. *
  721. * Define a new object-based command in a command table.
  722. *
  723. * Results:
  724. * The return value is a token for the command, which can
  725. * be used in future calls to Tcl_GetCommandName.
  726. *
  727. * Side effects:
  728. * If no command named "cmdName" already exists for interp, one is
  729. * created. Otherwise, if a command does exist, then if the
  730. * object-based Tcl_ObjCmdProc is TclInvokeStringCommand, we assume
  731. * Tcl_CreateCommand was called previously for the same command and
  732. * just set its Tcl_ObjCmdProc to the argument "proc"; otherwise, we
  733. * delete the old command.
  734. *
  735. * In the future, during bytecode evaluation when "cmdName" is seen as
  736. * the name of a command by Tcl_EvalObj or Tcl_Eval, the object-based
  737. * Tcl_ObjCmdProc proc will be called. When the command is deleted from
  738. * the table, deleteProc will be called. See the manual entry for
  739. * details on the calling sequence.
  740. *
  741. *----------------------------------------------------------------------
  742. */
  743. public delegate int dxObjCmdProc( object clientData, Interp interp, int argc, TclObject[] argv );
  744. public delegate void dxCmdDeleteProc( ref object clientData );
  745. public void createObjCommand( string cmdName, dxObjCmdProc proc, object clientData, dxCmdDeleteProc deleteProc )
  746. // Command object to associate with cmdName.
  747. {
  748. ImportRef oldRef = null;
  749. NamespaceCmd.Namespace ns;
  750. WrappedCommand cmd, refCmd;
  751. string tail;
  752. ImportedCmdData data;
  753. int _new;
  754. if ( deleted )
  755. {
  756. // The interpreter is being deleted. Don't create any new
  757. // commands; it's not safe to muck with the interpreter anymore.
  758. return;
  759. }
  760. // Determine where the command should reside. If its name contains
  761. // namespace qualifiers, we put it in the specified namespace;
  762. // otherwise, we always put it in the global namespace.
  763. if ( cmdName.IndexOf( "::" ) != -1 )
  764. {
  765. // Java does not support passing an address so we pass
  766. // an array of size 1 and then assign arr[0] to the value
  767. NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1];
  768. NamespaceCmd.Namespace[] dummyArr = new NamespaceCmd.Namespace[1];
  769. string[] tailArr = new string[1];
  770. NamespaceCmd.getNamespaceForQualName( this, cmdName, null, TCL.VarFlag.CREATE_NS_IF_UNKNOWN, nsArr, dummyArr, dummyArr, tailArr );
  771. ns = nsArr[0];
  772. tail = tailArr[0];
  773. if ( ( ns == null ) || ( (System.Object)tail == null ) )
  774. {
  775. return;
  776. }
  777. }
  778. else
  779. {
  780. ns = globalNs;
  781. tail = cmdName;
  782. }
  783. cmd = (WrappedCommand)ns.cmdTable[tail];
  784. if ( cmd != null )
  785. {
  786. /*
  787. * Command already exists. If its object-based Tcl_ObjCmdProc is
  788. * TclInvokeStringCommand, we just set its Tcl_ObjCmdProc to the
  789. * argument "proc". Otherwise, we delete the old command.
  790. */
  791. if ( cmd.objProc != null && cmd.objProc.GetType().Name == "TclInvokeStringCommand" )
  792. {
  793. cmd.objProc = proc;
  794. cmd.objClientData = clientData;
  795. cmd.deleteProc = deleteProc;
  796. cmd.deleteData = clientData;
  797. return;
  798. }
  799. /*
  800. * Otherwise, we delete the old command. Be careful to preserve
  801. * any existing import links so we can restore them down below.
  802. * That way, you can redefine a command and its import status
  803. * will remain intact.
  804. */
  805. oldRef = cmd.importRef;
  806. cmd.importRef = null;
  807. deleteCommandFromToken( cmd );
  808. // FIXME : create a test case for this condition!
  809. cmd = (WrappedCommand)ns.cmdTable[tail];
  810. if ( cmd != null )
  811. {
  812. // If the deletion callback recreated the command, just throw
  813. // away the new command (if we try to delete it again, we
  814. // could get stuck in an infinite loop).
  815. SupportClass.HashtableRemove( cmd.table, cmd.hashKey );
  816. }
  817. }
  818. cmd = new WrappedCommand();
  819. ns.cmdTable.Add( tail, cmd );
  820. cmd.table = ns.cmdTable;
  821. cmd.hashKey = tail;
  822. cmd.ns = ns;
  823. cmd.cmd = null;
  824. cmd.deleted = false;
  825. // FIXME : import feature not implemented
  826. //cmd.importRef = null;
  827. // TODO -- Determine if this is all correct
  828. cmd.objProc = proc;
  829. cmd.objClientData = clientData;
  830. //cmd.proc = TclInvokeObjectCommand;
  831. cmd.clientData = (object)cmd;
  832. cmd.deleteProc = deleteProc;
  833. cmd.deleteData = clientData;
  834. cmd.flags = 0;
  835. // Plug in any existing import references found above. Be sure
  836. // to update all of these references to point to the new command.
  837. if ( oldRef != null )
  838. {
  839. cmd.importRef = oldRef;
  840. while ( oldRef != null )
  841. {
  842. refCmd = oldRef.importedCmd;
  843. data = (ImportedCmdData)refCmd.cmd;
  844. data.realCmd = cmd;
  845. oldRef = oldRef.next;
  846. }
  847. }
  848. // There are no shadowed commands in Jacl because they are only
  849. // used in the 8.0 compiler
  850. return;
  851. }
  852. internal string getCommandFullName( WrappedCommand cmd )
  853. // Token for the command.
  854. {
  855. Interp interp = this;
  856. StringBuilder name = new StringBuilder();
  857. // Add the full name of the containing namespace, followed by the "::"
  858. // separator, and the command name.
  859. if ( cmd != null )
  860. {
  861. if ( cmd.ns != null )
  862. {
  863. name.Append( cmd.ns.fullName );
  864. if ( cmd.ns != interp.globalNs )
  865. {
  866. name.Append( "::" );
  867. }
  868. }
  869. if ( cmd.table != null )
  870. {
  871. name.Append( cmd.hashKey );
  872. }
  873. }
  874. return name.ToString();
  875. }
  876. public int deleteCommand( string cmdName )
  877. // Name of command to remove.
  878. {
  879. WrappedCommand cmd;
  880. // Find the desired command and delete it.
  881. try
  882. {
  883. cmd = NamespaceCmd.findCommand( this, cmdName, null, 0 );
  884. }
  885. catch ( TclException e )
  886. {
  887. throw new TclRuntimeError( "unexpected TclException: " + e.Message, e );
  888. }
  889. if ( cmd == null )
  890. {
  891. return -1;
  892. }
  893. if ( cmd.deleteProc != null )
  894. cmd.deleteProc( ref cmd.deleteData );
  895. return deleteCommandFromToken( cmd );
  896. }
  897. protected internal int deleteCommandFromToken( WrappedCommand cmd )
  898. // Wrapper Token for command to delete.
  899. {
  900. if ( cmd == null )
  901. {
  902. return -1;
  903. }
  904. ImportRef ref_Renamed, nextRef;
  905. WrappedCommand importCmd;
  906. // The code here is tricky. We can't delete the hash table entry
  907. // before invoking the deletion callback because there are cases
  908. // where the deletion callback needs to invoke the command (e.g.
  909. // object systems such as OTcl). However, this means that the
  910. // callback could try to delete or rename the command. The deleted
  911. // flag allows us to detect these cases and skip nested deletes.
  912. if ( cmd.deleted )
  913. {
  914. // Another deletion is already in progress. Remove the hash
  915. // table entry now, but don't invoke a callback or free the
  916. // command structure.
  917. if ( (System.Object)cmd.hashKey != null && cmd.table != null )
  918. {
  919. SupportClass.HashtableRemove( cmd.table, cmd.hashKey );
  920. cmd.table = null;
  921. cmd.hashKey = null;
  922. }
  923. return 0;
  924. }
  925. cmd.deleted = true;
  926. if ( cmd.cmd is CommandWithDispose )
  927. {
  928. ( (CommandWithDispose)cmd.cmd ).disposeCmd();
  929. }
  930. if ( cmd.deleteProc != null )
  931. {
  932. cmd.deleteProc( ref cmd.objClientData );
  933. }
  934. // If this command was imported into other namespaces, then imported
  935. // commands were created that refer back to this command. Delete these
  936. // imported commands now.
  937. for ( ref_Renamed = cmd.importRef; ref_Renamed != null; ref_Renamed = nextRef )
  938. {
  939. nextRef = ref_Renamed.next;
  940. importCmd = ref_Renamed.importedCmd;
  941. deleteCommandFromToken( importCmd );
  942. }
  943. // FIXME : what does this mean? Is this a mistake in the C comment?
  944. // Don't use hPtr to delete the hash entry here, because it's
  945. // possible that the deletion callback renamed the command.
  946. // Instead, use cmdPtr->hptr, and make sure that no-one else
  947. // has already deleted the hash entry.
  948. if ( cmd.table != null )
  949. {
  950. SupportClass.HashtableRemove( cmd.table, cmd.hashKey );
  951. cmd.table = null;
  952. cmd.hashKey = null;
  953. }
  954. // Drop the reference to the Command instance inside the WrappedCommand
  955. cmd.cmd = null;
  956. // We do not need to cleanup the WrappedCommand because GC will get it.
  957. return 0;
  958. }
  959. protected internal void renameCommand( string oldName, string newName )
  960. {
  961. Interp interp = this;
  962. string newTail;
  963. NamespaceCmd.Namespace cmdNs, newNs;
  964. WrappedCommand cmd;
  965. Hashtable table, oldTable;
  966. string hashKey, oldHashKey;
  967. // Find the existing command. An error is returned if cmdName can't
  968. // be found.
  969. cmd = NamespaceCmd.findCommand( interp, oldName, null, 0 );
  970. if ( cmd == null )
  971. {
  972. throw new TclException( interp, "can't " + ( ( ( (System.Object)newName == null ) || ( newName.Length == 0 ) ) ? "delete" : "rename" ) + " \"" + oldName + "\": command doesn't exist" );
  973. }
  974. cmdNs = cmd.ns;
  975. // If the new command name is NULL or empty, delete the command. Do this
  976. // with Tcl_DeleteCommandFromToken, since we already have the command.
  977. if ( ( (System.Object)newName == null ) || ( newName.Length == 0 ) )
  978. {
  979. deleteCommandFromToken( cmd );
  980. return;
  981. }
  982. // Make sure that the destination command does not already exist.
  983. // The rename operation is like creating a command, so we should
  984. // automatically create the containing namespaces just like
  985. // Tcl_CreateCommand would.
  986. NamespaceCmd.Namespace[] newNsArr = new NamespaceCmd.Namespace[1];
  987. NamespaceCmd.Namespace[] dummyArr = new NamespaceCmd.Namespace[1];
  988. string[] newTailArr = new string[1];
  989. NamespaceCmd.getNamespaceForQualName( interp, newName, null, TCL.VarFlag.CREATE_NS_IF_UNKNOWN, newNsArr, dummyArr, dummyArr, newTailArr );
  990. newNs = newNsArr[0];
  991. newTail = newTailArr[0];
  992. if ( ( newNs == null ) || ( (System.Object)newTail == null ) )
  993. {
  994. throw new TclException( interp, "can't rename to \"" + newName + "\": bad command name" );
  995. }
  996. if ( newNs.cmdTable[newTail] != null )
  997. {
  998. throw new TclException( interp, "can't rename to \"" + newName + "\": command already exists" );
  999. }
  1000. // Warning: any changes done in the code here are likely
  1001. // to be needed in Tcl_HideCommand() code too.
  1002. // (until the common parts are extracted out) --dl
  1003. // Put the command in the new namespace so we can check for an alias
  1004. // loop. Since we are adding a new command to a namespace, we must
  1005. // handle any shadowing of the global commands that this might create.
  1006. oldTable = cmd.table;
  1007. oldHashKey = cmd.hashKey;
  1008. newNs.cmdTable.Add( newTail, cmd );
  1009. cmd.table = newNs.cmdTable;
  1010. cmd.hashKey = newTail;
  1011. cmd.ns = newNs;
  1012. // FIXME : this is a nasty hack that fixes renaming for Procedures
  1013. // that move from one namespace to another, but the real problem
  1014. // is that a rename does not work for Command instances in general
  1015. if ( cmd.cmd is Procedure )
  1016. {
  1017. Procedure p = (Procedure)cmd.cmd;
  1018. p.ns = cmd.ns;
  1019. }
  1020. // Now check for an alias loop. If we detect one, put everything back
  1021. // the way it was and report the error.
  1022. try
  1023. {
  1024. interp.preventAliasLoop( interp, cmd );
  1025. }
  1026. catch ( TclException e )
  1027. {
  1028. newNs.cmdTable.Remove( newTail );
  1029. cmd.table = oldTable;
  1030. cmd.hashKey = oldHashKey;
  1031. cmd.ns = cmdNs;
  1032. throw;
  1033. }
  1034. // The new command name is okay, so remove the command from its
  1035. // current namespace. This is like deleting the command, so bump
  1036. // the cmdEpoch to invalidate any cached references to the command.
  1037. SupportClass.HashtableRemove( oldTable, oldHashKey );
  1038. return;
  1039. }
  1040. internal void preventAliasLoop( Interp cmdInterp, WrappedCommand cmd )
  1041. {
  1042. // If we are not creating or renaming an alias, then it is
  1043. // always OK to create or rename the command.
  1044. if ( !( cmd.cmd is InterpAliasCmd ) )
  1045. {
  1046. return;
  1047. }
  1048. // OK, we are dealing with an alias, so traverse the chain of aliases.
  1049. // If we encounter the alias we are defining (or renaming to) any in
  1050. // the chain then we have a loop.
  1051. InterpAliasCmd alias = (InterpAliasCmd)cmd.cmd;
  1052. InterpAliasCmd nextAlias = alias;
  1053. while ( true )
  1054. {
  1055. // If the target of the next alias in the chain is the same as
  1056. // the source alias, we have a loop.
  1057. WrappedCommand aliasCmd = nextAlias.getTargetCmd( this );
  1058. if ( aliasCmd == null )
  1059. {
  1060. return;
  1061. }
  1062. if ( aliasCmd.cmd == cmd.cmd )
  1063. {
  1064. throw new TclException( this, "cannot define or rename alias \"" + alias.name + "\": would create a loop" );
  1065. }
  1066. // Otherwise, follow the chain one step further. See if the target
  1067. // command is an alias - if so, follow the loop to its target
  1068. // command. Otherwise we do not have a loop.
  1069. if ( !( aliasCmd.cmd is InterpAliasCmd ) )
  1070. {
  1071. return;
  1072. }
  1073. nextAlias = (InterpAliasCmd)aliasCmd.cmd;
  1074. }
  1075. }
  1076. public Command getCommand( string cmdName )
  1077. // String name of the command.
  1078. {
  1079. // Find the desired command and return it.
  1080. WrappedCommand cmd;
  1081. try
  1082. {
  1083. cmd = NamespaceCmd.findCommand( this, cmdName, null, 0 );
  1084. }
  1085. catch ( TclException e )
  1086. {
  1087. throw new TclRuntimeError( "unexpected TclException: " + e.Message, e );
  1088. }
  1089. return ( ( cmd == null ) ? null : cmd.cmd );
  1090. }
  1091. public WrappedCommand getObjCommand( string cmdName )
  1092. // String name of the command.
  1093. {
  1094. // Find the desired command and return it.
  1095. WrappedCommand cmd;
  1096. try
  1097. {
  1098. cmd = NamespaceCmd.findCommand( this, cmdName, null, 0 );
  1099. }
  1100. catch ( TclException e )
  1101. {
  1102. throw new TclRuntimeError( "unexpected TclException: " + e.Message, e );
  1103. }
  1104. return ( ( cmd == null ) ? null : cmd );
  1105. }
  1106. public static bool commandComplete( string inString )
  1107. // The string to check.
  1108. {
  1109. return Parser.commandComplete( inString, inString.Length );
  1110. }
  1111. /*-----------------------------------------------------------------
  1112. *
  1113. * EVAL
  1114. *
  1115. *-----------------------------------------------------------------
  1116. */
  1117. public TclObject getResult()
  1118. {
  1119. return m_result;
  1120. }
  1121. public void setResult( TclObject r )
  1122. // A Tcl Object to be set as the result.
  1123. {
  1124. if ( r == null )
  1125. {
  1126. throw new System.NullReferenceException( "Interp.setResult() called with null TclObject argument." );
  1127. }
  1128. if ( r == m_result )
  1129. {
  1130. // Setting to current value (including m_nullResult) is a no-op.
  1131. return;
  1132. }
  1133. if ( m_result != m_nullResult )
  1134. {
  1135. m_result.release();
  1136. }
  1137. m_result = r;
  1138. if ( m_result != m_nullResult )
  1139. {
  1140. m_result.preserve();
  1141. }
  1142. }
  1143. public void setResult( string r )
  1144. // A string result.
  1145. {
  1146. if ( (System.Object)r == null )
  1147. {
  1148. resetResult();
  1149. }
  1150. else
  1151. {
  1152. setResult( TclString.newInstance( r ) );
  1153. }
  1154. }
  1155. public void setResult( int r )
  1156. // An int result.
  1157. {
  1158. setResult( TclInteger.newInstance( r ) );
  1159. }
  1160. public void setResult( double r )
  1161. // A double result.
  1162. {
  1163. setResult( TclDouble.newInstance( r ) );
  1164. }
  1165. public void setResult( bool r )
  1166. // A boolean result.
  1167. {
  1168. setResult( TclBoolean.newInstance( r ) );
  1169. }
  1170. public void resetResult()
  1171. {
  1172. if ( m_result != m_nullResult )
  1173. {
  1174. m_result.release();
  1175. m_result = TclString.newInstance( "" ); //m_nullResult;
  1176. m_result.preserve();
  1177. if ( !m_nullResult.Shared )
  1178. {
  1179. throw new TclRuntimeError( "m_nullResult is not shared" );
  1180. }
  1181. }
  1182. errAlreadyLogged = false;
  1183. errInProgress = false;
  1184. errCodeSet = false;
  1185. returnCode = TCL.CompletionCode.OK;
  1186. }
  1187. public void appendElement( object Element )
  1188. {
  1189. TclObject result;
  1190. result = getResult();
  1191. if ( result.Shared )
  1192. {
  1193. result = result.duplicate();
  1194. }
  1195. TclList.append( this, result, TclObj.newInstance( Element ) );
  1196. setResult( result );
  1197. }
  1198. public void appendElement(
  1199. string Element )
  1200. {
  1201. TclObject result;
  1202. result = getResult();
  1203. if ( result.Shared )
  1204. {
  1205. result = result.duplicate();
  1206. }
  1207. TclList.append( this, result, TclString.newInstance( Element ) );
  1208. setResult( result );
  1209. }
  1210. public void eval( string inString, int flags )
  1211. {
  1212. int evalFlags = this.evalFlags;
  1213. this.evalFlags &= ~Parser.TCL_ALLOW_EXCEPTIONS;
  1214. CharPointer script = new CharPointer( inString );
  1215. try
  1216. {
  1217. Parser.eval2( this, script.array, script.index, script.length(), flags );
  1218. }
  1219. catch ( TclException e )
  1220. {
  1221. if ( nestLevel != 0 )
  1222. {
  1223. throw;
  1224. }
  1225. // Update the interpreter's evaluation level count. If we are again at
  1226. // the top level, process any unusual return code returned by the
  1227. // evaluated code. Note that we don't propagate an exception that
  1228. // has a TCL.CompletionCode.RETURN error code when updateReturnInfo() returns TCL.CompletionCode.OK.
  1229. TCL.CompletionCode result = e.getCompletionCode();
  1230. if ( result == TCL.CompletionCode.RETURN )
  1231. {
  1232. result = updateReturnInfo();
  1233. }
  1234. if ( result != TCL.CompletionCode.EXIT && result != TCL.CompletionCode.OK && result != TCL.CompletionCode.ERROR && ( evalFlags & Parser.TCL_ALLOW_EXCEPTIONS ) == 0 )
  1235. {
  1236. processUnexpectedResult( result );
  1237. }
  1238. if ( result != TCL.CompletionCode.OK )
  1239. {
  1240. e.setCompletionCode( result );
  1241. throw;
  1242. }
  1243. }
  1244. }
  1245. public void eval( string script )
  1246. {
  1247. eval( script, 0 );
  1248. }
  1249. public void eval( TclObject tobj, int flags )
  1250. {
  1251. eval( tobj.ToString(), flags );
  1252. }
  1253. public void recordAndEval( TclObject script, int flags )
  1254. {
  1255. // Append the script to the event list by calling "history add <script>".
  1256. // We call the eval method with the command of type TclObject, so that
  1257. // we don't have to deal with funny chars ("{}[]$\) in the script.
  1258. TclObject cmd = null;
  1259. try
  1260. {
  1261. cmd = TclList.newInstance();
  1262. TclList.append( this, cmd, TclString.newInstance( "history" ) );
  1263. TclList.append( this, cmd, TclString.newInstance( "add" ) );
  1264. TclList.append( this, cmd, script );
  1265. cmd.preserve();
  1266. eval( cmd, TCL.EVAL_GLOBAL );
  1267. }
  1268. catch ( System.Exception e )
  1269. {
  1270. }
  1271. finally
  1272. {
  1273. cmd.release();
  1274. }
  1275. // Execute the command.
  1276. if ( ( flags & TCL.NO_EVAL ) == 0 )
  1277. {
  1278. eval( script, flags & TCL.EVAL_GLOBAL );
  1279. }
  1280. }
  1281. public void evalFile( string sFilename )
  1282. {
  1283. string fileContent; // Contains the content of the file.
  1284. fileContent = read

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