wasCSharpSQLite – Blame information for rev

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 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 *
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 using System.Text;
26  
27 namespace tcl.lang
28 {
29  
30 /// <summary> This class implements the built-in "namespace" command in Tcl.
31 /// See the user documentation for details on what it does.
32 /// </summary>
33  
34  
35 public class NamespaceCmd : InternalRep, Command
36 {
37  
38 // Flag passed to getNamespaceForQualName to indicate that it should
39 // search for a namespace rather than a command or variable inside a
40 // namespace. Note that this flag's value must not conflict with the values
41 // of TCL.VarFlag.GLOBAL_ONLY, TCL.VarFlag.NAMESPACE_ONLY, or TCL.VarFlag.CREATE_NS_IF_UNKNOWN.
42  
43  
44 // Initial size of stack allocated space for tail list - used when resetting
45 // shadowed command references in the functin: TclResetShadowedCmdRefs.
46  
47 //private static final int NUM_TRAIL_ELEMS = 5;
48  
49 // Count of the number of namespaces created. This value is used as a
50 // unique id for each namespace.
51  
52 private static long numNsCreated = 0;
53 private static Object nsMutex;
54  
55 //
56 // Flags used to represent the status of a namespace:
57 //
58 // NS_DYING - 1 means deleteNamespace has been called to delete the
59 // namespace but there are still active call frames on the Tcl
60 // stack that refer to the namespace. When the last call frame
61 // referring to it has been popped, it's variables and command
62 // will be destroyed and it will be marked "dead" (NS_DEAD).
63 // The namespace can no longer be looked up by name.
64 // NS_DEAD - 1 means deleteNamespace has been called to delete the
65 // namespace and no call frames still refer to it. Its
66 // variables and command have already been destroyed. This bit
67 // allows the namespace resolution code to recognize that the
68 // namespace is "deleted". When the last namespaceName object
69 // in any byte code code unit that refers to the namespace has
70 // been freed (i.e., when the namespace's refCount is 0), the
71 // namespace's storage will be freed.
72  
73 internal const int NS_DYING = 0x01;
74 internal const int NS_DEAD = 0x02;
75  
76  
77 // Flag passed to getNamespaceForQualName to have it create all namespace
78 // components of a namespace-qualified name that cannot be found. The new
79 // namespaces are created within their specified parent. Note that this
80 // flag's value must not conflict with the values of the flags
81 // TCL.VarFlag.GLOBAL_ONLY, TCL.VarFlag.NAMESPACE_ONLY, and TCL.VarFlag.FIND_ONLY_NS
82  
83 // internal const int TCL.VarFlag.CREATE_NS_IF_UNKNOWN = 0x800;
84  
85  
86 // This value corresponds to the Tcl_Obj.otherValuePtr pointer used
87 // in the C version of Tcl 8.1. Use it to keep track of a ResolvedNsName.
88  
89 private ResolvedNsName otherValue = null;
90  
91  
92 /*
93 *----------------------------------------------------------------------
94 *
95 * Tcl_GetCurrentNamespace -> getCurrentNamespace
96 *
97 * Returns a reference to an interpreter's currently active namespace.
98 *
99 * Results:
100 * Returns a reference to the interpreter's current namespace.
101 *
102 * Side effects:
103 * None.
104 *
105 *----------------------------------------------------------------------
106 */
107  
108 internal static Namespace getCurrentNamespace( Interp interp )
109 {
110 if ( interp.varFrame != null )
111 {
112 return interp.varFrame.ns;
113 }
114 else
115 {
116 return interp.globalNs;
117 }
118 }
119  
120 /*
121 *----------------------------------------------------------------------
122 *
123 * Tcl_GetGlobalNamespace -> getGlobalNamespace
124 *
125 * Returns a reference to an interpreter's global :: namespace.
126 *
127 * Results:
128 * Returns a reference to the specified interpreter's global namespace.
129 *
130 * Side effects:
131 * None.
132 *
133 *----------------------------------------------------------------------
134 */
135  
136 internal static Namespace getGlobalNamespace( Interp interp )
137 {
138 return interp.globalNs;
139 }
140  
141  
142 /*
143 *----------------------------------------------------------------------
144 *
145 * Tcl_PushCallFrame -> pushCallFrame
146 *
147 * Pushes a new call frame onto the interpreter's Tcl call stack.
148 * Called when executing a Tcl procedure or a "namespace eval" or
149 * "namespace inscope" command.
150 *
151 * Results:
152 * Returns if successful, raises TclException if something goes wrong.
153 *
154 * Side effects:
155 * Modifies the interpreter's Tcl call stack.
156 *
157 *----------------------------------------------------------------------
158 */
159  
160 internal static void pushCallFrame( Interp interp, CallFrame frame, Namespace namespace_Renamed, bool isProcCallFrame )
161 // If true, the frame represents a
162 // called Tcl procedure and may have local
163 // vars. Vars will ordinarily be looked up
164 // in the frame. If new variables are
165 // created, they will be created in the
166 // frame. If false, the frame is for a
167 // "namespace eval" or "namespace inscope"
168 // command and var references are treated
169 // as references to namespace variables.
170 {
171 Namespace ns;
172  
173 if ( namespace_Renamed == null )
174 {
175 ns = getCurrentNamespace( interp );
176 }
177 else
178 {
179 ns = namespace_Renamed;
180 if ( ( ns.flags & NS_DEAD ) != 0 )
181 {
182 throw new TclRuntimeError( "Trying to push call frame for dead namespace" );
183 }
184 }
185  
186 ns.activationCount++;
187 frame.ns = ns;
188 frame.isProcCallFrame = isProcCallFrame;
189 frame.objv = null;
190  
191 frame.caller = interp.frame;
192 frame.callerVar = interp.varFrame;
193  
194 if ( interp.varFrame != null )
195 {
196 frame.level = ( interp.varFrame.level + 1 );
197 }
198 else
199 {
200 frame.level = 1;
201 }
202  
203 // FIXME : does Jacl need a procPtr in the CallFrame class?
204 //frame.procPtr = null; // no called procedure
205  
206 frame.varTable = null; // and no local variables
207  
208 // Compiled locals are not part of Jacl's CallFrame
209  
210 // Push the new call frame onto the interpreter's stack of procedure
211 // call frames making it the current frame.
212  
213 interp.frame = frame;
214 interp.varFrame = frame;
215 }
216  
217  
218  
219 /*
220 *----------------------------------------------------------------------
221 *
222 * Tcl_PopCallFrame -> popCallFrame
223 *
224 * Removes a call frame from the Tcl call stack for the interpreter.
225 * Called to remove a frame previously pushed by Tcl_PushCallFrame.
226 *
227 * Results:
228 * None.
229 *
230 * Side effects:
231 * Modifies the call stack of the interpreter. Resets various fields of
232 * the popped call frame. If a namespace has been deleted and
233 * has no more activations on the call stack, the namespace is
234 * destroyed.
235 *
236 *----------------------------------------------------------------------
237 */
238  
239 internal static void popCallFrame( Interp interp )
240 {
241 CallFrame frame = interp.frame;
242 int saveErrFlag;
243 Namespace ns;
244  
245 // It's important to remove the call frame from the interpreter's stack
246 // of call frames before deleting local variables, so that traces
247 // invoked by the variable deletion don't see the partially-deleted
248 // frame.
249  
250 interp.frame = frame.caller;
251 interp.varFrame = frame.callerVar;
252  
253 // Delete the local variables. As a hack, we save then restore the
254 // ERR_IN_PROGRESS flag in the interpreter. The problem is that there
255 // could be unset traces on the variables, which cause scripts to be
256 // evaluated. This will clear the ERR_IN_PROGRESS flag, losing stack
257 // trace information if the procedure was exiting with an error. The
258 // code below preserves the flag. Unfortunately, that isn't really
259 // enough: we really should preserve the errorInfo variable too
260 // (otherwise a nested error in the trace script will trash errorInfo).
261 // What's really needed is a general-purpose mechanism for saving and
262 // restoring interpreter state.
263  
264 saveErrFlag = ( interp.flags & Parser.ERR_IN_PROGRESS );
265  
266 if ( frame.varTable != null )
267 {
268 Var.deleteVars( interp, frame.varTable );
269 frame.varTable = null;
270 }
271  
272 interp.flags |= saveErrFlag;
273  
274 // Decrement the namespace's count of active call frames. If the
275 // namespace is "dying" and there are no more active call frames,
276 // call Tcl_DeleteNamespace to destroy it.
277  
278 ns = frame.ns;
279 ns.activationCount--;
280 if ( ( ( ns.flags & NS_DYING ) != 0 ) && ( ns.activationCount == 0 ) )
281 {
282 deleteNamespace( ns );
283 }
284 frame.ns = null;
285 }
286  
287 /*
288 *----------------------------------------------------------------------
289 *
290 * Tcl_CreateNamespace --
291 *
292 * Creates a new namespace with the given name. If there is no
293 * active namespace (i.e., the interpreter is being initialized),
294 * the global :: namespace is created and returned.
295 *
296 * Results:
297 * Returns a reference to the new namespace if successful. If the
298 * namespace already exists or if another error occurs, this routine
299 * returns null, along with an error message in the interpreter's
300 * result object.
301 *
302 * Side effects:
303 * If the name contains "::" qualifiers and a parent namespace does
304 * not already exist, it is automatically created.
305 *
306 *----------------------------------------------------------------------
307 */
308  
309 internal static Namespace createNamespace( Interp interp, string name, DeleteProc deleteProc )
310 {
311 Namespace ns, ancestor;
312 Namespace parent;
313 Namespace globalNs = getGlobalNamespace( interp );
314 string simpleName;
315 StringBuilder buffer1, buffer2;
316  
317 // If there is no active namespace, the interpreter is being
318 // initialized.
319  
320 if ( ( globalNs == null ) && ( interp.varFrame == null ) )
321 {
322 // Treat this namespace as the global namespace, and avoid
323 // looking for a parent.
324  
325 parent = null;
326 simpleName = "";
327 }
328 else if ( name.Length == 0 )
329 {
330 /*
331 TclObject tobj = interp.getResult();
332 // FIXME : is there a test case to check this error result?
333 TclString.append(tobj,
334 "can't create namespace \"\": only global namespace can have empty name");
335 */
336  
337 // FIXME : is there a test case to check this error result?
338 interp.setResult( "can't create namespace \"\": only global namespace can have empty name" );
339 return null;
340 }
341 else
342 {
343 // Find the parent for the new namespace.
344  
345 // Java does not support passing an address so we pass
346 // an array of size 1 and then assign arr[0] to the value
347 Namespace[] parentArr = new Namespace[1];
348 Namespace[] dummyArr = new Namespace[1];
349 string[] simpleArr = new string[1];
350  
351 getNamespaceForQualName( interp, name, null, ( TCL.VarFlag.CREATE_NS_IF_UNKNOWN | TCL.VarFlag.LEAVE_ERR_MSG ), parentArr, dummyArr, dummyArr, simpleArr );
352  
353 // Get the values out of the arrays!
354 parent = parentArr[0];
355 simpleName = simpleArr[0];
356  
357  
358 // If the unqualified name at the end is empty, there were trailing
359 // "::"s after the namespace's name which we ignore. The new
360 // namespace was already (recursively) created and is referenced
361 // by parent.
362  
363 if ( simpleName.Length == 0 )
364 {
365 return parent;
366 }
367  
368 // Check for a bad namespace name and make sure that the name
369 // does not already exist in the parent namespace.
370  
371 if ( parent.childTable[simpleName] != null )
372 {
373 /*
374 TclObject tobj = interp.getResult();
375 // FIXME : is there a test case to check this error result?
376 TclString.append(tobj,
377 "can't create namespace \"" + name + "\": already exists");
378 */
379  
380 // FIXME : is there a test case to check this error result?
381 interp.setResult( "can't create namespace \"" + name + "\": already exists" );
382 return null;
383 }
384 }
385  
386 // Create the new namespace and root it in its parent. Increment the
387 // count of namespaces created.
388  
389 ns = new Namespace();
390 ns.name = simpleName;
391 ns.fullName = null; // set below
392 //ns.clientData = clientData;
393 ns.deleteProc = deleteProc;
394 ns.parent = parent;
395 ns.childTable = new Hashtable();
396 lock ( nsMutex )
397 {
398 numNsCreated++;
399 ns.nsId = numNsCreated;
400 }
401 ns.interp = interp;
402 ns.flags = 0;
403 ns.activationCount = 0;
404 // FIXME : there was a problem with the refcount because
405 // when the namespace was deleted the refocount was 0.
406 // We avoid this by just using a refcount of 1 for now.
407 // We can do ignore the refCount because GC will reclaim mem.
408 //ns.refCount = 0;
409 ns.refCount = 1;
410 ns.cmdTable = new Hashtable();
411 ns.varTable = new Hashtable();
412 ns.exportArray = null;
413 ns.numExportPatterns = 0;
414 ns.maxExportPatterns = 0;
415  
416 // Jacl does not use these tcl compiler specific members
417 //ns.cmdRefEpoch = 0;
418 //ns.resolverEpoch = 0;
419  
420 ns.resolver = null;
421  
422 if ( parent != null )
423 {
424 SupportClass.PutElement( parent.childTable, simpleName, ns );
425 }
426  
427 // Build the fully qualified name for this namespace.
428  
429 buffer1 = new StringBuilder();
430 buffer2 = new StringBuilder();
431 for ( ancestor = ns; ancestor != null; ancestor = ancestor.parent )
432 {
433 if ( ancestor != globalNs )
434 {
435 buffer1.Append( "::" );
436 buffer1.Append( ancestor.name );
437 }
438 buffer1.Append( buffer2 );
439  
440 buffer2.Length = 0;
441 buffer2.Append( buffer1 );
442 buffer1.Length = 0;
443 }
444  
445 name = buffer2.ToString();
446 ns.fullName = name;
447  
448 // Return a reference to the new namespace.
449  
450 return ns;
451 }
452  
453 /*
454 *----------------------------------------------------------------------
455 *
456 * Tcl_DeleteNamespace -> deleteNamespace
457 *
458 * Deletes a namespace and all of the commands, variables, and other
459 * namespaces within it.
460 *
461 * Results:
462 * None.
463 *
464 * Side effects:
465 * When a namespace is deleted, it is automatically removed as a
466 * child of its parent namespace. Also, all its commands, variables
467 * and child namespaces are deleted.
468 *
469 *----------------------------------------------------------------------
470 */
471  
472 internal static void deleteNamespace( Namespace namespace_Renamed )
473 {
474 Namespace ns = namespace_Renamed;
475 Interp interp = ns.interp;
476 Namespace globalNs = getGlobalNamespace( interp );
477  
478 // If the namespace is on the call frame stack, it is marked as "dying"
479 // (NS_DYING is OR'd into its flags): the namespace can't be looked up
480 // by name but its commands and variables are still usable by those
481 // active call frames. When all active call frames referring to the
482 // namespace have been popped from the Tcl stack, popCallFrame will
483 // call this procedure again to delete everything in the namespace.
484 // If no nsName objects refer to the namespace (i.e., if its refCount
485 // is zero), its commands and variables are deleted and the storage for
486 // its namespace structure is freed. Otherwise, if its refCount is
487 // nonzero, the namespace's commands and variables are deleted but the
488 // structure isn't freed. Instead, NS_DEAD is OR'd into the structure's
489 // flags to allow the namespace resolution code to recognize that the
490 // namespace is "deleted".
491  
492 if ( ns.activationCount > 0 )
493 {
494 ns.flags |= NS_DYING;
495 if ( ns.parent != null )
496 {
497 ns.parent.childTable.Remove( ns.name );
498 }
499 ns.parent = null;
500 }
501 else
502 {
503 // Delete the namespace and everything in it. If this is the global
504 // namespace, then clear it but don't free its storage unless the
505 // interpreter is being torn down.
506  
507 teardownNamespace( ns );
508  
509 if ( ( ns != globalNs ) || ( ( interp.flags & Parser.DELETED ) != 0 ) )
510 {
511 // If this is the global namespace, then it may have residual
512 // "errorInfo" and "errorCode" variables for errors that
513 // occurred while it was being torn down. Try to clear the
514 // variable list one last time.
515  
516 Var.deleteVars( ns.interp, ns.varTable );
517  
518 ns.childTable.Clear();
519 ns.cmdTable.Clear();
520  
521 // If the reference count is 0, then discard the namespace.
522 // Otherwise, mark it as "dead" so that it can't be used.
523  
524 if ( ns.refCount == 0 )
525 {
526 free( ns );
527 }
528 else
529 {
530 ns.flags |= NS_DEAD;
531 }
532 }
533 }
534 }
535  
536  
537 /*
538 *----------------------------------------------------------------------
539 *
540 * TclTeardownNamespace -> teardownNamespace
541 *
542 * Used internally to dismantle and unlink a namespace when it is
543 * deleted. Divorces the namespace from its parent, and deletes all
544 * commands, variables, and child namespaces.
545 *
546 * This is kept separate from Tcl_DeleteNamespace so that the global
547 * namespace can be handled specially. Global variables like
548 * "errorInfo" and "errorCode" need to remain intact while other
549 * namespaces and commands are torn down, in case any errors occur.
550 *
551 * Results:
552 * None.
553 *
554 * Side effects:
555 * Removes this namespace from its parent's child namespace hashtable.
556 * Deletes all commands, variables and namespaces in this namespace.
557 * If this is the global namespace, the "errorInfo" and "errorCode"
558 * variables are left alone and deleted later.
559 *
560 *----------------------------------------------------------------------
561 */
562  
563 internal static void teardownNamespace( Namespace ns )
564 {
565 Interp interp = ns.interp;
566 IEnumerator search;
567 Namespace globalNs = getGlobalNamespace( interp );
568 int i;
569  
570 // Start by destroying the namespace's variable table,
571 // since variables might trigger traces.
572  
573 if ( ns == globalNs )
574 {
575 // This is the global namespace, so be careful to preserve the
576 // "errorInfo" and "errorCode" variables. These might be needed
577 // later on if errors occur while deleting commands. We are careful
578 // to destroy and recreate the "errorInfo" and "errorCode"
579 // variables, in case they had any traces on them.
580  
581 string errorInfoStr, errorCodeStr;
582  
583 try
584 {
585  
586 errorInfoStr = interp.getVar( "errorInfo", TCL.VarFlag.GLOBAL_ONLY ).ToString();
587 }
588 catch ( TclException e )
589 {
590 errorInfoStr = null;
591 }
592  
593 try
594 {
595  
596 errorCodeStr = interp.getVar( "errorCode", TCL.VarFlag.GLOBAL_ONLY ).ToString();
597 }
598 catch ( TclException e )
599 {
600 errorCodeStr = null;
601 }
602  
603 Var.deleteVars( interp, ns.varTable );
604  
605 if ( (System.Object)errorInfoStr != null )
606 {
607 try
608 {
609 interp.setVar( "errorInfo", errorInfoStr, TCL.VarFlag.GLOBAL_ONLY );
610 }
611 catch ( TclException e )
612 {
613 // ignore an exception while setting this var
614 }
615 }
616 if ( (System.Object)errorCodeStr != null )
617 {
618 try
619 {
620 interp.setVar( "errorCode", errorCodeStr, TCL.VarFlag.GLOBAL_ONLY );
621 }
622 catch ( TclException e )
623 {
624 // ignore an exception while setting this var
625 }
626 }
627 }
628 else
629 {
630 // Variable table should be cleared.
631 Var.deleteVars( interp, ns.varTable );
632 }
633  
634 // Remove the namespace from its parent's child hashtable.
635  
636 if ( ns.parent != null )
637 {
638 ns.parent.childTable.Remove( ns.name );
639 }
640 ns.parent = null;
641  
642 // Delete all the child namespaces.
643 //
644 // BE CAREFUL: When each child is deleted, it will divorce
645 // itself from its parent. You can't traverse a hash table
646 // properly if its elements are being deleted. We use only
647 // the Tcl_FirstHashEntry function to be safe.
648  
649 foreach ( Namespace childNs in new ArrayList( ns.childTable.Values ) )
650 {
651 deleteNamespace( childNs );
652 }
653  
654 // Delete all commands in this namespace. Be careful when traversing the
655 // hash table: when each command is deleted, it removes itself from the
656 // command table.
657  
658 // FIXME : double check that using an enumeration for a hashtable
659 // that changes is ok in Java! Also call deleteCommand... correctly!
660 foreach ( WrappedCommand cmd in new ArrayList( ns.cmdTable.Values ) )
661 {
662 interp.deleteCommandFromToken( cmd );
663 }
664  
665 ns.cmdTable.Clear();
666  
667 // Free the namespace's export pattern array.
668  
669 if ( ns.exportArray != null )
670 {
671 ns.exportArray = null;
672 ns.numExportPatterns = 0;
673 ns.maxExportPatterns = 0;
674 }
675  
676 // Callback invoked when namespace is deleted
677  
678 if ( ns.deleteProc != null )
679 {
680 ns.deleteProc.delete();
681 }
682 ns.deleteProc = null;
683  
684 // Reset the namespace's id field to ensure that this namespace won't
685 // be interpreted as valid by, e.g., the cache validation code for
686 // cached command references in Tcl_GetCommandFromObj.
687  
688 ns.nsId = 0;
689 }
690  
691  
692 /*
693 *----------------------------------------------------------------------
694 *
695 * NamespaceFree -> free
696 *
697 * Called after a namespace has been deleted, when its
698 * reference count reaches 0. Frees the data structure
699 * representing the namespace.
700 *
701 * Results:
702 * None.
703 *
704 * Side effects:
705 * None.
706 *
707 *----------------------------------------------------------------------
708 */
709  
710 internal static void free( Namespace ns )
711 {
712 // Most of the namespace's contents are freed when the namespace is
713 // deleted by Tcl_DeleteNamespace. All that remains is to free its names
714 // (for error messages), and the structure itself.
715  
716 ns.name = null;
717 ns.fullName = null;
718 }
719  
720 /*
721 *----------------------------------------------------------------------
722 *
723 * Tcl_Export -> exportList
724 *
725 * Makes all the commands matching a pattern available to later be
726 * imported from the namespace specified by namespace (or the
727 * current namespace if namespace is null). The specified pattern is
728 * appended onto the namespace's export pattern list, which is
729 * optionally cleared beforehand.
730 *
731 * Results:
732 * Returns if successful, raises TclException if something goes wrong.
733 *
734 * Side effects:
735 * Appends the export pattern onto the namespace's export list.
736 * Optionally reset the namespace's export pattern list.
737 *
738 *----------------------------------------------------------------------
739 */
740  
741 internal static void exportList( Interp interp, Namespace namespace_Renamed, string pattern, bool resetListFirst )
742 {
743 int INIT_EXPORT_PATTERNS = 5;
744 Namespace ns, exportNs;
745 Namespace currNs = getCurrentNamespace( interp );
746 string simplePattern, patternCpy;
747 int neededElems, len, i;
748  
749 // If the specified namespace is null, use the current namespace.
750  
751 if ( namespace_Renamed == null )
752 {
753 ns = currNs;
754 }
755 else
756 {
757 ns = namespace_Renamed;
758 }
759  
760 // If resetListFirst is true (nonzero), clear the namespace's export
761 // pattern list.
762  
763 if ( resetListFirst )
764 {
765 if ( ns.exportArray != null )
766 {
767 for ( i = 0; i < ns.numExportPatterns; i++ )
768 {
769 ns.exportArray[i] = null;
770 }
771 ns.exportArray = null;
772 ns.numExportPatterns = 0;
773 ns.maxExportPatterns = 0;
774 }
775 }
776  
777 // Check that the pattern doesn't have namespace qualifiers.
778  
779 // Java does not support passing an address so we pass
780 // an array of size 1 and then assign arr[0] to the value
781 Namespace[] exportNsArr = new Namespace[1];
782 Namespace[] dummyArr = new Namespace[1];
783 string[] simplePatternArr = new string[1];
784  
785 getNamespaceForQualName( interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, exportNsArr, dummyArr, dummyArr, simplePatternArr );
786  
787 // get the values out of the arrays
788  
789 exportNs = exportNsArr[0];
790 simplePattern = simplePatternArr[0];
791  
792 if ( ( exportNs != ns ) || ( pattern.CompareTo( simplePattern ) != 0 ) )
793 {
794 throw new TclException( interp, "invalid export pattern \"" + pattern + "\": pattern can't specify a namespace" );
795 }
796  
797 // Make sure there is room in the namespace's pattern array for the
798 // new pattern.
799  
800 neededElems = ns.numExportPatterns + 1;
801 if ( ns.exportArray == null )
802 {
803 ns.exportArray = new string[INIT_EXPORT_PATTERNS];
804 ns.numExportPatterns = 0;
805 ns.maxExportPatterns = INIT_EXPORT_PATTERNS;
806 }
807 else if ( neededElems > ns.maxExportPatterns )
808 {
809 int numNewElems = 2 * ns.maxExportPatterns;
810 string[] newArray = new string[numNewElems];
811 Array.Copy( (System.Array)ns.exportArray, 0, (System.Array)newArray, 0, ns.numExportPatterns );
812 ns.exportArray = newArray;
813 ns.maxExportPatterns = numNewElems;
814 }
815  
816 // Add the pattern to the namespace's array of export patterns.
817  
818 ns.exportArray[ns.numExportPatterns] = pattern;
819 ns.numExportPatterns++;
820 return;
821 }
822  
823  
824 /*
825 *----------------------------------------------------------------------
826 *
827 * Tcl_AppendExportList -> appendExportList
828 *
829 * Appends onto the argument object the list of export patterns for the
830 * specified namespace.
831 *
832 * Results:
833 * The method will return when successful; in this case the object
834 * referenced by obj has each export pattern appended to it. If an
835 * error occurs, an exception and the interpreter's result
836 * holds an error message.
837 *
838 * Side effects:
839 * If necessary, the object referenced by obj is converted into
840 * a list object.
841 *
842 *----------------------------------------------------------------------
843 */
844  
845 internal static void appendExportList( Interp interp, Namespace namespace_Renamed, TclObject obj )
846 {
847 Namespace ns;
848 int i;
849  
850 // If the specified namespace is null, use the current namespace.
851  
852 if ( namespace_Renamed == null )
853 {
854 ns = getCurrentNamespace( interp );
855 }
856 else
857 {
858 ns = namespace_Renamed;
859 }
860  
861 // Append the export pattern list onto objPtr.
862  
863 for ( i = 0; i < ns.numExportPatterns; i++ )
864 {
865 TclList.append( interp, obj, TclString.newInstance( ns.exportArray[i] ) );
866 }
867 return;
868 }
869  
870  
871 /*
872 *----------------------------------------------------------------------
873 *
874 * Tcl_Import -> importList
875 *
876 * Imports all of the commands matching a pattern into the namespace
877 * specified by namespace (or the current namespace if namespace
878 * is null). This is done by creating a new command (the "imported
879 * command") that points to the real command in its original namespace.
880 *
881 * If matching commands are on the autoload path but haven't been
882 * loaded yet, this command forces them to be loaded, then creates
883 * the links to them.
884 *
885 * Results:
886 * Returns if successful, raises TclException if something goes wrong.
887 *
888 * Side effects:
889 * Creates new commands in the importing namespace. These indirect
890 * calls back to the real command and are deleted if the real commands
891 * are deleted.
892 *
893 *----------------------------------------------------------------------
894 */
895  
896 internal static void importList( Interp interp, Namespace namespace_Renamed, string pattern, bool allowOverwrite )
897 {
898 Namespace ns, importNs;
899 Namespace currNs = getCurrentNamespace( interp );
900 string simplePattern, cmdName;
901 IEnumerator search;
902 WrappedCommand cmd, realCmd;
903 ImportRef ref_Renamed;
904 WrappedCommand autoCmd, importedCmd;
905 ImportedCmdData data;
906 bool wasExported;
907 int i, result;
908  
909 // If the specified namespace is null, use the current namespace.
910  
911 if ( namespace_Renamed == null )
912 {
913 ns = currNs;
914 }
915 else
916 {
917 ns = namespace_Renamed;
918 }
919  
920 // First, invoke the "auto_import" command with the pattern
921 // being imported. This command is part of the Tcl library.
922 // It looks for imported commands in autoloaded libraries and
923 // loads them in. That way, they will be found when we try
924 // to create links below.
925  
926 autoCmd = findCommand( interp, "auto_import", null, TCL.VarFlag.GLOBAL_ONLY );
927  
928 if ( autoCmd != null )
929 {
930 TclObject[] objv = new TclObject[2];
931  
932 objv[0] = TclString.newInstance( "auto_import" );
933 objv[0].preserve();
934 objv[1] = TclString.newInstance( pattern );
935 objv[1].preserve();
936  
937 cmd = autoCmd;
938 try
939 {
940 // Invoke the command with the arguments
941 cmd.cmd.cmdProc( interp, objv );
942 }
943 finally
944 {
945 objv[0].release();
946 objv[1].release();
947 }
948  
949 interp.resetResult();
950 }
951  
952 // From the pattern, find the namespace from which we are importing
953 // and get the simple pattern (no namespace qualifiers or ::'s) at
954 // the end.
955  
956 if ( pattern.Length == 0 )
957 {
958 throw new TclException( interp, "empty import pattern" );
959 }
960  
961 // Java does not support passing an address so we pass
962 // an array of size 1 and then assign arr[0] to the value
963 Namespace[] importNsArr = new Namespace[1];
964 Namespace[] dummyArr = new Namespace[1];
965 string[] simplePatternArr = new string[1];
966  
967 getNamespaceForQualName( interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, importNsArr, dummyArr, dummyArr, simplePatternArr );
968  
969 importNs = importNsArr[0];
970 simplePattern = simplePatternArr[0];
971  
972 if ( importNs == null )
973 {
974 throw new TclException( interp, "unknown namespace in import pattern \"" + pattern + "\"" );
975 }
976 if ( importNs == ns )
977 {
978 if ( (System.Object)pattern == (System.Object)simplePattern )
979 {
980 throw new TclException( interp, "no namespace specified in import pattern \"" + pattern + "\"" );
981 }
982 else
983 {
984 throw new TclException( interp, "import pattern \"" + pattern + "\" tries to import from namespace \"" + importNs.name + "\" into itself" );
985 }
986 }
987  
988 // Scan through the command table in the source namespace and look for
989 // exported commands that match the string pattern. Create an "imported
990 // command" in the current namespace for each imported command; these
991 // commands redirect their invocations to the "real" command.
992  
993  
994 for ( search = importNs.cmdTable.Keys.GetEnumerator(); search.MoveNext(); )
995 {
996  
997 cmdName = ( (string)search.Current );
998 if ( Util.stringMatch( cmdName, simplePattern ) )
999 {
1000 // The command cmdName in the source namespace matches the
1001 // pattern. Check whether it was exported. If it wasn't,
1002 // we ignore it.
1003  
1004 wasExported = false;
1005 for ( i = 0; i < importNs.numExportPatterns; i++ )
1006 {
1007 if ( Util.stringMatch( cmdName, importNs.exportArray[i] ) )
1008 {
1009 wasExported = true;
1010 break;
1011 }
1012 }
1013 if ( !wasExported )
1014 {
1015 continue;
1016 }
1017  
1018 // Unless there is a name clash, create an imported command
1019 // in the current namespace that refers to cmdPtr.
1020  
1021 if ( ( ns.cmdTable[cmdName] == null ) || allowOverwrite )
1022 {
1023 // Create the imported command and its client data.
1024 // To create the new command in the current namespace,
1025 // generate a fully qualified name for it.
1026  
1027 StringBuilder ds;
1028  
1029 ds = new StringBuilder();
1030 ds.Append( ns.fullName );
1031 if ( ns != interp.globalNs )
1032 {
1033 ds.Append( "::" );
1034 }
1035 ds.Append( cmdName );
1036  
1037 // Check whether creating the new imported command in the
1038 // current namespace would create a cycle of imported->real
1039 // command references that also would destroy an existing
1040 // "real" command already in the current namespace.
1041  
1042 cmd = (WrappedCommand)importNs.cmdTable[cmdName];
1043  
1044 if ( cmd.cmd is ImportedCmdData )
1045 {
1046 // This is actually an imported command, find
1047 // the real command it references
1048 realCmd = getOriginalCommand( cmd );
1049 if ( ( realCmd != null ) && ( realCmd.ns == currNs ) && ( currNs.cmdTable[cmdName] != null ) )
1050 {
1051 throw new TclException( interp, "import pattern \"" + pattern + "\" would create a loop containing command \"" + ds.ToString() + "\"" );
1052 }
1053 }
1054  
1055 data = new ImportedCmdData();
1056  
1057 // Create the imported command inside the interp
1058 interp.createCommand( ds.ToString(), data );
1059  
1060 // Lookup in the namespace for the new WrappedCommand
1061 importedCmd = findCommand( interp, ds.ToString(), ns, ( TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.LEAVE_ERR_MSG ) );
1062  
1063 data.realCmd = cmd;
1064 data.self = importedCmd;
1065  
1066 // Create an ImportRef structure describing this new import
1067 // command and add it to the import ref list in the "real"
1068 // command.
1069  
1070 ref_Renamed = new ImportRef();
1071 ref_Renamed.importedCmd = importedCmd;
1072 ref_Renamed.next = cmd.importRef;
1073 cmd.importRef = ref_Renamed;
1074 }
1075 else
1076 {
1077 throw new TclException( interp, "can't import command \"" + cmdName + "\": already exists" );
1078 }
1079 }
1080 }
1081 return;
1082 }
1083  
1084 /*
1085 *----------------------------------------------------------------------
1086 *
1087 * Tcl_ForgetImport -> forgetImport
1088 *
1089 * Deletes previously imported commands. Given a pattern that may
1090 * include the name of an exporting namespace, this procedure first
1091 * finds all matching exported commands. It then looks in the namespace
1092 * specified by namespace for any corresponding previously imported
1093 * commands, which it deletes. If namespace is null, commands are
1094 * deleted from the current namespace.
1095 *
1096 * Results:
1097 * Returns if successful, raises TclException if something goes wrong.
1098 *
1099 * Side effects:
1100 * May delete commands.
1101 *
1102 *----------------------------------------------------------------------
1103 */
1104  
1105 internal static void forgetImport( Interp interp, Namespace namespace_Renamed, string pattern )
1106 {
1107 Namespace ns, importNs, actualCtx;
1108 string simplePattern, cmdName;
1109 IEnumerator search;
1110 WrappedCommand cmd;
1111  
1112 // If the specified namespace is null, use the current namespace.
1113  
1114 if ( namespace_Renamed == null )
1115 {
1116 ns = getCurrentNamespace( interp );
1117 }
1118 else
1119 {
1120 ns = namespace_Renamed;
1121 }
1122  
1123 // From the pattern, find the namespace from which we are importing
1124 // and get the simple pattern (no namespace qualifiers or ::'s) at
1125 // the end.
1126  
1127 // Java does not support passing an address so we pass
1128 // an array of size 1 and then assign arr[0] to the value
1129 Namespace[] importNsArr = new Namespace[1];
1130 Namespace[] dummyArr = new Namespace[1];
1131 Namespace[] actualCtxArr = new Namespace[1];
1132 string[] simplePatternArr = new string[1];
1133  
1134 getNamespaceForQualName( interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, importNsArr, dummyArr, actualCtxArr, simplePatternArr );
1135  
1136 // get the values out of the arrays
1137 importNs = importNsArr[0];
1138 actualCtx = actualCtxArr[0];
1139 simplePattern = simplePatternArr[0];
1140  
1141 // FIXME : the above call passes TCL.VarFlag.LEAVE_ERR_MSG, but
1142 // it seems like this will be a problem when exception is raised!
1143 if ( importNs == null )
1144 {
1145 throw new TclException( interp, "unknown namespace in namespace forget pattern \"" + pattern + "\"" );
1146 }
1147  
1148 // Scan through the command table in the source namespace and look for
1149 // exported commands that match the string pattern. If the current
1150 // namespace has an imported command that refers to one of those real
1151 // commands, delete it.
1152  
1153  
1154 for ( search = importNs.cmdTable.Keys.GetEnumerator(); search.MoveNext(); )
1155 {
1156  
1157 cmdName = ( (string)search.Current );
1158 if ( Util.stringMatch( cmdName, simplePattern ) )
1159 {
1160 cmd = (WrappedCommand)ns.cmdTable[cmdName];
1161 if ( cmd != null )
1162 {
1163 // cmd of same name in current namespace
1164 if ( cmd.cmd is ImportedCmdData )
1165 {
1166 interp.deleteCommandFromToken( cmd );
1167 }
1168 }
1169 }
1170 }
1171 return;
1172 }
1173  
1174  
1175 /*
1176 *----------------------------------------------------------------------
1177 *
1178 * TclGetOriginalCommand -> getOriginalCommand
1179 *
1180 * An imported command is created in a namespace when a "real" command
1181 * is imported from another namespace. If the specified command is an
1182 * imported command, this procedure returns the original command it
1183 * refers to.
1184 *
1185 * Results:
1186 * If the command was imported into a sequence of namespaces a, b,...,n
1187 * where each successive namespace just imports the command from the
1188 * previous namespace, this procedure returns the Tcl_Command token in
1189 * the first namespace, a. Otherwise, if the specified command is not
1190 * an imported command, the procedure returns null.
1191 *
1192 * Side effects:
1193 * None.
1194 *
1195 *----------------------------------------------------------------------
1196 */
1197  
1198 internal static WrappedCommand getOriginalCommand( WrappedCommand command )
1199 {
1200 WrappedCommand cmd = command;
1201 ImportedCmdData data;
1202  
1203 if ( !( cmd.cmd is ImportedCmdData ) )
1204 {
1205 return null;
1206 }
1207  
1208 while ( cmd.cmd is ImportedCmdData )
1209 {
1210 data = (ImportedCmdData)cmd.cmd;
1211 cmd = data.realCmd;
1212 }
1213 return cmd;
1214 }
1215  
1216  
1217 /*
1218 *----------------------------------------------------------------------
1219 *
1220 * InvokeImportedCmd -> invokeImportedCmd
1221 *
1222 * Invoked by Tcl whenever the user calls an imported command that
1223 * was created by Tcl_Import. Finds the "real" command (in another
1224 * namespace), and passes control to it.
1225 *
1226 * Results:
1227 * Returns if successful, raises TclException if something goes wrong.
1228 *
1229 * Side effects:
1230 * Returns a result in the interpreter's result object. If anything
1231 * goes wrong, the result object is set to an error message.
1232 *
1233 *----------------------------------------------------------------------
1234 */
1235  
1236 internal static void invokeImportedCmd( Interp interp, ImportedCmdData data, TclObject[] objv )
1237 {
1238 WrappedCommand realCmd = data.realCmd;
1239 realCmd.cmd.cmdProc( interp, objv );
1240 }
1241  
1242  
1243 /*
1244 *----------------------------------------------------------------------
1245 *
1246 * DeleteImportedCmd -> deleteImportedCmd
1247 *
1248 * Invoked by Tcl whenever an imported command is deleted. The "real"
1249 * command keeps a list of all the imported commands that refer to it,
1250 * so those imported commands can be deleted when the real command is
1251 * deleted. This procedure removes the imported command reference from
1252 * the real command's list, and frees up the memory associated with
1253 * the imported command.
1254 *
1255 * Results:
1256 * None.
1257 *
1258 * Side effects:
1259 * Removes the imported command from the real command's import list.
1260 *
1261 *----------------------------------------------------------------------
1262 */
1263  
1264 internal static void deleteImportedCmd( ImportedCmdData data )
1265 // The data object for this imported command
1266 {
1267 WrappedCommand realCmd = data.realCmd;
1268 WrappedCommand self = data.self;
1269 ImportRef ref_Renamed, prev;
1270  
1271 prev = null;
1272 for ( ref_Renamed = realCmd.importRef; ref_Renamed != null; ref_Renamed = ref_Renamed.next )
1273 {
1274 if ( ref_Renamed.importedCmd == self )
1275 {
1276 // Remove ref from real command's list of imported commands
1277 // that refer to it.
1278  
1279 if ( prev == null )
1280 {
1281 // ref is first in list
1282 realCmd.importRef = ref_Renamed.next;
1283 }
1284 else
1285 {
1286 prev.next = ref_Renamed.next;
1287 }
1288 ref_Renamed = null;
1289 data = null;
1290 return;
1291 }
1292 prev = ref_Renamed;
1293 }
1294  
1295 throw new TclRuntimeError( "DeleteImportedCmd: did not find cmd in real cmd's list of import references" );
1296 }
1297  
1298 /*
1299 *----------------------------------------------------------------------
1300 *
1301 * TclGetNamespaceForQualName -> getNamespaceForQualName
1302 *
1303 * Given a qualified name specifying a command, variable, or namespace,
1304 * and a namespace in which to resolve the name, this procedure returns
1305 * a pointer to the namespace that contains the item. A qualified name
1306 * consists of the "simple" name of an item qualified by the names of
1307 * an arbitrary number of containing namespace separated by "::"s. If
1308 * the qualified name starts with "::", it is interpreted absolutely
1309 * from the global namespace. Otherwise, it is interpreted relative to
1310 * the namespace specified by cxtNsPtr if it is non-null. If cxtNsPtr
1311 * is null, the name is interpreted relative to the current namespace.
1312 *
1313 * A relative name like "foo::bar::x" can be found starting in either
1314 * the current namespace or in the global namespace. So each search
1315 * usually follows two tracks, and two possible namespaces are
1316 * returned. If the procedure sets either nsPtrPtr[0] or altNsPtrPtr[0] to
1317 * null, then that path failed.
1318 *
1319 * If "flags" contains TCL.VarFlag.GLOBAL_ONLY, the relative qualified name is
1320 * sought only in the global :: namespace. The alternate search
1321 * (also) starting from the global namespace is ignored and
1322 * altNsPtrPtr[0] is set null.
1323 *
1324 * If "flags" contains TCL.VarFlag.NAMESPACE_ONLY, the relative qualified
1325 * name is sought only in the namespace specified by cxtNsPtr. The
1326 * alternate search starting from the global namespace is ignored and
1327 * altNsPtrPtr[0] is set null. If both TCL.VarFlag.GLOBAL_ONLY and
1328 * TCL.VarFlag.NAMESPACE_ONLY are specified, TCL.VarFlag.GLOBAL_ONLY is ignored and
1329 * the search starts from the namespace specified by cxtNsPtr.
1330 *
1331 * If "flags" contains TCL.VarFlag.CREATE_NS_IF_UNKNOWN, all namespace
1332 * components of the qualified name that cannot be found are
1333 * automatically created within their specified parent. This makes sure
1334 * that functions like Tcl_CreateCommand always succeed. There is no
1335 * alternate search path, so altNsPtrPtr[0] is set null.
1336 *
1337 * If "flags" contains TCL.VarFlag.FIND_ONLY_NS, the qualified name is treated as a
1338 * reference to a namespace, and the entire qualified name is
1339 * followed. If the name is relative, the namespace is looked up only
1340 * in the current namespace. A pointer to the namespace is stored in
1341 * nsPtrPtr[0] and null is stored in simpleNamePtr[0]. Otherwise, if
1342 * TCL.VarFlag.FIND_ONLY_NS is not specified, only the leading components are
1343 * treated as namespace names, and a pointer to the simple name of the
1344 * final component is stored in simpleNamePtr[0].
1345 *
1346 * Results:
1347 * It sets nsPtrPtr[0] and altNsPtrPtr[0] to point to the two possible
1348 * namespaces which represent the last (containing) namespace in the
1349 * qualified name. If the procedure sets either nsPtrPtr[0] or altNsPtrPtr[0]
1350 * to null, then the search along that path failed. The procedure also
1351 * stores a pointer to the simple name of the final component in
1352 * simpleNamePtr[0]. If the qualified name is "::" or was treated as a
1353 * namespace reference (TCL.VarFlag.FIND_ONLY_NS), the procedure stores a pointer
1354 * to the namespace in nsPtrPtr[0], null in altNsPtrPtr[0], and sets
1355 * simpleNamePtr[0] to an empty string.
1356 *
1357 * If there is an error, this procedure returns TCL_ERROR. If "flags"
1358 * contains TCL_LEAVE_ERR_MSG, an error message is returned in the
1359 * interpreter's result object. Otherwise, the interpreter's result
1360 * object is left unchanged.
1361 *
1362 * actualCxtPtrPtr[0] is set to the actual context namespace. It is
1363 * set to the input context namespace pointer in cxtNsPtr. If cxtNsPtr
1364 * is null, it is set to the current namespace context.
1365 *
1366 * Side effects:
1367 * If "flags" contains TCL.VarFlag.CREATE_NS_IF_UNKNOWN, new namespaces may be
1368 * created.
1369 *
1370 *----------------------------------------------------------------------
1371 */
1372  
1373 internal static void getNamespaceForQualName( Interp interp, string qualName, Namespace cxtNsPtr, TCL.VarFlag flags, Namespace[] nsPtrPtr, Namespace[] altNsPtrPtr, Namespace[] actualCxtPtrPtr, string[] simpleNamePtr )
1374 {
1375  
1376  
1377 // FIXME : remove extra method call checks when we are sure this works!
1378  
1379 if ( true )
1380 {
1381 // check invariants
1382 if ( ( nsPtrPtr == null ) || ( nsPtrPtr.Length != 1 ) )
1383 {
1384  
1385 throw new System.SystemException( "nsPtrPtr " + nsPtrPtr );
1386 }
1387 if ( ( altNsPtrPtr == null ) || ( altNsPtrPtr.Length != 1 ) )
1388 {
1389  
1390 throw new System.SystemException( "altNsPtrPtr " + altNsPtrPtr );
1391 }
1392 if ( ( actualCxtPtrPtr == null ) || ( actualCxtPtrPtr.Length != 1 ) )
1393 {
1394  
1395 throw new System.SystemException( "actualCxtPtrPtr " + actualCxtPtrPtr );
1396 }
1397 if ( ( simpleNamePtr == null ) || ( simpleNamePtr.Length != 1 ) )
1398 {
1399  
1400 throw new System.SystemException( "simpleNamePtr " + simpleNamePtr );
1401 }
1402 }
1403  
1404  
1405  
1406  
1407 Namespace ns = cxtNsPtr;
1408 Namespace altNs;
1409 Namespace globalNs = getGlobalNamespace( interp );
1410 Namespace entryNs;
1411 string start, end;
1412 string nsName;
1413 int len;
1414 int start_ind, end_ind, name_len;
1415  
1416 // Determine the context namespace ns in which to start the primary
1417 // search. If TCL.VarFlag.NAMESPACE_ONLY or TCL.VarFlag.FIND_ONLY_NS was specified, search
1418 // from the current namespace. If the qualName name starts with a "::"
1419 // or TCL.VarFlag.GLOBAL_ONLY was specified, search from the global
1420 // namespace. Otherwise, use the given namespace given in cxtNsPtr, or
1421 // if that is null, use the current namespace context. Note that we
1422 // always treat two or more adjacent ":"s as a namespace separator.
1423  
1424 if ( ( flags & ( TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.FIND_ONLY_NS ) ) != 0 )
1425 {
1426 ns = getCurrentNamespace( interp );
1427 }
1428 else if ( ( flags & TCL.VarFlag.GLOBAL_ONLY ) != 0 )
1429 {
1430 ns = globalNs;
1431 }
1432 else if ( ns == null )
1433 {
1434 if ( interp.varFrame != null )
1435 {
1436 ns = interp.varFrame.ns;
1437 }
1438 else
1439 {
1440 ns = interp.globalNs;
1441 }
1442 }
1443  
1444  
1445  
1446 start_ind = 0;
1447 name_len = qualName.Length;
1448  
1449 if ( ( name_len >= 2 ) && ( qualName[0] == ':' ) && ( qualName[1] == ':' ) )
1450 {
1451 start_ind = 2; // skip over the initial ::
1452  
1453 while ( ( start_ind < name_len ) && ( qualName[start_ind] == ':' ) )
1454 {
1455 start_ind++; // skip over a subsequent :
1456 }
1457  
1458 ns = globalNs;
1459 if ( start_ind >= name_len )
1460 {
1461 // qualName is just two or more ":"s
1462 nsPtrPtr[0] = globalNs;
1463 altNsPtrPtr[0] = null;
1464 actualCxtPtrPtr[0] = globalNs;
1465 simpleNamePtr[0] = ""; // points to empty string
1466 return;
1467 }
1468 }
1469 actualCxtPtrPtr[0] = ns;
1470  
1471  
1472 // Start an alternate search path starting with the global namespace.
1473 // However, if the starting context is the global namespace, or if the
1474 // flag is set to search only the namespace cxtNs, ignore the
1475 // alternate search path.
1476  
1477  
1478 altNs = globalNs;
1479 if ( ( ns == globalNs ) || ( ( flags & ( TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.FIND_ONLY_NS ) ) != 0 ) )
1480 {
1481 altNs = null;
1482 }
1483  
1484  
1485 // Loop to resolve each namespace qualifier in qualName.
1486  
1487 end_ind = start_ind;
1488  
1489 while ( start_ind < name_len )
1490 {
1491 // Find the next namespace qualifier (i.e., a name ending in "::")
1492 // or the end of the qualified name (i.e., a name ending in "\0").
1493 // Set len to the number of characters, starting from start,
1494 // in the name; set end to point after the "::"s or at the "\0".
1495  
1496 len = 0;
1497 for ( end_ind = start_ind; end_ind < name_len; end_ind++ )
1498 {
1499 if ( ( ( name_len - end_ind ) > 1 ) && ( qualName[end_ind] == ':' ) && ( qualName[end_ind + 1] == ':' ) )
1500 {
1501 end_ind += 2; // skip over the initial ::
1502 while ( ( end_ind < name_len ) && ( qualName[end_ind] == ':' ) )
1503 {
1504 end_ind++; // skip over a subsequent :
1505 }
1506 break;
1507 }
1508 len++;
1509 }
1510  
1511  
1512 if ( ( end_ind == name_len ) && !( ( end_ind - start_ind >= 2 ) && ( ( qualName[end_ind - 1] == ':' ) && ( qualName[end_ind - 2] == ':' ) ) ) )
1513 {
1514  
1515 // qualName ended with a simple name at start. If TCL.VarFlag.FIND_ONLY_NS
1516 // was specified, look this up as a namespace. Otherwise,
1517 // start is the name of a cmd or var and we are done.
1518  
1519 if ( ( flags & TCL.VarFlag.FIND_ONLY_NS ) != 0 )
1520 {
1521 // assign the string from start_ind to the end of the name string
1522 nsName = qualName.Substring( start_ind );
1523 }
1524 else
1525 {
1526 nsPtrPtr[0] = ns;
1527 altNsPtrPtr[0] = altNs;
1528 simpleNamePtr[0] = qualName.Substring( start_ind );
1529 return;
1530 }
1531 }
1532 else
1533 {
1534 // start points to the beginning of a namespace qualifier ending
1535 // in "::". Create new string with the namespace qualifier.
1536  
1537 nsName = qualName.Substring( start_ind, ( start_ind + len ) - ( start_ind ) );
1538 }
1539  
1540  
1541  
1542 // Look up the namespace qualifier nsName in the current namespace
1543 // context. If it isn't found but TCL.VarFlag.CREATE_NS_IF_UNKNOWN is set,
1544 // create that qualifying namespace. This is needed for procedures
1545 // like Tcl_CreateCommand that cannot fail.
1546  
1547 if ( ns != null )
1548 {
1549 entryNs = (Namespace)ns.childTable[nsName];
1550 if ( entryNs != null )
1551 {
1552 ns = entryNs;
1553 }
1554 else if ( ( flags & TCL.VarFlag.CREATE_NS_IF_UNKNOWN ) != 0 )
1555 {
1556 CallFrame frame = interp.newCallFrame();
1557  
1558 pushCallFrame( interp, frame, ns, false );
1559 ns = createNamespace( interp, nsName, null );
1560  
1561 popCallFrame( interp );
1562 if ( ns == null )
1563 {
1564 throw new System.SystemException( "Could not create namespace " + nsName );
1565 }
1566 }
1567 else
1568 {
1569 ns = null; // namespace not found and wasn't created
1570 }
1571 }
1572  
1573  
1574 // Look up the namespace qualifier in the alternate search path too.
1575  
1576 if ( altNs != null )
1577 {
1578 altNs = (Namespace)altNs.childTable[nsName];
1579 }
1580  
1581 // If both search paths have failed, return null results.
1582  
1583 if ( ( ns == null ) && ( altNs == null ) )
1584 {
1585 nsPtrPtr[0] = null;
1586 altNsPtrPtr[0] = null;
1587 simpleNamePtr[0] = null;
1588 return;
1589 }
1590  
1591 start_ind = end_ind;
1592 }
1593  
1594  
1595 // We ignore trailing "::"s in a namespace name, but in a command or
1596 // variable name, trailing "::"s refer to the cmd or var named {}.
1597  
1598 if ( ( ( flags & TCL.VarFlag.FIND_ONLY_NS ) != 0 ) || ( ( end_ind > start_ind ) && ( qualName[end_ind - 1] != ':' ) ) )
1599 {
1600 simpleNamePtr[0] = null; // found namespace name
1601 }
1602 else
1603 {
1604 // FIXME : make sure this does not throw exception when end_ind is at the end of the string
1605 simpleNamePtr[0] = qualName.Substring( end_ind ); // found cmd/var: points to empty string
1606 }
1607  
1608  
1609 // As a special case, if we are looking for a namespace and qualName
1610 // is "" and the current active namespace (ns) is not the global
1611 // namespace, return null (no namespace was found). This is because
1612 // namespaces can not have empty names except for the global namespace.
1613  
1614 if ( ( ( flags & TCL.VarFlag.FIND_ONLY_NS ) != 0 ) && ( name_len == 0 ) && ( ns != globalNs ) )
1615 {
1616 ns = null;
1617 }
1618  
1619 nsPtrPtr[0] = ns;
1620 altNsPtrPtr[0] = altNs;
1621 return;
1622 }
1623  
1624  
1625 /*
1626 *----------------------------------------------------------------------
1627 *
1628 * Tcl_FindNamespace -> findNamespace
1629 *
1630 * Searches for a namespace.
1631 *
1632 * Results:T
1633 * Returns a reference to the namespace if it is found. Otherwise,
1634 * returns null and leaves an error message in the interpreter's
1635 * result object if "flags" contains TCL.VarFlag.LEAVE_ERR_MSG.
1636 *
1637 * Side effects:
1638 * None.
1639 *
1640 *----------------------------------------------------------------------
1641 */
1642  
1643 internal static Namespace findNamespace( Interp interp, string name, Namespace contextNs, TCL.VarFlag flags )
1644 {
1645 Namespace ns;
1646  
1647 // Java does not support passing an address so we pass
1648 // an array of size 1 and then assign arr[0] to the value
1649 Namespace[] nsArr = new Namespace[1];
1650 Namespace[] dummy1Arr = new Namespace[1];
1651 string[] dummy2Arr = new string[1];
1652  
1653 // Find the namespace(s) that contain the specified namespace name.
1654 // Add the TCL.VarFlag.FIND_ONLY_NS flag to resolve the name all the way down
1655 // to its last component, a namespace.
1656  
1657 getNamespaceForQualName( interp, name, contextNs, ( flags | TCL.VarFlag.FIND_ONLY_NS ), nsArr, dummy1Arr, dummy1Arr, dummy2Arr );
1658  
1659  
1660 // Get the values out of the arrays!
1661 ns = nsArr[0];
1662  
1663 if ( ns != null )
1664 {
1665 return ns;
1666 }
1667 else if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
1668 {
1669 /*
1670 interp.resetResult();
1671 TclString.append(interp.getResult(), "unknown namespace \"" + name + "\"");
1672 */
1673  
1674 // FIXME : is there a test case for this error?
1675 interp.setResult( "unknown namespace \"" + name + "\"" );
1676 }
1677 return null;
1678 }
1679  
1680  
1681  
1682 /*
1683 *----------------------------------------------------------------------
1684 *
1685 * Tcl_FindCommand -> findCommand
1686 *
1687 * Searches for a command.
1688 *
1689 * Results:
1690 * Returns a token for the command if it is found. Otherwise, if it
1691 * can't be found or there is an error, returns null and leaves an
1692 * error message in the interpreter's result object if "flags"
1693 * contains TCL.VarFlag.LEAVE_ERR_MSG.
1694 *
1695 * Side effects:
1696 * None.
1697 *
1698 *----------------------------------------------------------------------
1699 */
1700  
1701 internal static WrappedCommand findCommand( Interp interp, string name, Namespace contextNs, TCL.VarFlag flags )
1702 {
1703 Interp.ResolverScheme res;
1704 Namespace cxtNs;
1705 Namespace[] ns = new Namespace[2];
1706 string simpleName;
1707 int search;
1708 //int result;
1709 WrappedCommand cmd;
1710  
1711 // If this namespace has a command resolver, then give it first
1712 // crack at the command resolution. If the interpreter has any
1713 // command resolvers, consult them next. The command resolver
1714 // procedures may return a Tcl_Command value, they may signal
1715 // to continue onward, or they may signal an error.
1716  
1717 if ( ( flags & TCL.VarFlag.GLOBAL_ONLY ) != 0 )
1718 {
1719 cxtNs = getGlobalNamespace( interp );
1720 }
1721 else if ( contextNs != null )
1722 {
1723 cxtNs = contextNs;
1724 }
1725 else
1726 {
1727 cxtNs = getCurrentNamespace( interp );
1728 }
1729  
1730 if ( cxtNs.resolver != null || interp.resolvers != null )
1731 {
1732 try
1733 {
1734 if ( cxtNs.resolver != null )
1735 {
1736 cmd = cxtNs.resolver.resolveCmd( interp, name, cxtNs, flags );
1737 }
1738 else
1739 {
1740 cmd = null;
1741 }
1742  
1743 if ( cmd == null && interp.resolvers != null )
1744 {
1745 IEnumerator enum_Renamed = interp.resolvers.GetEnumerator();
1746 while ( cmd == null && enum_Renamed.MoveNext() )
1747 {
1748 res = (Interp.ResolverScheme)enum_Renamed.Current;
1749 cmd = res.resolver.resolveCmd( interp, name, cxtNs, flags );
1750 }
1751 }
1752  
1753 if ( cmd != null )
1754 {
1755 return cmd;
1756 }
1757 }
1758 catch ( TclException e )
1759 {
1760 return null;
1761 }
1762 }
1763  
1764 // Java does not support passing an address so we pass
1765 // an array of size 1 and then assign arr[0] to the value
1766 Namespace[] ns0Arr = new Namespace[1];
1767 Namespace[] ns1Arr = new Namespace[1];
1768 Namespace[] cxtNsArr = new Namespace[1];
1769 string[] simpleNameArr = new string[1];
1770  
1771  
1772 // Find the namespace(s) that contain the command.
1773  
1774 getNamespaceForQualName( interp, name, contextNs, flags, ns0Arr, ns1Arr, cxtNsArr, simpleNameArr );
1775  
1776 // Get the values out of the arrays!
1777 ns[0] = ns0Arr[0];
1778 ns[1] = ns1Arr[0];
1779 cxtNs = cxtNsArr[0];
1780 simpleName = simpleNameArr[0];
1781  
1782  
1783  
1784 // Look for the command in the command table of its namespace.
1785 // Be sure to check both possible search paths: from the specified
1786 // namespace context and from the global namespace.
1787  
1788 cmd = null;
1789 for ( search = 0; ( search < 2 ) && ( cmd == null ); search++ )
1790 {
1791 if ( ( ns[search] != null ) && ( (System.Object)simpleName != null ) )
1792 {
1793 cmd = (WrappedCommand)ns[search].cmdTable[simpleName];
1794 }
1795 }
1796 if ( cmd != null )
1797 {
1798 return cmd;
1799 }
1800 else if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
1801 {
1802 throw new TclException( interp, "unknown command \"" + name + "\"" );
1803 }
1804  
1805 return null;
1806 }
1807  
1808  
1809  
1810 /*
1811 *----------------------------------------------------------------------
1812 *
1813 * Tcl_FindNamespaceVar -> findNamespaceVar
1814 *
1815 * Searches for a namespace variable, a variable not local to a
1816 * procedure. The variable can be either a scalar or an array, but
1817 * may not be an element of an array.
1818 *
1819 * Results:
1820 * Returns a token for the variable if it is found. Otherwise, if it
1821 * can't be found or there is an error, returns null and leaves an
1822 * error message in the interpreter's result object if "flags"
1823 * contains TCL.VarFlag.LEAVE_ERR_MSG.
1824 *
1825 * Side effects:
1826 * None.
1827 *
1828 *----------------------------------------------------------------------
1829 */
1830  
1831 internal static Var findNamespaceVar( Interp interp, string name, Namespace contextNs, TCL.VarFlag flags )
1832 {
1833 Interp.ResolverScheme res;
1834 Namespace cxtNs;
1835 Namespace[] ns = new Namespace[2];
1836 string simpleName;
1837 int search;
1838 //int result;
1839 Var var;
1840  
1841 // If this namespace has a variable resolver, then give it first
1842 // crack at the variable resolution. It may return a Tcl_Var
1843 // value, it may signal to continue onward, or it may signal
1844 // an error.
1845  
1846 if ( ( flags & TCL.VarFlag.GLOBAL_ONLY ) != 0 )
1847 {
1848 cxtNs = getGlobalNamespace( interp );
1849 }
1850 else if ( contextNs != null )
1851 {
1852 cxtNs = contextNs;
1853 }
1854 else
1855 {
1856 cxtNs = getCurrentNamespace( interp );
1857 }
1858  
1859 if ( cxtNs.resolver != null || interp.resolvers != null )
1860 {
1861 try
1862 {
1863 if ( cxtNs.resolver != null )
1864 {
1865 var = cxtNs.resolver.resolveVar( interp, name, cxtNs, flags );
1866 }
1867 else
1868 {
1869 var = null;
1870 }
1871  
1872 if ( var == null && interp.resolvers != null )
1873 {
1874 IEnumerator enum_Renamed = interp.resolvers.GetEnumerator();
1875 while ( var == null && enum_Renamed.MoveNext() )
1876 {
1877 res = (Interp.ResolverScheme)enum_Renamed.Current;
1878 var = res.resolver.resolveVar( interp, name, cxtNs, flags );
1879 }
1880 }
1881  
1882 if ( var != null )
1883 {
1884 return var;
1885 }
1886 }
1887 catch ( TclException e )
1888 {
1889 return null;
1890 }
1891 }
1892  
1893 // Java does not support passing an address so we pass
1894 // an array of size 1 and then assign arr[0] to the value
1895 Namespace[] ns0Arr = new Namespace[1];
1896 Namespace[] ns1Arr = new Namespace[1];
1897 Namespace[] cxtNsArr = new Namespace[1];
1898 string[] simpleNameArr = new string[1];
1899  
1900  
1901 // Find the namespace(s) that contain the variable.
1902  
1903 getNamespaceForQualName( interp, name, contextNs, flags, ns0Arr, ns1Arr, cxtNsArr, simpleNameArr );
1904  
1905 // Get the values out of the arrays!
1906 ns[0] = ns0Arr[0];
1907 ns[1] = ns1Arr[0];
1908 cxtNs = cxtNsArr[0];
1909 simpleName = simpleNameArr[0];
1910  
1911  
1912 // Look for the variable in the variable table of its namespace.
1913 // Be sure to check both possible search paths: from the specified
1914 // namespace context and from the global namespace.
1915  
1916 var = null;
1917 for ( search = 0; ( search < 2 ) && ( var == null ); search++ )
1918 {
1919 if ( ( ns[search] != null ) && ( (System.Object)simpleName != null ) )
1920 {
1921 var = (Var)ns[search].varTable[simpleName];
1922 }
1923 }
1924 if ( var != null )
1925 {
1926 return var;
1927 }
1928 else if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
1929 {
1930 /*
1931 interp.resetResult();
1932 TclString.append(interp.getResult(), "unknown variable \"" + name + "\"");
1933 */
1934  
1935 // FIXME : is there a test case for this error?
1936 interp.setResult( "unknown variable \"" + name + "\"" );
1937 }
1938 return null;
1939 }
1940  
1941 /*
1942 *----------------------------------------------------------------------
1943 *
1944 * GetNamespaceFromObj -> getNamespaceFromObj
1945 *
1946 * Returns the namespace specified by the name in a TclObject.
1947 *
1948 * Results:
1949 * This method will return the Namespace object whose name
1950 * is stored in the obj argument. If the namespace can't be found,
1951 * a TclException is raised.
1952 *
1953 * Side effects:
1954 * May update the internal representation for the object, caching the
1955 * namespace reference. The next time this procedure is called, the
1956 * namespace value can be found quickly.
1957 *
1958 * If anything goes wrong, an error message is left in the
1959 * interpreter's result object.
1960 *
1961 *----------------------------------------------------------------------
1962 */
1963  
1964 internal static Namespace getNamespaceFromObj( Interp interp, TclObject obj )
1965 {
1966 ResolvedNsName resName;
1967 Namespace ns;
1968 Namespace currNs = getCurrentNamespace( interp );
1969 int result;
1970  
1971 // Get the internal representation, converting to a namespace type if
1972 // needed. The internal representation is a ResolvedNsName that points
1973 // to the actual namespace.
1974  
1975 // FIXME : if NamespaceCmd is not the internal rep this needs to be changed!
1976 if ( !( obj.InternalRep is NamespaceCmd ) )
1977 {
1978 setNsNameFromAny( interp, obj );
1979 }
1980 resName = ( (NamespaceCmd)obj.InternalRep ).otherValue;
1981  
1982 // Check the context namespace of the resolved symbol to make sure that
1983 // it is fresh. If not, then force another conversion to the namespace
1984 // type, to discard the old rep and create a new one. Note that we
1985 // verify that the namespace id of the cached namespace is the same as
1986 // the id when we cached it; this insures that the namespace wasn't
1987 // deleted and a new one created at the same address.
1988  
1989 ns = null;
1990 if ( ( resName != null ) && ( resName.refNs == currNs ) && ( resName.nsId == resName.ns.nsId ) )
1991 {
1992 ns = resName.ns;
1993 if ( ( ns.flags & NS_DEAD ) != 0 )
1994 {
1995 ns = null;
1996 }
1997 }
1998 if ( ns == null )
1999 {
2000 // try again
2001 setNsNameFromAny( interp, obj );
2002 resName = ( (NamespaceCmd)obj.InternalRep ).otherValue;
2003 if ( resName != null )
2004 {
2005 ns = resName.ns;
2006 if ( ( ns.flags & NS_DEAD ) != 0 )
2007 {
2008 ns = null;
2009 }
2010 }
2011 }
2012 return ns;
2013 }
2014  
2015 /// <summary>----------------------------------------------------------------------
2016 ///
2017 /// Tcl_SetNamespaceResolvers -> setNamespaceResolver
2018 ///
2019 /// Sets the command/variable resolution object for a namespace,
2020 /// thereby changing the way that command/variable names are
2021 /// interpreted. This allows extension writers to support different
2022 /// name resolution schemes, such as those for object-oriented
2023 /// packages.
2024 ///
2025 /// Command resolution is handled by the following method:
2026 ///
2027 /// resolveCmd (Interp interp, String name,
2028 /// NamespaceCmd.Namespace context, int flags)
2029 /// throws TclException;
2030 ///
2031 /// Whenever a command is executed or NamespaceCmd.findCommand is invoked
2032 /// within the namespace, this method is called to resolve the
2033 /// command name. If this method is able to resolve the name,
2034 /// it should return the corresponding WrappedCommand. Otherwise,
2035 /// the procedure can return null, and the command will
2036 /// be treated under the usual name resolution rules. Or, it can
2037 /// throw a TclException, and the command will be considered invalid.
2038 ///
2039 /// Variable resolution is handled by the following method:
2040 ///
2041 /// resolveVar (Interp interp, String name,
2042 /// NamespaceCmd.Namespace context, int flags)
2043 /// throws TclException;
2044 ///
2045 /// If this method is able to resolve the name, it should return
2046 /// the variable as var object. The method may also
2047 /// return null, and the variable will be treated under the usual
2048 /// name resolution rules. Or, it can throw a TclException,
2049 /// and the variable will be considered invalid.
2050 ///
2051 /// Results:
2052 /// See above.
2053 ///
2054 /// Side effects:
2055 /// None.
2056 ///
2057 /// ----------------------------------------------------------------------
2058 /// </summary>
2059  
2060 internal static void setNamespaceResolver( Namespace namespace_Renamed, Resolver resolver )
2061 // command and variable resolution
2062 {
2063 // Plug in the new command resolver.
2064  
2065 namespace_Renamed.resolver = resolver;
2066 }
2067  
2068 /// <summary>----------------------------------------------------------------------
2069 ///
2070 /// Tcl_GetNamespaceResolvers -> getNamespaceResolver
2071 ///
2072 /// Returns the current command/variable resolution object
2073 /// for a namespace. By default, these objects are null.
2074 /// New objects can be installed by calling setNamespaceResolver,
2075 /// to provide new name resolution rules.
2076 ///
2077 /// Results:
2078 /// Returns the esolver object assigned to this namespace.
2079 /// Returns null otherwise.
2080 ///
2081 /// Side effects:
2082 /// None.
2083 ///
2084 /// ----------------------------------------------------------------------
2085 /// </summary>
2086  
2087 internal static Resolver getNamespaceResolver( Namespace namespace_Renamed )
2088 // Namespace whose resolution rules
2089 // are being queried.
2090 {
2091 return namespace_Renamed.resolver;
2092 }
2093  
2094 /*
2095 *----------------------------------------------------------------------
2096 *
2097 * Tcl_NamespaceObjCmd -> cmdProc
2098 *
2099 * Invoked to implement the "namespace" command that creates, deletes,
2100 * or manipulates Tcl namespaces. Handles the following syntax:
2101 *
2102 * namespace children ?name? ?pattern?
2103 * namespace code arg
2104 * namespace current
2105 * namespace delete ?name name...?
2106 * namespace eval name arg ?arg...?
2107 * namespace export ?-clear? ?pattern pattern...?
2108 * namespace forget ?pattern pattern...?
2109 * namespace import ?-force? ?pattern pattern...?
2110 * namespace inscope name arg ?arg...?
2111 * namespace origin name
2112 * namespace parent ?name?
2113 * namespace qualifiers string
2114 * namespace tail string
2115 * namespace which ?-command? ?-variable? name
2116 *
2117 * Results:
2118 * Returns if the command is successful. Raises Exception if
2119 * anything goes wrong.
2120 *
2121 * Side effects:
2122 * Based on the subcommand name (e.g., "import"), this procedure
2123 * dispatches to a corresponding member commands in this class.
2124 * This method's side effects depend on whatever that subcommand does.
2125 *----------------------------------------------------------------------
2126 */
2127  
2128 private static readonly string[] validCmds = new string[] { "children", "code", "current", "delete", "eval", "export", "forget", "import", "inscope", "origin", "parent", "qualifiers", "tail", "which" };
2129  
2130 private const int OPT_CHILDREN = 0;
2131 private const int OPT_CODE = 1;
2132 private const int OPT_CURRENT = 2;
2133 private const int OPT_DELETE = 3;
2134 private const int OPT_EVAL = 4;
2135 private const int OPT_EXPORT = 5;
2136 private const int OPT_FORGET = 6;
2137 private const int OPT_IMPORT = 7;
2138 private const int OPT_INSCOPE = 8;
2139 private const int OPT_ORIGIN = 9;
2140 private const int OPT_PARENT = 10;
2141 private const int OPT_QUALIFIERS = 11;
2142 private const int OPT_TAIL = 12;
2143 private const int OPT_WHICH = 13;
2144  
2145  
2146 public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv )
2147 {
2148  
2149 int i, opt;
2150  
2151 if ( objv.Length < 2 )
2152 {
2153 throw new TclNumArgsException( interp, 1, objv, "subcommand ?arg ...?" );
2154 }
2155  
2156 opt = TclIndex.get( interp, objv[1], validCmds, "option", 0 );
2157  
2158 switch ( opt )
2159 {
2160  
2161 case OPT_CHILDREN:
2162 {
2163 childrenCmd( interp, objv );
2164 return TCL.CompletionCode.RETURN;
2165 }
2166  
2167 case OPT_CODE:
2168 {
2169 codeCmd( interp, objv );
2170 return TCL.CompletionCode.RETURN;
2171 }
2172  
2173 case OPT_CURRENT:
2174 {
2175 currentCmd( interp, objv );
2176 return TCL.CompletionCode.RETURN;
2177 }
2178  
2179 case OPT_DELETE:
2180 {
2181 deleteCmd( interp, objv );
2182 return TCL.CompletionCode.RETURN;
2183 }
2184  
2185 case OPT_EVAL:
2186 {
2187 evalCmd( interp, objv );
2188 return TCL.CompletionCode.RETURN;
2189 }
2190  
2191 case OPT_EXPORT:
2192 {
2193 exportCmd( interp, objv );
2194 return TCL.CompletionCode.RETURN;
2195 }
2196  
2197 case OPT_FORGET:
2198 {
2199 forgetCmd( interp, objv );
2200 return TCL.CompletionCode.RETURN;
2201 }
2202  
2203 case OPT_IMPORT:
2204 {
2205 importCmd( interp, objv );
2206 return TCL.CompletionCode.RETURN;
2207 }
2208  
2209 case OPT_INSCOPE:
2210 {
2211 inscopeCmd( interp, objv );
2212 return TCL.CompletionCode.RETURN;
2213 }
2214  
2215 case OPT_ORIGIN:
2216 {
2217 originCmd( interp, objv );
2218 return TCL.CompletionCode.RETURN;
2219 }
2220  
2221 case OPT_PARENT:
2222 {
2223 parentCmd( interp, objv );
2224 return TCL.CompletionCode.RETURN;
2225 }
2226  
2227 case OPT_QUALIFIERS:
2228 {
2229 qualifiersCmd( interp, objv );
2230 return TCL.CompletionCode.RETURN;
2231 }
2232  
2233 case OPT_TAIL:
2234 {
2235 tailCmd( interp, objv );
2236 return TCL.CompletionCode.RETURN;
2237 }
2238  
2239 case OPT_WHICH:
2240 {
2241 whichCmd( interp, objv );
2242 return TCL.CompletionCode.RETURN;
2243 }
2244 } // end switch(opt)
2245 return TCL.CompletionCode.RETURN;
2246 }
2247  
2248  
2249 /*
2250 *----------------------------------------------------------------------
2251 *
2252 * NamespaceChildrenCmd -> childrenCmd
2253 *
2254 * Invoked to implement the "namespace children" command that returns a
2255 * list containing the fully-qualified names of the child namespaces of
2256 * a given namespace. Handles the following syntax:
2257 *
2258 * namespace children ?name? ?pattern?
2259 *
2260 * Results:
2261 * Nothing.
2262 *
2263 * Side effects:
2264 * Returns a result in the interpreter's result object. If anything
2265 * goes wrong, the result is an error message.
2266 *
2267 *----------------------------------------------------------------------
2268 */
2269  
2270 private static void childrenCmd( Interp interp, TclObject[] objv )
2271 {
2272 Namespace namespace_Renamed;
2273 Namespace ns;
2274 Namespace globalNs = getGlobalNamespace( interp );
2275 string pattern = null;
2276 StringBuilder buffer;
2277 IEnumerator search;
2278 TclObject list, elem;
2279  
2280 // Get a pointer to the specified namespace, or the current namespace.
2281  
2282 if ( objv.Length == 2 )
2283 {
2284 ns = getCurrentNamespace( interp );
2285 }
2286 else if ( ( objv.Length == 3 ) || ( objv.Length == 4 ) )
2287 {
2288 ns = getNamespaceFromObj( interp, objv[2] );
2289 if ( ns == null )
2290 {
2291  
2292 throw new TclException( interp, "unknown namespace \"" + objv[2].ToString() + "\" in namespace children command" );
2293 }
2294 }
2295 else
2296 {
2297 throw new TclNumArgsException( interp, 2, objv, "?name? ?pattern?" );
2298 }
2299  
2300 // Get the glob-style pattern, if any, used to narrow the search.
2301  
2302 buffer = new StringBuilder();
2303 if ( objv.Length == 4 )
2304 {
2305  
2306 string name = objv[3].ToString();
2307  
2308 if ( name.StartsWith( "::" ) )
2309 {
2310 pattern = name;
2311 }
2312 else
2313 {
2314 buffer.Append( ns.fullName );
2315 if ( ns != globalNs )
2316 {
2317 buffer.Append( "::" );
2318 }
2319 buffer.Append( name );
2320 pattern = buffer.ToString();
2321 }
2322 }
2323  
2324 // Create a list containing the full names of all child namespaces
2325 // whose names match the specified pattern, if any.
2326  
2327 list = TclList.newInstance();
2328 foreach ( Namespace childNs in ns.childTable.Values )
2329 {
2330 if ( ( (System.Object)pattern == null ) || Util.stringMatch( childNs.fullName, pattern ) )
2331 {
2332 elem = TclString.newInstance( childNs.fullName );
2333 TclList.append( interp, list, elem );
2334 }
2335 }
2336 interp.setResult( list );
2337 return;
2338 }
2339  
2340  
2341 /*
2342 *----------------------------------------------------------------------
2343 *
2344 * NamespaceCodeCmd -> codeCmd
2345 *
2346 * Invoked to implement the "namespace code" command to capture the
2347 * namespace context of a command. Handles the following syntax:
2348 *
2349 * namespace code arg
2350 *
2351 * Here "arg" can be a list. "namespace code arg" produces a result
2352 * equivalent to that produced by the command
2353 *
2354 * list namespace inscope [namespace current] $arg
2355 *
2356 * However, if "arg" is itself a scoped value starting with
2357 * "namespace inscope", then the result is just "arg".
2358 *
2359 * Results:
2360 * Nothing.
2361 *
2362 * Side effects:
2363 * If anything goes wrong, this procedure returns an error
2364 * message as the result in the interpreter's result object.
2365 *
2366 *----------------------------------------------------------------------
2367 */
2368  
2369  
2370 private static void codeCmd( Interp interp, TclObject[] objv )
2371 {
2372 Namespace currNs;
2373 TclObject list, obj;
2374 string arg, p;
2375 int length;
2376 int p_ind;
2377  
2378 if ( objv.Length != 3 )
2379 {
2380 throw new TclNumArgsException( interp, 2, objv, "arg" );
2381 }
2382  
2383 // If "arg" is already a scoped value, then return it directly.
2384  
2385  
2386 arg = objv[2].ToString();
2387 length = arg.Length;
2388  
2389 // FIXME : we need a test for this inscope code if there is not one already!
2390 if ( ( length > 17 ) && ( arg[0] == 'n' ) && arg.StartsWith( "namespace" ) )
2391 {
2392 for ( p_ind = 9; ( p_ind < length ) && ( arg[p_ind] == ' ' ); p_ind++ )
2393 {
2394 // empty body: skip over spaces
2395 }
2396 if ( ( ( length - p_ind ) >= 7 ) && ( arg[p_ind] == 'i' ) && arg.Substring( p_ind ).StartsWith( "inscope" ) )
2397 {
2398 interp.setResult( objv[2] );
2399 return;
2400 }
2401 }
2402  
2403 // Otherwise, construct a scoped command by building a list with
2404 // "namespace inscope", the full name of the current namespace, and
2405 // the argument "arg". By constructing a list, we ensure that scoped
2406 // commands are interpreted properly when they are executed later,
2407 // by the "namespace inscope" command.
2408  
2409 list = TclList.newInstance();
2410 TclList.append( interp, list, TclString.newInstance( "namespace" ) );
2411 TclList.append( interp, list, TclString.newInstance( "inscope" ) );
2412  
2413 currNs = getCurrentNamespace( interp );
2414 if ( currNs == getGlobalNamespace( interp ) )
2415 {
2416 obj = TclString.newInstance( "::" );
2417 }
2418 else
2419 {
2420 obj = TclString.newInstance( currNs.fullName );
2421 }
2422  
2423 TclList.append( interp, list, obj );
2424 TclList.append( interp, list, objv[2] );
2425  
2426 interp.setResult( list );
2427 return;
2428 }
2429  
2430 /*
2431 *----------------------------------------------------------------------
2432 *
2433 * NamespaceCurrentCmd -> currentCmd
2434 *
2435 * Invoked to implement the "namespace current" command which returns
2436 * the fully-qualified name of the current namespace. Handles the
2437 * following syntax:
2438 *
2439 * namespace current
2440 *
2441 * Results:
2442 * Returns if successful, raises TclException if something goes wrong.
2443 *
2444 * Side effects:
2445 * Returns a result in the interpreter's result object. If anything
2446 * goes wrong, the result is an error message.
2447 *
2448 *----------------------------------------------------------------------
2449 */
2450  
2451 private static void currentCmd( Interp interp, TclObject[] objv )
2452 {
2453  
2454 Namespace currNs;
2455  
2456 if ( objv.Length != 2 )
2457 {
2458 throw new TclNumArgsException( interp, 2, objv, null );
2459 }
2460  
2461 // The "real" name of the global namespace ("::") is the null string,
2462 // but we return "::" for it as a convenience to programmers. Note that
2463 // "" and "::" are treated as synonyms by the namespace code so that it
2464 // is still easy to do things like:
2465 //
2466 // namespace [namespace current]::bar { ... }
2467  
2468 currNs = getCurrentNamespace( interp );
2469  
2470 if ( currNs == getGlobalNamespace( interp ) )
2471 {
2472 // FIXME : appending to te result really screws everything up!
2473 // need to figure out how to disallow this!
2474 //TclString.append(interp.getResult(), "::");
2475 interp.setResult( "::" );
2476 }
2477 else
2478 {
2479 //TclString.append(interp.getResult(), currNs.fullName);
2480 interp.setResult( currNs.fullName );
2481 }
2482 }
2483  
2484 /*
2485 *----------------------------------------------------------------------
2486 *
2487 * NamespaceDeleteCmd -> deleteCmd
2488 *
2489 * Invoked to implement the "namespace delete" command to delete
2490 * namespace(s). Handles the following syntax:
2491 *
2492 * namespace delete ?name name...?
2493 *
2494 * Each name identifies a namespace. It may include a sequence of
2495 * namespace qualifiers separated by "::"s. If a namespace is found, it
2496 * is deleted: all variables and procedures contained in that namespace
2497 * are deleted. If that namespace is being used on the call stack, it
2498 * is kept alive (but logically deleted) until it is removed from the
2499 * call stack: that is, it can no longer be referenced by name but any
2500 * currently executing procedure that refers to it is allowed to do so
2501 * until the procedure returns. If the namespace can't be found, this
2502 * procedure returns an error. If no namespaces are specified, this
2503 * command does nothing.
2504 *
2505 * Results:
2506 * Returns if successful, raises TclException if something goes wrong.
2507 *
2508 * Side effects:
2509 * Deletes the specified namespaces. If anything goes wrong, this
2510 * procedure returns an error message in the interpreter's
2511 * result object.
2512 *
2513 *----------------------------------------------------------------------
2514 */
2515  
2516 private static void deleteCmd( Interp interp, TclObject[] objv )
2517 {
2518 Namespace namespace_Renamed;
2519 string name;
2520 int i;
2521  
2522 if ( objv.Length < 2 )
2523 {
2524 throw new TclNumArgsException( interp, 2, objv, "?name name...?" );
2525 }
2526  
2527 // Destroying one namespace may cause another to be destroyed. Break
2528 // this into two passes: first check to make sure that all namespaces on
2529 // the command line are valid, and report any errors.
2530  
2531 for ( i = 2; i < objv.Length; i++ )
2532 {
2533  
2534 name = objv[i].ToString();
2535 namespace_Renamed = findNamespace( interp, name, null, 0 );
2536  
2537 if ( namespace_Renamed == null )
2538 {
2539  
2540 throw new TclException( interp, "unknown namespace \"" + objv[i].ToString() + "\" in namespace delete command" );
2541 }
2542 }
2543  
2544 // Okay, now delete each namespace.
2545  
2546 for ( i = 2; i < objv.Length; i++ )
2547 {
2548  
2549 name = objv[i].ToString();
2550 namespace_Renamed = findNamespace( interp, name, null, 0 );
2551  
2552 if ( namespace_Renamed != null )
2553 {
2554 deleteNamespace( namespace_Renamed );
2555 }
2556 }
2557 }
2558  
2559 /*
2560 *----------------------------------------------------------------------
2561 *
2562 * NamespaceEvalCmd -> evalCmd
2563 *
2564 * Invoked to implement the "namespace eval" command. Executes
2565 * commands in a namespace. If the namespace does not already exist,
2566 * it is created. Handles the following syntax:
2567 *
2568 * namespace eval name arg ?arg...?
2569 *
2570 * If more than one arg argument is specified, the command that is
2571 * executed is the result of concatenating the arguments together with
2572 * a space between each argument.
2573 *
2574 * Results:
2575 * Returns if successful, raises TclException if something goes wrong.
2576 *
2577 * Side effects:
2578 * Returns the result of the command in the interpreter's result
2579 * object. If anything goes wrong, this procedure returns an error
2580 * message as the result.
2581 *
2582 *----------------------------------------------------------------------
2583 */
2584  
2585 private static void evalCmd( Interp interp, TclObject[] objv )
2586 {
2587 Namespace namespace_Renamed;
2588 CallFrame frame;
2589 string cmd;
2590 string name;
2591 int length;
2592  
2593 if ( objv.Length < 4 )
2594 {
2595 throw new TclNumArgsException( interp, 2, objv, "name arg ?arg...?" );
2596 }
2597  
2598 // Try to resolve the namespace reference, caching the result in the
2599 // namespace object along the way.
2600  
2601 namespace_Renamed = getNamespaceFromObj( interp, objv[2] );
2602  
2603 // If the namespace wasn't found, try to create it.
2604  
2605 if ( namespace_Renamed == null )
2606 {
2607  
2608 name = objv[2].ToString();
2609 namespace_Renamed = createNamespace( interp, name, null );
2610 if ( namespace_Renamed == null )
2611 {
2612 // FIXME : result hack, we get the interp result and throw it!
2613  
2614 throw new TclException( interp, interp.getResult().ToString() );
2615 }
2616 }
2617  
2618 // Make the specified namespace the current namespace and evaluate
2619 // the command(s).
2620  
2621 frame = interp.newCallFrame();
2622 pushCallFrame( interp, frame, namespace_Renamed, false );
2623  
2624 try
2625 {
2626 if ( objv.Length == 4 )
2627 {
2628 interp.eval( objv[3], 0 );
2629 }
2630 else
2631 {
2632 cmd = Util.concat( 3, objv.Length, objv );
2633  
2634 // eval() will delete the object when it decrements its
2635 // refcount after eval'ing it.
2636  
2637 interp.eval( cmd ); // do not pass TCL_EVAL_DIRECT, for compiler only
2638 }
2639 }
2640 catch ( TclException ex )
2641 {
2642 if ( ex.getCompletionCode() == TCL.CompletionCode.ERROR )
2643 {
2644 interp.addErrorInfo( "\n (in namespace eval \"" + namespace_Renamed.fullName + "\" script line " + interp.errorLine + ")" );
2645 }
2646 throw ex;
2647 }
2648 finally
2649 {
2650 popCallFrame( interp );
2651 }
2652  
2653 return;
2654 }
2655  
2656  
2657 /*
2658 *----------------------------------------------------------------------
2659 *
2660 * NamespaceExportCmd -> exportCmd
2661 *
2662 * Invoked to implement the "namespace export" command that specifies
2663 * which commands are exported from a namespace. The exported commands
2664 * are those that can be imported into another namespace using
2665 * "namespace import". Both commands defined in a namespace and
2666 * commands the namespace has imported can be exported by a
2667 * namespace. This command has the following syntax:
2668 *
2669 * namespace export ?-clear? ?pattern pattern...?
2670 *
2671 * Each pattern may contain "string match"-style pattern matching
2672 * special characters, but the pattern may not include any namespace
2673 * qualifiers: that is, the pattern must specify commands in the
2674 * current (exporting) namespace. The specified patterns are appended
2675 * onto the namespace's list of export patterns.
2676 *
2677 * To reset the namespace's export pattern list, specify the "-clear"
2678 * flag.
2679 *
2680 * If there are no export patterns and the "-clear" flag isn't given,
2681 * this command returns the namespace's current export list.
2682 *
2683 * Results:
2684 * Returns if successful, raises TclException if something goes wrong.
2685 *
2686 * Side effects:
2687 * Returns a result in the interpreter's result object. If anything
2688 * goes wrong, the result is an error message.
2689 *
2690 *----------------------------------------------------------------------
2691 */
2692  
2693  
2694 private static void exportCmd( Interp interp, TclObject[] objv )
2695 {
2696 Namespace currNs = getCurrentNamespace( interp );
2697 string pattern, inString;
2698 bool resetListFirst = false;
2699 int firstArg, patternCt, i;
2700  
2701 if ( objv.Length < 2 )
2702 {
2703 throw new TclNumArgsException( interp, 2, objv, "?-clear? ?pattern pattern...?" );
2704 }
2705  
2706 // Process the optional "-clear" argument.
2707  
2708 firstArg = 2;
2709 if ( firstArg < objv.Length )
2710 {
2711  
2712 inString = objv[firstArg].ToString();
2713 if ( inString.Equals( "-clear" ) )
2714 {
2715 resetListFirst = true;
2716 firstArg++;
2717 }
2718 }
2719  
2720 // If no pattern arguments are given, and "-clear" isn't specified,
2721 // return the namespace's current export pattern list.
2722  
2723 patternCt = ( objv.Length - firstArg );
2724 if ( patternCt == 0 )
2725 {
2726 if ( firstArg > 2 )
2727 {
2728 return;
2729 }
2730 else
2731 {
2732 // create list with export patterns
2733 TclObject list = TclList.newInstance();
2734 appendExportList( interp, currNs, list );
2735 interp.setResult( list );
2736 return;
2737 }
2738 }
2739  
2740 // Add each pattern to the namespace's export pattern list.
2741  
2742 for ( i = firstArg; i < objv.Length; i++ )
2743 {
2744  
2745 pattern = objv[i].ToString();
2746 exportList( interp, currNs, pattern, ( ( i == firstArg ) ? resetListFirst : false ) );
2747 }
2748 return;
2749 }
2750  
2751  
2752 /*
2753 *----------------------------------------------------------------------
2754 *
2755 * NamespaceForgetCmd -> forgetCmd
2756 *
2757 * Invoked to implement the "namespace forget" command to remove
2758 * imported commands from a namespace. Handles the following syntax:
2759 *
2760 * namespace forget ?pattern pattern...?
2761 *
2762 * Each pattern is a name like "foo::*" or "a::b::x*". That is, the
2763 * pattern may include the special pattern matching characters
2764 * recognized by the "string match" command, but only in the command
2765 * name at the end of the qualified name; the special pattern
2766 * characters may not appear in a namespace name. All of the commands
2767 * that match that pattern are checked to see if they have an imported
2768 * command in the current namespace that refers to the matched
2769 * command. If there is an alias, it is removed.
2770 *
2771 * Results:
2772 * Returns if successful, raises TclException if something goes wrong.
2773 *
2774 * Side effects:
2775 * Imported commands are removed from the current namespace. If
2776 * anything goes wrong, this procedure returns an error message in the
2777 * interpreter's result object.
2778 *
2779 *----------------------------------------------------------------------
2780 */
2781  
2782  
2783 private static void forgetCmd( Interp interp, TclObject[] objv )
2784 {
2785  
2786 string pattern;
2787 int i;
2788  
2789 if ( objv.Length < 2 )
2790 {
2791 throw new TclNumArgsException( interp, 2, objv, "?pattern pattern...?" );
2792 }
2793  
2794 for ( i = 2; i < objv.Length; i++ )
2795 {
2796  
2797 pattern = objv[i].ToString();
2798 forgetImport( interp, null, pattern );
2799 }
2800 return;
2801 }
2802  
2803  
2804 /*
2805 *----------------------------------------------------------------------
2806 *
2807 * NamespaceImportCmd -> importCmd
2808 *
2809 * Invoked to implement the "namespace import" command that imports
2810 * commands into a namespace. Handles the following syntax:
2811 *
2812 * namespace import ?-force? ?pattern pattern...?
2813 *
2814 * Each pattern is a namespace-qualified name like "foo::*",
2815 * "a::b::x*", or "bar::p". That is, the pattern may include the
2816 * special pattern matching characters recognized by the "string match"
2817 * command, but only in the command name at the end of the qualified
2818 * name; the special pattern characters may not appear in a namespace
2819 * name. All of the commands that match the pattern and which are
2820 * exported from their namespace are made accessible from the current
2821 * namespace context. This is done by creating a new "imported command"
2822 * in the current namespace that points to the real command in its
2823 * original namespace; when the imported command is called, it invokes
2824 * the real command.
2825 *
2826 * If an imported command conflicts with an existing command, it is
2827 * treated as an error. But if the "-force" option is included, then
2828 * existing commands are overwritten by the imported commands.
2829 *
2830 * Results:
2831 * Returns if successful, raises TclException if something goes wrong.
2832 *
2833 * Side effects:
2834 * Adds imported commands to the current namespace. If anything goes
2835 * wrong, this procedure returns an error message in the interpreter's
2836 * result object.
2837 *
2838 *----------------------------------------------------------------------
2839 */
2840  
2841  
2842 private static void importCmd( Interp interp, TclObject[] objv )
2843 {
2844  
2845 bool allowOverwrite = false;
2846 string inString, pattern;
2847 int i;
2848 int firstArg;
2849  
2850 if ( objv.Length < 2 )
2851 {
2852 throw new TclNumArgsException( interp, 2, objv, "?-force? ?pattern pattern...?" );
2853 }
2854  
2855 // Skip over the optional "-force" as the first argument.
2856  
2857 firstArg = 2;
2858 if ( firstArg < objv.Length )
2859 {
2860  
2861 inString = objv[firstArg].ToString();
2862 if ( inString.Equals( "-force" ) )
2863 {
2864 allowOverwrite = true;
2865 firstArg++;
2866 }
2867 }
2868  
2869 // Handle the imports for each of the patterns.
2870  
2871 for ( i = firstArg; i < objv.Length; i++ )
2872 {
2873  
2874 pattern = objv[i].ToString();
2875 importList( interp, null, pattern, allowOverwrite );
2876 }
2877 return;
2878 }
2879  
2880  
2881 /*
2882 *----------------------------------------------------------------------
2883 *
2884 * NamespaceInscopeCmd -> inscopeCmd
2885 *
2886 * Invoked to implement the "namespace inscope" command that executes a
2887 * script in the context of a particular namespace. This command is not
2888 * expected to be used directly by programmers; calls to it are
2889 * generated implicitly when programs use "namespace code" commands
2890 * to register callback scripts. Handles the following syntax:
2891 *
2892 * namespace inscope name arg ?arg...?
2893 *
2894 * The "namespace inscope" command is much like the "namespace eval"
2895 * command except that it has lappend semantics and the namespace must
2896 * already exist. It treats the first argument as a list, and appends
2897 * any arguments after the first onto the end as proper list elements.
2898 * For example,
2899 *
2900 * namespace inscope ::foo a b c d
2901 *
2902 * is equivalent to
2903 *
2904 * namespace eval ::foo [concat a [list b c d]]
2905 *
2906 * This lappend semantics is important because many callback scripts
2907 * are actually prefixes.
2908 *
2909 * Results:
2910 * Returns if successful, raises TclException if something goes wrong.
2911 *
2912 * Side effects:
2913 * Returns a result in the Tcl interpreter's result object.
2914 *
2915 *----------------------------------------------------------------------
2916 */
2917  
2918 private static void inscopeCmd( Interp interp, TclObject[] objv )
2919 {
2920 Namespace namespace_Renamed;
2921 CallFrame frame;
2922 int i, result;
2923  
2924 if ( objv.Length < 4 )
2925 {
2926 throw new TclNumArgsException( interp, 2, objv, "name arg ?arg...?" );
2927 }
2928  
2929 // Resolve the namespace reference.
2930  
2931 namespace_Renamed = getNamespaceFromObj( interp, objv[2] );
2932 if ( namespace_Renamed == null )
2933 {
2934  
2935 throw new TclException( interp, "unknown namespace \"" + objv[2].ToString() + "\" in inscope namespace command" );
2936 }
2937  
2938 // Make the specified namespace the current namespace.
2939  
2940 frame = interp.newCallFrame();
2941 pushCallFrame( interp, frame, namespace_Renamed, false );
2942  
2943  
2944 // Execute the command. If there is just one argument, just treat it as
2945 // a script and evaluate it. Otherwise, create a list from the arguments
2946 // after the first one, then concatenate the first argument and the list
2947 // of extra arguments to form the command to evaluate.
2948  
2949 try
2950 {
2951 if ( objv.Length == 4 )
2952 {
2953 interp.eval( objv[3], 0 );
2954 }
2955 else
2956 {
2957 TclObject[] concatObjv = new TclObject[2];
2958 TclObject list;
2959 string cmd;
2960  
2961 list = TclList.newInstance();
2962 for ( i = 4; i < objv.Length; i++ )
2963 {
2964 try
2965 {
2966 TclList.append( interp, list, objv[i] );
2967 }
2968 catch ( TclException ex )
2969 {
2970 list.release(); // free unneeded obj
2971 throw ex;
2972 }
2973 }
2974  
2975 concatObjv[0] = objv[3];
2976 concatObjv[1] = list;
2977 cmd = Util.concat( 0, 1, concatObjv );
2978 interp.eval( cmd ); // do not pass TCL_EVAL_DIRECT, for compiler only
2979 list.release(); // we're done with the list object
2980 }
2981 }
2982 catch ( TclException ex )
2983 {
2984 if ( ex.getCompletionCode() == TCL.CompletionCode.ERROR )
2985 {
2986 interp.addErrorInfo( "\n (in namespace inscope \"" + namespace_Renamed.fullName + "\" script line " + interp.errorLine + ")" );
2987 }
2988 throw ex;
2989 }
2990 finally
2991 {
2992 popCallFrame( interp );
2993 }
2994  
2995 return;
2996 }
2997  
2998  
2999 /*
3000 *----------------------------------------------------------------------
3001 *
3002 * NamespaceOriginCmd -> originCmd
3003 *
3004 * Invoked to implement the "namespace origin" command to return the
3005 * fully-qualified name of the "real" command to which the specified
3006 * "imported command" refers. Handles the following syntax:
3007 *
3008 * namespace origin name
3009 *
3010 * Results:
3011 * An imported command is created in an namespace when that namespace
3012 * imports a command from another namespace. If a command is imported
3013 * into a sequence of namespaces a, b,...,n where each successive
3014 * namespace just imports the command from the previous namespace, this
3015 * command returns the fully-qualified name of the original command in
3016 * the first namespace, a. If "name" does not refer to an alias, its
3017 * fully-qualified name is returned. The returned name is stored in the
3018 * interpreter's result object. This procedure returns TCL_OK if
3019 * successful, and TCL_ERROR if anything goes wrong.
3020 *
3021 * Side effects:
3022 * If anything goes wrong, this procedure returns an error message in
3023 * the interpreter's result object.
3024 *
3025 *----------------------------------------------------------------------
3026 */
3027  
3028 private static void originCmd( Interp interp, TclObject[] objv )
3029 {
3030 WrappedCommand command, origCommand;
3031  
3032 if ( objv.Length != 3 )
3033 {
3034 throw new TclNumArgsException( interp, 2, objv, "name" );
3035 }
3036  
3037 // FIXME : is this the right way to search for a command?
3038  
3039 //command = Tcl_GetCommandFromObj(interp, objv[2]);
3040  
3041 command = NamespaceCmd.findCommand( interp, objv[2].ToString(), null, 0 );
3042  
3043 if ( command == null )
3044 {
3045  
3046 throw new TclException( interp, "invalid command name \"" + objv[2].ToString() + "\"" );
3047 }
3048  
3049 origCommand = getOriginalCommand( command );
3050 if ( origCommand == null )
3051 {
3052 // The specified command isn't an imported command. Return the
3053 // command's name qualified by the full name of the namespace it
3054 // was defined in.
3055  
3056 interp.setResult( interp.getCommandFullName( command ) );
3057 }
3058 else
3059 {
3060 interp.setResult( interp.getCommandFullName( origCommand ) );
3061 }
3062 return;
3063 }
3064  
3065  
3066 /*
3067 *----------------------------------------------------------------------
3068 *
3069 * NamespaceParentCmd -> parentCmd
3070 *
3071 * Invoked to implement the "namespace parent" command that returns the
3072 * fully-qualified name of the parent namespace for a specified
3073 * namespace. Handles the following syntax:
3074 *
3075 * namespace parent ?name?
3076 *
3077 * Results:
3078 * Returns if successful, raises TclException if something goes wrong.
3079 *
3080 * Side effects:
3081 * Returns a result in the interpreter's result object. If anything
3082 * goes wrong, the result is an error message.
3083 *
3084 *----------------------------------------------------------------------
3085 */
3086  
3087 private static void parentCmd( Interp interp, TclObject[] objv )
3088 {
3089 Namespace ns;
3090  
3091 if ( objv.Length == 2 )
3092 {
3093 ns = getCurrentNamespace( interp );
3094 }
3095 else if ( objv.Length == 3 )
3096 {
3097 ns = getNamespaceFromObj( interp, objv[2] );
3098 if ( ns == null )
3099 {
3100  
3101 throw new TclException( interp, "unknown namespace \"" + objv[2].ToString() + "\" in namespace parent command" );
3102 }
3103 }
3104 else
3105 {
3106 throw new TclNumArgsException( interp, 2, objv, "?name?" );
3107 }
3108  
3109 // Report the parent of the specified namespace.
3110  
3111 if ( ns.parent != null )
3112 {
3113 interp.setResult( ns.parent.fullName );
3114 }
3115 }
3116  
3117  
3118 /*
3119 *----------------------------------------------------------------------
3120 *
3121 * NamespaceQualifiersCmd -> qualifiersCmd
3122 *
3123 * Invoked to implement the "namespace qualifiers" command that returns
3124 * any leading namespace qualifiers in a string. These qualifiers are
3125 * namespace names separated by "::"s. For example, for "::foo::p" this
3126 * command returns "::foo", and for "::" it returns "". This command
3127 * is the complement of the "namespace tail" command. Note that this
3128 * command does not check whether the "namespace" names are, in fact,
3129 * the names of currently defined namespaces. Handles the following
3130 * syntax:
3131 *
3132 * namespace qualifiers string
3133 *
3134 * Results:
3135 * Returns if successful, raises TclException if something goes wrong.
3136 *
3137 * Side effects:
3138 * Returns a result in the interpreter's result object. If anything
3139 * goes wrong, the result is an error message.
3140 *
3141 *----------------------------------------------------------------------
3142 */
3143  
3144 private static void qualifiersCmd( Interp interp, TclObject[] objv )
3145 {
3146 string name;
3147 int p;
3148  
3149 if ( objv.Length != 3 )
3150 {
3151 throw new TclNumArgsException( interp, 2, objv, "string" );
3152 }
3153  
3154 // Find the end of the string, then work backward and find
3155 // the start of the last "::" qualifier.
3156  
3157  
3158 name = objv[2].ToString();
3159 p = name.Length;
3160  
3161 while ( --p >= 0 )
3162 {
3163 if ( ( name[p] == ':' ) && ( p > 0 ) && ( name[p - 1] == ':' ) )
3164 {
3165 p -= 2; // back up over the ::
3166 while ( ( p >= 0 ) && ( name[p] == ':' ) )
3167 {
3168 p--; // back up over the preceeding :
3169 }
3170 break;
3171 }
3172 }
3173  
3174 if ( p >= 0 )
3175 {
3176 interp.setResult( name.Substring( 0, ( p + 1 ) - ( 0 ) ) );
3177 }
3178 // When no result is set the empty string is the result
3179 return;
3180 }
3181  
3182  
3183 /*
3184 *----------------------------------------------------------------------
3185 *
3186 * NamespaceTailCmd -> tailCmd
3187 *
3188 * Invoked to implement the "namespace tail" command that returns the
3189 * trailing name at the end of a string with "::" namespace
3190 * qualifiers. These qualifiers are namespace names separated by
3191 * "::"s. For example, for "::foo::p" this command returns "p", and for
3192 * "::" it returns "". This command is the complement of the "namespace
3193 * qualifiers" command. Note that this command does not check whether
3194 * the "namespace" names are, in fact, the names of currently defined
3195 * namespaces. Handles the following syntax:
3196 *
3197 * namespace tail string
3198 *
3199 * Results:
3200 * Returns if successful, raises TclException if something goes wrong.
3201 *
3202 * Side effects:
3203 * Returns a result in the interpreter's result object. If anything
3204 * goes wrong, the result is an error message.
3205 *
3206 *----------------------------------------------------------------------
3207 */
3208  
3209  
3210 private static void tailCmd( Interp interp, TclObject[] objv )
3211 {
3212 string name;
3213 int p;
3214  
3215 if ( objv.Length != 3 )
3216 {
3217 throw new TclNumArgsException( interp, 2, objv, "string" );
3218 }
3219  
3220 // Find the end of the string, then work backward and find the
3221 // last "::" qualifier.
3222  
3223  
3224 name = objv[2].ToString();
3225 p = name.Length;
3226  
3227 while ( --p > 0 )
3228 {
3229 if ( ( name[p] == ':' ) && ( name[p - 1] == ':' ) )
3230 {
3231 p++; // just after the last "::"
3232 break;
3233 }
3234 }
3235  
3236 if ( p >= 0 )
3237 {
3238 interp.setResult( name.Substring( p ) );
3239 }
3240 return;
3241 }
3242  
3243  
3244 /*
3245 *----------------------------------------------------------------------
3246 *
3247 * NamespaceWhichCmd -> whichCmd
3248 *
3249 * Invoked to implement the "namespace which" command that returns the
3250 * fully-qualified name of a command or variable. If the specified
3251 * command or variable does not exist, it returns "". Handles the
3252 * following syntax:
3253 *
3254 * namespace which ?-command? ?-variable? name
3255 *
3256 * Results:
3257 * Returns if successful, raises TclException if something goes wrong.
3258 *
3259 * Side effects:
3260 * Returns a result in the interpreter's result object. If anything
3261 * goes wrong, the result is an error message.
3262 *
3263 *----------------------------------------------------------------------
3264 */
3265  
3266  
3267 private static void whichCmd( Interp interp, TclObject[] objv )
3268 {
3269 string arg;
3270 WrappedCommand cmd;
3271 Var variable;
3272 int argIndex, lookup;
3273  
3274 if ( objv.Length < 3 )
3275 {
3276 throw new TclNumArgsException( interp, 2, objv, "?-command? ?-variable? name" );
3277 }
3278  
3279 // Look for a flag controlling the lookup.
3280  
3281 argIndex = 2;
3282 lookup = 0; // assume command lookup by default
3283  
3284 arg = objv[2].ToString();
3285 if ( ( arg.Length > 1 ) && ( arg[0] == '-' ) )
3286 {
3287 if ( arg.Equals( "-command" ) )
3288 {
3289 lookup = 0;
3290 }
3291 else if ( arg.Equals( "-variable" ) )
3292 {
3293 lookup = 1;
3294 }
3295 else
3296 {
3297 throw new TclNumArgsException( interp, 2, objv, "?-command? ?-variable? name" );
3298 }
3299 argIndex = 3;
3300 }
3301 if ( objv.Length != ( argIndex + 1 ) )
3302 {
3303 throw new TclNumArgsException( interp, 2, objv, "?-command? ?-variable? name" );
3304 }
3305  
3306 // FIXME : check that this implementation works!
3307  
3308 switch ( lookup )
3309 {
3310  
3311 case 0:
3312  
3313 arg = objv[argIndex].ToString();
3314  
3315 // FIXME : is this the right way to lookup a Command token?
3316 //cmd = Tcl_GetCommandFromObj(interp, objv[argIndex]);
3317 cmd = NamespaceCmd.findCommand( interp, arg, null, 0 );
3318  
3319 if ( cmd == null )
3320 {
3321 return; // cmd not found, just return (no error)
3322 }
3323 interp.setResult( interp.getCommandFullName( cmd ) );
3324 return;
3325  
3326  
3327 case 1:
3328  
3329 arg = objv[argIndex].ToString();
3330 variable = NamespaceCmd.findNamespaceVar( interp, arg, null, 0 );
3331 if ( variable != null )
3332 {
3333 interp.setResult( Var.getVariableFullName( interp, variable ) );
3334 }
3335 return;
3336 }
3337  
3338 return;
3339 }
3340  
3341  
3342 /*
3343 *----------------------------------------------------------------------
3344 *
3345 * FreeNsNameInternalRep -> dispose
3346 *
3347 * Frees the resources associated with a object's internal
3348 * representation. See src/tcljava/tcl/lang/InternalRep.java
3349 *
3350 * Results:
3351 * None.
3352 *
3353 * Side effects:
3354 * Decrements the ref count of any Namespace structure pointed
3355 * to by the nsName's internal representation. If there are no more
3356 * references to the namespace, it's structure will be freed.
3357 *
3358 *----------------------------------------------------------------------
3359 */
3360  
3361 public void dispose()
3362 {
3363 bool debug;
3364 System.Diagnostics.Debug.WriteLine( "dispose() called for namespace object " + ( otherValue == null ? null : otherValue.ns ) );
3365  
3366 ResolvedNsName resName = otherValue;
3367 Namespace ns;
3368  
3369 // Decrement the reference count of the namespace. If there are no
3370 // more references, free it up.
3371  
3372 if ( resName != null )
3373 {
3374 resName.refCount--;
3375 if ( resName.refCount == 0 )
3376 {
3377  
3378 // Decrement the reference count for the cached namespace. If
3379 // the namespace is dead, and there are no more references to
3380 // it, free it.
3381  
3382 ns = resName.ns;
3383 ns.refCount--;
3384 if ( ( ns.refCount == 0 ) && ( ( ns.flags & NS_DEAD ) != 0 ) )
3385 {
3386 free( ns );
3387 }
3388 otherValue = null;
3389 }
3390 }
3391 }
3392  
3393  
3394 /*
3395 *----------------------------------------------------------------------
3396 *
3397 * DupNsNameInternalRep -> duplicate
3398 *
3399 * Get a copy of this Object for copy-on-write
3400 * operations. We just increment its useCount and return the same
3401 * ReflectObject because ReflectObject's cannot be modified, so
3402 * they don't need copy-on-write protections.
3403 *
3404 * Results:
3405 * None.
3406 *
3407 * Side effects:
3408 * None.
3409 *
3410 *----------------------------------------------------------------------
3411 */
3412  
3413 public InternalRep duplicate()
3414 {
3415 System.Diagnostics.Debug.WriteLine( "duplicate() called for namespace object " + ( otherValue == null ? null : otherValue.ns ) );
3416  
3417 ResolvedNsName resName = otherValue;
3418  
3419 if ( resName != null )
3420 {
3421 resName.refCount++;
3422 }
3423  
3424 return this;
3425 }
3426  
3427  
3428 /*
3429 *----------------------------------------------------------------------
3430 *
3431 * SetNsNameFromAny -> setNsNameFromAny
3432 *
3433 * Attempt to generate a nsName internal representation for a
3434 * TclObject.
3435 *
3436 * Results:
3437 * Returns if the value could be converted to a proper
3438 * namespace reference. Otherwise, raises TclException.
3439 *
3440 * Side effects:
3441 * If successful, the object is made a nsName object. Its internal rep
3442 * is set to point to a ResolvedNsName, which contains a cached pointer
3443 * to the Namespace. Reference counts are kept on both the
3444 * ResolvedNsName and the Namespace, so we can keep track of their
3445 * usage and free them when appropriate.
3446 *
3447 *----------------------------------------------------------------------
3448 */
3449  
3450 private static void setNsNameFromAny( Interp interp, TclObject tobj )
3451 {
3452 string name;
3453 Namespace ns;
3454 ResolvedNsName resName;
3455  
3456 // Java does not support passing an address so we pass
3457 // an array of size 1 and then assign arr[0] to the value
3458 Namespace[] nsArr = new Namespace[1];
3459 Namespace[] dummy1Arr = new Namespace[1];
3460 string[] dummy2Arr = new string[1];
3461  
3462 // Get the string representation.
3463  
3464 name = tobj.ToString();
3465  
3466 // Look for the namespace "name" in the current namespace. If there is
3467 // an error parsing the (possibly qualified) name, return an error.
3468 // If the namespace isn't found, we convert the object to an nsName
3469 // object with a null ResolvedNsName internal rep.
3470  
3471 getNamespaceForQualName( interp, name, null, TCL.VarFlag.FIND_ONLY_NS, nsArr, dummy1Arr, dummy1Arr, dummy2Arr );
3472  
3473  
3474 // Get the values out of the arrays!
3475 ns = nsArr[0];
3476  
3477 // If we found a namespace, then create a new ResolvedNsName structure
3478 // that holds a reference to it.
3479  
3480 if ( ns != null )
3481 {
3482 Namespace currNs = getCurrentNamespace( interp );
3483  
3484 ns.refCount++;
3485 resName = new ResolvedNsName();
3486 resName.ns = ns;
3487 resName.nsId = ns.nsId;
3488 resName.refNs = currNs;
3489 resName.refCount = 1;
3490 }
3491 else
3492 {
3493 resName = null;
3494 }
3495  
3496 // By setting the new internal rep we free up the old one.
3497  
3498 // FIXME : should a NamespaceCmd wrap a ResolvedNsName?
3499 // this is confusing because it seems like the C code uses
3500 // a ResolvedNsName like it is the InternalRep.
3501  
3502 NamespaceCmd wrap = new NamespaceCmd();
3503 wrap.otherValue = resName;
3504 tobj.InternalRep = wrap;
3505  
3506 return;
3507 }
3508  
3509  
3510 /*
3511 *----------------------------------------------------------------------
3512 *
3513 * UpdateStringOfNsName -> toString
3514 *
3515 * Return the string representation for a nsName object.
3516 * This method is called only by TclObject.toString()
3517 * when TclObject.stringRep is null.
3518 *
3519 * Results:
3520 * None.
3521 *
3522 * Side effects:
3523 * None.
3524 *
3525 *----------------------------------------------------------------------
3526 */
3527  
3528 public override string ToString()
3529 {
3530 bool debug;
3531  
3532 System.Diagnostics.Debug.WriteLine( "toString() called for namespace object " + ( otherValue == null ? null : otherValue.ns ) );
3533  
3534 ResolvedNsName resName = otherValue;
3535 Namespace ns;
3536 string name = "";
3537  
3538 if ( ( resName != null ) && ( resName.nsId == resName.ns.nsId ) )
3539 {
3540 ns = resName.ns;
3541 if ( ( ns.flags & NS_DEAD ) != 0 )
3542 {
3543 ns = null;
3544 }
3545 if ( ns != null )
3546 {
3547 name = ns.fullName;
3548 }
3549 }
3550  
3551 return name;
3552 }
3553  
3554  
3555 // This interface is used to provide a callback when a namespace is deleted
3556 // (ported Tcl_NamespaceDeleteProc to NamespaceCmd.DeleteProc)
3557  
3558 internal interface DeleteProc
3559 {
3560 void delete();
3561 }
3562  
3563  
3564 // This structure contains a cached pointer to a namespace that is the
3565 // result of resolving the namespace's name in some other namespace. It is
3566 // the internal representation for a nsName object. It contains the
3567 // pointer along with some information that is used to check the cached
3568 // pointer's validity. (ported Tcl_Namespace to NamespaceCmd.Namespace)
3569  
3570 public class Namespace
3571 {
3572 internal string name; // The namespace's simple (unqualified)
3573 // name. This contains no ::'s. The name of
3574 // the global namespace is "" although "::"
3575 // is an synonym.
3576  
3577 internal string fullName; // The namespace's fully qualified name.
3578 // This starts with ::.
3579  
3580 internal DeleteProc deleteProc; // method to invoke when namespace is deleted
3581  
3582 internal Namespace parent; // reference to the namespace that contains
3583 // this one. null is this is the global namespace.
3584  
3585 internal Hashtable childTable; // Contains any child namespaces. Indexed
3586 // by strings; values are references to
3587 // Namespace objects
3588  
3589 internal long nsId; // Unique id for the namespace.
3590 internal Interp interp; // The interpreter containing this namespace.
3591  
3592 internal int flags; // OR-ed combination of the namespace
3593 // status flags NS_DYING and NS_DEAD (listed below)
3594  
3595 internal int activationCount; // Number of "activations" or active call
3596 // frames for this namespace that are on
3597 // the Tcl call stack. The namespace won't
3598 // be freed until activationCount becomes zero.
3599  
3600 internal int refCount; // Count of references by nsName
3601 // objects. The namespace can't be freed
3602 // until refCount becomes zero.
3603  
3604 internal Hashtable cmdTable; // Contains all the commands currently
3605 // registered in the namespace. Indexed by
3606 // strings; values have type (WrappedCommand).
3607 // Commands imported by Tcl_Import have
3608 // Command structures that point (via an
3609 // ImportedCmdRef structure) to the
3610 // Command structure in the source
3611 // namespace's command table.
3612  
3613 internal Hashtable varTable; // Contains all the (global) variables
3614 // currently in this namespace. Indexed
3615 // by strings; values have type (Var).
3616  
3617 internal string[] exportArray; // Reference to an array of string patterns
3618 // specifying which commands are exported.
3619 // A pattern may include "string match"
3620 // style wildcard characters to specify
3621 // multiple commands; however, no namespace
3622 // qualifiers are allowed. null if no
3623 // export patterns are registered.
3624  
3625 internal int numExportPatterns; // Number of export patterns currently
3626 // registered using "namespace export".
3627  
3628 internal int maxExportPatterns; // Mumber of export patterns for which
3629 // space is currently allocated.
3630  
3631  
3632 internal Resolver resolver;
3633 // If non-null, this object overrides the
3634 // usual command and variable resolution
3635 // mechanism in Tcl. This procedure is invoked
3636 // within findCommand and findNamespaceVar to
3637 // resolve all command and variable references
3638 // within the namespace.
3639  
3640 // When printing out a Namespace use the full namespace name string
3641  
3642 public override string ToString()
3643 {
3644 return fullName;
3645 }
3646 }
3647  
3648  
3649 // (ported ResolvedNsName to NamespaceCmd.ResolvedNsName)
3650  
3651 internal class ResolvedNsName
3652 {
3653 internal Namespace ns; // reference to namespace object
3654 internal long nsId; // sPtr's unique namespace id. Used to
3655 // verify that ns is still valid
3656 // (e.g., it's possible that the namespace
3657 // was deleted and a new one created at
3658 // the same address).
3659  
3660 internal Namespace refNs; // reference to the namespace containing the
3661 // reference (not the namespace that
3662 // contains the referenced namespace).
3663 internal int refCount; // Reference count: 1 for each nsName
3664 // object that has a pointer to this
3665 // ResolvedNsName structure as its internal
3666 // rep. This structure can be freed when
3667 // refCount becomes zero.
3668 }
3669 static NamespaceCmd()
3670 {
3671 nsMutex = new System.Object();
3672 }
3673 }
3674 }