PageRenderTime 62ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/trunk/managed/csharpsqlite/TCL/src/commands/NamespaceCmd.cs

https://bitbucket.org/KyanhaLLC/opensim-libs
C# | 3658 lines | 1632 code | 560 blank | 1466 comment | 432 complexity | 12fb30405e0ed62db687a6b89fe50b51 MD5 | raw file
Possible License(s): Apache-2.0, BSD-2-Clause, MIT, LGPL-2.1, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, GPL-3.0, BSD-3-Clause

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

  1. #undef DEBUG
  2. /*
  3. * NamespaceCmd.java
  4. *
  5. * Copyright (c) 1993-1997 Lucent Technologies.
  6. * Copyright (c) 1997 Sun Microsystems, Inc.
  7. * Copyright (c) 1998-1999 by Scriptics Corporation.
  8. * Copyright (c) 1999 Moses DeJong
  9. *
  10. * Originally implemented by
  11. * Michael J. McLennan
  12. * Bell Labs Innovations for Lucent Technologies
  13. * mmclennan@lucent.com
  14. *
  15. * See the file "license.terms" for information on usage and
  16. * redistribution of this file, and for a DISCLAIMER OF ALL
  17. * WARRANTIES.
  18. *
  19. * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
  20. * $Header$
  21. * RCS @(#) $Id: NamespaceCmd.java,v 1.12 2001/05/05 22:38:13 mdejong Exp $
  22. */
  23. using System;
  24. using System.Collections;
  25. namespace tcl.lang
  26. {
  27. /// <summary> This class implements the built-in "namespace" command in Tcl.
  28. /// See the user documentation for details on what it does.
  29. /// </summary>
  30. public class NamespaceCmd : InternalRep, Command
  31. {
  32. // Flag passed to getNamespaceForQualName to indicate that it should
  33. // search for a namespace rather than a command or variable inside a
  34. // namespace. Note that this flag's value must not conflict with the values
  35. // of TCL.VarFlag.GLOBAL_ONLY, TCL.VarFlag.NAMESPACE_ONLY, or TCL.VarFlag.CREATE_NS_IF_UNKNOWN.
  36. // Initial size of stack allocated space for tail list - used when resetting
  37. // shadowed command references in the functin: TclResetShadowedCmdRefs.
  38. //private static final int NUM_TRAIL_ELEMS = 5;
  39. // Count of the number of namespaces created. This value is used as a
  40. // unique id for each namespace.
  41. private static long numNsCreated = 0;
  42. private static Object nsMutex;
  43. //
  44. // Flags used to represent the status of a namespace:
  45. //
  46. // NS_DYING - 1 means deleteNamespace has been called to delete the
  47. // namespace but there are still active call frames on the Tcl
  48. // stack that refer to the namespace. When the last call frame
  49. // referring to it has been popped, it's variables and command
  50. // will be destroyed and it will be marked "dead" (NS_DEAD).
  51. // The namespace can no longer be looked up by name.
  52. // NS_DEAD - 1 means deleteNamespace has been called to delete the
  53. // namespace and no call frames still refer to it. Its
  54. // variables and command have already been destroyed. This bit
  55. // allows the namespace resolution code to recognize that the
  56. // namespace is "deleted". When the last namespaceName object
  57. // in any byte code code unit that refers to the namespace has
  58. // been freed (i.e., when the namespace's refCount is 0), the
  59. // namespace's storage will be freed.
  60. internal const int NS_DYING = 0x01;
  61. internal const int NS_DEAD = 0x02;
  62. // Flag passed to getNamespaceForQualName to have it create all namespace
  63. // components of a namespace-qualified name that cannot be found. The new
  64. // namespaces are created within their specified parent. Note that this
  65. // flag's value must not conflict with the values of the flags
  66. // TCL.VarFlag.GLOBAL_ONLY, TCL.VarFlag.NAMESPACE_ONLY, and TCL.VarFlag.FIND_ONLY_NS
  67. // internal const int TCL.VarFlag.CREATE_NS_IF_UNKNOWN = 0x800;
  68. // This value corresponds to the Tcl_Obj.otherValuePtr pointer used
  69. // in the C version of Tcl 8.1. Use it to keep track of a ResolvedNsName.
  70. private ResolvedNsName otherValue = null;
  71. /*
  72. *----------------------------------------------------------------------
  73. *
  74. * Tcl_GetCurrentNamespace -> getCurrentNamespace
  75. *
  76. * Returns a reference to an interpreter's currently active namespace.
  77. *
  78. * Results:
  79. * Returns a reference to the interpreter's current namespace.
  80. *
  81. * Side effects:
  82. * None.
  83. *
  84. *----------------------------------------------------------------------
  85. */
  86. internal static Namespace getCurrentNamespace(Interp interp)
  87. {
  88. if (interp.varFrame != null)
  89. {
  90. return interp.varFrame.ns;
  91. }
  92. else
  93. {
  94. return interp.globalNs;
  95. }
  96. }
  97. /*
  98. *----------------------------------------------------------------------
  99. *
  100. * Tcl_GetGlobalNamespace -> getGlobalNamespace
  101. *
  102. * Returns a reference to an interpreter's global :: namespace.
  103. *
  104. * Results:
  105. * Returns a reference to the specified interpreter's global namespace.
  106. *
  107. * Side effects:
  108. * None.
  109. *
  110. *----------------------------------------------------------------------
  111. */
  112. internal static Namespace getGlobalNamespace(Interp interp)
  113. {
  114. return interp.globalNs;
  115. }
  116. /*
  117. *----------------------------------------------------------------------
  118. *
  119. * Tcl_PushCallFrame -> pushCallFrame
  120. *
  121. * Pushes a new call frame onto the interpreter's Tcl call stack.
  122. * Called when executing a Tcl procedure or a "namespace eval" or
  123. * "namespace inscope" command.
  124. *
  125. * Results:
  126. * Returns if successful, raises TclException if something goes wrong.
  127. *
  128. * Side effects:
  129. * Modifies the interpreter's Tcl call stack.
  130. *
  131. *----------------------------------------------------------------------
  132. */
  133. internal static void pushCallFrame(Interp interp, CallFrame frame, Namespace namespace_Renamed, bool isProcCallFrame)
  134. // If true, the frame represents a
  135. // called Tcl procedure and may have local
  136. // vars. Vars will ordinarily be looked up
  137. // in the frame. If new variables are
  138. // created, they will be created in the
  139. // frame. If false, the frame is for a
  140. // "namespace eval" or "namespace inscope"
  141. // command and var references are treated
  142. // as references to namespace variables.
  143. {
  144. Namespace ns;
  145. if (namespace_Renamed == null)
  146. {
  147. ns = getCurrentNamespace(interp);
  148. }
  149. else
  150. {
  151. ns = namespace_Renamed;
  152. if ((ns.flags & NS_DEAD) != 0)
  153. {
  154. throw new TclRuntimeError("Trying to push call frame for dead namespace");
  155. }
  156. }
  157. ns.activationCount++;
  158. frame.ns = ns;
  159. frame.isProcCallFrame = isProcCallFrame;
  160. frame.objv = null;
  161. frame.caller = interp.frame;
  162. frame.callerVar = interp.varFrame;
  163. if (interp.varFrame != null)
  164. {
  165. frame.level = (interp.varFrame.level + 1);
  166. }
  167. else
  168. {
  169. frame.level = 1;
  170. }
  171. // FIXME : does Jacl need a procPtr in the CallFrame class?
  172. //frame.procPtr = null; // no called procedure
  173. frame.varTable = null; // and no local variables
  174. // Compiled locals are not part of Jacl's CallFrame
  175. // Push the new call frame onto the interpreter's stack of procedure
  176. // call frames making it the current frame.
  177. interp.frame = frame;
  178. interp.varFrame = frame;
  179. }
  180. /*
  181. *----------------------------------------------------------------------
  182. *
  183. * Tcl_PopCallFrame -> popCallFrame
  184. *
  185. * Removes a call frame from the Tcl call stack for the interpreter.
  186. * Called to remove a frame previously pushed by Tcl_PushCallFrame.
  187. *
  188. * Results:
  189. * None.
  190. *
  191. * Side effects:
  192. * Modifies the call stack of the interpreter. Resets various fields of
  193. * the popped call frame. If a namespace has been deleted and
  194. * has no more activations on the call stack, the namespace is
  195. * destroyed.
  196. *
  197. *----------------------------------------------------------------------
  198. */
  199. internal static void popCallFrame(Interp interp)
  200. {
  201. CallFrame frame = interp.frame;
  202. int saveErrFlag;
  203. Namespace ns;
  204. // It's important to remove the call frame from the interpreter's stack
  205. // of call frames before deleting local variables, so that traces
  206. // invoked by the variable deletion don't see the partially-deleted
  207. // frame.
  208. interp.frame = frame.caller;
  209. interp.varFrame = frame.callerVar;
  210. // Delete the local variables. As a hack, we save then restore the
  211. // ERR_IN_PROGRESS flag in the interpreter. The problem is that there
  212. // could be unset traces on the variables, which cause scripts to be
  213. // evaluated. This will clear the ERR_IN_PROGRESS flag, losing stack
  214. // trace information if the procedure was exiting with an error. The
  215. // code below preserves the flag. Unfortunately, that isn't really
  216. // enough: we really should preserve the errorInfo variable too
  217. // (otherwise a nested error in the trace script will trash errorInfo).
  218. // What's really needed is a general-purpose mechanism for saving and
  219. // restoring interpreter state.
  220. saveErrFlag = (interp.flags & Parser.ERR_IN_PROGRESS);
  221. if (frame.varTable != null)
  222. {
  223. Var.deleteVars(interp, frame.varTable);
  224. frame.varTable = null;
  225. }
  226. interp.flags |= saveErrFlag;
  227. // Decrement the namespace's count of active call frames. If the
  228. // namespace is "dying" and there are no more active call frames,
  229. // call Tcl_DeleteNamespace to destroy it.
  230. ns = frame.ns;
  231. ns.activationCount--;
  232. if (((ns.flags & NS_DYING) != 0) && (ns.activationCount == 0))
  233. {
  234. deleteNamespace(ns);
  235. }
  236. frame.ns = null;
  237. }
  238. /*
  239. *----------------------------------------------------------------------
  240. *
  241. * Tcl_CreateNamespace --
  242. *
  243. * Creates a new namespace with the given name. If there is no
  244. * active namespace (i.e., the interpreter is being initialized),
  245. * the global :: namespace is created and returned.
  246. *
  247. * Results:
  248. * Returns a reference to the new namespace if successful. If the
  249. * namespace already exists or if another error occurs, this routine
  250. * returns null, along with an error message in the interpreter's
  251. * result object.
  252. *
  253. * Side effects:
  254. * If the name contains "::" qualifiers and a parent namespace does
  255. * not already exist, it is automatically created.
  256. *
  257. *----------------------------------------------------------------------
  258. */
  259. internal static Namespace createNamespace(Interp interp, string name, DeleteProc deleteProc)
  260. {
  261. Namespace ns, ancestor;
  262. Namespace parent;
  263. Namespace globalNs = getGlobalNamespace(interp);
  264. string simpleName;
  265. System.Text.StringBuilder buffer1, buffer2;
  266. // If there is no active namespace, the interpreter is being
  267. // initialized.
  268. if ((globalNs == null) && (interp.varFrame == null))
  269. {
  270. // Treat this namespace as the global namespace, and avoid
  271. // looking for a parent.
  272. parent = null;
  273. simpleName = "";
  274. }
  275. else if (name.Length == 0)
  276. {
  277. /*
  278. TclObject tobj = interp.getResult();
  279. // FIXME : is there a test case to check this error result?
  280. TclString.append(tobj,
  281. "can't create namespace \"\": only global namespace can have empty name");
  282. */
  283. // FIXME : is there a test case to check this error result?
  284. interp.setResult("can't create namespace \"\": only global namespace can have empty name");
  285. return null;
  286. }
  287. else
  288. {
  289. // Find the parent for the new namespace.
  290. // Java does not support passing an address so we pass
  291. // an array of size 1 and then assign arr[0] to the value
  292. Namespace[] parentArr = new Namespace[1];
  293. Namespace[] dummyArr = new Namespace[1];
  294. string[] simpleArr = new string[1];
  295. getNamespaceForQualName(interp, name, null, (TCL.VarFlag.CREATE_NS_IF_UNKNOWN | TCL.VarFlag.LEAVE_ERR_MSG), parentArr, dummyArr, dummyArr, simpleArr);
  296. // Get the values out of the arrays!
  297. parent = parentArr[0];
  298. simpleName = simpleArr[0];
  299. // If the unqualified name at the end is empty, there were trailing
  300. // "::"s after the namespace's name which we ignore. The new
  301. // namespace was already (recursively) created and is referenced
  302. // by parent.
  303. if (simpleName.Length == 0)
  304. {
  305. return parent;
  306. }
  307. // Check for a bad namespace name and make sure that the name
  308. // does not already exist in the parent namespace.
  309. if (parent.childTable[simpleName] != null)
  310. {
  311. /*
  312. TclObject tobj = interp.getResult();
  313. // FIXME : is there a test case to check this error result?
  314. TclString.append(tobj,
  315. "can't create namespace \"" + name + "\": already exists");
  316. */
  317. // FIXME : is there a test case to check this error result?
  318. interp.setResult("can't create namespace \"" + name + "\": already exists");
  319. return null;
  320. }
  321. }
  322. // Create the new namespace and root it in its parent. Increment the
  323. // count of namespaces created.
  324. ns = new Namespace();
  325. ns.name = simpleName;
  326. ns.fullName = null; // set below
  327. //ns.clientData = clientData;
  328. ns.deleteProc = deleteProc;
  329. ns.parent = parent;
  330. ns.childTable = new Hashtable();
  331. lock (nsMutex)
  332. {
  333. numNsCreated++;
  334. ns.nsId = numNsCreated;
  335. }
  336. ns.interp = interp;
  337. ns.flags = 0;
  338. ns.activationCount = 0;
  339. // FIXME : there was a problem with the refcount because
  340. // when the namespace was deleted the refocount was 0.
  341. // We avoid this by just using a refcount of 1 for now.
  342. // We can do ignore the refCount because GC will reclaim mem.
  343. //ns.refCount = 0;
  344. ns.refCount = 1;
  345. ns.cmdTable = new Hashtable();
  346. ns.varTable = new Hashtable();
  347. ns.exportArray = null;
  348. ns.numExportPatterns = 0;
  349. ns.maxExportPatterns = 0;
  350. // Jacl does not use these tcl compiler specific members
  351. //ns.cmdRefEpoch = 0;
  352. //ns.resolverEpoch = 0;
  353. ns.resolver = null;
  354. if (parent != null)
  355. {
  356. SupportClass.PutElement(parent.childTable, simpleName, ns);
  357. }
  358. // Build the fully qualified name for this namespace.
  359. buffer1 = new System.Text.StringBuilder();
  360. buffer2 = new System.Text.StringBuilder();
  361. for (ancestor = ns; ancestor != null; ancestor = ancestor.parent)
  362. {
  363. if (ancestor != globalNs)
  364. {
  365. buffer1.Append("::");
  366. buffer1.Append(ancestor.name);
  367. }
  368. buffer1.Append(buffer2);
  369. buffer2.Length = 0;
  370. buffer2.Append(buffer1);
  371. buffer1.Length = 0;
  372. }
  373. name = buffer2.ToString();
  374. ns.fullName = name;
  375. // Return a reference to the new namespace.
  376. return ns;
  377. }
  378. /*
  379. *----------------------------------------------------------------------
  380. *
  381. * Tcl_DeleteNamespace -> deleteNamespace
  382. *
  383. * Deletes a namespace and all of the commands, variables, and other
  384. * namespaces within it.
  385. *
  386. * Results:
  387. * None.
  388. *
  389. * Side effects:
  390. * When a namespace is deleted, it is automatically removed as a
  391. * child of its parent namespace. Also, all its commands, variables
  392. * and child namespaces are deleted.
  393. *
  394. *----------------------------------------------------------------------
  395. */
  396. internal static void deleteNamespace(Namespace namespace_Renamed)
  397. {
  398. Namespace ns = namespace_Renamed;
  399. Interp interp = ns.interp;
  400. Namespace globalNs = getGlobalNamespace(interp);
  401. // If the namespace is on the call frame stack, it is marked as "dying"
  402. // (NS_DYING is OR'd into its flags): the namespace can't be looked up
  403. // by name but its commands and variables are still usable by those
  404. // active call frames. When all active call frames referring to the
  405. // namespace have been popped from the Tcl stack, popCallFrame will
  406. // call this procedure again to delete everything in the namespace.
  407. // If no nsName objects refer to the namespace (i.e., if its refCount
  408. // is zero), its commands and variables are deleted and the storage for
  409. // its namespace structure is freed. Otherwise, if its refCount is
  410. // nonzero, the namespace's commands and variables are deleted but the
  411. // structure isn't freed. Instead, NS_DEAD is OR'd into the structure's
  412. // flags to allow the namespace resolution code to recognize that the
  413. // namespace is "deleted".
  414. if (ns.activationCount > 0)
  415. {
  416. ns.flags |= NS_DYING;
  417. if (ns.parent != null)
  418. {
  419. ns.parent.childTable.Remove(ns.name);
  420. }
  421. ns.parent = null;
  422. }
  423. else
  424. {
  425. // Delete the namespace and everything in it. If this is the global
  426. // namespace, then clear it but don't free its storage unless the
  427. // interpreter is being torn down.
  428. teardownNamespace(ns);
  429. if ((ns != globalNs) || ((interp.flags & Parser.DELETED) != 0))
  430. {
  431. // If this is the global namespace, then it may have residual
  432. // "errorInfo" and "errorCode" variables for errors that
  433. // occurred while it was being torn down. Try to clear the
  434. // variable list one last time.
  435. Var.deleteVars(ns.interp, ns.varTable);
  436. ns.childTable.Clear();
  437. ns.cmdTable.Clear();
  438. // If the reference count is 0, then discard the namespace.
  439. // Otherwise, mark it as "dead" so that it can't be used.
  440. if (ns.refCount == 0)
  441. {
  442. free(ns);
  443. }
  444. else
  445. {
  446. ns.flags |= NS_DEAD;
  447. }
  448. }
  449. }
  450. }
  451. /*
  452. *----------------------------------------------------------------------
  453. *
  454. * TclTeardownNamespace -> teardownNamespace
  455. *
  456. * Used internally to dismantle and unlink a namespace when it is
  457. * deleted. Divorces the namespace from its parent, and deletes all
  458. * commands, variables, and child namespaces.
  459. *
  460. * This is kept separate from Tcl_DeleteNamespace so that the global
  461. * namespace can be handled specially. Global variables like
  462. * "errorInfo" and "errorCode" need to remain intact while other
  463. * namespaces and commands are torn down, in case any errors occur.
  464. *
  465. * Results:
  466. * None.
  467. *
  468. * Side effects:
  469. * Removes this namespace from its parent's child namespace hashtable.
  470. * Deletes all commands, variables and namespaces in this namespace.
  471. * If this is the global namespace, the "errorInfo" and "errorCode"
  472. * variables are left alone and deleted later.
  473. *
  474. *----------------------------------------------------------------------
  475. */
  476. internal static void teardownNamespace(Namespace ns)
  477. {
  478. Interp interp = ns.interp;
  479. IEnumerator search;
  480. Namespace globalNs = getGlobalNamespace(interp);
  481. int i;
  482. // Start by destroying the namespace's variable table,
  483. // since variables might trigger traces.
  484. if (ns == globalNs)
  485. {
  486. // This is the global namespace, so be careful to preserve the
  487. // "errorInfo" and "errorCode" variables. These might be needed
  488. // later on if errors occur while deleting commands. We are careful
  489. // to destroy and recreate the "errorInfo" and "errorCode"
  490. // variables, in case they had any traces on them.
  491. string errorInfoStr, errorCodeStr;
  492. try
  493. {
  494. errorInfoStr = interp.getVar("errorInfo", TCL.VarFlag.GLOBAL_ONLY).ToString();
  495. }
  496. catch (TclException e)
  497. {
  498. errorInfoStr = null;
  499. }
  500. try
  501. {
  502. errorCodeStr = interp.getVar("errorCode", TCL.VarFlag.GLOBAL_ONLY).ToString();
  503. }
  504. catch (TclException e)
  505. {
  506. errorCodeStr = null;
  507. }
  508. Var.deleteVars(interp, ns.varTable);
  509. if ((System.Object) errorInfoStr != null)
  510. {
  511. try
  512. {
  513. interp.setVar("errorInfo", errorInfoStr, TCL.VarFlag.GLOBAL_ONLY);
  514. }
  515. catch (TclException e)
  516. {
  517. // ignore an exception while setting this var
  518. }
  519. }
  520. if ((System.Object) errorCodeStr != null)
  521. {
  522. try
  523. {
  524. interp.setVar("errorCode", errorCodeStr, TCL.VarFlag.GLOBAL_ONLY);
  525. }
  526. catch (TclException e)
  527. {
  528. // ignore an exception while setting this var
  529. }
  530. }
  531. }
  532. else
  533. {
  534. // Variable table should be cleared.
  535. Var.deleteVars(interp, ns.varTable);
  536. }
  537. // Remove the namespace from its parent's child hashtable.
  538. if (ns.parent != null)
  539. {
  540. ns.parent.childTable.Remove(ns.name);
  541. }
  542. ns.parent = null;
  543. // Delete all the child namespaces.
  544. //
  545. // BE CAREFUL: When each child is deleted, it will divorce
  546. // itself from its parent. You can't traverse a hash table
  547. // properly if its elements are being deleted. We use only
  548. // the Tcl_FirstHashEntry function to be safe.
  549. foreach (Namespace childNs in new ArrayList(ns.childTable.Values))
  550. {
  551. deleteNamespace(childNs);
  552. }
  553. // Delete all commands in this namespace. Be careful when traversing the
  554. // hash table: when each command is deleted, it removes itself from the
  555. // command table.
  556. // FIXME : double check that using an enumeration for a hashtable
  557. // that changes is ok in Java! Also call deleteCommand... correctly!
  558. foreach(WrappedCommand cmd in new ArrayList(ns.cmdTable.Values))
  559. {
  560. interp.deleteCommandFromToken(cmd);
  561. }
  562. ns.cmdTable.Clear();
  563. // Free the namespace's export pattern array.
  564. if (ns.exportArray != null)
  565. {
  566. ns.exportArray = null;
  567. ns.numExportPatterns = 0;
  568. ns.maxExportPatterns = 0;
  569. }
  570. // Callback invoked when namespace is deleted
  571. if (ns.deleteProc != null)
  572. {
  573. ns.deleteProc.delete();
  574. }
  575. ns.deleteProc = null;
  576. // Reset the namespace's id field to ensure that this namespace won't
  577. // be interpreted as valid by, e.g., the cache validation code for
  578. // cached command references in Tcl_GetCommandFromObj.
  579. ns.nsId = 0;
  580. }
  581. /*
  582. *----------------------------------------------------------------------
  583. *
  584. * NamespaceFree -> free
  585. *
  586. * Called after a namespace has been deleted, when its
  587. * reference count reaches 0. Frees the data structure
  588. * representing the namespace.
  589. *
  590. * Results:
  591. * None.
  592. *
  593. * Side effects:
  594. * None.
  595. *
  596. *----------------------------------------------------------------------
  597. */
  598. internal static void free(Namespace ns)
  599. {
  600. // Most of the namespace's contents are freed when the namespace is
  601. // deleted by Tcl_DeleteNamespace. All that remains is to free its names
  602. // (for error messages), and the structure itself.
  603. ns.name = null;
  604. ns.fullName = null;
  605. }
  606. /*
  607. *----------------------------------------------------------------------
  608. *
  609. * Tcl_Export -> exportList
  610. *
  611. * Makes all the commands matching a pattern available to later be
  612. * imported from the namespace specified by namespace (or the
  613. * current namespace if namespace is null). The specified pattern is
  614. * appended onto the namespace's export pattern list, which is
  615. * optionally cleared beforehand.
  616. *
  617. * Results:
  618. * Returns if successful, raises TclException if something goes wrong.
  619. *
  620. * Side effects:
  621. * Appends the export pattern onto the namespace's export list.
  622. * Optionally reset the namespace's export pattern list.
  623. *
  624. *----------------------------------------------------------------------
  625. */
  626. internal static void exportList(Interp interp, Namespace namespace_Renamed, string pattern, bool resetListFirst)
  627. {
  628. int INIT_EXPORT_PATTERNS = 5;
  629. Namespace ns, exportNs;
  630. Namespace currNs = getCurrentNamespace(interp);
  631. string simplePattern, patternCpy;
  632. int neededElems, len, i;
  633. // If the specified namespace is null, use the current namespace.
  634. if (namespace_Renamed == null)
  635. {
  636. ns = currNs;
  637. }
  638. else
  639. {
  640. ns = namespace_Renamed;
  641. }
  642. // If resetListFirst is true (nonzero), clear the namespace's export
  643. // pattern list.
  644. if (resetListFirst)
  645. {
  646. if (ns.exportArray != null)
  647. {
  648. for (i = 0; i < ns.numExportPatterns; i++)
  649. {
  650. ns.exportArray[i] = null;
  651. }
  652. ns.exportArray = null;
  653. ns.numExportPatterns = 0;
  654. ns.maxExportPatterns = 0;
  655. }
  656. }
  657. // Check that the pattern doesn't have namespace qualifiers.
  658. // Java does not support passing an address so we pass
  659. // an array of size 1 and then assign arr[0] to the value
  660. Namespace[] exportNsArr = new Namespace[1];
  661. Namespace[] dummyArr = new Namespace[1];
  662. string[] simplePatternArr = new string[1];
  663. getNamespaceForQualName(interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, exportNsArr, dummyArr, dummyArr, simplePatternArr);
  664. // get the values out of the arrays
  665. exportNs = exportNsArr[0];
  666. simplePattern = simplePatternArr[0];
  667. if ((exportNs != ns) || (pattern.CompareTo(simplePattern) != 0))
  668. {
  669. throw new TclException(interp, "invalid export pattern \"" + pattern + "\": pattern can't specify a namespace");
  670. }
  671. // Make sure there is room in the namespace's pattern array for the
  672. // new pattern.
  673. neededElems = ns.numExportPatterns + 1;
  674. if (ns.exportArray == null)
  675. {
  676. ns.exportArray = new string[INIT_EXPORT_PATTERNS];
  677. ns.numExportPatterns = 0;
  678. ns.maxExportPatterns = INIT_EXPORT_PATTERNS;
  679. }
  680. else if (neededElems > ns.maxExportPatterns)
  681. {
  682. int numNewElems = 2 * ns.maxExportPatterns;
  683. string[] newArray = new string[numNewElems];
  684. Array.Copy((System.Array) ns.exportArray, 0, (System.Array) newArray, 0, ns.numExportPatterns);
  685. ns.exportArray = newArray;
  686. ns.maxExportPatterns = numNewElems;
  687. }
  688. // Add the pattern to the namespace's array of export patterns.
  689. ns.exportArray[ns.numExportPatterns] = pattern;
  690. ns.numExportPatterns++;
  691. return ;
  692. }
  693. /*
  694. *----------------------------------------------------------------------
  695. *
  696. * Tcl_AppendExportList -> appendExportList
  697. *
  698. * Appends onto the argument object the list of export patterns for the
  699. * specified namespace.
  700. *
  701. * Results:
  702. * The method will return when successful; in this case the object
  703. * referenced by obj has each export pattern appended to it. If an
  704. * error occurs, an exception and the interpreter's result
  705. * holds an error message.
  706. *
  707. * Side effects:
  708. * If necessary, the object referenced by obj is converted into
  709. * a list object.
  710. *
  711. *----------------------------------------------------------------------
  712. */
  713. internal static void appendExportList(Interp interp, Namespace namespace_Renamed, TclObject obj)
  714. {
  715. Namespace ns;
  716. int i;
  717. // If the specified namespace is null, use the current namespace.
  718. if (namespace_Renamed == null)
  719. {
  720. ns = getCurrentNamespace(interp);
  721. }
  722. else
  723. {
  724. ns = namespace_Renamed;
  725. }
  726. // Append the export pattern list onto objPtr.
  727. for (i = 0; i < ns.numExportPatterns; i++)
  728. {
  729. TclList.append(interp, obj, TclString.newInstance(ns.exportArray[i]));
  730. }
  731. return ;
  732. }
  733. /*
  734. *----------------------------------------------------------------------
  735. *
  736. * Tcl_Import -> importList
  737. *
  738. * Imports all of the commands matching a pattern into the namespace
  739. * specified by namespace (or the current namespace if namespace
  740. * is null). This is done by creating a new command (the "imported
  741. * command") that points to the real command in its original namespace.
  742. *
  743. * If matching commands are on the autoload path but haven't been
  744. * loaded yet, this command forces them to be loaded, then creates
  745. * the links to them.
  746. *
  747. * Results:
  748. * Returns if successful, raises TclException if something goes wrong.
  749. *
  750. * Side effects:
  751. * Creates new commands in the importing namespace. These indirect
  752. * calls back to the real command and are deleted if the real commands
  753. * are deleted.
  754. *
  755. *----------------------------------------------------------------------
  756. */
  757. internal static void importList(Interp interp, Namespace namespace_Renamed, string pattern, bool allowOverwrite)
  758. {
  759. Namespace ns, importNs;
  760. Namespace currNs = getCurrentNamespace(interp);
  761. string simplePattern, cmdName;
  762. IEnumerator search;
  763. WrappedCommand cmd, realCmd;
  764. ImportRef ref_Renamed;
  765. WrappedCommand autoCmd, importedCmd;
  766. ImportedCmdData data;
  767. bool wasExported;
  768. int i, result;
  769. // If the specified namespace is null, use the current namespace.
  770. if (namespace_Renamed == null)
  771. {
  772. ns = currNs;
  773. }
  774. else
  775. {
  776. ns = namespace_Renamed;
  777. }
  778. // First, invoke the "auto_import" command with the pattern
  779. // being imported. This command is part of the Tcl library.
  780. // It looks for imported commands in autoloaded libraries and
  781. // loads them in. That way, they will be found when we try
  782. // to create links below.
  783. autoCmd = findCommand(interp, "auto_import", null, TCL.VarFlag.GLOBAL_ONLY);
  784. if (autoCmd != null)
  785. {
  786. TclObject[] objv = new TclObject[2];
  787. objv[0] = TclString.newInstance("auto_import");
  788. objv[0].preserve();
  789. objv[1] = TclString.newInstance(pattern);
  790. objv[1].preserve();
  791. cmd = autoCmd;
  792. try
  793. {
  794. // Invoke the command with the arguments
  795. cmd.cmd.cmdProc(interp, objv);
  796. }
  797. finally
  798. {
  799. objv[0].release();
  800. objv[1].release();
  801. }
  802. interp.resetResult();
  803. }
  804. // From the pattern, find the namespace from which we are importing
  805. // and get the simple pattern (no namespace qualifiers or ::'s) at
  806. // the end.
  807. if (pattern.Length == 0)
  808. {
  809. throw new TclException(interp, "empty import pattern");
  810. }
  811. // Java does not support passing an address so we pass
  812. // an array of size 1 and then assign arr[0] to the value
  813. Namespace[] importNsArr = new Namespace[1];
  814. Namespace[] dummyArr = new Namespace[1];
  815. string[] simplePatternArr = new string[1];
  816. getNamespaceForQualName(interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, importNsArr, dummyArr, dummyArr, simplePatternArr);
  817. importNs = importNsArr[0];
  818. simplePattern = simplePatternArr[0];
  819. if (importNs == null)
  820. {
  821. throw new TclException(interp, "unknown namespace in import pattern \"" + pattern + "\"");
  822. }
  823. if (importNs == ns)
  824. {
  825. if ((System.Object) pattern == (System.Object) simplePattern)
  826. {
  827. throw new TclException(interp, "no namespace specified in import pattern \"" + pattern + "\"");
  828. }
  829. else
  830. {
  831. throw new TclException(interp, "import pattern \"" + pattern + "\" tries to import from namespace \"" + importNs.name + "\" into itself");
  832. }
  833. }
  834. // Scan through the command table in the source namespace and look for
  835. // exported commands that match the string pattern. Create an "imported
  836. // command" in the current namespace for each imported command; these
  837. // commands redirect their invocations to the "real" command.
  838. for (search = importNs.cmdTable.Keys.GetEnumerator(); search.MoveNext(); )
  839. {
  840. cmdName = ((string) search.Current);
  841. if (Util.stringMatch(cmdName, simplePattern))
  842. {
  843. // The command cmdName in the source namespace matches the
  844. // pattern. Check whether it was exported. If it wasn't,
  845. // we ignore it.
  846. wasExported = false;
  847. for (i = 0; i < importNs.numExportPatterns; i++)
  848. {
  849. if (Util.stringMatch(cmdName, importNs.exportArray[i]))
  850. {
  851. wasExported = true;
  852. break;
  853. }
  854. }
  855. if (!wasExported)
  856. {
  857. continue;
  858. }
  859. // Unless there is a name clash, create an imported command
  860. // in the current namespace that refers to cmdPtr.
  861. if ((ns.cmdTable[cmdName] == null) || allowOverwrite)
  862. {
  863. // Create the imported command and its client data.
  864. // To create the new command in the current namespace,
  865. // generate a fully qualified name for it.
  866. System.Text.StringBuilder ds;
  867. ds = new System.Text.StringBuilder();
  868. ds.Append(ns.fullName);
  869. if (ns != interp.globalNs)
  870. {
  871. ds.Append("::");
  872. }
  873. ds.Append(cmdName);
  874. // Check whether creating the new imported command in the
  875. // current namespace would create a cycle of imported->real
  876. // command references that also would destroy an existing
  877. // "real" command already in the current namespace.
  878. cmd = (WrappedCommand) importNs.cmdTable[cmdName];
  879. if (cmd.cmd is ImportedCmdData)
  880. {
  881. // This is actually an imported command, find
  882. // the real command it references
  883. realCmd = getOriginalCommand(cmd);
  884. if ((realCmd != null) && (realCmd.ns == currNs) && (currNs.cmdTable[cmdName] != null))
  885. {
  886. throw new TclException(interp, "import pattern \"" + pattern + "\" would create a loop containing command \"" + ds.ToString() + "\"");
  887. }
  888. }
  889. data = new ImportedCmdData();
  890. // Create the imported command inside the interp
  891. interp.createCommand(ds.ToString(), data);
  892. // Lookup in the namespace for the new WrappedCommand
  893. importedCmd = findCommand(interp, ds.ToString(), ns, (TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.LEAVE_ERR_MSG));
  894. data.realCmd = cmd;
  895. data.self = importedCmd;
  896. // Create an ImportRef structure describing this new import
  897. // command and add it to the import ref list in the "real"
  898. // command.
  899. ref_Renamed = new ImportRef();
  900. ref_Renamed.importedCmd = importedCmd;
  901. ref_Renamed.next = cmd.importRef;
  902. cmd.importRef = ref_Renamed;
  903. }
  904. else
  905. {
  906. throw new TclException(interp, "can't import command \"" + cmdName + "\": already exists");
  907. }
  908. }
  909. }
  910. return ;
  911. }
  912. /*
  913. *----------------------------------------------------------------------
  914. *
  915. * Tcl_ForgetImport -> forgetImport
  916. *
  917. * Deletes previously imported commands. Given a pattern that may
  918. * include the name of an exporting namespace, this procedure first
  919. * finds all matching exported commands. It then looks in the namespace
  920. * specified by namespace for any corresponding previously imported
  921. * commands, which it deletes. If namespace is null, commands are
  922. * deleted from the current namespace.
  923. *
  924. * Results:
  925. * Returns if successful, raises TclException if something goes wrong.
  926. *
  927. * Side effects:
  928. * May delete commands.
  929. *
  930. *----------------------------------------------------------------------
  931. */
  932. internal static void forgetImport(Interp interp, Namespace namespace_Renamed, string pattern)
  933. {
  934. Namespace ns, importNs, actualCtx;
  935. string simplePattern, cmdName;
  936. IEnumerator search;
  937. WrappedCommand cmd;
  938. // If the specified namespace is null, use the current namespace.
  939. if (namespace_Renamed == null)
  940. {
  941. ns = getCurrentNamespace(interp);
  942. }
  943. else
  944. {
  945. ns = namespace_Renamed;
  946. }
  947. // From the pattern, find the namespace from which we are importing
  948. // and get the simple pattern (no namespace qualifiers or ::'s) at
  949. // the end.
  950. // Java does not support passing an address so we pass
  951. // an array of size 1 and then assign arr[0] to the value
  952. Namespace[] importNsArr = new Namespace[1];
  953. Namespace[] dummyArr = new Namespace[1];
  954. Namespace[] actualCtxArr = new Namespace[1];
  955. string[] simplePatternArr = new string[1];
  956. getNamespaceForQualName(interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, importNsArr, dummyArr, actualCtxArr, simplePatternArr);
  957. // get the values out of the arrays
  958. importNs = importNsArr[0];
  959. actualCtx = actualCtxArr[0];
  960. simplePattern = simplePatternArr[0];
  961. // FIXME : the above call passes TCL.VarFlag.LEAVE_ERR_MSG, but
  962. // it seems like this will be a problem when exception is raised!
  963. if (importNs == null)
  964. {
  965. throw new TclException(interp, "unknown namespace in namespace forget pattern \"" + pattern + "\"");
  966. }
  967. // Scan through the command table in the source namespace and look for
  968. // exported commands that match the string pattern. If the current
  969. // namespace has an imported command that refers to one of those real
  970. // commands, delete it.
  971. for (search = importNs.cmdTable.Keys.GetEnumerator(); search.MoveNext(); )
  972. {
  973. cmdName = ((string) search.Current);
  974. if (Util.stringMatch(cmdName, simplePattern))
  975. {
  976. cmd = (WrappedCommand) ns.cmdTable[cmdName];
  977. if (cmd != null)
  978. {
  979. // cmd of same name in current namespace
  980. if (cmd.cmd is ImportedCmdData)
  981. {
  982. interp.deleteCommandFromToken(cmd);
  983. }
  984. }
  985. }
  986. }
  987. return ;
  988. }
  989. /*
  990. *----------------------------------------------------------------------
  991. *
  992. * TclGetOriginalCommand -> getOriginalCommand
  993. *
  994. * An imported command is created in a namespace when a "real" command
  995. * is imported from another namespace. If the specified command is an
  996. * imported command, this procedure returns the original command it
  997. * refers to.
  998. *
  999. * Results:
  1000. * If the command was imported into a sequence of namespaces a, b,...,n
  1001. * where each successive namespace just imports the command from the
  1002. * previous namespace, this procedure returns the Tcl_Command token in
  1003. * the first namespace, a. Otherwise, if the specified command is not
  1004. * an imported command, the procedure returns null.
  1005. *
  1006. * Side effects:
  1007. * None.
  1008. *
  1009. *----------------------------------------------------------------------
  1010. */
  1011. internal static WrappedCommand getOriginalCommand(WrappedCommand command)
  1012. {
  1013. WrappedCommand cmd = command;
  1014. ImportedCmdData data;
  1015. if (!(cmd.cmd is ImportedCmdData))
  1016. {
  1017. return null;
  1018. }
  1019. while (cmd.cmd is ImportedCmdData)
  1020. {
  1021. data = (ImportedCmdData) cmd.cmd;
  1022. cmd = data.realCmd;
  1023. }
  1024. return cmd;
  1025. }
  1026. /*
  1027. *----------------------------------------------------------------------
  1028. *
  1029. * InvokeImportedCmd -> invokeImportedCmd
  1030. *
  1031. * Invoked by Tcl whenever the user calls an imported command that
  1032. * was created by Tcl_Import. Finds the "real" command (in another
  1033. * namespace), and passes control to it.
  1034. *
  1035. * Results:
  1036. * Returns if successful, raises TclException if something goes wrong.
  1037. *
  1038. * Side effects:
  1039. * Returns a result in the interpreter's result object. If anything
  1040. * goes wrong, the result object is set to an error message.
  1041. *
  1042. *----------------------------------------------------------------------
  1043. */
  1044. internal static void invokeImportedCmd(Interp interp, ImportedCmdData data, TclObject[] objv)
  1045. {
  1046. WrappedCommand realCmd = data.realCmd;
  1047. realCmd.cmd.cmdProc(interp, objv);
  1048. }
  1049. /*
  1050. *----------------------------------------------------------------------
  1051. *
  1052. * DeleteImportedCmd -> deleteImportedCmd
  1053. *
  1054. * Invoked by Tcl whenever an imported command is deleted. The "real"
  1055. * command keeps a list of all the imported commands that refer to it,
  1056. * so those imported commands can be deleted when the real command is
  1057. * deleted. This procedure removes the imported command reference from
  1058. * the real command's list, and frees up the memory associated with
  1059. * the imported command.
  1060. *
  1061. * Results:
  1062. * None.
  1063. *
  1064. * Side effects:
  1065. * Removes the imported command from the real command's import list.
  1066. *
  1067. *----------------------------------------------------------------------
  1068. */
  1069. internal static void deleteImportedCmd(ImportedCmdData data)
  1070. // The data object for this imported command
  1071. {
  1072. WrappedCommand realCmd = data.realCmd;
  1073. WrappedCommand self = data.self;
  1074. ImportRef ref_Renamed, prev;
  1075. prev = null;
  1076. for (ref_Renamed = realCmd.importRef; ref_Renamed != null; ref_Renamed = ref_Renamed.next)
  1077. {
  1078. if (ref_Renamed.importedCmd == self)
  1079. {
  1080. // Remove ref from real command's list of imported commands
  1081. // that refer to it.
  1082. if (prev == null)
  1083. {
  1084. // ref is first in list
  1085. realCmd.importRef = ref_Renamed.next;
  1086. }
  1087. else
  1088. {
  1089. prev.next = ref_Renamed.next;
  1090. }
  1091. ref_Renamed = null;
  1092. data = null;
  1093. return ;
  1094. }
  1095. prev = ref_Renamed;
  1096. }
  1097. throw new TclRuntimeError("DeleteImportedCmd: did not find cmd in real cmd's list of import references");
  1098. }
  1099. /*
  1100. *----------------------------------------------------------------------
  1101. *
  1102. * TclGetNamespaceForQualName -> getNamespaceForQualName
  1103. *
  1104. * Given a qualified name specifying a command, variable, or namespace,
  1105. * and a namespace in which to resolve the name, this procedure returns
  1106. * a pointer to the namespace that contains the item. A qualified name
  1107. * consists of the "simple" name of an item qualified by the names of
  1108. * an arbitrary number of containing namespace separated by "::"s. If
  1109. * the qualified name starts with "::", it is interpreted absolutely
  1110. * from the global namespace. Otherwise, it is interpreted relative to
  1111. * the namespace specified by cxtNsPtr if it is non-null. If cxtNsPtr
  1112. * is null, the name is interpreted relative to the current namespace.
  1113. *
  1114. * A relative name like "foo::bar::x" can be found starting in either
  1115. * the current namespace or in the global namespace. So each search
  1116. * usually follows two tracks, and two possible namespaces are
  1117. * returned. If the procedure sets either nsPtrPtr[0] or altNsPtrPtr[0] to
  1118. * null, then that path failed.
  1119. *
  1120. * If "flags" contains TCL.VarFlag.GLOBAL_ONLY, the relative qualified name is
  1121. * sought only in the global :: namespace. The alternate search
  1122. * (also) starting from the global namespace is ignored and
  1123. * altNsPtrPtr[0] is set null.
  1124. *
  1125. * If "flags" contains TCL.VarFlag.NAMESPACE_ONLY, the relative qualified
  1126. * name is sought only in the namespace specified by cxtNsPtr. The
  1127. * alternate search starting from the global namespace is ignored and
  1128. * altNsPtrPtr[0] is set null. If both TCL.VarFlag.GLOBAL_ONLY and
  1129. * TCL.VarFlag.NAMESPACE_ONLY are specified, TCL.VarFlag.GLOBAL_ONLY is ignored and
  1130. * the search starts from the namespace specified by cxtNsPtr.
  1131. *
  1132. * If "flags" contains TCL.VarFlag.CREATE_NS_IF_UNKNOWN, all namespace
  1133. * components of the qualified name that cannot be found are
  1134. * automatically created within their specified parent. This makes sure
  1135. * that functions like Tcl_CreateCommand always succeed. There is no
  1136. * alternate search path, so altNsPtrPtr[0] is set null.
  1137. *
  1138. * If "flags" contains TCL.VarFlag.FIND_ONLY_NS, the qualified name is treated as a
  1139. * reference to a namespace, and the entire qualified name is
  1140. * followed. If the name is relative, the namespace is looked up only
  1141. * in the current namespace. A pointer to the namespace is stored in
  1142. * nsPtrPtr[0] and null is stored in simpleNamePtr[0]. Otherwise, if
  1143. * TCL.VarFlag.FIND_ONLY_NS is not specified, only the leading components are
  1144. * treated as namespace names, and a pointer to the simple name of the
  1145. * final component is stored in simpleNamePtr[0].
  1146. *
  1147. * Results:
  1148. * It sets nsPtrPtr[0] and altNsPtrPtr[0] to point to the two possible
  1149. * namespaces which represent the last (containing) namespace in the
  1150. * qualified name. If the procedure sets either nsPtrPtr[0] or altNsPtrPtr[0]
  1151. * to null, then the search along that path failed. The procedure also
  1152. * stores a pointer to the simple name of the final component in
  1153. * simpleNamePtr[0]. If the qualified name is "::" or was treated as a
  1154. * namespace reference (TCL.VarFlag.FIND_ONLY_NS), the procedure stores a pointer
  1155. * to the namespace in nsPtrPtr[0], null in altNsPtrPtr[0], and sets
  1156. * simpleNamePtr[0] to an empty string.
  1157. *
  1158. * If there is an error, this procedure returns TCL_ERROR. If "flags"
  1159. * contains TCL_LEAVE_ERR_MSG, an error message is returned in the
  1160. * interpreter's result object. Otherwise, the interpreter's result
  1161. * object is left unchanged.
  1162. *
  1163. * actualCxtPtrPtr[0] is set to the actual context namespace. It is
  1164. * set to the input context namespace pointer in cxtNsPtr. If cxtNsPtr
  1165. * is null, it is set to the current namespace context.
  1166. *
  1167. * Side effects:
  1168. * If "flags" contains TCL.VarFlag.CREATE_NS_IF_UNKNOWN, new namespaces may be
  1169. * created.
  1170. *
  1171. *----------------------------------------------------------------------
  1172. */
  1173. internal static void getNamespaceForQualName(Interp interp, string qualName, Namespace cxtNsPtr, TCL.VarFlag flags, Namespace[] nsPtrPtr, Namespace[] altNsPtrPtr, Namespace[] actualCxtPtrPtr, string[] simpleNamePtr)
  1174. {
  1175. // FIXME : remove extra method call checks when we are sure this works!
  1176. if (true)
  1177. {
  1178. // check invariants
  1179. if ((nsPtrPtr == null) || (nsPtrPtr.Length != 1))
  1180. {
  1181. throw new System.SystemException("nsPtrPtr " + nsPtrPtr);
  1182. }
  1183. if ((altNsPtrPtr == null) || (altNsPtrPtr.Length != 1))
  1184. {
  1185. throw new System.SystemException("altNsPtrPtr " + altNsPtrPtr);
  1186. }
  1187. if ((actualCxtPtrPtr == null) || (actualCxtPtrPtr.Length != 1))
  1188. {
  1189. throw new System.SystemException("actualCxtPtrPtr " + actualCxtPtrPtr);
  1190. }
  1191. if ((simpleNamePtr == null) || (simpleNamePtr.Length != 1))
  1192. {
  1193. throw new System.SystemException("simpleNamePtr " + simpleNamePtr);
  1194. }
  1195. }
  1196. Namespace ns = cxtNsPtr;
  1197. Namespace altNs;
  1198. Namespace globalNs = getGlobalNamespace(interp);
  1199. Namespace entryNs;
  1200. string start, end;
  1201. string nsName;
  1202. int len;
  1203. int start_ind, end_ind, name_len;
  1204. // Determine the context namespace ns in which to start the primary
  1205. // search. If TCL.VarFlag.NAMESPACE_ONLY or TCL.VarFlag.FIND_ONLY_NS was specified, search
  1206. // from the current namespace. If the qualName name starts with a "::"
  1207. // or TCL.VarFlag.GLOBAL_ONLY was specified, search from the global
  1208. // namespace. Otherwise, use the given namespace given in cxtNsPtr, or
  1209. // if that is null, use the current namespace context. Note that we
  1210. // always treat two or more adjacent ":"s as a namespace separator.
  1211. if ((flags & (TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.FIND_ONLY_NS)) != 0)
  1212. {
  1213. ns = getCurrentNamespace(interp);
  1214. }
  1215. else if ((flags & TCL.VarFlag.GLOBAL_ONLY) != 0)
  1216. {
  1217. ns = globalNs;
  1218. }
  1219. else if (ns == null)
  1220. {
  1221. if (interp.varFrame != null)
  1222. {
  1223. ns = interp.varFrame.ns;
  1224. }
  1225. else
  1226. {
  1227. ns = interp.globalNs;
  1228. }
  1229. }
  1230. start_ind = 0;
  1231. name_len = qualName.Length;
  1232. if ((name_len >= 2) && (qualName[0] == ':') && (qualName[1] == ':'))
  1233. {
  1234. start_ind = 2; // skip over the initial ::
  1235. while ((start_ind < name_len) && (qualName[start_ind] == ':'))
  1236. {
  1237. start_ind++; // skip over a subsequent :
  1238. }
  1239. ns = globalNs;
  1240. if (start_ind >= name_len)
  1241. {
  1242. // qualName is just two or more ":"s
  1243. nsPtrPtr[0] = globalNs;
  1244. altNsPtrPtr[0] = null;
  1245. actualCxtPtrPtr[0] = globalNs;
  1246. simpleNamePtr[0] = ""; // points to empty string
  1247. return ;
  1248. }
  1249. }
  1250. actualCxtPtrPtr[0] = ns;
  1251. // Start an alternate search path starting with the global namespace.
  1252. // However, if the starting context is the global namespace, or if the
  1253. // flag is set to search only the namespace cxtNs, ignore the
  1254. // alternate search path.
  1255. altNs = globalNs;
  1256. if ((ns == globalNs) || ((flags & (TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.FIND_ONLY_NS)) != 0))
  1257. {
  1258. altNs = null;
  1259. }
  1260. // Loop to resolve each namespace qualifier in qualName.
  1261. end_ind = start_ind;
  1262. while (start_ind < name_len)
  1263. {
  1264. // Find the next namespace qualifier (i.e., a name ending in "::")
  1265. // or the end of the qualified name (i.e., a name ending in "\0").
  1266. // Set len to the number of characters, starting from start,
  1267. // in the name; set end to point after the "::"s or at the "\0".
  1268. len = 0;
  1269. for (end_ind = start_ind; end_ind < name_len; end_ind++)
  1270. {
  1271. if (((name_len - end_ind) > 1) && (qualName[end_ind] == ':') && (qualName[end_ind + 1] == ':'))
  1272. {
  1273. end_ind += 2; // skip over the initial ::
  1274. while ((end_ind < name_len) && (qualName[end_ind] == ':'))
  1275. {
  1276. end_ind++; // skip over a subsequent :
  1277. }
  1278. break;
  1279. }
  1280. len++;
  1281. }
  1282. if ((end_ind == name_len) && !((end_ind - start_ind >= 2) && ((qualName[end_ind - 1] == ':') && (qualName[end_ind - 2] == ':'))))
  1283. {
  1284. // qualName ended with a simple name at start. If TCL.VarFlag.FIND_ONLY_NS
  1285. // was specified, look this up as a namespace. Otherwise,
  1286. // start is the name of a cmd or var and we are done.
  1287. if ((flags & TCL.VarFlag.FIND_ONLY_NS) != 0)
  1288. {
  1289. // assign the string from start_ind to the end of the name string
  1290. nsName = qualName.Substring(start_ind);
  1291. }
  1292. else
  1293. {
  1294. nsPtrPtr[0] = ns;
  1295. altNsPtrPtr[0] = altNs;
  1296. simpleNamePtr[0] = qualName.Substring(start_ind);
  1297. return ;
  1298. }
  1299. }
  1300. else
  1301. {
  1302. // start points to the beginning of a namespace qualifier ending
  1303. // in "::". Create new string with the namespace qualifier.
  1304. nsName = qualName.Substring(start_ind, (start_ind + len) - (start_ind));
  1305. }
  1306. // Look up the namespace qualifier nsName in the current namespace
  1307. // context. If it isn't found but TCL.VarFlag.CREATE_NS_IF_UNKNOWN is set,
  1308. // create that qualifying namespace. This is needed for procedures
  1309. // like Tcl_CreateCommand that cannot fail.
  1310. if (ns != null)
  1311. {
  1312. entryNs = (Namespace) ns.childTable[nsName];
  1313. if (entryNs != null)
  1314. {
  1315. ns = entryNs;
  1316. }
  1317. else if ((flags & TCL.VarFlag.CREATE_NS_IF_UNKNOWN) != 0)
  1318. {
  1319. CallFrame frame = interp.newCallFrame();
  1320. pushCallFrame(interp, frame, ns, false);
  1321. ns = createNamespace(interp, nsName, null);
  1322. popCallFrame(interp);
  1323. if (ns == null)
  1324. {
  1325. throw new System.SystemException("Could not create namespace " + nsName);
  1326. }
  1327. }
  1328. else
  1329. {
  1330. ns = null; // namespace not found and wasn't created
  1331. }
  1332. }
  1333. // Look up the namespace qualifier in the alternate search path too.
  1334. if (altNs != null)
  1335. {
  1336. altNs = (Namespace) altNs.childTable[nsName];
  1337. }
  1338. // If both search paths have failed, return null results.
  1339. if ((ns == null) && (altNs == null))
  1340. {
  1341. nsPtrPtr[0] = null;
  1342. altNsPtrPtr[0] = null;
  1343. simpleNamePtr[0] = null;
  1344. return ;
  1345. }
  1346. start_ind = end_ind;
  1347. }
  1348. // We ignore trailing "::"s in a namespace name, but in a command or
  1349. // variable name, trailing "::"s refer to the cmd or var named {}.
  1350. if (((flags & TCL.VarFlag.FIND_ONLY_NS) != 0) || ((end_ind > start_ind) && (qualName[end_ind - 1] != ':')))
  1351. {
  1352. simpleNamePtr[0] = null; // found namespace name
  1353. }
  1354. else
  1355. {
  1356. // FIXME : make sure this does not throw exception when end_ind is at the end of the string
  1357. simpleNamePtr[0] = qualName.Substring(end_ind); // found cmd/var: points to empty string
  1358. }
  1359. // As a special case, if we are looking for a namespace and qualName
  1360. // is "" and the current active namespace (ns) i…

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