Source Code Cross Referenced for Namespace.java in  » Scripting » jacl » tcl » lang » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » jacl » tcl.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Namespace.java
0003:         *
0004:         * Copyright (c) 1993-1997 Lucent Technologies.
0005:         * Copyright (c) 1997 Sun Microsystems, Inc.
0006:         * Copyright (c) 1998-1999 by Scriptics Corporation.
0007:         * Copyright (c) 1999-2005 Moses DeJong
0008:         *
0009:         * Originally implemented by
0010:         *   Michael J. McLennan
0011:         *   Bell Labs Innovations for Lucent Technologies
0012:
0013:         *   mmclennan@lucent.com
0014:         *
0015:         * See the file "license.terms" for information on usage and
0016:         * redistribution of this file, and for a DISCLAIMER OF ALL
0017:         * WARRANTIES.
0018:         *
0019:         * RCS: @(#) $Id: Namespace.java,v 1.6 2006/01/26 19:49:18 mdejong Exp $
0020:         */
0021:
0022:        package tcl.lang;
0023:
0024:        import java.util.*;
0025:
0026:        // This structure contains a cached pointer to a namespace that is the
0027:        // result of resolving the namespace's name in some other namespace. It is
0028:        // the internal representation for a nsName object. It contains the
0029:        // pointer along with some information that is used to check the cached
0030:        // pointer's validity. (ported Tcl_Namespace to Namespace)
0031:
0032:        public class Namespace {
0033:            public String name; // The namespace's simple (unqualified)
0034:            // name. This contains no ::'s. The name of
0035:            // the global namespace is "" although "::"
0036:            // is an synonym.
0037:            public String fullName; // The namespace's fully qualified name.
0038:            // This starts with ::.
0039:            public DeleteProc deleteProc; // method to invoke when namespace is deleted
0040:
0041:            public Namespace parent; // reference to the namespace that contains
0042:            // this one. null is this is the global namespace.
0043:            public HashMap childTable; // Contains any child namespaces. Indexed
0044:            // by strings; values are references to
0045:            // Namespace objects
0046:            public long nsId; // Unique id for the namespace.
0047:
0048:            public Interp interp; // The interpreter containing this namespace.
0049:
0050:            public int flags; // OR-ed combination of the namespace
0051:            // status flags NS_DYING and NS_DEAD (listed below)
0052:
0053:            public int activationCount; // Number of "activations" or active call
0054:            // frames for this namespace that are on
0055:            // the Tcl call stack. The namespace won't
0056:            // be freed until activationCount becomes zero.
0057:
0058:            public int refCount; // Count of references by nsName
0059:            // objects. The namespace can't be freed
0060:            // until refCount becomes zero.
0061:
0062:            public HashMap cmdTable; // Contains all the commands currently
0063:            // registered in the namespace. Indexed by
0064:            // strings; values have type (WrappedCommand).
0065:            // Commands imported by Tcl_Import have
0066:            // Command structures that point (via an
0067:            // ImportedCmdRef structure) to the
0068:            // Command structure in the source
0069:            // namespace's command table.
0070:            public HashMap varTable; // Contains all the (global) variables
0071:            // currently in this namespace. Indexed
0072:            // by strings; values have type (Var).
0073:
0074:            public String[] exportArray; // Reference to an array of string patterns
0075:            // specifying which commands are exported.
0076:            // A pattern may include "string match"
0077:            // style wildcard characters to specify
0078:            // multiple commands; however, no namespace
0079:            // qualifiers are allowed. null if no
0080:            // export patterns are registered.
0081:
0082:            public int numExportPatterns; // Number of export patterns currently
0083:            // registered using "namespace export".
0084:
0085:            public int maxExportPatterns; // Mumber of export patterns for which
0086:            // space is currently allocated.
0087:
0088:            public Resolver resolver;
0089:
0090:            // If non-null, this object overrides the
0091:            // usual command and variable resolution
0092:            // mechanism in Tcl. This procedure is invoked
0093:            // within findCommand and findNamespaceVar to
0094:            // resolve all command and variable references
0095:            // within the namespace.
0096:
0097:            // When printing out a Namespace use the full namespace name string
0098:
0099:            public String toString() {
0100:                return fullName;
0101:            }
0102:
0103:            // This interface is used to provide a callback when a namespace is deleted
0104:            // (ported Tcl_NamespaceDeleteProc to Namespace.DeleteProc)
0105:
0106:            public static interface DeleteProc {
0107:                public void delete();
0108:            }
0109:
0110:            // (ported ResolvedNsName to Namespace.ResolvedNsName)
0111:
0112:            static class ResolvedNsName {
0113:                Namespace ns; // reference to namespace object
0114:                long nsId; // sPtr's unique namespace id. Used to
0115:                // verify that ns is still valid
0116:                // (e.g., it's possible that the namespace
0117:                // was deleted and a new one created at
0118:                // the same address).
0119:
0120:                Namespace refNs; // reference to the namespace containing the
0121:                // reference (not the namespace that
0122:                // contains the referenced namespace).
0123:                int refCount; // Reference count: 1 for each nsName
0124:                // object that has a pointer to this
0125:                // ResolvedNsName structure as its internal
0126:                // rep. This structure can be freed when
0127:                // refCount becomes zero.
0128:            }
0129:
0130:            // Flag passed to getNamespaceForQualName to indicate that it should
0131:            // search for a namespace rather than a command or variable inside a
0132:            // namespace. Note that this flag's value must not conflict with the values
0133:            // of TCL.GLOBAL_ONLY, TCL.NAMESPACE_ONLY, or CREATE_NS_IF_UNKNOWN.
0134:
0135:            public static final int FIND_ONLY_NS = 0x1000;
0136:
0137:            // Initial size of array of namespace refs - used in resetShadowedCmdRefs()
0138:
0139:            private static final int NUM_TRAIL_ELEMS = 5;
0140:
0141:            // Count of the number of namespaces created. This value is used as a
0142:            // unique id for each namespace.
0143:
0144:            private static long numNsCreated = 0;
0145:            private static Object nsMutex = new Object();
0146:
0147:            //
0148:            // Flags used to represent the status of a namespace:
0149:            //
0150:            // NS_DYING -	1 means deleteNamespace has been called to delete the
0151:            //		namespace but there are still active call frames on the Tcl
0152:            //		stack that refer to the namespace. When the last call frame
0153:            //		referring to it has been popped, it's variables and command
0154:            //		will be destroyed and it will be marked "dead" (NS_DEAD).
0155:            //		The namespace can no longer be looked up by name.
0156:            // NS_DEAD -	1 means deleteNamespace has been called to delete the
0157:            //		namespace and no call frames still refer to it. Its
0158:            //		variables and command have already been destroyed. This bit
0159:            //		allows the namespace resolution code to recognize that the
0160:            //		namespace is "deleted". When the last namespaceName object
0161:            //		in any byte code code unit that refers to the namespace has
0162:            //		been freed (i.e., when the namespace's refCount is 0), the
0163:            //		namespace's storage will be freed.
0164:
0165:            static final int NS_DYING = 0x01;
0166:            static final int NS_DEAD = 0x02;
0167:
0168:            // Flag passed to getNamespaceForQualName to have it create all namespace
0169:            // components of a namespace-qualified name that cannot be found. The new
0170:            // namespaces are created within their specified parent. Note that this
0171:            // flag's value must not conflict with the values of the flags
0172:            // TCL.GLOBAL_ONLY, TCL.NAMESPACE_ONLY, and FIND_ONLY_NS
0173:
0174:            public static final int CREATE_NS_IF_UNKNOWN = 0x800;
0175:
0176:            /*
0177:             *----------------------------------------------------------------------
0178:             *
0179:             * Tcl_GetCurrentNamespace -> getCurrentNamespace
0180:             *
0181:             *	Returns a reference to an interpreter's currently active namespace.
0182:             *
0183:             * Results:
0184:             *	Returns a reference to the interpreter's current namespace.
0185:             *
0186:             * Side effects:
0187:             *	None.
0188:             *
0189:             *----------------------------------------------------------------------
0190:             */
0191:
0192:            public static Namespace getCurrentNamespace(Interp interp) {
0193:                if (interp.varFrame != null) {
0194:                    return interp.varFrame.ns;
0195:                } else {
0196:                    return interp.globalNs;
0197:                }
0198:            }
0199:
0200:            /*
0201:             *----------------------------------------------------------------------
0202:             *
0203:             * Tcl_GetGlobalNamespace -> getGlobalNamespace
0204:             *
0205:             *	Returns a reference to an interpreter's global :: namespace.
0206:             *
0207:             * Results:
0208:             *	Returns a reference to the specified interpreter's global namespace.
0209:             *
0210:             * Side effects:
0211:             *	None.
0212:             *
0213:             *----------------------------------------------------------------------
0214:             */
0215:
0216:            public static Namespace getGlobalNamespace(Interp interp) {
0217:                return interp.globalNs;
0218:            }
0219:
0220:            /*
0221:             *----------------------------------------------------------------------
0222:             *
0223:             * Tcl_PushCallFrame -> pushCallFrame
0224:             *
0225:             *	Pushes a new call frame onto the interpreter's Tcl call stack.
0226:             *	Called when executing a Tcl procedure or a "namespace eval" or
0227:             *	"namespace inscope" command. 
0228:             *
0229:             * Results:
0230:             *  Returns if successful, raises TclException if something goes wrong.
0231:             *
0232:             * Side effects:
0233:             *	Modifies the interpreter's Tcl call stack.
0234:             *
0235:             *----------------------------------------------------------------------
0236:             */
0237:
0238:            public static void pushCallFrame(Interp interp, // Interpreter in which the new call frame
0239:                    // is to be pushed.
0240:                    CallFrame frame, // Points to a call frame object to
0241:                    // push. The call frame will be initialized
0242:                    // by this method. The caller can pop the frame
0243:                    // later with popCallFrame.
0244:                    Namespace namespace, // Points to the namespace in which the
0245:                    // interpreter's current namespace will
0246:                    // be used.
0247:                    boolean isProcCallFrame) // If true, the frame represents a
0248:            // called Tcl procedure and may have local
0249:            // vars. Vars will ordinarily be looked up
0250:            // in the frame. If new variables are
0251:            // created, they will be created in the
0252:            // frame. If false, the frame is for a
0253:            // "namespace eval" or "namespace inscope"
0254:            // command and var references are treated
0255:            // as references to namespace variables.
0256:            {
0257:                Namespace ns;
0258:
0259:                if (namespace == null) {
0260:                    ns = getCurrentNamespace(interp);
0261:                } else {
0262:                    ns = namespace;
0263:                    if ((ns.flags & NS_DEAD) != 0) {
0264:                        throw new TclRuntimeError(
0265:                                "Trying to push call frame for dead namespace");
0266:                    }
0267:                }
0268:
0269:                ns.activationCount++;
0270:                frame.ns = ns;
0271:                frame.isProcCallFrame = isProcCallFrame;
0272:                frame.objv = null;
0273:
0274:                frame.caller = interp.frame;
0275:                frame.callerVar = interp.varFrame;
0276:
0277:                if (interp.varFrame != null) {
0278:                    frame.level = (interp.varFrame.level + 1);
0279:                } else {
0280:                    frame.level = 1;
0281:                }
0282:
0283:                // FIXME : does Jacl need a procPtr in the CallFrame class?
0284:                //frame.procPtr = null; 	   // no called procedure
0285:
0286:                frame.varTable = null; // and no local variables
0287:
0288:                // Compiled locals are not part of Jacl's CallFrame
0289:
0290:                // Push the new call frame onto the interpreter's stack of procedure
0291:                // call frames making it the current frame.
0292:
0293:                interp.frame = frame;
0294:                interp.varFrame = frame;
0295:            }
0296:
0297:            /*
0298:             *----------------------------------------------------------------------
0299:             *
0300:             * Tcl_PopCallFrame -> popCallFrame
0301:             *
0302:             *	Removes a call frame from the Tcl call stack for the interpreter.
0303:             *	Called to remove a frame previously pushed by Tcl_PushCallFrame.
0304:             *
0305:             * Results:
0306:             *	None.
0307:             *
0308:             * Side effects:
0309:             *	Modifies the call stack of the interpreter. Resets various fields of
0310:             *	the popped call frame. If a namespace has been deleted and
0311:             *	has no more activations on the call stack, the namespace is
0312:             *	destroyed.
0313:             *
0314:             *----------------------------------------------------------------------
0315:             */
0316:
0317:            public static void popCallFrame(Interp interp) {
0318:                CallFrame frame = interp.frame;
0319:                int saveErrFlag;
0320:                Namespace ns;
0321:
0322:                // It's important to remove the call frame from the interpreter's stack
0323:                // of call frames before deleting local variables, so that traces
0324:                // invoked by the variable deletion don't see the partially-deleted
0325:                // frame.
0326:
0327:                interp.frame = frame.caller;
0328:                interp.varFrame = frame.callerVar;
0329:
0330:                // Delete the local variables. As a hack, we save then restore the
0331:                // ERR_IN_PROGRESS flag in the interpreter. The problem is that there
0332:                // could be unset traces on the variables, which cause scripts to be
0333:                // evaluated. This will clear the ERR_IN_PROGRESS flag, losing stack
0334:                // trace information if the procedure was exiting with an error. The
0335:                // code below preserves the flag. Unfortunately, that isn't really
0336:                // enough: we really should preserve the errorInfo variable too
0337:                // (otherwise a nested error in the trace script will trash errorInfo).
0338:                // What's really needed is a general-purpose mechanism for saving and
0339:                // restoring interpreter state.
0340:
0341:                saveErrFlag = (interp.flags & Parser.ERR_IN_PROGRESS);
0342:
0343:                if (frame.varTable != null) {
0344:                    Var.deleteVars(interp, frame.varTable);
0345:                    frame.varTable = null;
0346:                }
0347:
0348:                interp.flags |= saveErrFlag;
0349:
0350:                // Decrement the namespace's count of active call frames. If the
0351:                // namespace is "dying" and there are no more active call frames,
0352:                // call Tcl_DeleteNamespace to destroy it.
0353:
0354:                ns = frame.ns;
0355:                ns.activationCount--;
0356:                if (((ns.flags & NS_DYING) != 0) && (ns.activationCount == 0)) {
0357:                    deleteNamespace(ns);
0358:                }
0359:                frame.ns = null;
0360:            }
0361:
0362:            /*
0363:             *----------------------------------------------------------------------
0364:             *
0365:             * Tcl_CreateNamespace --
0366:             *
0367:             *	Creates a new namespace with the given name. If there is no
0368:             *	active namespace (i.e., the interpreter is being initialized),
0369:             *	the global :: namespace is created and returned.
0370:             *
0371:             * Results:
0372:             *	Returns a reference to the new namespace if successful. If the
0373:             *	namespace already exists or if another error occurs, this routine
0374:             *	returns null, along with an error message in the interpreter's
0375:             *	result object.
0376:             *
0377:             * Side effects:
0378:             *	If the name contains "::" qualifiers and a parent namespace does
0379:             *	not already exist, it is automatically created. 
0380:             *
0381:             *----------------------------------------------------------------------
0382:             */
0383:
0384:            public static Namespace createNamespace(Interp interp, // Interpreter in which a new namespace
0385:                    // is being created
0386:                    String name, // Name for the new namespace. May be a
0387:                    // qualified name with names of ancestor
0388:                    // namespaces separated by "::"s.
0389:                    DeleteProc deleteProc // Procedure called when namespace is deleted.
0390:            // null if no procedure should be called
0391:            ) {
0392:                Namespace ns, ancestor;
0393:                Namespace parent;
0394:                Namespace globalNs = getGlobalNamespace(interp);
0395:                String simpleName;
0396:                StringBuffer buffer1, buffer2;
0397:
0398:                // If there is no active namespace, the interpreter is being
0399:                // initialized. 
0400:
0401:                if ((globalNs == null) && (interp.varFrame == null)) {
0402:                    // Treat this namespace as the global namespace, and avoid
0403:                    // looking for a parent.
0404:
0405:                    parent = null;
0406:                    simpleName = "";
0407:                } else if (name.length() == 0) {
0408:                    /*
0409:                    TclObject tobj = interp.getResult();
0410:                    // FIXME : is there a test case to check this error result?
0411:                    TclString.append(tobj,
0412:                      "can't create namespace \"\": only global namespace can have empty name");
0413:                     */
0414:
0415:                    // FIXME : is there a test case to check this error result?
0416:                    interp
0417:                            .setResult("can't create namespace \"\": only global namespace can have empty name");
0418:                    return null;
0419:                } else {
0420:                    // Find the parent for the new namespace.
0421:
0422:                    GetNamespaceForQualNameResult gnfqnr = interp.getnfqnResult;
0423:                    getNamespaceForQualName(interp, name, null,
0424:                            (CREATE_NS_IF_UNKNOWN | TCL.LEAVE_ERR_MSG), gnfqnr);
0425:                    parent = gnfqnr.ns;
0426:                    simpleName = gnfqnr.simpleName;
0427:
0428:                    // If the unqualified name at the end is empty, there were trailing
0429:                    // "::"s after the namespace's name which we ignore. The new
0430:                    // namespace was already (recursively) created and is referenced
0431:                    // by parent.
0432:
0433:                    if (simpleName.length() == 0) {
0434:                        return parent;
0435:                    }
0436:
0437:                    // Check for a bad namespace name and make sure that the name
0438:                    // does not already exist in the parent namespace.
0439:
0440:                    if (parent.childTable.get(simpleName) != null) {
0441:                        /*
0442:                        TclObject tobj = interp.getResult();
0443:                        // FIXME : is there a test case to check this error result?
0444:                        TclString.append(tobj,
0445:                            "can't create namespace \"" + name + "\": already exists");
0446:                         */
0447:
0448:                        // FIXME : is there a test case to check this error result?
0449:                        interp.setResult("can't create namespace \"" + name
0450:                                + "\": already exists");
0451:                        return null;
0452:                    }
0453:                }
0454:
0455:                // Create the new namespace and root it in its parent. Increment the
0456:                // count of namespaces created.
0457:
0458:                ns = new Namespace();
0459:                ns.name = simpleName;
0460:                ns.fullName = null; // set below
0461:                //ns.clientData       = clientData;
0462:                ns.deleteProc = deleteProc;
0463:                ns.parent = parent;
0464:                ns.childTable = new HashMap();
0465:                synchronized (nsMutex) {
0466:                    numNsCreated++;
0467:                    ns.nsId = numNsCreated;
0468:                }
0469:                ns.interp = interp;
0470:                ns.flags = 0;
0471:                ns.activationCount = 0;
0472:                // FIXME : there was a problem with the refcount because
0473:                // when the namespace was deleted the refocount was 0.
0474:                // We avoid this by just using a refcount of 1 for now.
0475:                // We can do ignore the refCount because GC will reclaim mem.
0476:                //ns.refCount           = 0;
0477:                ns.refCount = 1;
0478:                ns.cmdTable = new HashMap();
0479:                ns.varTable = new HashMap();
0480:                ns.exportArray = null;
0481:                ns.numExportPatterns = 0;
0482:                ns.maxExportPatterns = 0;
0483:
0484:                // Jacl does not use these tcl compiler specific members
0485:                //ns.cmdRefEpoch        = 0;
0486:                //ns.resolverEpoch      = 0;
0487:
0488:                ns.resolver = null;
0489:
0490:                if (parent != null) {
0491:                    parent.childTable.put(simpleName, ns);
0492:                }
0493:
0494:                // Build the fully qualified name for this namespace.
0495:
0496:                buffer1 = new StringBuffer();
0497:                buffer2 = new StringBuffer();
0498:                for (ancestor = ns; ancestor != null; ancestor = ancestor.parent) {
0499:                    if (ancestor != globalNs) {
0500:                        buffer1.append("::");
0501:                        buffer1.append(ancestor.name);
0502:                    }
0503:                    buffer1.append(buffer2);
0504:
0505:                    buffer2.setLength(0);
0506:                    buffer2.append(buffer1);
0507:                    buffer1.setLength(0);
0508:                }
0509:
0510:                name = buffer2.toString();
0511:                ns.fullName = name;
0512:
0513:                // Return a reference to the new namespace.
0514:
0515:                return ns;
0516:            }
0517:
0518:            /*
0519:             *----------------------------------------------------------------------
0520:             *
0521:             * Tcl_DeleteNamespace -> deleteNamespace
0522:             *
0523:             *	Deletes a namespace and all of the commands, variables, and other
0524:             *	namespaces within it.
0525:             *
0526:             * Results:
0527:             *	None.
0528:             *
0529:             * Side effects:
0530:             *	When a namespace is deleted, it is automatically removed as a
0531:             *	child of its parent namespace. Also, all its commands, variables
0532:             *	and child namespaces are deleted.
0533:             *
0534:             *----------------------------------------------------------------------
0535:             */
0536:
0537:            public static void deleteNamespace(Namespace namespace) {
0538:                Namespace ns = namespace;
0539:                Interp interp = ns.interp;
0540:                Namespace globalNs = getGlobalNamespace(interp);
0541:
0542:                // If the namespace is on the call frame stack, it is marked as "dying"
0543:                // (NS_DYING is OR'd into its flags): the namespace can't be looked up
0544:                // by name but its commands and variables are still usable by those
0545:                // active call frames. When all active call frames referring to the
0546:                // namespace have been popped from the Tcl stack, popCallFrame will
0547:                // call this procedure again to delete everything in the namespace.
0548:                // If no nsName objects refer to the namespace (i.e., if its refCount 
0549:                // is zero), its commands and variables are deleted and the storage for
0550:                // its namespace structure is freed. Otherwise, if its refCount is
0551:                // nonzero, the namespace's commands and variables are deleted but the
0552:                // structure isn't freed. Instead, NS_DEAD is OR'd into the structure's
0553:                // flags to allow the namespace resolution code to recognize that the
0554:                // namespace is "deleted".
0555:
0556:                if (ns.activationCount > 0) {
0557:                    ns.flags |= NS_DYING;
0558:                    if (ns.parent != null) {
0559:                        ns.parent.childTable.remove(ns.name);
0560:                    }
0561:                    ns.parent = null;
0562:                } else {
0563:                    // Delete the namespace and everything in it. If this is the global
0564:                    // namespace, then clear it but don't free its storage unless the
0565:                    // interpreter is being torn down.
0566:
0567:                    teardownNamespace(ns);
0568:
0569:                    if ((ns != globalNs)
0570:                            || ((interp.flags & Parser.DELETED) != 0)) {
0571:                        // If this is the global namespace, then it may have residual
0572:                        // "errorInfo" and "errorCode" variables for errors that
0573:                        // occurred while it was being torn down.  Try to clear the
0574:                        // variable list one last time.
0575:
0576:                        Var.deleteVars(ns.interp, ns.varTable);
0577:
0578:                        ns.childTable.clear();
0579:                        ns.cmdTable.clear();
0580:
0581:                        // If the reference count is 0, then discard the namespace.
0582:                        // Otherwise, mark it as "dead" so that it can't be used.
0583:
0584:                        if (ns.refCount == 0) {
0585:                            free(ns);
0586:                        } else {
0587:                            ns.flags |= NS_DEAD;
0588:                        }
0589:                    }
0590:                }
0591:            }
0592:
0593:            /*
0594:             *----------------------------------------------------------------------
0595:             *
0596:             * TclTeardownNamespace -> teardownNamespace
0597:             *
0598:             *	Used internally to dismantle and unlink a namespace when it is
0599:             *	deleted. Divorces the namespace from its parent, and deletes all
0600:             *	commands, variables, and child namespaces.
0601:             *
0602:             *	This is kept separate from Tcl_DeleteNamespace so that the global
0603:             *	namespace can be handled specially. Global variables like
0604:             *	"errorInfo" and "errorCode" need to remain intact while other
0605:             *	namespaces and commands are torn down, in case any errors occur.
0606:             *
0607:             * Results:
0608:             *	None.
0609:             *
0610:             * Side effects:
0611:             *	Removes this namespace from its parent's child namespace hashtable.
0612:             *	Deletes all commands, variables and namespaces in this namespace.
0613:             *	If this is the global namespace, the "errorInfo" and "errorCode"
0614:             *	variables are left alone and deleted later.
0615:             *
0616:             *----------------------------------------------------------------------
0617:             */
0618:
0619:            static void teardownNamespace(Namespace ns) {
0620:                Interp interp = ns.interp;
0621:                Namespace childNs;
0622:                WrappedCommand cmd;
0623:                Namespace globalNs = getGlobalNamespace(interp);
0624:                int i;
0625:
0626:                // Start by destroying the namespace's variable table,
0627:                // since variables might trigger traces.
0628:
0629:                if (ns == globalNs) {
0630:                    // This is the global namespace, so be careful to preserve the
0631:                    // "errorInfo" and "errorCode" variables. These might be needed
0632:                    // later on if errors occur while deleting commands. We are careful
0633:                    // to destroy and recreate the "errorInfo" and "errorCode"
0634:                    // variables, in case they had any traces on them.
0635:
0636:                    String errorInfoStr, errorCodeStr;
0637:
0638:                    try {
0639:                        errorInfoStr = interp.getVar("errorInfo",
0640:                                TCL.GLOBAL_ONLY).toString();
0641:                    } catch (TclException e) {
0642:                        errorInfoStr = null;
0643:                    }
0644:
0645:                    try {
0646:                        errorCodeStr = interp.getVar("errorCode",
0647:                                TCL.GLOBAL_ONLY).toString();
0648:                    } catch (TclException e) {
0649:                        errorCodeStr = null;
0650:                    }
0651:
0652:                    Var.deleteVars(interp, ns.varTable);
0653:
0654:                    if (errorInfoStr != null) {
0655:                        try {
0656:                            interp.setVar("errorInfo", errorInfoStr,
0657:                                    TCL.GLOBAL_ONLY);
0658:                        } catch (TclException e) {
0659:                            // ignore an exception while setting this var
0660:                        }
0661:                    }
0662:                    if (errorCodeStr != null) {
0663:                        try {
0664:                            interp.setVar("errorCode", errorCodeStr,
0665:                                    TCL.GLOBAL_ONLY);
0666:                        } catch (TclException e) {
0667:                            // ignore an exception while setting this var
0668:                        }
0669:                    }
0670:                } else {
0671:                    // Variable table should be cleared.
0672:                    Var.deleteVars(interp, ns.varTable);
0673:                }
0674:
0675:                // Remove the namespace from its parent's child hashtable.
0676:
0677:                if (ns.parent != null) {
0678:                    ns.parent.childTable.remove(ns.name);
0679:                }
0680:                ns.parent = null;
0681:
0682:                // Delete all the child namespaces.
0683:                //
0684:                // BE CAREFUL: When each child is deleted, it will divorce
0685:                //    itself from its parent. You can't traverse a hash table
0686:                //    properly if its elements are being deleted. We use only
0687:                //    the Tcl_FirstHashEntry function to be safe.
0688:
0689:                while ((childNs = (Namespace) FirstHashEntry(ns.childTable)) != null) {
0690:                    deleteNamespace(childNs);
0691:                }
0692:
0693:                // Delete all commands in this namespace. Be careful when traversing the
0694:                // hash table: when each command is deleted, it removes itself from the
0695:                // command table.
0696:
0697:                while ((cmd = (WrappedCommand) FirstHashEntry(ns.cmdTable)) != null) {
0698:                    interp.deleteCommandFromToken(cmd);
0699:                }
0700:
0701:                // Free the namespace's export pattern array.
0702:
0703:                if (ns.exportArray != null) {
0704:                    ns.exportArray = null;
0705:                    ns.numExportPatterns = 0;
0706:                    ns.maxExportPatterns = 0;
0707:                }
0708:
0709:                // Callback invoked when namespace is deleted
0710:
0711:                if (ns.deleteProc != null) {
0712:                    ns.deleteProc.delete();
0713:                }
0714:                ns.deleteProc = null;
0715:
0716:                // Reset the namespace's id field to ensure that this namespace won't
0717:                // be interpreted as valid by, e.g., the cache validation code for
0718:                // cached command references in Tcl_GetCommandFromObj.
0719:
0720:                ns.nsId = 0;
0721:            }
0722:
0723:            /*
0724:             *----------------------------------------------------------------------
0725:             *
0726:             * NamespaceFree -> free
0727:             *
0728:             *	Called after a namespace has been deleted, when its
0729:             *	reference count reaches 0.  Frees the data structure
0730:             *	representing the namespace.
0731:             *
0732:             * Results:
0733:             *	None.
0734:             *
0735:             * Side effects:
0736:             *	None.
0737:             *
0738:             *----------------------------------------------------------------------
0739:             */
0740:
0741:            static void free(Namespace ns) {
0742:                // Most of the namespace's contents are freed when the namespace is
0743:                // deleted by Tcl_DeleteNamespace. All that remains is to free its names
0744:                // (for error messages), and the structure itself.
0745:
0746:                ns.name = null;
0747:                ns.fullName = null;
0748:            }
0749:
0750:            /*
0751:             *----------------------------------------------------------------------
0752:             *
0753:             * Tcl_Export -> exportList
0754:             *
0755:             *	Makes all the commands matching a pattern available to later be
0756:             *	imported from the namespace specified by namespace (or the
0757:             *	current namespace if namespace is null). The specified pattern is
0758:             *	appended onto the namespace's export pattern list, which is
0759:             *	optionally cleared beforehand.
0760:             *
0761:             * Results:
0762:             *  Returns if successful, raises TclException if something goes wrong.
0763:             *
0764:             * Side effects:
0765:             *	Appends the export pattern onto the namespace's export list.
0766:             *	Optionally reset the namespace's export pattern list.
0767:             *
0768:             *----------------------------------------------------------------------
0769:             */
0770:
0771:            public static void exportList(Interp interp, // current interpreter
0772:                    Namespace namespace, // Points to the namespace from which 
0773:                    // commands are to be exported. null for
0774:                    // the current namespace.
0775:                    String pattern, // String pattern indicating which commands
0776:                    // to export. This pattern may not include
0777:                    // any namespace qualifiers; only commands
0778:                    // in the specified namespace may be
0779:                    // exported.
0780:                    boolean resetListFirst // If true, resets the namespace's
0781:            // export list before appending 
0782:            // If false, return an error if an imported
0783:            // cmd conflicts
0784:            ) throws TclException {
0785:                final int INIT_EXPORT_PATTERNS = 5;
0786:                Namespace ns, exportNs;
0787:                Namespace currNs = getCurrentNamespace(interp);
0788:                String simplePattern, patternCpy;
0789:                int neededElems, len, i;
0790:
0791:                // If the specified namespace is null, use the current namespace.
0792:
0793:                if (namespace == null) {
0794:                    ns = currNs;
0795:                } else {
0796:                    ns = namespace;
0797:                }
0798:
0799:                // If resetListFirst is true (nonzero), clear the namespace's export
0800:                // pattern list.
0801:
0802:                if (resetListFirst) {
0803:                    if (ns.exportArray != null) {
0804:                        for (i = 0; i < ns.numExportPatterns; i++) {
0805:                            ns.exportArray[i] = null;
0806:                        }
0807:                        ns.exportArray = null;
0808:                        ns.numExportPatterns = 0;
0809:                        ns.maxExportPatterns = 0;
0810:                    }
0811:                }
0812:
0813:                // Check that the pattern doesn't have namespace qualifiers.
0814:
0815:                GetNamespaceForQualNameResult gnfqnr = interp.getnfqnResult;
0816:                getNamespaceForQualName(interp, pattern, ns, TCL.LEAVE_ERR_MSG,
0817:                        gnfqnr);
0818:                exportNs = gnfqnr.ns;
0819:                simplePattern = gnfqnr.simpleName;
0820:
0821:                if ((exportNs != ns) || (pattern.compareTo(simplePattern) != 0)) {
0822:                    throw new TclException(interp, "invalid export pattern \""
0823:                            + pattern + "\": pattern can't specify a namespace");
0824:                }
0825:
0826:                // Make sure there is room in the namespace's pattern array for the
0827:                // new pattern.
0828:
0829:                neededElems = ns.numExportPatterns + 1;
0830:                if (ns.exportArray == null) {
0831:                    ns.exportArray = new String[INIT_EXPORT_PATTERNS];
0832:                    ns.numExportPatterns = 0;
0833:                    ns.maxExportPatterns = INIT_EXPORT_PATTERNS;
0834:                } else if (neededElems > ns.maxExportPatterns) {
0835:                    int numNewElems = 2 * ns.maxExportPatterns;
0836:                    String[] newArray = new String[numNewElems];
0837:                    System.arraycopy(ns.exportArray, 0, newArray, 0,
0838:                            ns.numExportPatterns);
0839:                    ns.exportArray = newArray;
0840:                    ns.maxExportPatterns = numNewElems;
0841:                }
0842:
0843:                // Add the pattern to the namespace's array of export patterns.
0844:
0845:                ns.exportArray[ns.numExportPatterns] = pattern;
0846:                ns.numExportPatterns++;
0847:                return;
0848:            }
0849:
0850:            /*
0851:             *----------------------------------------------------------------------
0852:             *
0853:             * Tcl_AppendExportList -> appendExportList
0854:             *
0855:             *	Appends onto the argument object the list of export patterns for the
0856:             *	specified namespace.
0857:             *
0858:             * Results:
0859:             *	The method will return when successful; in this case the object
0860:             *	referenced by obj has each export pattern appended to it. If an
0861:             *	error occurs, an exception and the interpreter's result
0862:             *	holds an error message.
0863:             *
0864:             * Side effects:
0865:             *	If necessary, the object referenced by obj is converted into
0866:             *	a list object.
0867:             *
0868:             *----------------------------------------------------------------------
0869:             */
0870:
0871:            static void appendExportList(Interp interp, // Interpreter used for error reporting.
0872:                    Namespace namespace, // Points to the namespace whose export
0873:                    // pattern list is appended onto obj.
0874:                    // null for the current namespace.
0875:                    TclObject obj // Points to the Tcl object onto which the
0876:            // export pattern list is appended.
0877:            ) throws TclException {
0878:                Namespace ns;
0879:                int i;
0880:
0881:                // If the specified namespace is null, use the current namespace.
0882:
0883:                if (namespace == null) {
0884:                    ns = getCurrentNamespace(interp);
0885:                } else {
0886:                    ns = namespace;
0887:                }
0888:
0889:                // Append the export pattern list onto objPtr.
0890:
0891:                for (i = 0; i < ns.numExportPatterns; i++) {
0892:                    TclList.append(interp, obj, TclString
0893:                            .newInstance(ns.exportArray[i]));
0894:                }
0895:                return;
0896:            }
0897:
0898:            /*
0899:             *----------------------------------------------------------------------
0900:             *
0901:             * Tcl_Import -> importList
0902:             *
0903:             *	Imports all of the commands matching a pattern into the namespace
0904:             *	specified by namespace (or the current namespace if namespace
0905:             *	is null). This is done by creating a new command (the "imported
0906:             *	command") that points to the real command in its original namespace.
0907:             *
0908:             *      If matching commands are on the autoload path but haven't been
0909:             *	loaded yet, this command forces them to be loaded, then creates
0910:             *	the links to them.
0911:             *
0912:             * Results:
0913:             *  Returns if successful, raises TclException if something goes wrong.
0914:             *
0915:             * Side effects:
0916:             *	Creates new commands in the importing namespace. These indirect
0917:             *	calls back to the real command and are deleted if the real commands
0918:             *	are deleted.
0919:             *
0920:             *----------------------------------------------------------------------
0921:             */
0922:
0923:            public static void importList(Interp interp, // Current interpreter.
0924:                    Namespace namespace, // reference to the namespace into which the
0925:                    // commands are to be imported. null for
0926:                    // the current namespace.
0927:                    String pattern, // String pattern indicating which commands
0928:                    // to import. This pattern should be
0929:                    // qualified by the name of the namespace
0930:                    // from which to import the command(s).
0931:                    boolean allowOverwrite // If true, allow existing commands to
0932:            // be overwritten by imported commands.
0933:            // If 0, return an error if an imported
0934:            // cmd conflicts with an existing one.
0935:            ) throws TclException {
0936:                Namespace ns, importNs;
0937:                Namespace currNs = getCurrentNamespace(interp);
0938:                String simplePattern, cmdName;
0939:                WrappedCommand cmd, realCmd;
0940:                ImportRef ref;
0941:                WrappedCommand autoCmd, importedCmd;
0942:                ImportedCmdData data;
0943:                boolean wasExported;
0944:                int i, result;
0945:
0946:                // If the specified namespace is null, use the current namespace.
0947:
0948:                if (namespace == null) {
0949:                    ns = currNs;
0950:                } else {
0951:                    ns = namespace;
0952:                }
0953:
0954:                // First, invoke the "auto_import" command with the pattern
0955:                // being imported.  This command is part of the Tcl library.
0956:                // It looks for imported commands in autoloaded libraries and
0957:                // loads them in.  That way, they will be found when we try
0958:                // to create links below.
0959:
0960:                autoCmd = findCommand(interp, "auto_import", null,
0961:                        TCL.GLOBAL_ONLY);
0962:
0963:                if (autoCmd != null) {
0964:                    TclObject[] objv = new TclObject[2];
0965:
0966:                    objv[0] = TclString.newInstance("auto_import");
0967:                    objv[0].preserve();
0968:                    objv[1] = TclString.newInstance(pattern);
0969:                    objv[1].preserve();
0970:
0971:                    cmd = autoCmd;
0972:                    try {
0973:                        // Invoke the command with the arguments
0974:                        cmd.cmd.cmdProc(interp, objv);
0975:                    } finally {
0976:                        objv[0].release();
0977:                        objv[1].release();
0978:                    }
0979:
0980:                    interp.resetResult();
0981:                }
0982:
0983:                // From the pattern, find the namespace from which we are importing
0984:                // and get the simple pattern (no namespace qualifiers or ::'s) at
0985:                // the end.
0986:
0987:                if (pattern.length() == 0) {
0988:                    throw new TclException(interp, "empty import pattern");
0989:                }
0990:
0991:                GetNamespaceForQualNameResult gnfqnr = interp.getnfqnResult;
0992:                getNamespaceForQualName(interp, pattern, ns, TCL.LEAVE_ERR_MSG,
0993:                        gnfqnr);
0994:                importNs = gnfqnr.ns;
0995:                simplePattern = gnfqnr.simpleName;
0996:
0997:                if (importNs == null) {
0998:                    throw new TclException(interp,
0999:                            "unknown namespace in import pattern \"" + pattern
1000:                                    + "\"");
1001:                }
1002:                if (importNs == ns) {
1003:                    if (pattern == simplePattern) {
1004:                        throw new TclException(interp,
1005:                                "no namespace specified in import pattern \""
1006:                                        + pattern + "\"");
1007:                    } else {
1008:                        throw new TclException(interp, "import pattern \""
1009:                                + pattern
1010:                                + "\" tries to import from namespace \""
1011:                                + importNs.name + "\" into itself");
1012:                    }
1013:                }
1014:
1015:                // Scan through the command table in the source namespace and look for
1016:                // exported commands that match the string pattern. Create an "imported
1017:                // command" in the current namespace for each imported command; these
1018:                // commands redirect their invocations to the "real" command.
1019:
1020:                for (Iterator iter = importNs.cmdTable.entrySet().iterator(); iter
1021:                        .hasNext();) {
1022:                    Map.Entry entry = (Map.Entry) iter.next();
1023:                    cmdName = (String) entry.getKey();
1024:
1025:                    if (Util.stringMatch(cmdName, simplePattern)) {
1026:                        // The command cmdName in the source namespace matches the
1027:                        // pattern. Check whether it was exported. If it wasn't,
1028:                        // we ignore it.
1029:
1030:                        wasExported = false;
1031:                        for (i = 0; i < importNs.numExportPatterns; i++) {
1032:                            if (Util.stringMatch(cmdName,
1033:                                    importNs.exportArray[i])) {
1034:                                wasExported = true;
1035:                                break;
1036:                            }
1037:                        }
1038:                        if (!wasExported) {
1039:                            continue;
1040:                        }
1041:
1042:                        // Unless there is a name clash, create an imported command
1043:                        // in the current namespace that refers to cmdPtr.
1044:
1045:                        if ((ns.cmdTable.get(cmdName) == null)
1046:                                || allowOverwrite) {
1047:                            // Create the imported command and its client data.
1048:                            // To create the new command in the current namespace, 
1049:                            // generate a fully qualified name for it.
1050:
1051:                            StringBuffer ds;
1052:
1053:                            ds = new StringBuffer();
1054:                            ds.append(ns.fullName);
1055:                            if (ns != interp.globalNs) {
1056:                                ds.append("::");
1057:                            }
1058:                            ds.append(cmdName);
1059:
1060:                            // Check whether creating the new imported command in the
1061:                            // current namespace would create a cycle of imported->real
1062:                            // command references that also would destroy an existing
1063:                            // "real" command already in the current namespace.
1064:
1065:                            cmd = (WrappedCommand) importNs.cmdTable
1066:                                    .get(cmdName);
1067:
1068:                            if (cmd.cmd instanceof  ImportedCmdData) {
1069:                                // This is actually an imported command, find
1070:                                // the real command it references
1071:                                realCmd = getOriginalCommand(cmd);
1072:                                if ((realCmd != null)
1073:                                        && (realCmd.ns == currNs)
1074:                                        && (currNs.cmdTable.get(cmdName) != null)) {
1075:                                    throw new TclException(
1076:                                            interp,
1077:                                            "import pattern \""
1078:                                                    + pattern
1079:                                                    + "\" would create a loop containing command \""
1080:                                                    + ds.toString() + "\"");
1081:                                }
1082:                            }
1083:
1084:                            data = new ImportedCmdData();
1085:
1086:                            // Create the imported command inside the interp
1087:                            interp.createCommand(ds.toString(), data);
1088:
1089:                            // Lookup in the namespace for the new WrappedCommand
1090:                            importedCmd = findCommand(interp, ds.toString(),
1091:                                    ns,
1092:                                    (TCL.NAMESPACE_ONLY | TCL.LEAVE_ERR_MSG));
1093:
1094:                            data.realCmd = cmd;
1095:                            data.self = importedCmd;
1096:
1097:                            // Create an ImportRef structure describing this new import
1098:                            // command and add it to the import ref list in the "real"
1099:                            // command.
1100:
1101:                            ref = new ImportRef();
1102:                            ref.importedCmd = importedCmd;
1103:                            ref.next = cmd.importRef;
1104:                            cmd.importRef = ref;
1105:                        } else {
1106:                            throw new TclException(interp,
1107:                                    "can't import command \"" + cmdName
1108:                                            + "\": already exists");
1109:                        }
1110:                    }
1111:                }
1112:                return;
1113:            }
1114:
1115:            /*
1116:             *----------------------------------------------------------------------
1117:             *
1118:             * Tcl_ForgetImport -> forgetImport
1119:             *
1120:             *	Deletes previously imported commands. Given a pattern that may
1121:             *	include the name of an exporting namespace, this procedure first
1122:             *	finds all matching exported commands. It then looks in the namespace
1123:             *	specified by namespace for any corresponding previously imported
1124:             *	commands, which it deletes. If namespace is null, commands are
1125:             *	deleted from the current namespace.
1126:             *
1127:             * Results:
1128:             *  Returns if successful, raises TclException if something goes wrong.
1129:             *
1130:             * Side effects:
1131:             *	May delete commands. 
1132:             *
1133:             *----------------------------------------------------------------------
1134:             */
1135:
1136:            static void forgetImport(Interp interp, // Current interpreter.
1137:                    Namespace namespace, // Points to the namespace from which
1138:                    // previously imported commands should be
1139:                    // removed. null for current namespace.
1140:                    String pattern // String pattern indicating which imported
1141:            // commands to remove. This pattern should
1142:            // be qualified by the name of the
1143:            // namespace from which the command(s) were
1144:            // imported.
1145:            ) throws TclException {
1146:                Namespace ns, importNs, actualCtx;
1147:                String simplePattern, cmdName;
1148:                WrappedCommand cmd;
1149:
1150:                // If the specified namespace is null, use the current namespace.
1151:
1152:                if (namespace == null) {
1153:                    ns = getCurrentNamespace(interp);
1154:                } else {
1155:                    ns = namespace;
1156:                }
1157:
1158:                // From the pattern, find the namespace from which we are importing
1159:                // and get the simple pattern (no namespace qualifiers or ::'s) at
1160:                // the end.
1161:
1162:                GetNamespaceForQualNameResult gnfqnr = interp.getnfqnResult;
1163:                getNamespaceForQualName(interp, pattern, ns, TCL.LEAVE_ERR_MSG,
1164:                        gnfqnr);
1165:                importNs = gnfqnr.ns;
1166:                actualCtx = gnfqnr.actualCxt;
1167:                simplePattern = gnfqnr.simpleName;
1168:
1169:                // FIXME : the above call passes TCL.LEAVE_ERR_MSG, but
1170:                // it seems like this will be a problem when exception is raised!
1171:                if (importNs == null) {
1172:                    throw new TclException(interp,
1173:                            "unknown namespace in namespace forget pattern \""
1174:                                    + pattern + "\"");
1175:                }
1176:
1177:                // Scan through the command table in the source namespace and look for
1178:                // exported commands that match the string pattern. If the current
1179:                // namespace has an imported command that refers to one of those real
1180:                // commands, delete it. The importNs.cmdTable should not change during
1181:                // this iteration.
1182:
1183:                for (Iterator iter = importNs.cmdTable.entrySet().iterator(); iter
1184:                        .hasNext();) {
1185:                    Map.Entry entry = (Map.Entry) iter.next();
1186:                    cmdName = (String) entry.getKey();
1187:
1188:                    if (Util.stringMatch(cmdName, simplePattern)) {
1189:                        cmd = (WrappedCommand) ns.cmdTable.get(cmdName);
1190:                        if (cmd != null) { // cmd of same name in current namespace
1191:                            if (cmd.cmd instanceof  ImportedCmdData) {
1192:                                interp.deleteCommandFromToken(cmd);
1193:                            }
1194:                        }
1195:                    }
1196:                }
1197:                return;
1198:            }
1199:
1200:            /*
1201:             *----------------------------------------------------------------------
1202:             *
1203:             * TclGetOriginalCommand -> getOriginalCommand
1204:             *
1205:             *	An imported command is created in a namespace when a "real" command
1206:             *	is imported from another namespace. If the specified command is an
1207:             *	imported command, this procedure returns the original command it
1208:             *	refers to.
1209:             *
1210:             * Results:
1211:             *	If the command was imported into a sequence of namespaces a, b,...,n
1212:             *	where each successive namespace just imports the command from the
1213:             *	previous namespace, this procedure returns the Tcl_Command token in
1214:             *	the first namespace, a. Otherwise, if the specified command is not
1215:             *	an imported command, the procedure returns null.
1216:             *
1217:             * Side effects:
1218:             *	None.
1219:             *
1220:             *----------------------------------------------------------------------
1221:             */
1222:
1223:            public static WrappedCommand getOriginalCommand(
1224:                    WrappedCommand command // The imported command for which the original
1225:            // command should be returned.
1226:            ) {
1227:                WrappedCommand cmd = command;
1228:                ImportedCmdData data;
1229:
1230:                if (!(cmd.cmd instanceof  ImportedCmdData)) {
1231:                    return null;
1232:                }
1233:
1234:                while (cmd.cmd instanceof  ImportedCmdData) {
1235:                    data = (ImportedCmdData) cmd.cmd;
1236:                    cmd = data.realCmd;
1237:                }
1238:                return cmd;
1239:            }
1240:
1241:            /*
1242:             *----------------------------------------------------------------------
1243:             *
1244:             * InvokeImportedCmd -> invokeImportedCmd
1245:             *
1246:             *	Invoked by Tcl whenever the user calls an imported command that
1247:             *	was created by Tcl_Import. Finds the "real" command (in another
1248:             *	namespace), and passes control to it.
1249:             *
1250:             * Results:
1251:             *	Returns if successful, raises TclException if something goes wrong.
1252:             *
1253:             * Side effects:
1254:             *	Returns a result in the interpreter's result object. If anything
1255:             *	goes wrong, the result object is set to an error message.
1256:             *
1257:             *----------------------------------------------------------------------
1258:             */
1259:
1260:            static void invokeImportedCmd(Interp interp, // Current interpreter.
1261:                    ImportedCmdData data, // The data object for this imported command
1262:                    TclObject[] objv // Argument objects
1263:            ) throws TclException {
1264:                WrappedCommand realCmd = data.realCmd;
1265:                realCmd.cmd.cmdProc(interp, objv);
1266:            }
1267:
1268:            /*
1269:             *----------------------------------------------------------------------
1270:             *
1271:             * DeleteImportedCmd -> deleteImportedCmd
1272:             *
1273:             *	Invoked by Tcl whenever an imported command is deleted. The "real"
1274:             *	command keeps a list of all the imported commands that refer to it,
1275:             *	so those imported commands can be deleted when the real command is
1276:             *	deleted. This procedure removes the imported command reference from
1277:             *	the real command's list, and frees up the memory associated with
1278:             *	the imported command.
1279:             *
1280:             * Results:
1281:             *	None.
1282:             *
1283:             * Side effects:
1284:             *	Removes the imported command from the real command's import list.
1285:             *
1286:             *----------------------------------------------------------------------
1287:             */
1288:
1289:            static void deleteImportedCmd(ImportedCmdData data) // The data object for this imported command
1290:            {
1291:                WrappedCommand realCmd = data.realCmd;
1292:                WrappedCommand self = data.self;
1293:                ImportRef ref, prev;
1294:
1295:                prev = null;
1296:                for (ref = realCmd.importRef; ref != null; ref = ref.next) {
1297:                    if (ref.importedCmd == self) {
1298:                        // Remove ref from real command's list of imported commands
1299:                        // that refer to it.
1300:
1301:                        if (prev == null) { // ref is first in list
1302:                            realCmd.importRef = ref.next;
1303:                        } else {
1304:                            prev.next = ref.next;
1305:                        }
1306:                        ref = null;
1307:                        data = null;
1308:                        return;
1309:                    }
1310:                    prev = ref;
1311:                }
1312:
1313:                throw new TclRuntimeError(
1314:                        "DeleteImportedCmd: did not find cmd in real cmd's list of import references");
1315:            }
1316:
1317:            /*
1318:             *----------------------------------------------------------------------
1319:             *
1320:             * TclGetNamespaceForQualName -> getNamespaceForQualName
1321:             *
1322:             *	Given a qualified name specifying a command, variable, or namespace,
1323:             *	and a namespace in which to resolve the name, this procedure returns
1324:             *	a pointer to the namespace that contains the item. A qualified name
1325:             *	consists of the "simple" name of an item qualified by the names of
1326:             *	an arbitrary number of containing namespace separated by "::"s. If
1327:             *	the qualified name starts with "::", it is interpreted absolutely
1328:             *	from the global namespace. Otherwise, it is interpreted relative to
1329:             *	the namespace specified by cxtNs if it is non-null. If cxtNs
1330:             *	is null, the name is interpreted relative to the current namespace.
1331:             *
1332:             *	A relative name like "foo::bar::x" can be found starting in either
1333:             *	the current namespace or in the global namespace. So each search
1334:             *	usually follows two tracks, and two possible namespaces are
1335:             *	returned. If the procedure sets either gnfqnr.ns or gnfqnr.altNs to
1336:             *	null, then that path failed.
1337:             *
1338:             *	If "flags" contains TCL.GLOBAL_ONLY, the relative qualified name is
1339:             *	sought only in the global :: namespace. The alternate search
1340:             *	(also) starting from the global namespace is ignored and
1341:             *	gnfqnr.altNs is set null. 
1342:             *
1343:             *	If "flags" contains TCL.NAMESPACE_ONLY, the relative qualified
1344:             *	name is sought only in the namespace specified by cxtNs. The
1345:             *	alternate search starting from the global namespace is ignored and
1346:             *	gnfqnr.altNs is set null. If both TCL.GLOBAL_ONLY and
1347:             *	TCL.NAMESPACE_ONLY are specified, TCL.GLOBAL_ONLY is ignored and
1348:             *	the search starts from the namespace specified by cxtNs.
1349:             *
1350:             *	If "flags" contains CREATE_NS_IF_UNKNOWN, all namespace
1351:             *	components of the qualified name that cannot be found are
1352:             *	automatically created within their specified parent. This makes sure
1353:             *	that functions like Tcl_CreateCommand always succeed. There is no
1354:             *	alternate search path, so gnfqnr.altNs is set null.
1355:             *
1356:             *	If "flags" contains FIND_ONLY_NS, the qualified name is treated as a
1357:             *	reference to a namespace, and the entire qualified name is
1358:             *	followed. If the name is relative, the namespace is looked up only
1359:             *	in the current namespace. A pointer to the namespace is stored in
1360:             *	gnfqnr.ns and null is stored in gnfqnr.simpleName. Otherwise, if
1361:             *	FIND_ONLY_NS is not specified, only the leading components are
1362:             *	treated as namespace names, and a pointer to the simple name of the
1363:             *	final component is stored in gnfqnr.simpleName.
1364:             *
1365:             * Results:
1366:             *	It sets gnfqnr.ns and gnfqnr.altNs to point to the two possible
1367:             *	namespaces which represent the last (containing) namespace in the
1368:             *	qualified name. If the procedure sets either gnfqnr.ns or gnfqnr.altNs
1369:             *	to null, then the search along that path failed.  The procedure also
1370:             *	stores a pointer to the simple name of the final component in
1371:             *	gnfqnr.simpleName. If the qualified name is "::" or was treated as a
1372:             *	namespace reference (FIND_ONLY_NS), the procedure stores a pointer
1373:             *	to the namespace in gnfqnr.ns, null in gnfqnr.altNs, and sets
1374:             *	gnfqnr.simpleName to an empty string.
1375:             *
1376:             *	If there is an error, this procedure returns TCL_ERROR. If "flags"
1377:             *	contains TCL_LEAVE_ERR_MSG, an error message is returned in the
1378:             *	interpreter's result object. Otherwise, the interpreter's result
1379:             *	object is left unchanged.
1380:             *
1381:             *	gnfqnr.actualCxt is set to the actual context namespace. It is
1382:             *	set to the input context namespace pointer in cxtNs. If cxtNs
1383:             *	is null, it is set to the current namespace context. Note that
1384:             *	the GetNamespaceForQualNameResult result object is defined below.
1385:             *
1386:             * Side effects:
1387:             *	If "flags" contains CREATE_NS_IF_UNKNOWN, new namespaces may be
1388:             *	created.
1389:             *
1390:             *----------------------------------------------------------------------
1391:             */
1392:
1393:            static class GetNamespaceForQualNameResult {
1394:                Namespace ns;
1395:                Namespace altNs;
1396:                Namespace actualCxt;
1397:                String simpleName;
1398:            }
1399:
1400:            static void getNamespaceForQualName(Interp interp, // Interpreter in which to find the
1401:                    // namespace containing qualName.
1402:                    String qualName, // A namespace-qualified name of an
1403:                    // command, variable, or namespace.
1404:                    Namespace cxtNs, // The namespace in which to start the
1405:                    // search for qualName's namespace. If null
1406:                    // start from the current namespace.
1407:                    // Ignored if TCL.GLOBAL_ONLY is set.
1408:                    int flags, // Flags controlling the search: an OR'd
1409:                    // combination of TCL.GLOBAL_ONLY,
1410:                    // TCL.NAMESPACE_ONLY,
1411:                    // CREATE_NS_IF_UNKNOWN, and
1412:                    // FIND_ONLY_NS.
1413:                    GetNamespaceForQualNameResult gnfqnr)
1414:
1415:            // gnfqnr.ns                 // Where this procedure stores a pointer
1416:            // to containing namespace if qualName is
1417:            // found starting from cxtNs or, if
1418:            // TCL_GLOBAL_ONLY is set, if qualName is
1419:            // found in the global :: namespace. null
1420:            // is stored otherwise. This is an array
1421:            // of length 1, value is stored at index 0
1422:            // gnfqnr.altNs              // Where this procedure stores a pointer
1423:            // to containing namespace if qualName is
1424:            // found starting from the global ::
1425:            // namespace. null is stored if qualName
1426:            // isn't found starting from :: or if the
1427:            // TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
1428:            // CREATE_NS_IF_UNKNOWN, FIND_ONLY_NS flag
1429:            // is set. This is an array of length 1.
1430:            // The value is stored at index 0
1431:            // gnfqnr.actualCxt          // Address where procedure stores a pointer
1432:            // to the actual namespace from which the
1433:            // search started. This is either cxtNs,
1434:            // the :: namespace if TCL_GLOBAL_ONLY was
1435:            // specified, or the current namespace if
1436:            // cxtNs was null. This is an array of
1437:            // length 1. The value is stored at index 0.
1438:            // gnfqnr.simpleName	     // Where this procedure stores the
1439:            // simple name at end of the qualName, or
1440:            // null if qualName is "::" or the flag
1441:            // FIND_ONLY_NS was specified. This is an
1442:            // array of length 1, with value at index 0
1443:            {
1444:                gnfqnr.ns = null;
1445:                gnfqnr.altNs = null;
1446:                gnfqnr.actualCxt = null;
1447:                gnfqnr.simpleName = null;
1448:
1449:                Namespace ns = cxtNs;
1450:                Namespace altNs;
1451:                Namespace globalNs = getGlobalNamespace(interp);
1452:                Namespace entryNs;
1453:                String start, end;
1454:                String nsName;
1455:                int len;
1456:                int start_ind, end_ind, name_len;
1457:
1458:                // Determine the context namespace ns in which to start the primary
1459:                // search.  If the qualName name starts with a "::" or TCL_GLOBAL_ONLY
1460:                // was specified, search from the global namespace. Otherwise, use the
1461:                // namespace given in cxtNs, or if that is null, use the current
1462:                // namespace context. Note that we always treat two or more
1463:                // adjacent ":"s as a namespace separator.
1464:
1465:                if ((flags & TCL.GLOBAL_ONLY) != 0) {
1466:                    ns = globalNs;
1467:                } else if (ns == null) {
1468:                    if (interp.varFrame != null) {
1469:                        ns = interp.varFrame.ns;
1470:                    } else {
1471:                        ns = interp.globalNs;
1472:                    }
1473:                }
1474:
1475:                start_ind = 0;
1476:                name_len = qualName.length();
1477:
1478:                if ((name_len >= 2) && (qualName.charAt(0) == ':')
1479:                        && (qualName.charAt(1) == ':')) {
1480:                    start_ind = 2; // skip over the initial ::
1481:
1482:                    while ((start_ind < name_len)
1483:                            && (qualName.charAt(start_ind) == ':')) {
1484:                        start_ind++; // skip over a subsequent :
1485:                    }
1486:
1487:                    ns = globalNs;
1488:                    if (start_ind >= name_len) { // qualName is just two or more ":"s
1489:                        gnfqnr.ns = globalNs;
1490:                        gnfqnr.altNs = null;
1491:                        gnfqnr.actualCxt = globalNs;
1492:                        gnfqnr.simpleName = "";
1493:                        return;
1494:                    }
1495:                }
1496:                gnfqnr.actualCxt = ns;
1497:
1498:                // Start an alternate search path starting with the global namespace.
1499:                // However, if the starting context is the global namespace, or if the
1500:                // flag is set to search only the namespace cxtNs, ignore the
1501:                // alternate search path.
1502:
1503:                altNs = globalNs;
1504:                if ((ns == globalNs)
1505:                        || ((flags & (TCL.NAMESPACE_ONLY | FIND_ONLY_NS)) != 0)) {
1506:                    altNs = null;
1507:                }
1508:
1509:                // Loop to resolve each namespace qualifier in qualName.	
1510:
1511:                end_ind = start_ind;
1512:
1513:                while (start_ind < name_len) {
1514:                    // Find the next namespace qualifier (i.e., a name ending in "::")
1515:                    // or the end of the qualified name  (i.e., a name ending in "\0").
1516:                    // Set len to the number of characters, starting from start,
1517:                    // in the name; set end to point after the "::"s or at the "\0".
1518:
1519:                    len = 0;
1520:                    for (end_ind = start_ind; end_ind < name_len; end_ind++) {
1521:                        if (((name_len - end_ind) > 1)
1522:                                && (qualName.charAt(end_ind) == ':')
1523:                                && (qualName.charAt(end_ind + 1) == ':')) {
1524:                            end_ind += 2; // skip over the initial ::
1525:                            while ((end_ind < name_len)
1526:                                    && (qualName.charAt(end_ind) == ':')) {
1527:                                end_ind++; // skip over a subsequent :
1528:                            }
1529:                            break;
1530:                        }
1531:                        len++;
1532:                    }
1533:
1534:                    if ((end_ind == name_len)
1535:                            && !((end_ind - start_ind >= 2) && ((qualName
1536:                                    .charAt(end_ind - 1) == ':') && (qualName
1537:                                    .charAt(end_ind - 2) == ':')))) {
1538:
1539:                        // qualName ended with a simple name at start. If FIND_ONLY_NS
1540:                        // was specified, look this up as a namespace. Otherwise,
1541:                        // start is the name of a cmd or var and we are done.
1542:
1543:                        if ((flags & FIND_ONLY_NS) != 0) {
1544:                            // assign the string from start_ind to the end of the name string
1545:                            nsName = qualName.substring(start_ind);
1546:                        } else {
1547:                            gnfqnr.ns = ns;
1548:                            gnfqnr.altNs = altNs;
1549:                            gnfqnr.simpleName = qualName.substring(start_ind);
1550:                            return;
1551:                        }
1552:                    } else {
1553:                        // start points to the beginning of a namespace qualifier ending
1554:                        // in "::". Create new string with the namespace qualifier.
1555:
1556:                        nsName = qualName.substring(start_ind, start_ind + len);
1557:                    }
1558:
1559:                    // Look up the namespace qualifier nsName in the current namespace
1560:                    // context. If it isn't found but CREATE_NS_IF_UNKNOWN is set,
1561:                    // create that qualifying namespace. This is needed for procedures
1562:                    // like Tcl_CreateCommand that cannot fail.
1563:
1564:                    if (ns != null) {
1565:                        entryNs = (Namespace) ns.childTable.get(nsName);
1566:                        if (entryNs != null) {
1567:                            ns = entryNs;
1568:                        } else if ((flags & CREATE_NS_IF_UNKNOWN) != 0) {
1569:                            CallFrame frame = interp.newCallFrame();
1570:
1571:                            pushCallFrame(interp, frame, ns, false);
1572:                            ns = createNamespace(interp, nsName, null);
1573:
1574:                            popCallFrame(interp);
1575:                            if (ns == null) {
1576:                                throw new RuntimeException(
1577:                                        "Could not create namespace " + nsName);
1578:                            }
1579:                        } else {
1580:                            ns = null; // namespace not found and wasn't created
1581:                        }
1582:                    }
1583:
1584:                    // Look up the namespace qualifier in the alternate search path too.
1585:
1586:                    if (altNs != null) {
1587:                        altNs = (Namespace) altNs.childTable.get(nsName);
1588:                    }
1589:
1590:                    // If both search paths have failed, return null results.
1591:
1592:                    if ((ns == null) && (altNs == null)) {
1593:                        gnfqnr.ns = null;
1594:                        gnfqnr.altNs = null;
1595:                        gnfqnr.simpleName = null;
1596:                        return;
1597:                    }
1598:
1599:                    start_ind = end_ind;
1600:                }
1601:
1602:                // We ignore trailing "::"s in a namespace name, but in a command or
1603:                // variable name, trailing "::"s refer to the cmd or var named {}.
1604:
1605:                if (((flags & FIND_ONLY_NS) != 0)
1606:                        || ((end_ind > start_ind) && (qualName
1607:                                .charAt(end_ind - 1) != ':'))) {
1608:                    gnfqnr.simpleName = null; // found namespace name
1609:                } else {
1610:                    // FIXME : make sure this does not throw exception when end_ind is at the end of the string 
1611:                    gnfqnr.simpleName = qualName.substring(end_ind); // found cmd/var: points to empty string
1612:                }
1613:
1614:                // As a special case, if we are looking for a namespace and qualName
1615:                // is "" and the current active namespace (ns) is not the global
1616:                // namespace, return null (no namespace was found). This is because
1617:                // namespaces can not have empty names except for the global namespace.
1618:
1619:                if (((flags & FIND_ONLY_NS) != 0) && (name_len == 0)
1620:                        && (ns != globalNs)) {
1621:                    ns = null;
1622:                }
1623:
1624:                gnfqnr.ns = ns;
1625:                gnfqnr.altNs = altNs;
1626:                return;
1627:            }
1628:
1629:            /*
1630:             *----------------------------------------------------------------------
1631:             *
1632:             * Tcl_FindNamespace -> findNamespace
1633:             *
1634:             *	Searches for a namespace.
1635:             *
1636:             * Results:
1637:             *	Returns a reference to the namespace if it is found. Otherwise,
1638:             *	returns null and leaves an error message in the interpreter's
1639:             *	result object if "flags" contains TCL.LEAVE_ERR_MSG.
1640:             *
1641:             * Side effects:
1642:             *	None.
1643:             *
1644:             *----------------------------------------------------------------------
1645:             */
1646:
1647:            public static Namespace findNamespace(Interp interp, // The interpreter in which to find the
1648:                    // namespace.
1649:                    String name, // Namespace name. If it starts with "::",
1650:                    // will be looked up in global namespace.
1651:                    // Else, looked up first in contextNs
1652:                    // (current namespace if contextNs is
1653:                    // null), then in global namespace.
1654:                    Namespace contextNs, // Ignored if TCL.GLOBAL_ONLY flag is set
1655:                    // or if the name starts with "::".
1656:                    // Otherwise, points to namespace in which
1657:                    // to resolve name; if null, look up name
1658:                    // in the current namespace.
1659:                    int flags) // Flags controlling namespace lookup: an
1660:            // OR'd combination of TCL.GLOBAL_ONLY and
1661:            // TCL.LEAVE_ERR_MSG flags.
1662:            {
1663:                Namespace ns;
1664:
1665:                // Find the namespace(s) that contain the specified namespace name.
1666:                // Add the FIND_ONLY_NS flag to resolve the name all the way down
1667:                // to its last component, a namespace.
1668:
1669:                GetNamespaceForQualNameResult gnfqnr = interp.getnfqnResult;
1670:                getNamespaceForQualName(interp, name, contextNs,
1671:                        (flags | FIND_ONLY_NS), gnfqnr);
1672:                ns = gnfqnr.ns;
1673:
1674:                if (ns != null) {
1675:                    return ns;
1676:                } else if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
1677:                    /*
1678:                    interp.resetResult();
1679:                    TclString.append(interp.getResult(), "unknown namespace \"" + name + "\"");
1680:                     */
1681:
1682:                    // FIXME : is there a test case for this error?
1683:                    interp.setResult("unknown namespace \"" + name + "\"");
1684:                }
1685:                return null;
1686:            }
1687:
1688:            /*
1689:             *----------------------------------------------------------------------
1690:             *
1691:             * Tcl_FindCommand -> findCommand
1692:             *
1693:             *	Searches for a command.
1694:             *
1695:             * Results:
1696:             *	Returns a token for the command if it is found. Otherwise, if it
1697:             *	can't be found or there is an error, returns null and leaves an
1698:             *	error message in the interpreter's result object if "flags"
1699:             *	contains TCL.LEAVE_ERR_MSG.
1700:             *
1701:             * Side effects:
1702:             *	None.
1703:             *
1704:             *----------------------------------------------------------------------
1705:             */
1706:
1707:            public static WrappedCommand findCommand(Interp interp, // The interpreter in which to find the
1708:                    // command.
1709:                    String name, // Command's name. If it starts with "::",
1710:                    // will be looked up in global namespace.
1711:                    // Else, looked up first in contextNs
1712:                    // (current namespace if contextNs is
1713:                    // null), then in global namespace.
1714:                    Namespace contextNs, // Ignored if TCL.GLOBAL_ONLY flag set.
1715:                    // Otherwise, points to namespace in which
1716:                    // to resolve name. If null, look up name
1717:                    // in the current namespace.
1718:                    int flags // An OR'd combination of flags:
1719:            // TCL.GLOBAL_ONLY (look up name only in
1720:            // global namespace), TCL.NAMESPACE_ONLY
1721:            // (look up only in contextNs, or the
1722:            // current namespace if contextNs is
1723:            // null), and TCL.LEAVE_ERR_MSG. If both
1724:            // TCL.GLOBAL_ONLY and TCL.NAMESPACE_ONLY
1725:            // are given, TCL.GLOBAL_ONLY is ignored.
1726:            ) throws TclException {
1727:                Interp.ResolverScheme res;
1728:                Namespace cxtNs;
1729:                Namespace ns0, ns1;
1730:                String simpleName;
1731:                int search;
1732:                WrappedCommand cmd;
1733:
1734:                // If this namespace has a command resolver, then give it first
1735:                // crack at the command resolution.  If the interpreter has any
1736:                // command resolvers, consult them next.  The command resolver
1737:                // procedures may return a Tcl_Command value, they may signal
1738:                // to continue onward, or they may signal an error.
1739:
1740:                if ((flags & TCL.GLOBAL_ONLY) != 0) {
1741:                    cxtNs = getGlobalNamespace(interp);
1742:                } else if (contextNs != null) {
1743:                    cxtNs = contextNs;
1744:                } else {
1745:                    cxtNs = getCurrentNamespace(interp);
1746:                }
1747:
1748:                if (cxtNs.resolver != null || interp.resolvers != null) {
1749:                    try {
1750:                        if (cxtNs.resolver != null) {
1751:                            cmd = cxtNs.resolver.resolveCmd(interp, name,
1752:                                    cxtNs, flags);
1753:                        } else {
1754:                            cmd = null;
1755:                        }
1756:
1757:                        if (cmd == null && interp.resolvers != null) {
1758:                            for (ListIterator iter = interp.resolvers
1759:                                    .listIterator(); cmd == null
1760:                                    && iter.hasNext();) {
1761:                                res = (Interp.ResolverScheme) iter.next();
1762:                                cmd = res.resolver.resolveCmd(interp, name,
1763:                                        cxtNs, flags);
1764:                            }
1765:                        }
1766:
1767:                        if (cmd != null) {
1768:                            return cmd;
1769:                        }
1770:                    } catch (TclException e) {
1771:                        return null;
1772:                    }
1773:                }
1774:
1775:                // Find the namespace(s) that contain the command.
1776:
1777:                GetNamespaceForQualNameResult gnfqnr = interp.getnfqnResult;
1778:                getNamespaceForQualName(interp, name, contextNs, flags, gnfqnr);
1779:                ns0 = gnfqnr.ns;
1780:                ns1 = gnfqnr.altNs;
1781:                cxtNs = gnfqnr.actualCxt;
1782:                simpleName = gnfqnr.simpleName;
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:                    Namespace ns;
1791:                    if (search == 0) {
1792:                        ns = ns0;
1793:                    } else if (search == 1) {
1794:                        ns = ns1;
1795:                    } else {
1796:                        throw new TclRuntimeError("bad search value" + search);
1797:                    }
1798:                    if ((ns != null) && (simpleName != null)) {
1799:                        cmd = (WrappedCommand) ns.cmdTable.get(simpleName);
1800:                    }
1801:                }
1802:                if (cmd != null) {
1803:                    return cmd;
1804:                } else if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
1805:                    throw new TclException(interp, "unknown command \"" + name
1806:                            + "\"");
1807:                }
1808:
1809:                return null;
1810:            }
1811:
1812:            /*
1813:             *----------------------------------------------------------------------
1814:             *
1815:             * Tcl_FindNamespaceVar -> findNamespaceVar
1816:             *
1817:             *	Searches for a namespace variable, a variable not local to a
1818:             *	procedure. The variable can be either a scalar or an array, but
1819:             *	may not be an element of an array.
1820:             *
1821:             * Results:
1822:             *	Returns a token for the variable if it is found. Otherwise, if it
1823:             *	can't be found or there is an error, returns null and leaves an
1824:             *	error message in the interpreter's result object if "flags"
1825:             *	contains TCL.LEAVE_ERR_MSG.
1826:             *
1827:             * Side effects:
1828:             *	None.
1829:             *
1830:             *----------------------------------------------------------------------
1831:             */
1832:
1833:            public static Var findNamespaceVar(Interp interp, // The interpreter in which to find the
1834:                    // variable.
1835:                    String name, // Variable's name. name. If it starts with "::",
1836:                    // will be looked up in global namespace.
1837:                    // Else, looked up first in contextNs
1838:                    // (current namespace if contextNs is
1839:                    // null), then in global namespace.
1840:                    Namespace contextNs, // Ignored if TCL.GLOBAL_ONLY flag set.
1841:                    // Otherwise, points to namespace in which
1842:                    // to resolve name. If null, look up name
1843:                    // in the current namespace.
1844:                    int flags // An OR'd combination of flags:
1845:            // TCL.GLOBAL_ONLY (look up name only in
1846:            // global namespace), TCL.NAMESPACE_ONLY
1847:            // (look up only in contextNs, or the
1848:            // current namespace if contextNs is
1849:            // null), and TCL.LEAVE_ERR_MSG. If both
1850:            // TCL.GLOBAL_ONLY and TCL.NAMESPACE_ONLY
1851:            // are given, TCL.GLOBAL_ONLY is ignored.
1852:            ) throws TclException {
1853:                Interp.ResolverScheme res;
1854:                Namespace cxtNs;
1855:                Namespace ns0, ns1;
1856:                String simpleName;
1857:                int search;
1858:                Var var;
1859:
1860:                // If this namespace has a variable resolver, then give it first
1861:                // crack at the variable resolution.  It may return a Tcl_Var
1862:                // value, it may signal to continue onward, or it may signal
1863:                // an error.
1864:
1865:                if ((flags & TCL.GLOBAL_ONLY) != 0) {
1866:                    cxtNs = getGlobalNamespace(interp);
1867:                } else if (contextNs != null) {
1868:                    cxtNs = contextNs;
1869:                } else {
1870:                    cxtNs = getCurrentNamespace(interp);
1871:                }
1872:
1873:                if (cxtNs.resolver != null || interp.resolvers != null) {
1874:                    try {
1875:                        if (cxtNs.resolver != null) {
1876:                            var = cxtNs.resolver.resolveVar(interp, name,
1877:                                    cxtNs, flags);
1878:                        } else {
1879:                            var = null;
1880:                        }
1881:
1882:                        if (var == null && interp.resolvers != null) {
1883:                            for (ListIterator iter = interp.resolvers
1884:                                    .listIterator(); var == null
1885:                                    && iter.hasNext();) {
1886:                                res = (Interp.ResolverScheme) iter.next();
1887:                                var = res.resolver.resolveVar(interp, name,
1888:                                        cxtNs, flags);
1889:                            }
1890:                        }
1891:
1892:                        if (var != null) {
1893:                            return var;
1894:                        }
1895:                    } catch (TclException e) {
1896:                        return null;
1897:                    }
1898:                }
1899:
1900:                // Find the namespace(s) that contain the variable.
1901:
1902:                GetNamespaceForQualNameResult gnfqnr = interp.getnfqnResult;
1903:                getNamespaceForQualName(interp, name, contextNs, flags, gnfqnr);
1904:                ns0 = gnfqnr.ns;
1905:                ns1 = gnfqnr.altNs;
1906:                cxtNs = gnfqnr.actualCxt;
1907:                simpleName = gnfqnr.simpleName;
1908:
1909:                // Look for the variable in the variable table of its namespace.
1910:                // Be sure to check both possible search paths: from the specified
1911:                // namespace context and from the global namespace.
1912:
1913:                var = null;
1914:                for (search = 0; (search < 2) && (var == null); search++) {
1915:                    Namespace ns;
1916:                    if (search == 0) {
1917:                        ns = ns0;
1918:                    } else if (search == 1) {
1919:                        ns = ns1;
1920:                    } else {
1921:                        throw new TclRuntimeError("bad search value" + search);
1922:                    }
1923:                    if ((ns != null) && (simpleName != null)) {
1924:                        var = (Var) ns.varTable.get(simpleName);
1925:                    }
1926:                }
1927:                if (var != null) {
1928:                    return var;
1929:                } else if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
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:             * TclResetShadowedCmdRefs -> resetShadowedCmdRefs
1945:             *
1946:             *	Called when a command is added to a namespace to check for existing
1947:             *	command references that the new command may invalidate. Consider the
1948:             *	following cases that could happen when you add a command "foo" to a
1949:             *	namespace "b":
1950:             *	   1. It could shadow a command named "foo" at the global scope.
1951:             *	      If it does, all command references in the namespace "b" are
1952:             *	      suspect.
1953:             *	   2. Suppose the namespace "b" resides in a namespace "a".
1954:             *	      Then to "a" the new command "b::foo" could shadow another
1955:             *	      command "b::foo" in the global namespace. If so, then all
1956:             *	      command references in "a" are suspect.
1957:             *	The same checks are applied to all parent namespaces, until we
1958:             *	reach the global :: namespace.
1959:             *
1960:             * Results:
1961:             *	None.
1962:             *
1963:             * Side effects:
1964:             *	If the new command shadows an existing command, then the
1965:             *	epoch for each command in each namespace that sees the
1966:             *	shadow is incremented. This invalidates any command caches
1967:             *  inside each command in the namespace. The next time the
1968:             *  command is used, cached refrences will be resolved from scratch.
1969:             *
1970:             *----------------------------------------------------------------------
1971:             */
1972:
1973:            static void resetShadowedCmdRefs(Interp interp, // Interpreter containing the new command
1974:                    WrappedCommand newCmd) // Command added to a namespace
1975:            {
1976:                String cmdName;
1977:                Namespace ns, tmpNs;
1978:                Namespace trailNs, shadowNs;
1979:                Namespace globalNs = getGlobalNamespace(interp);
1980:                int i;
1981:                boolean found;
1982:                WrappedCommand wcmd;
1983:
1984:                // Array used to hold the trail list.
1985:
1986:                Namespace[] trailArray = null;
1987:                int trailFront = -1;
1988:                int trailSize = NUM_TRAIL_ELEMS;
1989:
1990:                // Start at the namespace containing the new command, and work up
1991:                // through the list of parents. Stop just before the global namespace,
1992:                // since the global namespace can't "shadow" its own entries.
1993:                // 
1994:                // The namespace "trail" list we build consists of the names of each
1995:                // namespace that encloses the new command, in order from outermost to
1996:                // innermost: for example, "a" then "b". Each iteration of this loop
1997:                // eventually extends the trail upwards by one namespace, ns. We use
1998:                // this trail list to see if ns (e.g. "a" in 2. above) could have
1999:                // now-invalid cached command references. This will happen if ns
2000:                // (e.g. "a") contains a sequence of child namespaces (e.g. "b")
2001:                // such that there is a identically-named sequence of child namespaces
2002:                // starting from :: (e.g. "::b") whose tail namespace contains a command
2003:                // also named cmdName.
2004:
2005:                cmdName = newCmd.hashKey;
2006:                for (ns = newCmd.ns; (ns != null) && (ns != globalNs); ns = ns.parent) {
2007:                    // Find the maximal sequence of child namespaces contained in ns
2008:                    // such that there is a identically-named sequence of child
2009:                    // namespaces starting from ::. shadowNs will be the tail of this
2010:                    // sequence, or the deepest namespace under :: that might contain a
2011:                    // command now shadowed by cmdName. We check below if shadowNs
2012:                    // actually contains a command cmdName.
2013:
2014:                    found = true;
2015:                    shadowNs = globalNs;
2016:
2017:                    for (i = trailFront; i >= 0; i--) {
2018:                        trailNs = trailArray[i];
2019:                        tmpNs = (Namespace) shadowNs.childTable
2020:                                .get(trailNs.name);
2021:                        if (tmpNs != null) {
2022:                            shadowNs = tmpNs;
2023:                        } else {
2024:                            found = false;
2025:                            break;
2026:                        }
2027:                    }
2028:
2029:                    // If shadowNs contains a command named cmdName, we invalidate
2030:                    // all of the command refs cached in ns. As a boundary case,
2031:                    // shadowNs is initially :: and we check for case 1. above.
2032:
2033:                    if (found) {
2034:                        wcmd = (WrappedCommand) shadowNs.cmdTable.get(cmdName);
2035:                        if (wcmd != null) {
2036:                            // Invalidate cached command ref in each command
2037:                            // defined in this namespace.
2038:
2039:                            //nsPtr->cmdRefEpoch++;
2040:
2041:                            for (Iterator iter = ns.cmdTable.entrySet()
2042:                                    .iterator(); iter.hasNext();) {
2043:                                Map.Entry entry = (Map.Entry) iter.next();
2044:                                wcmd = (WrappedCommand) entry.getValue();
2045:                                wcmd.incrEpoch();
2046:                            }
2047:                        }
2048:                    }
2049:
2050:                    // Insert ns at the front of the trail list: i.e., at the end
2051:                    // of the trail array.
2052:
2053:                    if (trailArray == null) {
2054:                        trailArray = new Namespace[NUM_TRAIL_ELEMS];
2055:                    }
2056:
2057:                    trailFront++;
2058:                    if (trailFront == trailSize) {
2059:                        int size = trailSize * 2;
2060:                        Namespace[] tmp = new Namespace[size];
2061:                        System.arraycopy(trailArray, 0, tmp, 0,
2062:                                trailArray.length);
2063:                        trailArray = tmp;
2064:                        trailSize = size;
2065:                    }
2066:                    trailArray[trailFront] = ns;
2067:                }
2068:            }
2069:
2070:            /**
2071:             *----------------------------------------------------------------------
2072:             *
2073:             * Tcl_SetNamespaceResolvers -> setNamespaceResolver
2074:             *
2075:             *	Sets the command/variable resolution object for a namespace,
2076:             *	thereby changing the way that command/variable names are
2077:             *	interpreted.  This allows extension writers to support different
2078:             *	name resolution schemes, such as those for object-oriented
2079:             *	packages.
2080:             *
2081:             *	Command resolution is handled by the following method:
2082:             *
2083:             *  resolveCmd (Interp interp, String name,
2084:             *      Namespace context, int flags)
2085:             *  throws TclException;
2086:             *          
2087:             *	Whenever a command is executed or Namespace.findCommand is invoked
2088:             *	within the namespace, this method is called to resolve the
2089:             *	command name.  If this method is able to resolve the name,
2090:             *	it should return the corresponding WrappedCommand.  Otherwise,
2091:             *	the procedure can return null, and the command will
2092:             *	be treated under the usual name resolution rules.  Or, it can
2093:             *	throw a TclException, and the command will be considered invalid.
2094:             *
2095:             *	Variable resolution is handled by the following method:
2096:             *
2097:             *  resolveVar (Interp interp, String name,
2098:             *      Namespace context, int flags)
2099:             *  throws TclException;
2100:             *
2101:             *  If this method is able to resolve the name, it should return
2102:             *  the variable as Var object.  The method may also
2103:             *	return null, and the variable will be treated under the usual
2104:             *  name resolution rules.  Or, it can throw a TclException,
2105:             *	and the variable will be considered invalid.
2106:             *
2107:             * Results:
2108:             *	See above.
2109:             *
2110:             * Side effects:
2111:             *	None.
2112:             *
2113:             *----------------------------------------------------------------------
2114:             */
2115:
2116:            public static void setNamespaceResolver(Namespace namespace, // Namespace whose resolution rules
2117:                    // are being modified.
2118:                    Resolver resolver) // command and variable resolution
2119:            {
2120:                //  Plug in the new command resolver.
2121:
2122:                namespace.resolver = resolver;
2123:            }
2124:
2125:            /**
2126:             *----------------------------------------------------------------------
2127:             *
2128:             * Tcl_GetNamespaceResolvers -> getNamespaceResolver
2129:             *
2130:             *	Returns the current command/variable resolution object
2131:             *	for a namespace.  By default, these objects are null.
2132:             *	New objects can be installed by calling setNamespaceResolver,
2133:             *  to provide new name resolution rules.
2134:             *
2135:             * Results:
2136:             *	Returns the esolver object assigned to this namespace.
2137:             *	Returns null otherwise.
2138:             *
2139:             * Side effects:
2140:             *	None.
2141:             *
2142:             *----------------------------------------------------------------------
2143:             */
2144:
2145:            static Resolver getNamespaceResolver(Namespace namespace) // Namespace whose resolution rules
2146:            // are being queried.
2147:            {
2148:                return namespace.resolver;
2149:            }
2150:
2151:            /**
2152:             *----------------------------------------------------------------------
2153:             *
2154:             * Tcl_FirstHashEntry -> FirstHashEntry
2155:             *
2156:             *	Return the first Object value contained in the given table.
2157:             *	This method is used only when taking apart a table where
2158:             *	entries in the table could be removed elsewhere. An Iterator
2159:             *	is no longer valid once entries have been removed so it
2160:             *	is not possible to take a table apart safely with a single
2161:             *	iterator. This method returns null when there are no more
2162:             *	elements in the table, so it should not be used with a
2163:             *	table that contains null values. This method is not efficient,
2164:             *	but it is required when dealing with a Java Iterator when
2165:             *	the table being iterated could have elements added or deleted.
2166:             *
2167:             *----------------------------------------------------------------------
2168:             */
2169:
2170:            static Object FirstHashEntry(HashMap table) {
2171:                Object retVal;
2172:                Set eset = table.entrySet();
2173:                if (eset.size() == 0) {
2174:                    return null;
2175:                }
2176:                Iterator iter = eset.iterator();
2177:                if (!iter.hasNext()) {
2178:                    throw new TclRuntimeError(
2179:                            "no next() object but set size was " + eset.size());
2180:                }
2181:                Map.Entry entry = (Map.Entry) iter.next();
2182:                retVal = entry.getValue();
2183:                if (retVal == null) {
2184:                    throw new TclRuntimeError("entry value should not be null");
2185:                }
2186:                return retVal;
2187:            }
2188:
2189:        } // end class Namespace
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.