home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / generic / tclNamesp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  119.7 KB  |  3,766 lines  |  [TEXT/CWIE]

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