tclNamesp.c

Go to the documentation of this file.
00001 /*
00002  * tclNamesp.c --
00003  *
00004  *      Contains support for namespaces, which provide a separate context of
00005  *      commands and global variables. The global :: namespace is the
00006  *      traditional Tcl "global" scope. Other namespaces are created as
00007  *      children of the global namespace. These other namespaces contain
00008  *      special-purpose commands and variables for packages. Also includes the
00009  *      TIP#112 ensemble machinery.
00010  *
00011  * Copyright (c) 1993-1997 Lucent Technologies.
00012  * Copyright (c) 1997 Sun Microsystems, Inc.
00013  * Copyright (c) 1998-1999 by Scriptics Corporation.
00014  * Copyright (c) 2002-2005 Donal K. Fellows.
00015  * Copyright (c) 2006 Neil Madden.
00016  * Contributions from Don Porter, NIST, 2007. (not subject to US copyright)
00017  *
00018  * Originally implemented by
00019  *   Michael J. McLennan
00020  *   Bell Labs Innovations for Lucent Technologies
00021  *   mmclennan@lucent.com
00022  *
00023  * See the file "license.terms" for information on usage and redistribution of
00024  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
00025  *
00026  * RCS: @(#) $Id: tclNamesp.c,v 1.161 2007/12/13 15:23:19 dgp Exp $
00027  */
00028 
00029 #include "tclInt.h"
00030 
00031 /*
00032  * Thread-local storage used to avoid having a global lock on data that is not
00033  * limited to a single interpreter.
00034  */
00035 
00036 typedef struct ThreadSpecificData {
00037     long numNsCreated;          /* Count of the number of namespaces created
00038                                  * within the thread. This value is used as a
00039                                  * unique id for each namespace. Cannot be
00040                                  * per-interp because the nsId is used to
00041                                  * distinguish objects which can be passed
00042                                  * around between interps in the same thread,
00043                                  * but does not need to be global because
00044                                  * object internal reps are always per-thread
00045                                  * anyway. */
00046 } ThreadSpecificData;
00047 
00048 static Tcl_ThreadDataKey dataKey;
00049 
00050 /*
00051  * This structure contains a cached pointer to a namespace that is the result
00052  * of resolving the namespace's name in some other namespace. It is the
00053  * internal representation for a nsName object. It contains the pointer along
00054  * with some information that is used to check the cached pointer's validity.
00055  */
00056 
00057 typedef struct ResolvedNsName {
00058     Namespace *nsPtr;          /* A cached pointer to the Namespace that the
00059                                 * name resolved to. */
00060     Namespace *refNsPtr;       /* Points to the namespace context in which the
00061                                 * name was resolved. NULL if the name is fully
00062                                 * qualified and thus the resolution does not
00063                                 * depend on the context. */
00064     int refCount;               /* Reference count: 1 for each nsName object
00065                                  * that has a pointer to this ResolvedNsName
00066                                  * structure as its internal rep. This
00067                                  * structure can be freed when refCount
00068                                  * becomes zero. */
00069 } ResolvedNsName;
00070 
00071 /*
00072  * The client data for an ensemble command. This consists of the table of
00073  * commands that are actually exported by the namespace, and an epoch counter
00074  * that, combined with the exportLookupEpoch field of the namespace structure,
00075  * defines whether the table contains valid data or will need to be recomputed
00076  * next time the ensemble command is called.
00077  */
00078 
00079 typedef struct EnsembleConfig {
00080     Namespace *nsPtr;           /* The namspace backing this ensemble up. */
00081     Tcl_Command token;          /* The token for the command that provides
00082                                  * ensemble support for the namespace, or NULL
00083                                  * if the command has been deleted (or never
00084                                  * existed; the global namespace never has an
00085                                  * ensemble command.) */
00086     int epoch;                  /* The epoch at which this ensemble's table of
00087                                  * exported commands is valid. */
00088     char **subcommandArrayPtr;  /* Array of ensemble subcommand names. At all
00089                                  * consistent points, this will have the same
00090                                  * number of entries as there are entries in
00091                                  * the subcommandTable hash. */
00092     Tcl_HashTable subcommandTable;
00093                                 /* Hash table of ensemble subcommand names,
00094                                  * which are its keys so this also provides
00095                                  * the storage management for those subcommand
00096                                  * names. The contents of the entry values are
00097                                  * object version the prefix lists to use when
00098                                  * substituting for the command/subcommand to
00099                                  * build the ensemble implementation command.
00100                                  * Has to be stored here as well as in
00101                                  * subcommandDict because that field is NULL
00102                                  * when we are deriving the ensemble from the
00103                                  * namespace exports list. FUTURE WORK: use
00104                                  * object hash table here. */
00105     struct EnsembleConfig *next;/* The next ensemble in the linked list of
00106                                  * ensembles associated with a namespace. If
00107                                  * this field points to this ensemble, the
00108                                  * structure has already been unlinked from
00109                                  * all lists, and cannot be found by scanning
00110                                  * the list from the namespace's ensemble
00111                                  * field. */
00112     int flags;                  /* ORed combo of TCL_ENSEMBLE_PREFIX, ENS_DEAD
00113                                  * and ENSEMBLE_COMPILE. */
00114 
00115     /* OBJECT FIELDS FOR ENSEMBLE CONFIGURATION */
00116 
00117     Tcl_Obj *subcommandDict;    /* Dictionary providing mapping from
00118                                  * subcommands to their implementing command
00119                                  * prefixes, or NULL if we are to build the
00120                                  * map automatically from the namespace
00121                                  * exports. */
00122     Tcl_Obj *subcmdList;        /* List of commands that this ensemble
00123                                  * actually provides, and whose implementation
00124                                  * will be built using the subcommandDict (if
00125                                  * present and defined) and by simple mapping
00126                                  * to the namespace otherwise. If NULL,
00127                                  * indicates that we are using the (dynamic)
00128                                  * list of currently exported commands. */
00129     Tcl_Obj *unknownHandler;    /* Script prefix used to handle the case when
00130                                  * no match is found (according to the rule
00131                                  * defined by flag bit TCL_ENSEMBLE_PREFIX) or
00132                                  * NULL to use the default error-generating
00133                                  * behaviour. The script execution gets all
00134                                  * the arguments to the ensemble command
00135                                  * (including objv[0]) and will have the
00136                                  * results passed directly back to the caller
00137                                  * (including the error code) unless the code
00138                                  * is TCL_CONTINUE in which case the
00139                                  * subcommand will be reparsed by the ensemble
00140                                  * core, presumably because the ensemble
00141                                  * itself has been updated. */
00142 } EnsembleConfig;
00143 
00144 #define ENS_DEAD        0x1     /* Flag value to say that the ensemble is dead
00145                                  * and on its way out. */
00146 
00147 /*
00148  * Declarations for functions local to this file:
00149  */
00150 
00151 static void             DeleteImportedCmd(ClientData clientData);
00152 static int              DoImport(Tcl_Interp *interp,
00153                             Namespace *nsPtr, Tcl_HashEntry *hPtr,
00154                             const char *cmdName, const char *pattern,
00155                             Namespace *importNsPtr, int allowOverwrite);
00156 static void             DupNsNameInternalRep(Tcl_Obj *objPtr,Tcl_Obj *copyPtr);
00157 static char *           ErrorCodeRead(ClientData clientData,Tcl_Interp *interp,
00158                             const char *name1, const char *name2, int flags);
00159 static char *           ErrorInfoRead(ClientData clientData,Tcl_Interp *interp,
00160                             const char *name1, const char *name2, int flags);
00161 static char *           EstablishErrorCodeTraces(ClientData clientData,
00162                             Tcl_Interp *interp, const char *name1,
00163                             const char *name2, int flags);
00164 static char *           EstablishErrorInfoTraces(ClientData clientData,
00165                             Tcl_Interp *interp, const char *name1,
00166                             const char *name2, int flags);
00167 static void             FreeNsNameInternalRep(Tcl_Obj *objPtr);
00168 static int              GetNamespaceFromObj(Tcl_Interp *interp,
00169                             Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr);
00170 static int              InvokeImportedCmd(ClientData clientData,
00171                             Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
00172 static int              NamespaceChildrenCmd(ClientData dummy,
00173                             Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
00174 static int              NamespaceCodeCmd(ClientData dummy, Tcl_Interp *interp,
00175                             int objc, Tcl_Obj *const objv[]);
00176 static int              NamespaceCurrentCmd(ClientData dummy,
00177                             Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
00178 static int              NamespaceDeleteCmd(ClientData dummy,Tcl_Interp *interp,
00179                             int objc, Tcl_Obj *const objv[]);
00180 static int              NamespaceEnsembleCmd(ClientData dummy,
00181                             Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
00182 static int              NamespaceEvalCmd(ClientData dummy, Tcl_Interp *interp,
00183                             int objc, Tcl_Obj *const objv[]);
00184 static int              NamespaceExistsCmd(ClientData dummy,Tcl_Interp *interp,
00185                             int objc, Tcl_Obj *const objv[]);
00186 static int              NamespaceExportCmd(ClientData dummy,Tcl_Interp *interp,
00187                             int objc, Tcl_Obj *const objv[]);
00188 static int              NamespaceForgetCmd(ClientData dummy,Tcl_Interp *interp,
00189                             int objc, Tcl_Obj *const objv[]);
00190 static void             NamespaceFree(Namespace *nsPtr);
00191 static int              NamespaceImportCmd(ClientData dummy,Tcl_Interp *interp,
00192                             int objc, Tcl_Obj *const objv[]);
00193 static int              NamespaceInscopeCmd(ClientData dummy,
00194                             Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
00195 static int              NamespaceOriginCmd(ClientData dummy,Tcl_Interp *interp,
00196                             int objc, Tcl_Obj *const objv[]);
00197 static int              NamespaceParentCmd(ClientData dummy,Tcl_Interp *interp,
00198                             int objc, Tcl_Obj *const objv[]);
00199 static int              NamespacePathCmd(ClientData dummy, Tcl_Interp *interp,
00200                             int objc, Tcl_Obj *const objv[]);
00201 static int              NamespaceQualifiersCmd(ClientData dummy,
00202                             Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
00203 static int              NamespaceTailCmd(ClientData dummy, Tcl_Interp *interp,
00204                             int objc, Tcl_Obj *const objv[]);
00205 static int              NamespaceUpvarCmd(ClientData dummy, Tcl_Interp *interp,
00206                             int objc, Tcl_Obj *const objv[]);
00207 static int              NamespaceUnknownCmd(ClientData dummy,
00208                             Tcl_Interp *interp, int objc,
00209                             Tcl_Obj *const objv[]);
00210 static int              NamespaceWhichCmd(ClientData dummy, Tcl_Interp *interp,
00211                             int objc, Tcl_Obj *const objv[]);
00212 static int              SetNsNameFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
00213 static int              NsEnsembleImplementationCmd(ClientData clientData,
00214                             Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
00215 static void             BuildEnsembleConfig(EnsembleConfig *ensemblePtr);
00216 static int              NsEnsembleStringOrder(const void *strPtr1,
00217                             const void *strPtr2);
00218 static void             DeleteEnsembleConfig(ClientData clientData);
00219 static void             MakeCachedEnsembleCommand(Tcl_Obj *objPtr,
00220                             EnsembleConfig *ensemblePtr,
00221                             const char *subcmdName, Tcl_Obj *prefixObjPtr);
00222 static void             FreeEnsembleCmdRep(Tcl_Obj *objPtr);
00223 static void             DupEnsembleCmdRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr);
00224 static void             StringOfEnsembleCmdRep(Tcl_Obj *objPtr);
00225 static void             UnlinkNsPath(Namespace *nsPtr);
00226 
00227 /*
00228  * This structure defines a Tcl object type that contains a namespace
00229  * reference. It is used in commands that take the name of a namespace as an
00230  * argument. The namespace reference is resolved, and the result in cached in
00231  * the object.
00232  */
00233 
00234 static Tcl_ObjType nsNameType = {
00235     "nsName",                   /* the type's name */
00236     FreeNsNameInternalRep,      /* freeIntRepProc */
00237     DupNsNameInternalRep,       /* dupIntRepProc */
00238     NULL,                       /* updateStringProc */
00239     SetNsNameFromAny            /* setFromAnyProc */
00240 };
00241 
00242 /*
00243  * This structure defines a Tcl object type that contains a reference to an
00244  * ensemble subcommand (e.g. the "length" in [string length ab]). It is used
00245  * to cache the mapping between the subcommand itself and the real command
00246  * that implements it.
00247  */
00248 
00249 Tcl_ObjType tclEnsembleCmdType = {
00250     "ensembleCommand",          /* the type's name */
00251     FreeEnsembleCmdRep,         /* freeIntRepProc */
00252     DupEnsembleCmdRep,          /* dupIntRepProc */
00253     StringOfEnsembleCmdRep,     /* updateStringProc */
00254     NULL                        /* setFromAnyProc */
00255 };
00256 
00257 /*
00258  *----------------------------------------------------------------------
00259  *
00260  * TclInitNamespaceSubsystem --
00261  *
00262  *      This function is called to initialize all the structures that are used
00263  *      by namespaces on a per-process basis.
00264  *
00265  * Results:
00266  *      None.
00267  *
00268  * Side effects:
00269  *      None.
00270  *
00271  *----------------------------------------------------------------------
00272  */
00273 
00274 void
00275 TclInitNamespaceSubsystem(void)
00276 {
00277     /*
00278      * Does nothing for now.
00279      */
00280 }
00281 
00282 /*
00283  *----------------------------------------------------------------------
00284  *
00285  * Tcl_GetCurrentNamespace --
00286  *
00287  *      Returns a pointer to an interpreter's currently active namespace.
00288  *
00289  * Results:
00290  *      Returns a pointer to the interpreter's current namespace.
00291  *
00292  * Side effects:
00293  *      None.
00294  *
00295  *----------------------------------------------------------------------
00296  */
00297 
00298 Tcl_Namespace *
00299 Tcl_GetCurrentNamespace(
00300     register Tcl_Interp *interp)/* Interpreter whose current namespace is
00301                                  * being queried. */
00302 {
00303     return TclGetCurrentNamespace(interp);
00304 }
00305 
00306 /*
00307  *----------------------------------------------------------------------
00308  *
00309  * Tcl_GetGlobalNamespace --
00310  *
00311  *      Returns a pointer to an interpreter's global :: namespace.
00312  *
00313  * Results:
00314  *      Returns a pointer to the specified interpreter's global namespace.
00315  *
00316  * Side effects:
00317  *      None.
00318  *
00319  *----------------------------------------------------------------------
00320  */
00321 
00322 Tcl_Namespace *
00323 Tcl_GetGlobalNamespace(
00324     register Tcl_Interp *interp)/* Interpreter whose global namespace should
00325                                  * be returned. */
00326 {
00327     return TclGetGlobalNamespace(interp);
00328 }
00329 
00330 /*
00331  *----------------------------------------------------------------------
00332  *
00333  * Tcl_PushCallFrame --
00334  *
00335  *      Pushes a new call frame onto the interpreter's Tcl call stack. Called
00336  *      when executing a Tcl procedure or a "namespace eval" or "namespace
00337  *      inscope" command.
00338  *
00339  * Results:
00340  *      Returns TCL_OK if successful, or TCL_ERROR (along with an error
00341  *      message in the interpreter's result object) if something goes wrong.
00342  *
00343  * Side effects:
00344  *      Modifies the interpreter's Tcl call stack.
00345  *
00346  *----------------------------------------------------------------------
00347  */
00348 
00349 int
00350 Tcl_PushCallFrame(
00351     Tcl_Interp *interp,         /* Interpreter in which the new call frame is
00352                                  * to be pushed. */
00353     Tcl_CallFrame *callFramePtr,/* Points to a call frame structure to push.
00354                                  * Storage for this has already been allocated
00355                                  * by the caller; typically this is the
00356                                  * address of a CallFrame structure allocated
00357                                  * on the caller's C stack. The call frame
00358                                  * will be initialized by this function. The
00359                                  * caller can pop the frame later with
00360                                  * Tcl_PopCallFrame, and it is responsible for
00361                                  * freeing the frame's storage. */
00362     Tcl_Namespace *namespacePtr,/* Points to the namespace in which the frame
00363                                  * will execute. If NULL, the interpreter's
00364                                  * current namespace will be used. */
00365     int isProcCallFrame)        /* If nonzero, the frame represents a called
00366                                  * Tcl procedure and may have local vars. Vars
00367                                  * will ordinarily be looked up in the frame.
00368                                  * If new variables are created, they will be
00369                                  * created in the frame. If 0, the frame is
00370                                  * for a "namespace eval" or "namespace
00371                                  * inscope" command and var references are
00372                                  * treated as references to namespace
00373                                  * variables. */
00374 {
00375     Interp *iPtr = (Interp *) interp;
00376     register CallFrame *framePtr = (CallFrame *) callFramePtr;
00377     register Namespace *nsPtr;
00378 
00379     if (namespacePtr == NULL) {
00380         nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
00381     } else {
00382         nsPtr = (Namespace *) namespacePtr;
00383 
00384         /*
00385          * TODO: Examine whether it would be better to guard based on NS_DYING
00386          * or NS_KILLED. It appears that these are not tested because they can
00387          * be set in a global interp that has been [namespace delete]d, but
00388          * which never really completely goes away because of lingering global
00389          * things like ::errorInfo and [::unknown] and hidden commands.
00390          * Review of those designs might permit stricter checking here.
00391          */
00392 
00393         if (nsPtr->flags & NS_DEAD) {
00394             Tcl_Panic("Trying to push call frame for dead namespace");
00395             /*NOTREACHED*/
00396         }
00397     }
00398 
00399     nsPtr->activationCount++;
00400     framePtr->nsPtr = nsPtr;
00401     framePtr->isProcCallFrame = isProcCallFrame;
00402     framePtr->objc = 0;
00403     framePtr->objv = NULL;
00404     framePtr->callerPtr = iPtr->framePtr;
00405     framePtr->callerVarPtr = iPtr->varFramePtr;
00406     if (iPtr->varFramePtr != NULL) {
00407         framePtr->level = (iPtr->varFramePtr->level + 1);
00408     } else {
00409         framePtr->level = 0;
00410     }
00411     framePtr->procPtr = NULL;           /* no called procedure */
00412     framePtr->varTablePtr = NULL;       /* and no local variables */
00413     framePtr->numCompiledLocals = 0;
00414     framePtr->compiledLocals = NULL;
00415     framePtr->clientData = NULL;
00416     framePtr->localCachePtr = NULL;
00417 
00418     /*
00419      * Push the new call frame onto the interpreter's stack of procedure call
00420      * frames making it the current frame.
00421      */
00422 
00423     iPtr->framePtr = framePtr;
00424     iPtr->varFramePtr = framePtr;
00425     return TCL_OK;
00426 }
00427 
00428 /*
00429  *----------------------------------------------------------------------
00430  *
00431  * Tcl_PopCallFrame --
00432  *
00433  *      Removes a call frame from the Tcl call stack for the interpreter.
00434  *      Called to remove a frame previously pushed by Tcl_PushCallFrame.
00435  *
00436  * Results:
00437  *      None.
00438  *
00439  * Side effects:
00440  *      Modifies the call stack of the interpreter. Resets various fields of
00441  *      the popped call frame. If a namespace has been deleted and has no more
00442  *      activations on the call stack, the namespace is destroyed.
00443  *
00444  *----------------------------------------------------------------------
00445  */
00446 
00447 void
00448 Tcl_PopCallFrame(
00449     Tcl_Interp *interp)         /* Interpreter with call frame to pop. */
00450 {
00451     register Interp *iPtr = (Interp *) interp;
00452     register CallFrame *framePtr = iPtr->framePtr;
00453     Namespace *nsPtr;
00454 
00455     /*
00456      * It's important to remove the call frame from the interpreter's stack of
00457      * call frames before deleting local variables, so that traces invoked by
00458      * the variable deletion don't see the partially-deleted frame.
00459      */
00460 
00461     if (framePtr->callerPtr) {
00462         iPtr->framePtr = framePtr->callerPtr;
00463         iPtr->varFramePtr = framePtr->callerVarPtr;
00464     } else {
00465         /* Tcl_PopCallFrame: trying to pop rootCallFrame! */
00466     }
00467 
00468     if (framePtr->varTablePtr != NULL) {
00469         TclDeleteVars(iPtr, framePtr->varTablePtr);
00470         ckfree((char *) framePtr->varTablePtr);
00471         framePtr->varTablePtr = NULL;
00472     }
00473     if (framePtr->numCompiledLocals > 0) {
00474         TclDeleteCompiledLocalVars(iPtr, framePtr);
00475         if (--framePtr->localCachePtr->refCount == 0) {
00476             TclFreeLocalCache(interp, framePtr->localCachePtr);
00477         }
00478         framePtr->localCachePtr = NULL;
00479     }
00480 
00481     /*
00482      * Decrement the namespace's count of active call frames. If the namespace
00483      * is "dying" and there are no more active call frames, call
00484      * Tcl_DeleteNamespace to destroy it.
00485      */
00486 
00487     nsPtr = framePtr->nsPtr;
00488     nsPtr->activationCount--;
00489     if ((nsPtr->flags & NS_DYING)
00490             && (nsPtr->activationCount - (nsPtr == iPtr->globalNsPtr) == 0)) {
00491         Tcl_DeleteNamespace((Tcl_Namespace *) nsPtr);
00492     }
00493     framePtr->nsPtr = NULL;
00494 }
00495 
00496 /*
00497  *----------------------------------------------------------------------
00498  *
00499  * TclPushStackFrame --
00500  *
00501  *      Allocates a new call frame in the interpreter's execution stack, then
00502  *      pushes it onto the interpreter's Tcl call stack. Called when executing
00503  *      a Tcl procedure or a "namespace eval" or "namespace inscope" command.
00504  *
00505  * Results:
00506  *      Returns TCL_OK if successful, or TCL_ERROR (along with an error
00507  *      message in the interpreter's result object) if something goes wrong.
00508  *
00509  * Side effects:
00510  *      Modifies the interpreter's Tcl call stack.
00511  *
00512  *----------------------------------------------------------------------
00513  */
00514 
00515 int
00516 TclPushStackFrame(
00517     Tcl_Interp *interp,         /* Interpreter in which the new call frame is
00518                                  * to be pushed. */
00519     Tcl_CallFrame **framePtrPtr,/* Place to store a pointer to the stack
00520                                  * allocated call frame. */
00521     Tcl_Namespace *namespacePtr,/* Points to the namespace in which the frame
00522                                  * will execute. If NULL, the interpreter's
00523                                  * current namespace will be used. */
00524     int isProcCallFrame)        /* If nonzero, the frame represents a called
00525                                  * Tcl procedure and may have local vars. Vars
00526                                  * will ordinarily be looked up in the frame.
00527                                  * If new variables are created, they will be
00528                                  * created in the frame. If 0, the frame is
00529                                  * for a "namespace eval" or "namespace
00530                                  * inscope" command and var references are
00531                                  * treated as references to namespace
00532                                  * variables. */
00533 {
00534     *framePtrPtr = (Tcl_CallFrame *) TclStackAlloc(interp, sizeof(CallFrame));
00535     return Tcl_PushCallFrame(interp, *framePtrPtr, namespacePtr,
00536             isProcCallFrame);
00537 }
00538 
00539 void
00540 TclPopStackFrame(
00541     Tcl_Interp *interp)         /* Interpreter with call frame to pop. */
00542 {
00543     CallFrame *freePtr = ((Interp *)interp)->framePtr;
00544 
00545     Tcl_PopCallFrame(interp);
00546     TclStackFree(interp, freePtr);
00547 }
00548 
00549 /*
00550  *----------------------------------------------------------------------
00551  *
00552  * EstablishErrorCodeTraces --
00553  *
00554  *      Creates traces on the ::errorCode variable to keep its value
00555  *      consistent with the expectations of legacy code.
00556  *
00557  * Results:
00558  *      None.
00559  *
00560  * Side effects:
00561  *      Read and unset traces are established on ::errorCode.
00562  *
00563  *----------------------------------------------------------------------
00564  */
00565 
00566 static char *
00567 EstablishErrorCodeTraces(
00568     ClientData clientData,
00569     Tcl_Interp *interp,
00570     const char *name1,
00571     const char *name2,
00572     int flags)
00573 {
00574     Tcl_TraceVar(interp, "errorCode", TCL_GLOBAL_ONLY | TCL_TRACE_READS,
00575             ErrorCodeRead, NULL);
00576     Tcl_TraceVar(interp, "errorCode", TCL_GLOBAL_ONLY | TCL_TRACE_UNSETS,
00577             EstablishErrorCodeTraces, NULL);
00578     return NULL;
00579 }
00580 
00581 /*
00582  *----------------------------------------------------------------------
00583  *
00584  * ErrorCodeRead --
00585  *
00586  *      Called when the ::errorCode variable is read. Copies the current value
00587  *      of the interp's errorCode field into ::errorCode.
00588  *
00589  * Results:
00590  *      None.
00591  *
00592  * Side effects:
00593  *      None.
00594  *
00595  *----------------------------------------------------------------------
00596  */
00597 
00598 static char *
00599 ErrorCodeRead(
00600     ClientData clientData,
00601     Tcl_Interp *interp,
00602     const char *name1,
00603     const char *name2,
00604     int flags)
00605 {
00606     Interp *iPtr = (Interp *)interp;
00607 
00608     if (Tcl_InterpDeleted(interp) || !(iPtr->flags & ERR_LEGACY_COPY)) {
00609         return NULL;
00610     }
00611     if (iPtr->errorCode) {
00612         Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL,
00613                 iPtr->errorCode, TCL_GLOBAL_ONLY);
00614         return NULL;
00615     }
00616     if (NULL == Tcl_ObjGetVar2(interp, iPtr->ecVar, NULL, TCL_GLOBAL_ONLY)) {
00617         Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL,
00618                 Tcl_NewObj(), TCL_GLOBAL_ONLY);
00619     }
00620     return NULL;
00621 }
00622 
00623 /*
00624  *----------------------------------------------------------------------
00625  *
00626  * EstablishErrorInfoTraces --
00627  *
00628  *      Creates traces on the ::errorInfo variable to keep its value
00629  *      consistent with the expectations of legacy code.
00630  *
00631  * Results:
00632  *      None.
00633  *
00634  * Side effects:
00635  *      Read and unset traces are established on ::errorInfo.
00636  *
00637  *----------------------------------------------------------------------
00638  */
00639 
00640 static char *
00641 EstablishErrorInfoTraces(
00642     ClientData clientData,
00643     Tcl_Interp *interp,
00644     const char *name1,
00645     const char *name2,
00646     int flags)
00647 {
00648     Tcl_TraceVar(interp, "errorInfo", TCL_GLOBAL_ONLY | TCL_TRACE_READS,
00649             ErrorInfoRead, NULL);
00650     Tcl_TraceVar(interp, "errorInfo", TCL_GLOBAL_ONLY | TCL_TRACE_UNSETS,
00651             EstablishErrorInfoTraces, NULL);
00652     return NULL;
00653 }
00654 
00655 /*
00656  *----------------------------------------------------------------------
00657  *
00658  * ErrorInfoRead --
00659  *
00660  *      Called when the ::errorInfo variable is read. Copies the current value
00661  *      of the interp's errorInfo field into ::errorInfo.
00662  *
00663  * Results:
00664  *      None.
00665  *
00666  * Side effects:
00667  *      None.
00668  *
00669  *----------------------------------------------------------------------
00670  */
00671 
00672 static char *
00673 ErrorInfoRead(
00674     ClientData clientData,
00675     Tcl_Interp *interp,
00676     const char *name1,
00677     const char *name2,
00678     int flags)
00679 {
00680     Interp *iPtr = (Interp *) interp;
00681 
00682     if (Tcl_InterpDeleted(interp) || !(iPtr->flags & ERR_LEGACY_COPY)) {
00683         return NULL;
00684     }
00685     if (iPtr->errorInfo) {
00686         Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL,
00687                 iPtr->errorInfo, TCL_GLOBAL_ONLY);
00688         return NULL;
00689     }
00690     if (NULL == Tcl_ObjGetVar2(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY)) {
00691         Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL,
00692                 Tcl_NewObj(), TCL_GLOBAL_ONLY);
00693     }
00694     return NULL;
00695 }
00696 
00697 /*
00698  *----------------------------------------------------------------------
00699  *
00700  * Tcl_CreateNamespace --
00701  *
00702  *      Creates a new namespace with the given name. If there is no active
00703  *      namespace (i.e., the interpreter is being initialized), the global ::
00704  *      namespace is created and returned.
00705  *
00706  * Results:
00707  *      Returns a pointer to the new namespace if successful. If the namespace
00708  *      already exists or if another error occurs, this routine returns NULL,
00709  *      along with an error message in the interpreter's result object.
00710  *
00711  * Side effects:
00712  *      If the name contains "::" qualifiers and a parent namespace does not
00713  *      already exist, it is automatically created.
00714  *
00715  *----------------------------------------------------------------------
00716  */
00717 
00718 Tcl_Namespace *
00719 Tcl_CreateNamespace(
00720     Tcl_Interp *interp,         /* Interpreter in which a new namespace is
00721                                  * being created. Also used for error
00722                                  * reporting. */
00723     const char *name,           /* Name for the new namespace. May be a
00724                                  * qualified name with names of ancestor
00725                                  * namespaces separated by "::"s. */
00726     ClientData clientData,      /* One-word value to store with namespace. */
00727     Tcl_NamespaceDeleteProc *deleteProc)
00728                                 /* Function called to delete client data when
00729                                  * the namespace is deleted. NULL if no
00730                                  * function should be called. */
00731 {
00732     Interp *iPtr = (Interp *) interp;
00733     register Namespace *nsPtr, *ancestorPtr;
00734     Namespace *parentPtr, *dummy1Ptr, *dummy2Ptr;
00735     Namespace *globalNsPtr = iPtr->globalNsPtr;
00736     const char *simpleName;
00737     Tcl_HashEntry *entryPtr;
00738     Tcl_DString buffer1, buffer2;
00739     Tcl_DString *namePtr, *buffPtr;
00740     int newEntry, nameLen;
00741     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
00742 
00743     /*
00744      * If there is no active namespace, the interpreter is being initialized.
00745      */
00746 
00747     if ((globalNsPtr == NULL) && (iPtr->varFramePtr == NULL)) {
00748         /*
00749          * Treat this namespace as the global namespace, and avoid looking for
00750          * a parent.
00751          */
00752 
00753         parentPtr = NULL;
00754         simpleName = "";
00755     } else if (*name == '\0') {
00756         Tcl_ResetResult(interp);
00757         Tcl_AppendResult(interp, "can't create namespace \"\": "
00758                 "only global namespace can have empty name", NULL);
00759         return NULL;
00760     } else {
00761         /*
00762          * Find the parent for the new namespace.
00763          */
00764 
00765         TclGetNamespaceForQualName(interp, name, NULL,
00766                 /*flags*/ (TCL_CREATE_NS_IF_UNKNOWN | TCL_LEAVE_ERR_MSG),
00767                 &parentPtr, &dummy1Ptr, &dummy2Ptr, &simpleName);
00768 
00769         /*
00770          * If the unqualified name at the end is empty, there were trailing
00771          * "::"s after the namespace's name which we ignore. The new namespace
00772          * was already (recursively) created and is pointed to by parentPtr.
00773          */
00774 
00775         if (*simpleName == '\0') {
00776             return (Tcl_Namespace *) parentPtr;
00777         }
00778 
00779         /*
00780          * Check for a bad namespace name and make sure that the name does not
00781          * already exist in the parent namespace.
00782          */
00783 
00784         if (Tcl_FindHashEntry(&parentPtr->childTable, simpleName) != NULL) {
00785             Tcl_AppendResult(interp, "can't create namespace \"", name,
00786                     "\": already exists", NULL);
00787             return NULL;
00788         }
00789     }
00790 
00791     /*
00792      * Create the new namespace and root it in its parent. Increment the count
00793      * of namespaces created.
00794      */
00795 
00796     nsPtr = (Namespace *) ckalloc(sizeof(Namespace));
00797     nsPtr->name = ckalloc((unsigned) (strlen(simpleName)+1));
00798     strcpy(nsPtr->name, simpleName);
00799     nsPtr->fullName = NULL;             /* Set below. */
00800     nsPtr->clientData = clientData;
00801     nsPtr->deleteProc = deleteProc;
00802     nsPtr->parentPtr = parentPtr;
00803     Tcl_InitHashTable(&nsPtr->childTable, TCL_STRING_KEYS);
00804     nsPtr->nsId = ++(tsdPtr->numNsCreated);
00805     nsPtr->interp = interp;
00806     nsPtr->flags = 0;
00807     nsPtr->activationCount = 0;
00808     nsPtr->refCount = 0;
00809     Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS);
00810     TclInitVarHashTable(&nsPtr->varTable, nsPtr);
00811     nsPtr->exportArrayPtr = NULL;
00812     nsPtr->numExportPatterns = 0;
00813     nsPtr->maxExportPatterns = 0;
00814     nsPtr->cmdRefEpoch = 0;
00815     nsPtr->resolverEpoch = 0;
00816     nsPtr->cmdResProc = NULL;
00817     nsPtr->varResProc = NULL;
00818     nsPtr->compiledVarResProc = NULL;
00819     nsPtr->exportLookupEpoch = 0;
00820     nsPtr->ensembles = NULL;
00821     nsPtr->unknownHandlerPtr = NULL;
00822     nsPtr->commandPathLength = 0;
00823     nsPtr->commandPathArray = NULL;
00824     nsPtr->commandPathSourceList = NULL;
00825 
00826     if (parentPtr != NULL) {
00827         entryPtr = Tcl_CreateHashEntry(&parentPtr->childTable, simpleName,
00828                 &newEntry);
00829         Tcl_SetHashValue(entryPtr, nsPtr);
00830     } else {
00831         /*
00832          * In the global namespace create traces to maintain the ::errorInfo
00833          * and ::errorCode variables.
00834          */
00835 
00836         iPtr->globalNsPtr = nsPtr;
00837         EstablishErrorInfoTraces(NULL, interp, NULL, NULL, 0);
00838         EstablishErrorCodeTraces(NULL, interp, NULL, NULL, 0);
00839     }
00840 
00841     /*
00842      * Build the fully qualified name for this namespace.
00843      */
00844 
00845     Tcl_DStringInit(&buffer1);
00846     Tcl_DStringInit(&buffer2);
00847     namePtr = &buffer1;
00848     buffPtr = &buffer2;
00849     for (ancestorPtr = nsPtr; ancestorPtr != NULL;
00850             ancestorPtr = ancestorPtr->parentPtr) {
00851         if (ancestorPtr != globalNsPtr) {
00852             register Tcl_DString *tempPtr = namePtr;
00853 
00854             Tcl_DStringAppend(buffPtr, "::", 2);
00855             Tcl_DStringAppend(buffPtr, ancestorPtr->name, -1);
00856             Tcl_DStringAppend(buffPtr, Tcl_DStringValue(namePtr),
00857                     Tcl_DStringLength(namePtr));
00858 
00859             /*
00860              * Clear the unwanted buffer or we end up appending to previous
00861              * results, making the namespace fullNames of nested namespaces
00862              * very wrong (and strange).
00863              */
00864 
00865             Tcl_DStringSetLength(namePtr, 0);
00866 
00867             /*
00868              * Now swap the buffer pointers so that we build in the other
00869              * buffer. This is faster than repeated copying back and forth
00870              * between buffers.
00871              */
00872 
00873             namePtr = buffPtr;
00874             buffPtr = tempPtr;
00875         }
00876     }
00877 
00878     name = Tcl_DStringValue(namePtr);
00879     nameLen = Tcl_DStringLength(namePtr);
00880     nsPtr->fullName = ckalloc((unsigned) (nameLen+1));
00881     memcpy(nsPtr->fullName, name, (unsigned) nameLen + 1);
00882 
00883     Tcl_DStringFree(&buffer1);
00884     Tcl_DStringFree(&buffer2);
00885 
00886     /*
00887      * Return a pointer to the new namespace.
00888      */
00889 
00890     return (Tcl_Namespace *) nsPtr;
00891 }
00892 
00893 /*
00894  *----------------------------------------------------------------------
00895  *
00896  * Tcl_DeleteNamespace --
00897  *
00898  *      Deletes a namespace and all of the commands, variables, and other
00899  *      namespaces within it.
00900  *
00901  * Results:
00902  *      None.
00903  *
00904  * Side effects:
00905  *      When a namespace is deleted, it is automatically removed as a child of
00906  *      its parent namespace. Also, all its commands, variables and child
00907  *      namespaces are deleted.
00908  *
00909  *----------------------------------------------------------------------
00910  */
00911 
00912 void
00913 Tcl_DeleteNamespace(
00914     Tcl_Namespace *namespacePtr)/* Points to the namespace to delete. */
00915 {
00916     register Namespace *nsPtr = (Namespace *) namespacePtr;
00917     Interp *iPtr = (Interp *) nsPtr->interp;
00918     Namespace *globalNsPtr = (Namespace *)
00919             TclGetGlobalNamespace((Tcl_Interp *) iPtr);
00920     Tcl_HashEntry *entryPtr;
00921 
00922     /*
00923      * If the namespace has associated ensemble commands, delete them first.
00924      * This leaves the actual contents of the namespace alone (unless they are
00925      * linked ensemble commands, of course). Note that this code is actually
00926      * reentrant so command delete traces won't purturb things badly.
00927      */
00928 
00929     while (nsPtr->ensembles != NULL) {
00930         EnsembleConfig *ensemblePtr = (EnsembleConfig *) nsPtr->ensembles;
00931 
00932         /*
00933          * Splice out and link to indicate that we've already been killed.
00934          */
00935 
00936         nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr->next;
00937         ensemblePtr->next = ensemblePtr;
00938         Tcl_DeleteCommandFromToken(nsPtr->interp, ensemblePtr->token);
00939     }
00940 
00941     /*
00942      * If the namespace has a registered unknown handler (TIP 181), then free
00943      * it here.
00944      */
00945 
00946     if (nsPtr->unknownHandlerPtr != NULL) {
00947         Tcl_DecrRefCount(nsPtr->unknownHandlerPtr);
00948         nsPtr->unknownHandlerPtr = NULL;
00949     }
00950 
00951     /*
00952      * If the namespace is on the call frame stack, it is marked as "dying"
00953      * (NS_DYING is OR'd into its flags): the namespace can't be looked up by
00954      * name but its commands and variables are still usable by those active
00955      * call frames. When all active call frames referring to the namespace
00956      * have been popped from the Tcl stack, Tcl_PopCallFrame will call this
00957      * function again to delete everything in the namespace. If no nsName
00958      * objects refer to the namespace (i.e., if its refCount is zero), its
00959      * commands and variables are deleted and the storage for its namespace
00960      * structure is freed. Otherwise, if its refCount is nonzero, the
00961      * namespace's commands and variables are deleted but the structure isn't
00962      * freed. Instead, NS_DEAD is OR'd into the structure's flags to allow the
00963      * namespace resolution code to recognize that the namespace is "deleted".
00964      * The structure's storage is freed by FreeNsNameInternalRep when its
00965      * refCount reaches 0.
00966      */
00967 
00968     if (nsPtr->activationCount - (nsPtr == globalNsPtr) > 0) {
00969         nsPtr->flags |= NS_DYING;
00970         if (nsPtr->parentPtr != NULL) {
00971             entryPtr = Tcl_FindHashEntry(&nsPtr->parentPtr->childTable,
00972                     nsPtr->name);
00973             if (entryPtr != NULL) {
00974                 Tcl_DeleteHashEntry(entryPtr);
00975             }
00976         }
00977         nsPtr->parentPtr = NULL;
00978     } else if (!(nsPtr->flags & NS_KILLED)) {
00979         /*
00980          * Delete the namespace and everything in it. If this is the global
00981          * namespace, then clear it but don't free its storage unless the
00982          * interpreter is being torn down. Set the NS_KILLED flag to avoid
00983          * recursive calls here - if the namespace is really in the process of
00984          * being deleted, ignore any second call.
00985          */
00986 
00987         nsPtr->flags |= (NS_DYING|NS_KILLED);
00988 
00989         TclTeardownNamespace(nsPtr);
00990 
00991         if ((nsPtr != globalNsPtr) || (iPtr->flags & DELETED)) {
00992             /*
00993              * If this is the global namespace, then it may have residual
00994              * "errorInfo" and "errorCode" variables for errors that occurred
00995              * while it was being torn down. Try to clear the variable list
00996              * one last time.
00997              */
00998 
00999             TclDeleteNamespaceVars(nsPtr);
01000 
01001             Tcl_DeleteHashTable(&nsPtr->childTable);
01002             Tcl_DeleteHashTable(&nsPtr->cmdTable);
01003 
01004             /*
01005              * If the reference count is 0, then discard the namespace.
01006              * Otherwise, mark it as "dead" so that it can't be used.
01007              */
01008 
01009             if (nsPtr->refCount == 0) {
01010                 NamespaceFree(nsPtr);
01011             } else {
01012                 nsPtr->flags |= NS_DEAD;
01013             }
01014         } else {
01015             /*
01016              * Restore the ::errorInfo and ::errorCode traces.
01017              */
01018 
01019             EstablishErrorInfoTraces(NULL, nsPtr->interp, NULL, NULL, 0);
01020             EstablishErrorCodeTraces(NULL, nsPtr->interp, NULL, NULL, 0);
01021 
01022             /*
01023              * We didn't really kill it, so remove the KILLED marks, so it can
01024              * get killed later, avoiding mem leaks.
01025              */
01026 
01027             nsPtr->flags &= ~(NS_DYING|NS_KILLED);
01028         }
01029     }
01030 }
01031 
01032 /*
01033  *----------------------------------------------------------------------
01034  *
01035  * TclTeardownNamespace --
01036  *
01037  *      Used internally to dismantle and unlink a namespace when it is
01038  *      deleted. Divorces the namespace from its parent, and deletes all
01039  *      commands, variables, and child namespaces.
01040  *
01041  *      This is kept separate from Tcl_DeleteNamespace so that the global
01042  *      namespace can be handled specially.
01043  *
01044  * Results:
01045  *      None.
01046  *
01047  * Side effects:
01048  *      Removes this namespace from its parent's child namespace hashtable.
01049  *      Deletes all commands, variables and namespaces in this namespace.
01050  *
01051  *----------------------------------------------------------------------
01052  */
01053 
01054 void
01055 TclTeardownNamespace(
01056     register Namespace *nsPtr)  /* Points to the namespace to be dismantled
01057                                  * and unlinked from its parent. */
01058 {
01059     Interp *iPtr = (Interp *) nsPtr->interp;
01060     register Tcl_HashEntry *entryPtr;
01061     Tcl_HashSearch search;
01062     Tcl_Namespace *childNsPtr;
01063     Tcl_Command cmd;
01064     int i;
01065 
01066     /*
01067      * Start by destroying the namespace's variable table, since variables
01068      * might trigger traces. Variable table should be cleared but not freed!
01069      * TclDeleteNamespaceVars frees it, so we reinitialize it afterwards.
01070      */
01071 
01072     TclDeleteNamespaceVars(nsPtr);
01073     TclInitVarHashTable(&nsPtr->varTable, nsPtr);
01074 
01075     /*
01076      * Delete all commands in this namespace. Be careful when traversing the
01077      * hash table: when each command is deleted, it removes itself from the
01078      * command table.
01079      *
01080      * Don't optimize to Tcl_NextHashEntry() because of traces.
01081      */
01082 
01083     for (entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
01084             entryPtr != NULL;
01085             entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search)) {
01086         cmd = Tcl_GetHashValue(entryPtr);
01087         Tcl_DeleteCommandFromToken((Tcl_Interp *) iPtr, cmd);
01088     }
01089     Tcl_DeleteHashTable(&nsPtr->cmdTable);
01090     Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS);
01091 
01092     /*
01093      * Remove the namespace from its parent's child hashtable.
01094      */
01095 
01096     if (nsPtr->parentPtr != NULL) {
01097         entryPtr = Tcl_FindHashEntry(&nsPtr->parentPtr->childTable,
01098                 nsPtr->name);
01099         if (entryPtr != NULL) {
01100             Tcl_DeleteHashEntry(entryPtr);
01101         }
01102     }
01103     nsPtr->parentPtr = NULL;
01104 
01105     /*
01106      * Delete the namespace path if one is installed.
01107      */
01108 
01109     if (nsPtr->commandPathLength != 0) {
01110         UnlinkNsPath(nsPtr);
01111         nsPtr->commandPathLength = 0;
01112     }
01113     if (nsPtr->commandPathSourceList != NULL) {
01114         NamespacePathEntry *nsPathPtr = nsPtr->commandPathSourceList;
01115         do {
01116             if (nsPathPtr->nsPtr != NULL && nsPathPtr->creatorNsPtr != NULL) {
01117                 nsPathPtr->creatorNsPtr->cmdRefEpoch++;
01118             }
01119             nsPathPtr->nsPtr = NULL;
01120             nsPathPtr = nsPathPtr->nextPtr;
01121         } while (nsPathPtr != NULL);
01122         nsPtr->commandPathSourceList = NULL;
01123     }
01124 
01125     /*
01126      * Delete all the child namespaces.
01127      *
01128      * BE CAREFUL: When each child is deleted, it will divorce itself from its
01129      * parent. You can't traverse a hash table properly if its elements are
01130      * being deleted. We use only the Tcl_FirstHashEntry function to be safe.
01131      *
01132      * Don't optimize to Tcl_NextHashEntry() because of traces.
01133      */
01134 
01135     for (entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search);
01136             entryPtr != NULL;
01137             entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search)) {
01138         childNsPtr = Tcl_GetHashValue(entryPtr);
01139         Tcl_DeleteNamespace(childNsPtr);
01140     }
01141 
01142     /*
01143      * Free the namespace's export pattern array.
01144      */
01145 
01146     if (nsPtr->exportArrayPtr != NULL) {
01147         for (i = 0;  i < nsPtr->numExportPatterns;  i++) {
01148             ckfree(nsPtr->exportArrayPtr[i]);
01149         }
01150         ckfree((char *) nsPtr->exportArrayPtr);
01151         nsPtr->exportArrayPtr = NULL;
01152         nsPtr->numExportPatterns = 0;
01153         nsPtr->maxExportPatterns = 0;
01154     }
01155 
01156     /*
01157      * Free any client data associated with the namespace.
01158      */
01159 
01160     if (nsPtr->deleteProc != NULL) {
01161         (*nsPtr->deleteProc)(nsPtr->clientData);
01162     }
01163     nsPtr->deleteProc = NULL;
01164     nsPtr->clientData = NULL;
01165 
01166     /*
01167      * Reset the namespace's id field to ensure that this namespace won't be
01168      * interpreted as valid by, e.g., the cache validation code for cached
01169      * command references in Tcl_GetCommandFromObj.
01170      */
01171 
01172     nsPtr->nsId = 0;
01173 }
01174 
01175 /*
01176  *----------------------------------------------------------------------
01177  *
01178  * NamespaceFree --
01179  *
01180  *      Called after a namespace has been deleted, when its reference count
01181  *      reaches 0. Frees the data structure representing the namespace.
01182  *
01183  * Results:
01184  *      None.
01185  *
01186  * Side effects:
01187  *      None.
01188  *
01189  *----------------------------------------------------------------------
01190  */
01191 
01192 static void
01193 NamespaceFree(
01194     register Namespace *nsPtr)  /* Points to the namespace to free. */
01195 {
01196     /*
01197      * Most of the namespace's contents are freed when the namespace is
01198      * deleted by Tcl_DeleteNamespace. All that remains is to free its names
01199      * (for error messages), and the structure itself.
01200      */
01201 
01202     ckfree(nsPtr->name);
01203     ckfree(nsPtr->fullName);
01204 
01205     ckfree((char *) nsPtr);
01206 }
01207 
01208 /*
01209  *----------------------------------------------------------------------
01210  *
01211  * Tcl_Export --
01212  *
01213  *      Makes all the commands matching a pattern available to later be
01214  *      imported from the namespace specified by namespacePtr (or the current
01215  *      namespace if namespacePtr is NULL). The specified pattern is appended
01216  *      onto the namespace's export pattern list, which is optionally cleared
01217  *      beforehand.
01218  *
01219  * Results:
01220  *      Returns TCL_OK if successful, or TCL_ERROR (along with an error
01221  *      message in the interpreter's result) if something goes wrong.
01222  *
01223  * Side effects:
01224  *      Appends the export pattern onto the namespace's export list.
01225  *      Optionally reset the namespace's export pattern list.
01226  *
01227  *----------------------------------------------------------------------
01228  */
01229 
01230 int
01231 Tcl_Export(
01232     Tcl_Interp *interp,         /* Current interpreter. */
01233     Tcl_Namespace *namespacePtr,/* Points to the namespace from which commands
01234                                  * are to be exported. NULL for the current
01235                                  * namespace. */
01236     const char *pattern,        /* String pattern indicating which commands to
01237                                  * export. This pattern may not include any
01238                                  * namespace qualifiers; only commands in the
01239                                  * specified namespace may be exported. */
01240     int resetListFirst)         /* If nonzero, resets the namespace's export
01241                                  * list before appending. */
01242 {
01243 #define INIT_EXPORT_PATTERNS 5
01244     Namespace *nsPtr, *exportNsPtr, *dummyPtr;
01245     Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
01246     const char *simplePattern;
01247     char *patternCpy;
01248     int neededElems, len, i;
01249 
01250     /*
01251      * If the specified namespace is NULL, use the current namespace.
01252      */
01253 
01254     if (namespacePtr == NULL) {
01255         nsPtr = (Namespace *) currNsPtr;
01256     } else {
01257         nsPtr = (Namespace *) namespacePtr;
01258     }
01259 
01260     /*
01261      * If resetListFirst is true (nonzero), clear the namespace's export
01262      * pattern list.
01263      */
01264 
01265     if (resetListFirst) {
01266         if (nsPtr->exportArrayPtr != NULL) {
01267             for (i = 0;  i < nsPtr->numExportPatterns;  i++) {
01268                 ckfree(nsPtr->exportArrayPtr[i]);
01269             }
01270             ckfree((char *) nsPtr->exportArrayPtr);
01271             nsPtr->exportArrayPtr = NULL;
01272             TclInvalidateNsCmdLookup(nsPtr);
01273             nsPtr->numExportPatterns = 0;
01274             nsPtr->maxExportPatterns = 0;
01275         }
01276     }
01277 
01278     /*
01279      * Check that the pattern doesn't have namespace qualifiers.
01280      */
01281 
01282     TclGetNamespaceForQualName(interp, pattern, nsPtr,
01283             /*flags*/ (TCL_LEAVE_ERR_MSG | TCL_NAMESPACE_ONLY),
01284             &exportNsPtr, &dummyPtr, &dummyPtr, &simplePattern);
01285 
01286     if ((exportNsPtr != nsPtr) || (strcmp(pattern, simplePattern) != 0)) {
01287         Tcl_AppendResult(interp, "invalid export pattern \"", pattern,
01288                 "\": pattern can't specify a namespace", NULL);
01289         return TCL_ERROR;
01290     }
01291 
01292     /*
01293      * Make sure that we don't already have the pattern in the array
01294      */
01295 
01296     if (nsPtr->exportArrayPtr != NULL) {
01297         for (i = 0;  i < nsPtr->numExportPatterns;  i++) {
01298             if (strcmp(pattern, nsPtr->exportArrayPtr[i]) == 0) {
01299                 /*
01300                  * The pattern already exists in the list.
01301                  */
01302 
01303                 return TCL_OK;
01304             }
01305         }
01306     }
01307 
01308     /*
01309      * Make sure there is room in the namespace's pattern array for the new
01310      * pattern.
01311      */
01312 
01313     neededElems = nsPtr->numExportPatterns + 1;
01314     if (neededElems > nsPtr->maxExportPatterns) {
01315         nsPtr->maxExportPatterns = nsPtr->maxExportPatterns ?
01316                 2 * nsPtr->maxExportPatterns : INIT_EXPORT_PATTERNS;
01317         nsPtr->exportArrayPtr = (char **)
01318                 ckrealloc((char *) nsPtr->exportArrayPtr,
01319                 sizeof(char *) * nsPtr->maxExportPatterns);
01320     }
01321 
01322     /*
01323      * Add the pattern to the namespace's array of export patterns.
01324      */
01325 
01326     len = strlen(pattern);
01327     patternCpy = ckalloc((unsigned) (len + 1));
01328     memcpy(patternCpy, pattern, (unsigned) len + 1);
01329 
01330     nsPtr->exportArrayPtr[nsPtr->numExportPatterns] = patternCpy;
01331     nsPtr->numExportPatterns++;
01332 
01333     /*
01334      * The list of commands actually exported from the namespace might have
01335      * changed (probably will have!) However, we do not need to recompute this
01336      * just yet; next time we need the info will be soon enough.
01337      */
01338 
01339     TclInvalidateNsCmdLookup(nsPtr);
01340 
01341     return TCL_OK;
01342 #undef INIT_EXPORT_PATTERNS
01343 }
01344 
01345 /*
01346  *----------------------------------------------------------------------
01347  *
01348  * Tcl_AppendExportList --
01349  *
01350  *      Appends onto the argument object the list of export patterns for the
01351  *      specified namespace.
01352  *
01353  * Results:
01354  *      The return value is normally TCL_OK; in this case the object
01355  *      referenced by objPtr has each export pattern appended to it. If an
01356  *      error occurs, TCL_ERROR is returned and the interpreter's result holds
01357  *      an error message.
01358  *
01359  * Side effects:
01360  *      If necessary, the object referenced by objPtr is converted into a list
01361  *      object.
01362  *
01363  *----------------------------------------------------------------------
01364  */
01365 
01366 int
01367 Tcl_AppendExportList(
01368     Tcl_Interp *interp,         /* Interpreter used for error reporting. */
01369     Tcl_Namespace *namespacePtr,/* Points to the namespace whose export
01370                                  * pattern list is appended onto objPtr. NULL
01371                                  * for the current namespace. */
01372     Tcl_Obj *objPtr)            /* Points to the Tcl object onto which the
01373                                  * export pattern list is appended. */
01374 {
01375     Namespace *nsPtr;
01376     int i, result;
01377 
01378     /*
01379      * If the specified namespace is NULL, use the current namespace.
01380      */
01381 
01382     if (namespacePtr == NULL) {
01383         nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
01384     } else {
01385         nsPtr = (Namespace *) namespacePtr;
01386     }
01387 
01388     /*
01389      * Append the export pattern list onto objPtr.
01390      */
01391 
01392     for (i = 0;  i < nsPtr->numExportPatterns;  i++) {
01393         result = Tcl_ListObjAppendElement(interp, objPtr,
01394                 Tcl_NewStringObj(nsPtr->exportArrayPtr[i], -1));
01395         if (result != TCL_OK) {
01396             return result;
01397         }
01398     }
01399     return TCL_OK;
01400 }
01401 
01402 /*
01403  *----------------------------------------------------------------------
01404  *
01405  * Tcl_Import --
01406  *
01407  *      Imports all of the commands matching a pattern into the namespace
01408  *      specified by namespacePtr (or the current namespace if contextNsPtr is
01409  *      NULL). This is done by creating a new command (the "imported command")
01410  *      that points to the real command in its original namespace.
01411  *
01412  *      If matching commands are on the autoload path but haven't been loaded
01413  *      yet, this command forces them to be loaded, then creates the links to
01414  *      them.
01415  *
01416  * Results:
01417  *      Returns TCL_OK if successful, or TCL_ERROR (along with an error
01418  *      message in the interpreter's result) if something goes wrong.
01419  *
01420  * Side effects:
01421  *      Creates new commands in the importing namespace. These indirect calls
01422  *      back to the real command and are deleted if the real commands are
01423  *      deleted.
01424  *
01425  *----------------------------------------------------------------------
01426  */
01427 
01428 int
01429 Tcl_Import(
01430     Tcl_Interp *interp,         /* Current interpreter. */
01431     Tcl_Namespace *namespacePtr,/* Points to the namespace into which the
01432                                  * commands are to be imported. NULL for the
01433                                  * current namespace. */
01434     const char *pattern,        /* String pattern indicating which commands to
01435                                  * import. This pattern should be qualified by
01436                                  * the name of the namespace from which to
01437                                  * import the command(s). */
01438     int allowOverwrite)         /* If nonzero, allow existing commands to be
01439                                  * overwritten by imported commands. If 0,
01440                                  * return an error if an imported cmd
01441                                  * conflicts with an existing one. */
01442 {
01443     Namespace *nsPtr, *importNsPtr, *dummyPtr;
01444     const char *simplePattern;
01445     register Tcl_HashEntry *hPtr;
01446     Tcl_HashSearch search;
01447 
01448     /*
01449      * If the specified namespace is NULL, use the current namespace.
01450      */
01451 
01452     if (namespacePtr == NULL) {
01453         nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
01454     } else {
01455         nsPtr = (Namespace *) namespacePtr;
01456     }
01457 
01458     /*
01459      * First, invoke the "auto_import" command with the pattern being
01460      * imported. This command is part of the Tcl library. It looks for
01461      * imported commands in autoloaded libraries and loads them in. That way,
01462      * they will be found when we try to create links below.
01463      *
01464      * Note that we don't just call Tcl_EvalObjv() directly because we do not
01465      * want absence of the command to be a failure case.
01466      */
01467 
01468     if (Tcl_FindCommand(interp,"auto_import",NULL,TCL_GLOBAL_ONLY) != NULL) {
01469         Tcl_Obj *objv[2];
01470         int result;
01471 
01472         TclNewLiteralStringObj(objv[0], "auto_import");
01473         objv[1] = Tcl_NewStringObj(pattern, -1);
01474 
01475         Tcl_IncrRefCount(objv[0]);
01476         Tcl_IncrRefCount(objv[1]);
01477         result = Tcl_EvalObjv(interp, 2, objv, TCL_GLOBAL_ONLY);
01478         Tcl_DecrRefCount(objv[0]);
01479         Tcl_DecrRefCount(objv[1]);
01480 
01481         if (result != TCL_OK) {
01482             return TCL_ERROR;
01483         }
01484         Tcl_ResetResult(interp);
01485     }
01486 
01487     /*
01488      * From the pattern, find the namespace from which we are importing and
01489      * get the simple pattern (no namespace qualifiers or ::'s) at the end.
01490      */
01491 
01492     if (strlen(pattern) == 0) {
01493         Tcl_SetObjResult(interp, Tcl_NewStringObj("empty import pattern", -1));
01494         return TCL_ERROR;
01495     }
01496     TclGetNamespaceForQualName(interp, pattern, nsPtr,
01497             /*flags*/ (TCL_LEAVE_ERR_MSG | TCL_NAMESPACE_ONLY),
01498             &importNsPtr, &dummyPtr, &dummyPtr, &simplePattern);
01499 
01500     if (importNsPtr == NULL) {
01501         Tcl_AppendResult(interp, "unknown namespace in import pattern \"",
01502                 pattern, "\"", NULL);
01503         Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", pattern, NULL);
01504         return TCL_ERROR;
01505     }
01506     if (importNsPtr == nsPtr) {
01507         if (pattern == simplePattern) {
01508             Tcl_AppendResult(interp,
01509                     "no namespace specified in import pattern \"", pattern,
01510                     "\"", NULL);
01511         } else {
01512             Tcl_AppendResult(interp, "import pattern \"", pattern,
01513                     "\" tries to import from namespace \"",
01514                     importNsPtr->name, "\" into itself", NULL);
01515         }
01516         return TCL_ERROR;
01517     }
01518 
01519     /*
01520      * Scan through the command table in the source namespace and look for
01521      * exported commands that match the string pattern. Create an "imported
01522      * command" in the current namespace for each imported command; these
01523      * commands redirect their invocations to the "real" command.
01524      */
01525 
01526     if ((simplePattern != NULL) && TclMatchIsTrivial(simplePattern)) {
01527         hPtr = Tcl_FindHashEntry(&importNsPtr->cmdTable, simplePattern);
01528         if (hPtr == NULL) {
01529             return TCL_OK;
01530         }
01531         return DoImport(interp, nsPtr, hPtr, simplePattern, pattern,
01532                 importNsPtr, allowOverwrite);
01533     }
01534     for (hPtr = Tcl_FirstHashEntry(&importNsPtr->cmdTable, &search);
01535             (hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) {
01536         char *cmdName = Tcl_GetHashKey(&importNsPtr->cmdTable, hPtr);
01537         if (Tcl_StringMatch(cmdName, simplePattern) &&
01538                 DoImport(interp, nsPtr, hPtr, cmdName, pattern, importNsPtr,
01539                 allowOverwrite) == TCL_ERROR) {
01540             return TCL_ERROR;
01541         }
01542     }
01543     return TCL_OK;
01544 }
01545 
01546 /*
01547  *----------------------------------------------------------------------
01548  *
01549  * DoImport --
01550  *
01551  *      Import a particular command from one namespace into another. Helper
01552  *      for Tcl_Import().
01553  *
01554  * Results:
01555  *      Standard Tcl result code. If TCL_ERROR, appends an error message to
01556  *      the interpreter result.
01557  *
01558  * Side effects:
01559  *      A new command is created in the target namespace unless this is a
01560  *      reimport of exactly the same command as before.
01561  *
01562  *----------------------------------------------------------------------
01563  */
01564 
01565 static int
01566 DoImport(
01567     Tcl_Interp *interp,
01568     Namespace *nsPtr,
01569     Tcl_HashEntry *hPtr,
01570     const char *cmdName,
01571     const char *pattern,
01572     Namespace *importNsPtr,
01573     int allowOverwrite)
01574 {
01575     int i = 0, exported = 0;
01576     Tcl_HashEntry *found;
01577 
01578     /*
01579      * The command cmdName in the source namespace matches the pattern. Check
01580      * whether it was exported. If it wasn't, we ignore it.
01581      */
01582 
01583     while (!exported && (i < importNsPtr->numExportPatterns)) {
01584         exported |= Tcl_StringMatch(cmdName, importNsPtr->exportArrayPtr[i++]);
01585     }
01586     if (!exported) {
01587         return TCL_OK;
01588     }
01589 
01590     /*
01591      * Unless there is a name clash, create an imported command in the current
01592      * namespace that refers to cmdPtr.
01593      */
01594 
01595     found = Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName);
01596     if ((found == NULL) || allowOverwrite) {
01597         /*
01598          * Create the imported command and its client data. To create the new
01599          * command in the current namespace, generate a fully qualified name
01600          * for it.
01601          */
01602 
01603         Tcl_DString ds;
01604         Tcl_Command importedCmd;
01605         ImportedCmdData *dataPtr;
01606         Command *cmdPtr;
01607         ImportRef *refPtr;
01608 
01609         Tcl_DStringInit(&ds);
01610         Tcl_DStringAppend(&ds, nsPtr->fullName, -1);
01611         if (nsPtr != ((Interp *) interp)->globalNsPtr) {
01612             Tcl_DStringAppend(&ds, "::", 2);
01613         }
01614         Tcl_DStringAppend(&ds, cmdName, -1);
01615 
01616         /*
01617          * Check whether creating the new imported command in the current
01618          * namespace would create a cycle of imported command references.
01619          */
01620 
01621         cmdPtr = Tcl_GetHashValue(hPtr);
01622         if (found != NULL && cmdPtr->deleteProc == DeleteImportedCmd) {
01623             Command *overwrite = Tcl_GetHashValue(found);
01624             Command *link = cmdPtr;
01625 
01626             while (link->deleteProc == DeleteImportedCmd) {
01627                 ImportedCmdData *dataPtr = link->objClientData;
01628 
01629                 link = dataPtr->realCmdPtr;
01630                 if (overwrite == link) {
01631                     Tcl_AppendResult(interp, "import pattern \"", pattern,
01632                             "\" would create a loop containing command \"",
01633                             Tcl_DStringValue(&ds), "\"", NULL);
01634                     Tcl_DStringFree(&ds);
01635                     return TCL_ERROR;
01636                 }
01637             }
01638         }
01639 
01640         dataPtr = (ImportedCmdData *) ckalloc(sizeof(ImportedCmdData));
01641         importedCmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds),
01642                 InvokeImportedCmd, dataPtr, DeleteImportedCmd);
01643         dataPtr->realCmdPtr = cmdPtr;
01644         dataPtr->selfPtr = (Command *) importedCmd;
01645         dataPtr->selfPtr->compileProc = cmdPtr->compileProc;
01646         Tcl_DStringFree(&ds);
01647 
01648         /*
01649          * Create an ImportRef structure describing this new import command
01650          * and add it to the import ref list in the "real" command.
01651          */
01652 
01653         refPtr = (ImportRef *) ckalloc(sizeof(ImportRef));
01654         refPtr->importedCmdPtr = (Command *) importedCmd;
01655         refPtr->nextPtr = cmdPtr->importRefPtr;
01656         cmdPtr->importRefPtr = refPtr;
01657     } else {
01658         Command *overwrite = Tcl_GetHashValue(found);
01659 
01660         if (overwrite->deleteProc == DeleteImportedCmd) {
01661             ImportedCmdData *dataPtr = overwrite->objClientData;
01662 
01663             if (dataPtr->realCmdPtr == Tcl_GetHashValue(hPtr)) {
01664                 /*
01665                  * Repeated import of same command is acceptable.
01666                  */
01667 
01668                 return TCL_OK;
01669             }
01670         }
01671         Tcl_AppendResult(interp, "can't import command \"", cmdName,
01672                 "\": already exists", NULL);
01673         return TCL_ERROR;
01674     }
01675     return TCL_OK;
01676 }
01677 
01678 /*
01679  *----------------------------------------------------------------------
01680  *
01681  * Tcl_ForgetImport --
01682  *
01683  *      Deletes commands previously imported into the namespace indicated.
01684  *      The by namespacePtr, or the current namespace of interp, when
01685  *      namespacePtr is NULL. The pattern controls which imported commands are
01686  *      deleted. A simple pattern, one without namespace separators, matches
01687  *      the current command names of imported commands in the namespace.
01688  *      Matching imported commands are deleted. A qualified pattern is
01689  *      interpreted as deletion selection on the basis of where the command is
01690  *      imported from. The original command and "first link" command for each
01691  *      imported command are determined, and they are matched against the
01692  *      pattern. A match leads to deletion of the imported command.
01693  *
01694  * Results:
01695  *      Returns TCL_ERROR and records an error message in the interp result if
01696  *      a namespace qualified pattern refers to a namespace that does not
01697  *      exist. Otherwise, returns TCL_OK.
01698  *
01699  * Side effects:
01700  *      May delete commands.
01701  *
01702  *----------------------------------------------------------------------
01703  */
01704 
01705 int
01706 Tcl_ForgetImport(
01707     Tcl_Interp *interp,         /* Current interpreter. */
01708     Tcl_Namespace *namespacePtr,/* Points to the namespace from which
01709                                  * previously imported commands should be
01710                                  * removed. NULL for current namespace. */
01711     const char *pattern)        /* String pattern indicating which imported
01712                                  * commands to remove. */
01713 {
01714     Namespace *nsPtr, *sourceNsPtr, *dummyPtr;
01715     const char *simplePattern;
01716     char *cmdName;
01717     register Tcl_HashEntry *hPtr;
01718     Tcl_HashSearch search;
01719 
01720     /*
01721      * If the specified namespace is NULL, use the current namespace.
01722      */
01723 
01724     if (namespacePtr == NULL) {
01725         nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
01726     } else {
01727         nsPtr = (Namespace *) namespacePtr;
01728     }
01729 
01730     /*
01731      * Parse the pattern into its namespace-qualification (if any) and the
01732      * simple pattern.
01733      */
01734 
01735     TclGetNamespaceForQualName(interp, pattern, nsPtr,
01736             /*flags*/ (TCL_LEAVE_ERR_MSG | TCL_NAMESPACE_ONLY),
01737             &sourceNsPtr, &dummyPtr, &dummyPtr, &simplePattern);
01738 
01739     if (sourceNsPtr == NULL) {
01740         Tcl_AppendResult(interp,
01741                 "unknown namespace in namespace forget pattern \"",
01742                 pattern, "\"", NULL);
01743         Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", pattern, NULL);
01744         return TCL_ERROR;
01745     }
01746 
01747     if (strcmp(pattern, simplePattern) == 0) {
01748         /*
01749          * The pattern is simple. Delete any imported commands that match it.
01750          */
01751 
01752         if (TclMatchIsTrivial(simplePattern)) {
01753             Command *cmdPtr;
01754 
01755             hPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simplePattern);
01756             if ((hPtr != NULL)
01757                     && (cmdPtr = Tcl_GetHashValue(hPtr))
01758                     && (cmdPtr->deleteProc == DeleteImportedCmd)) {
01759                 Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
01760             }
01761             return TCL_OK;
01762         }
01763         for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
01764                 (hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) {
01765             Command *cmdPtr = Tcl_GetHashValue(hPtr);
01766 
01767             if (cmdPtr->deleteProc != DeleteImportedCmd) {
01768                 continue;
01769             }
01770             cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, hPtr);
01771             if (Tcl_StringMatch(cmdName, simplePattern)) {
01772                 Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
01773             }
01774         }
01775         return TCL_OK;
01776     }
01777 
01778     /*
01779      * The pattern was namespace-qualified.
01780      */
01781 
01782     for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); (hPtr != NULL);
01783             hPtr = Tcl_NextHashEntry(&search)) {
01784         Tcl_CmdInfo info;
01785         Tcl_Command token = Tcl_GetHashValue(hPtr);
01786         Tcl_Command origin = TclGetOriginalCommand(token);
01787 
01788         if (Tcl_GetCommandInfoFromToken(origin, &info) == 0) {
01789             continue;                   /* Not an imported command. */
01790         }
01791         if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) {
01792             /*
01793              * Original not in namespace we're matching. Check the first link
01794              * in the import chain.
01795              */
01796 
01797             Command *cmdPtr = (Command *) token;
01798             ImportedCmdData *dataPtr = cmdPtr->objClientData;
01799             Tcl_Command firstToken = (Tcl_Command) dataPtr->realCmdPtr;
01800 
01801             if (firstToken == origin) {
01802                 continue;
01803             }
01804             Tcl_GetCommandInfoFromToken(firstToken, &info);
01805             if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) {
01806                 continue;
01807             }
01808             origin = firstToken;
01809         }
01810         if (Tcl_StringMatch(Tcl_GetCommandName(NULL, origin), simplePattern)) {
01811             Tcl_DeleteCommandFromToken(interp, token);
01812         }
01813     }
01814     return TCL_OK;
01815 }
01816 
01817 /*
01818  *----------------------------------------------------------------------
01819  *
01820  * TclGetOriginalCommand --
01821  *
01822  *      An imported command is created in an namespace when a "real" command
01823  *      is imported from another namespace. If the specified command is an
01824  *      imported command, this function returns the original command it refers
01825  *      to.
01826  *
01827  * Results:
01828  *      If the command was imported into a sequence of namespaces a, b,...,n
01829  *      where each successive namespace just imports the command from the
01830  *      previous namespace, this function returns the Tcl_Command token in the
01831  *      first namespace, a. Otherwise, if the specified command is not an
01832  *      imported command, the function returns NULL.
01833  *
01834  * Side effects:
01835  *      None.
01836  *
01837  *----------------------------------------------------------------------
01838  */
01839 
01840 Tcl_Command
01841 TclGetOriginalCommand(
01842     Tcl_Command command)        /* The imported command for which the original
01843                                  * command should be returned. */
01844 {
01845     register Command *cmdPtr = (Command *) command;
01846     ImportedCmdData *dataPtr;
01847 
01848     if (cmdPtr->deleteProc != DeleteImportedCmd) {
01849         return NULL;
01850     }
01851 
01852     while (cmdPtr->deleteProc == DeleteImportedCmd) {
01853         dataPtr = cmdPtr->objClientData;
01854         cmdPtr = dataPtr->realCmdPtr;
01855     }
01856     return (Tcl_Command) cmdPtr;
01857 }
01858 
01859 /*
01860  *----------------------------------------------------------------------
01861  *
01862  * InvokeImportedCmd --
01863  *
01864  *      Invoked by Tcl whenever the user calls an imported command that was
01865  *      created by Tcl_Import. Finds the "real" command (in another
01866  *      namespace), and passes control to it.
01867  *
01868  * Results:
01869  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
01870  *
01871  * Side effects:
01872  *      Returns a result in the interpreter's result object. If anything goes
01873  *      wrong, the result object is set to an error message.
01874  *
01875  *----------------------------------------------------------------------
01876  */
01877 
01878 static int
01879 InvokeImportedCmd(
01880     ClientData clientData,      /* Points to the imported command's
01881                                  * ImportedCmdData structure. */
01882     Tcl_Interp *interp,         /* Current interpreter. */
01883     int objc,                   /* Number of arguments. */
01884     Tcl_Obj *const objv[])      /* The argument objects. */
01885 {
01886     register ImportedCmdData *dataPtr = clientData;
01887     register Command *realCmdPtr = dataPtr->realCmdPtr;
01888 
01889     return (*realCmdPtr->objProc)(realCmdPtr->objClientData, interp,
01890             objc, objv);
01891 }
01892 
01893 /*
01894  *----------------------------------------------------------------------
01895  *
01896  * DeleteImportedCmd --
01897  *
01898  *      Invoked by Tcl whenever an imported command is deleted. The "real"
01899  *      command keeps a list of all the imported commands that refer to it, so
01900  *      those imported commands can be deleted when the real command is
01901  *      deleted. This function removes the imported command reference from the
01902  *      real command's list, and frees up the memory associated with the
01903  *      imported command.
01904  *
01905  * Results:
01906  *      None.
01907  *
01908  * Side effects:
01909  *      Removes the imported command from the real command's import list.
01910  *
01911  *----------------------------------------------------------------------
01912  */
01913 
01914 static void
01915 DeleteImportedCmd(
01916     ClientData clientData)      /* Points to the imported command's
01917                                  * ImportedCmdData structure. */
01918 {
01919     ImportedCmdData *dataPtr = clientData;
01920     Command *realCmdPtr = dataPtr->realCmdPtr;
01921     Command *selfPtr = dataPtr->selfPtr;
01922     register ImportRef *refPtr, *prevPtr;
01923 
01924     prevPtr = NULL;
01925     for (refPtr = realCmdPtr->importRefPtr; refPtr != NULL;
01926             refPtr = refPtr->nextPtr) {
01927         if (refPtr->importedCmdPtr == selfPtr) {
01928             /*
01929              * Remove *refPtr from real command's list of imported commands
01930              * that refer to it.
01931              */
01932 
01933             if (prevPtr == NULL) { /* refPtr is first in list. */
01934                 realCmdPtr->importRefPtr = refPtr->nextPtr;
01935             } else {
01936                 prevPtr->nextPtr = refPtr->nextPtr;
01937             }
01938             ckfree((char *) refPtr);
01939             ckfree((char *) dataPtr);
01940             return;
01941         }
01942         prevPtr = refPtr;
01943     }
01944 
01945     Tcl_Panic("DeleteImportedCmd: did not find cmd in real cmd's list of import references");
01946 }
01947 
01948 /*
01949  *----------------------------------------------------------------------
01950  *
01951  * TclGetNamespaceForQualName --
01952  *
01953  *      Given a qualified name specifying a command, variable, or namespace,
01954  *      and a namespace in which to resolve the name, this function returns a
01955  *      pointer to the namespace that contains the item. A qualified name
01956  *      consists of the "simple" name of an item qualified by the names of an
01957  *      arbitrary number of containing namespace separated by "::"s. If the
01958  *      qualified name starts with "::", it is interpreted absolutely from the
01959  *      global namespace. Otherwise, it is interpreted relative to the
01960  *      namespace specified by cxtNsPtr if it is non-NULL. If cxtNsPtr is
01961  *      NULL, the name is interpreted relative to the current namespace.
01962  *
01963  *      A relative name like "foo::bar::x" can be found starting in either the
01964  *      current namespace or in the global namespace. So each search usually
01965  *      follows two tracks, and two possible namespaces are returned. If the
01966  *      function sets either *nsPtrPtr or *altNsPtrPtr to NULL, then that path
01967  *      failed.
01968  *
01969  *      If "flags" contains TCL_GLOBAL_ONLY, the relative qualified name is
01970  *      sought only in the global :: namespace. The alternate search (also)
01971  *      starting from the global namespace is ignored and *altNsPtrPtr is set
01972  *      NULL.
01973  *
01974  *      If "flags" contains TCL_NAMESPACE_ONLY, the relative qualified name is
01975  *      sought only in the namespace specified by cxtNsPtr. The alternate
01976  *      search starting from the global namespace is ignored and *altNsPtrPtr
01977  *      is set NULL. If both TCL_GLOBAL_ONLY and TCL_NAMESPACE_ONLY are
01978  *      specified, TCL_GLOBAL_ONLY is ignored and the search starts from the
01979  *      namespace specified by cxtNsPtr.
01980  *
01981  *      If "flags" contains TCL_CREATE_NS_IF_UNKNOWN, all namespace components
01982  *      of the qualified name that cannot be found are automatically created
01983  *      within their specified parent. This makes sure that functions like
01984  *      Tcl_CreateCommand always succeed. There is no alternate search path,
01985  *      so *altNsPtrPtr is set NULL.
01986  *
01987  *      If "flags" contains TCL_FIND_ONLY_NS, the qualified name is treated as
01988  *      a reference to a namespace, and the entire qualified name is followed.
01989  *      If the name is relative, the namespace is looked up only in the
01990  *      current namespace. A pointer to the namespace is stored in *nsPtrPtr
01991  *      and NULL is stored in *simpleNamePtr. Otherwise, if TCL_FIND_ONLY_NS
01992  *      is not specified, only the leading components are treated as namespace
01993  *      names, and a pointer to the simple name of the final component is
01994  *      stored in *simpleNamePtr.
01995  *
01996  * Results:
01997  *      It sets *nsPtrPtr and *altNsPtrPtr to point to the two possible
01998  *      namespaces which represent the last (containing) namespace in the
01999  *      qualified name. If the function sets either *nsPtrPtr or *altNsPtrPtr
02000  *      to NULL, then the search along that path failed. The function also
02001  *      stores a pointer to the simple name of the final component in
02002  *      *simpleNamePtr. If the qualified name is "::" or was treated as a
02003  *      namespace reference (TCL_FIND_ONLY_NS), the function stores a pointer
02004  *      to the namespace in *nsPtrPtr, NULL in *altNsPtrPtr, and sets
02005  *      *simpleNamePtr to point to an empty string.
02006  *
02007  *      If there is an error, this function returns TCL_ERROR. If "flags"
02008  *      contains TCL_LEAVE_ERR_MSG, an error message is returned in the
02009  *      interpreter's result object. Otherwise, the interpreter's result
02010  *      object is left unchanged.
02011  *
02012  *      *actualCxtPtrPtr is set to the actual context namespace. It is set to
02013  *      the input context namespace pointer in cxtNsPtr. If cxtNsPtr is NULL,
02014  *      it is set to the current namespace context.
02015  *
02016  *      For backwards compatibility with the TclPro byte code loader, this
02017  *      function always returns TCL_OK.
02018  *
02019  * Side effects:
02020  *      If "flags" contains TCL_CREATE_NS_IF_UNKNOWN, new namespaces may be
02021  *      created.
02022  *
02023  *----------------------------------------------------------------------
02024  */
02025 
02026 int
02027 TclGetNamespaceForQualName(
02028     Tcl_Interp *interp,         /* Interpreter in which to find the namespace
02029                                  * containing qualName. */
02030     const char *qualName,       /* A namespace-qualified name of an command,
02031                                  * variable, or namespace. */
02032     Namespace *cxtNsPtr,        /* The namespace in which to start the search
02033                                  * for qualName's namespace. If NULL start
02034                                  * from the current namespace. Ignored if
02035                                  * TCL_GLOBAL_ONLY is set. */
02036     int flags,                  /* Flags controlling the search: an OR'd
02037                                  * combination of TCL_GLOBAL_ONLY,
02038                                  * TCL_NAMESPACE_ONLY, TCL_FIND_ONLY_NS, and
02039                                  * TCL_CREATE_NS_IF_UNKNOWN. */
02040     Namespace **nsPtrPtr,       /* Address where function stores a pointer to
02041                                  * containing namespace if qualName is found
02042                                  * starting from *cxtNsPtr or, if
02043                                  * TCL_GLOBAL_ONLY is set, if qualName is
02044                                  * found in the global :: namespace. NULL is
02045                                  * stored otherwise. */
02046     Namespace **altNsPtrPtr,    /* Address where function stores a pointer to
02047                                  * containing namespace if qualName is found
02048                                  * starting from the global :: namespace.
02049                                  * NULL is stored if qualName isn't found
02050                                  * starting from :: or if the TCL_GLOBAL_ONLY,
02051                                  * TCL_NAMESPACE_ONLY, TCL_FIND_ONLY_NS,
02052                                  * TCL_CREATE_NS_IF_UNKNOWN flag is set. */
02053     Namespace **actualCxtPtrPtr,/* Address where function stores a pointer to
02054                                  * the actual namespace from which the search
02055                                  * started. This is either cxtNsPtr, the ::
02056                                  * namespace if TCL_GLOBAL_ONLY was specified,
02057                                  * or the current namespace if cxtNsPtr was
02058                                  * NULL. */
02059     const char **simpleNamePtr) /* Address where function stores the simple
02060                                  * name at end of the qualName, or NULL if
02061                                  * qualName is "::" or the flag
02062                                  * TCL_FIND_ONLY_NS was specified. */
02063 {
02064     Interp *iPtr = (Interp *) interp;
02065     Namespace *nsPtr = cxtNsPtr;
02066     Namespace *altNsPtr;
02067     Namespace *globalNsPtr = iPtr->globalNsPtr;
02068     const char *start, *end;
02069     const char *nsName;
02070     Tcl_HashEntry *entryPtr;
02071     Tcl_DString buffer;
02072     int len;
02073 
02074     /*
02075      * Determine the context namespace nsPtr in which to start the primary
02076      * search. If the qualName name starts with a "::" or TCL_GLOBAL_ONLY was
02077      * specified, search from the global namespace. Otherwise, use the
02078      * namespace given in cxtNsPtr, or if that is NULL, use the current
02079      * namespace context. Note that we always treat two or more adjacent ":"s
02080      * as a namespace separator.
02081      */
02082 
02083     if (flags & TCL_GLOBAL_ONLY) {
02084         nsPtr = globalNsPtr;
02085     } else if (nsPtr == NULL) {
02086         nsPtr = iPtr->varFramePtr->nsPtr;
02087     }
02088 
02089     start = qualName;                   /* Points to start of qualifying
02090                                          * namespace. */
02091     if ((*qualName == ':') && (*(qualName+1) == ':')) {
02092         start = qualName+2;             /* Skip over the initial :: */
02093         while (*start == ':') {
02094             start++;                    /* Skip over a subsequent : */
02095         }
02096         nsPtr = globalNsPtr;
02097         if (*start == '\0') {           /* qualName is just two or more
02098                                          * ":"s. */
02099             *nsPtrPtr = globalNsPtr;
02100             *altNsPtrPtr = NULL;
02101             *actualCxtPtrPtr = globalNsPtr;
02102             *simpleNamePtr = start;     /* Points to empty string. */
02103             return TCL_OK;
02104         }
02105     }
02106     *actualCxtPtrPtr = nsPtr;
02107 
02108     /*
02109      * Start an alternate search path starting with the global namespace.
02110      * However, if the starting context is the global namespace, or if the
02111      * flag is set to search only the namespace *cxtNsPtr, ignore the
02112      * alternate search path.
02113      */
02114 
02115     altNsPtr = globalNsPtr;
02116     if ((nsPtr == globalNsPtr)
02117             || (flags & (TCL_NAMESPACE_ONLY | TCL_FIND_ONLY_NS))) {
02118         altNsPtr = NULL;
02119     }
02120 
02121     /*
02122      * Loop to resolve each namespace qualifier in qualName.
02123      */
02124 
02125     Tcl_DStringInit(&buffer);
02126     end = start;
02127     while (*start != '\0') {
02128         /*
02129          * Find the next namespace qualifier (i.e., a name ending in "::") or
02130          * the end of the qualified name (i.e., a name ending in "\0"). Set
02131          * len to the number of characters, starting from start, in the name;
02132          * set end to point after the "::"s or at the "\0".
02133          */
02134 
02135         len = 0;
02136         for (end = start;  *end != '\0';  end++) {
02137             if ((*end == ':') && (*(end+1) == ':')) {
02138                 end += 2;               /* Skip over the initial :: */
02139                 while (*end == ':') {
02140                     end++;              /* Skip over the subsequent : */
02141                 }
02142                 break;                  /* Exit for loop; end is after ::'s */
02143             }
02144             len++;
02145         }
02146 
02147         if (*end=='\0' && !(end-start>=2 && *(end-1)==':' && *(end-2)==':')) {
02148             /*
02149              * qualName ended with a simple name at start. If TCL_FIND_ONLY_NS
02150              * was specified, look this up as a namespace. Otherwise, start is
02151              * the name of a cmd or var and we are done.
02152              */
02153 
02154             if (flags & TCL_FIND_ONLY_NS) {
02155                 nsName = start;
02156             } else {
02157                 *nsPtrPtr = nsPtr;
02158                 *altNsPtrPtr = altNsPtr;
02159                 *simpleNamePtr = start;
02160                 Tcl_DStringFree(&buffer);
02161                 return TCL_OK;
02162             }
02163         } else {
02164             /*
02165              * start points to the beginning of a namespace qualifier ending
02166              * in "::". end points to the start of a name in that namespace
02167              * that might be empty. Copy the namespace qualifier to a buffer
02168              * so it can be null terminated. We can't modify the incoming
02169              * qualName since it may be a string constant.
02170              */
02171 
02172             Tcl_DStringSetLength(&buffer, 0);
02173             Tcl_DStringAppend(&buffer, start, len);
02174             nsName = Tcl_DStringValue(&buffer);
02175         }
02176 
02177         /*
02178          * Look up the namespace qualifier nsName in the current namespace
02179          * context. If it isn't found but TCL_CREATE_NS_IF_UNKNOWN is set,
02180          * create that qualifying namespace. This is needed for functions like
02181          * Tcl_CreateCommand that cannot fail.
02182          */
02183 
02184         if (nsPtr != NULL) {
02185             entryPtr = Tcl_FindHashEntry(&nsPtr->childTable, nsName);
02186             if (entryPtr != NULL) {
02187                 nsPtr = Tcl_GetHashValue(entryPtr);
02188             } else if (flags & TCL_CREATE_NS_IF_UNKNOWN) {
02189                 Tcl_CallFrame *framePtr;
02190 
02191                 (void) TclPushStackFrame(interp, &framePtr,
02192                         (Tcl_Namespace *) nsPtr, /*isProcCallFrame*/ 0);
02193 
02194                 nsPtr = (Namespace *) Tcl_CreateNamespace(interp, nsName,
02195                         NULL, NULL);
02196                 TclPopStackFrame(interp);
02197 
02198                 if (nsPtr == NULL) {
02199                     Tcl_Panic("Could not create namespace '%s'", nsName);
02200                 }
02201             } else {                    /* Namespace not found and was not
02202                                          * created. */
02203                 nsPtr = NULL;
02204             }
02205         }
02206 
02207         /*
02208          * Look up the namespace qualifier in the alternate search path too.
02209          */
02210 
02211         if (altNsPtr != NULL) {
02212             entryPtr = Tcl_FindHashEntry(&altNsPtr->childTable, nsName);
02213             if (entryPtr != NULL) {
02214                 altNsPtr = Tcl_GetHashValue(entryPtr);
02215             } else {
02216                 altNsPtr = NULL;
02217             }
02218         }
02219 
02220         /*
02221          * If both search paths have failed, return NULL results.
02222          */
02223 
02224         if ((nsPtr == NULL) && (altNsPtr == NULL)) {
02225             *nsPtrPtr = NULL;
02226             *altNsPtrPtr = NULL;
02227             *simpleNamePtr = NULL;
02228             Tcl_DStringFree(&buffer);
02229             return TCL_OK;
02230         }
02231 
02232         start = end;
02233     }
02234 
02235     /*
02236      * We ignore trailing "::"s in a namespace name, but in a command or
02237      * variable name, trailing "::"s refer to the cmd or var named {}.
02238      */
02239 
02240     if ((flags & TCL_FIND_ONLY_NS) || (end>start && *(end-1)!=':')) {
02241         *simpleNamePtr = NULL;          /* Found namespace name. */
02242     } else {
02243         *simpleNamePtr = end;           /* Found cmd/var: points to empty
02244                                          * string. */
02245     }
02246 
02247     /*
02248      * As a special case, if we are looking for a namespace and qualName is ""
02249      * and the current active namespace (nsPtr) is not the global namespace,
02250      * return NULL (no namespace was found). This is because namespaces can
02251      * not have empty names except for the global namespace.
02252      */
02253 
02254     if ((flags & TCL_FIND_ONLY_NS) && (*qualName == '\0')
02255             && (nsPtr != globalNsPtr)) {
02256         nsPtr = NULL;
02257     }
02258 
02259     *nsPtrPtr = nsPtr;
02260     *altNsPtrPtr = altNsPtr;
02261     Tcl_DStringFree(&buffer);
02262     return TCL_OK;
02263 }
02264 
02265 /*
02266  *----------------------------------------------------------------------
02267  *
02268  * Tcl_FindNamespace --
02269  *
02270  *      Searches for a namespace.
02271  *
02272  * Results:
02273  *      Returns a pointer to the namespace if it is found. Otherwise, returns
02274  *      NULL and leaves an error message in the interpreter's result object if
02275  *      "flags" contains TCL_LEAVE_ERR_MSG.
02276  *
02277  * Side effects:
02278  *      None.
02279  *
02280  *----------------------------------------------------------------------
02281  */
02282 
02283 Tcl_Namespace *
02284 Tcl_FindNamespace(
02285     Tcl_Interp *interp,         /* The interpreter in which to find the
02286                                  * namespace. */
02287     const char *name,           /* Namespace name. If it starts with "::",
02288                                  * will be looked up in global namespace.
02289                                  * Else, looked up first in contextNsPtr
02290                                  * (current namespace if contextNsPtr is
02291                                  * NULL), then in global namespace. */
02292     Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag is set or
02293                                  * if the name starts with "::". Otherwise,
02294                                  * points to namespace in which to resolve
02295                                  * name; if NULL, look up name in the current
02296                                  * namespace. */
02297     register int flags)         /* Flags controlling namespace lookup: an OR'd
02298                                  * combination of TCL_GLOBAL_ONLY and
02299                                  * TCL_LEAVE_ERR_MSG flags. */
02300 {
02301     Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr;
02302     const char *dummy;
02303 
02304     /*
02305      * Find the namespace(s) that contain the specified namespace name. Add
02306      * the TCL_FIND_ONLY_NS flag to resolve the name all the way down to its
02307      * last component, a namespace.
02308      */
02309 
02310     TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr,
02311             flags|TCL_FIND_ONLY_NS, &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy);
02312 
02313     if (nsPtr != NULL) {
02314         return (Tcl_Namespace *) nsPtr;
02315     } else if (flags & TCL_LEAVE_ERR_MSG) {
02316         Tcl_ResetResult(interp);
02317         Tcl_AppendResult(interp, "unknown namespace \"", name, "\"", NULL);
02318         Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", name, NULL);
02319     }
02320     return NULL;
02321 }
02322 
02323 /*
02324  *----------------------------------------------------------------------
02325  *
02326  * Tcl_FindCommand --
02327  *
02328  *      Searches for a command.
02329  *
02330  * Results:
02331  *      Returns a token for the command if it is found. Otherwise, if it can't
02332  *      be found or there is an error, returns NULL and leaves an error
02333  *      message in the interpreter's result object if "flags" contains
02334  *      TCL_LEAVE_ERR_MSG.
02335  *
02336  * Side effects:
02337  *      None.
02338  *
02339  *----------------------------------------------------------------------
02340  */
02341 
02342 Tcl_Command
02343 Tcl_FindCommand(
02344     Tcl_Interp *interp,         /* The interpreter in which to find the
02345                                  * command and to report errors. */
02346     const char *name,           /* Command's name. If it starts with "::",
02347                                  * will be looked up in global namespace.
02348                                  * Else, looked up first in contextNsPtr
02349                                  * (current namespace if contextNsPtr is
02350                                  * NULL), then in global namespace. */
02351     Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag set.
02352                                  * Otherwise, points to namespace in which to
02353                                  * resolve name. If NULL, look up name in the
02354                                  * current namespace. */
02355     int flags)                  /* An OR'd combination of flags:
02356                                  * TCL_GLOBAL_ONLY (look up name only in
02357                                  * global namespace), TCL_NAMESPACE_ONLY (look
02358                                  * up only in contextNsPtr, or the current
02359                                  * namespace if contextNsPtr is NULL), and
02360                                  * TCL_LEAVE_ERR_MSG. If both TCL_GLOBAL_ONLY
02361                                  * and TCL_NAMESPACE_ONLY are given,
02362                                  * TCL_GLOBAL_ONLY is ignored. */
02363 {
02364     Interp *iPtr = (Interp *) interp;
02365     Namespace *cxtNsPtr;
02366     register Tcl_HashEntry *entryPtr;
02367     register Command *cmdPtr;
02368     const char *simpleName;
02369     int result;
02370 
02371     /*
02372      * If this namespace has a command resolver, then give it first crack at
02373      * the command resolution. If the interpreter has any command resolvers,
02374      * consult them next. The command resolver functions may return a
02375      * Tcl_Command value, they may signal to continue onward, or they may
02376      * signal an error.
02377      */
02378 
02379     if ((flags & TCL_GLOBAL_ONLY) || !strncmp(name, "::", 2)) {
02380         cxtNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
02381     } else if (contextNsPtr != NULL) {
02382         cxtNsPtr = (Namespace *) contextNsPtr;
02383     } else {
02384         cxtNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
02385     }
02386 
02387     if (cxtNsPtr->cmdResProc != NULL || iPtr->resolverPtr != NULL) {
02388         ResolverScheme *resPtr = iPtr->resolverPtr;
02389         Tcl_Command cmd;
02390 
02391         if (cxtNsPtr->cmdResProc) {
02392             result = (*cxtNsPtr->cmdResProc)(interp, name,
02393                     (Tcl_Namespace *) cxtNsPtr, flags, &cmd);
02394         } else {
02395             result = TCL_CONTINUE;
02396         }
02397 
02398         while (result == TCL_CONTINUE && resPtr) {
02399             if (resPtr->cmdResProc) {
02400                 result = (*resPtr->cmdResProc)(interp, name,
02401                         (Tcl_Namespace *) cxtNsPtr, flags, &cmd);
02402             }
02403             resPtr = resPtr->nextPtr;
02404         }
02405 
02406         if (result == TCL_OK) {
02407             return cmd;
02408         } else if (result != TCL_CONTINUE) {
02409             return NULL;
02410         }
02411     }
02412 
02413     /*
02414      * Find the namespace(s) that contain the command.
02415      */
02416 
02417     cmdPtr = NULL;
02418     if (cxtNsPtr->commandPathLength!=0 && strncmp(name, "::", 2)) {
02419         int i;
02420         Namespace *pathNsPtr, *realNsPtr, *dummyNsPtr;
02421 
02422         (void) TclGetNamespaceForQualName(interp, name, cxtNsPtr,
02423                 TCL_NAMESPACE_ONLY, &realNsPtr, &dummyNsPtr, &dummyNsPtr,
02424                 &simpleName);
02425         if ((realNsPtr != NULL) && (simpleName != NULL)) {
02426             if ((cxtNsPtr == realNsPtr)
02427                     || !(realNsPtr->flags & NS_DYING)) {
02428                 entryPtr = Tcl_FindHashEntry(&realNsPtr->cmdTable, simpleName);
02429                 if (entryPtr != NULL) {
02430                     cmdPtr = Tcl_GetHashValue(entryPtr);
02431                 }
02432             }
02433         }
02434 
02435         /*
02436          * Next, check along the path.
02437          */
02438 
02439         for (i=0 ; i<cxtNsPtr->commandPathLength && cmdPtr==NULL ; i++) {
02440             pathNsPtr = cxtNsPtr->commandPathArray[i].nsPtr;
02441             if (pathNsPtr == NULL) {
02442                 continue;
02443             }
02444             (void) TclGetNamespaceForQualName(interp, name, pathNsPtr,
02445                     TCL_NAMESPACE_ONLY, &realNsPtr, &dummyNsPtr, &dummyNsPtr,
02446                     &simpleName);
02447             if ((realNsPtr != NULL) && (simpleName != NULL)
02448                     && !(realNsPtr->flags & NS_DYING)) {
02449                 entryPtr = Tcl_FindHashEntry(&realNsPtr->cmdTable, simpleName);
02450                 if (entryPtr != NULL) {
02451                     cmdPtr = Tcl_GetHashValue(entryPtr);
02452                 }
02453             }
02454         }
02455 
02456         /*
02457          * If we've still not found the command, look in the global namespace
02458          * as a last resort.
02459          */
02460 
02461         if (cmdPtr == NULL) {
02462             (void) TclGetNamespaceForQualName(interp, name, NULL,
02463                     TCL_GLOBAL_ONLY, &realNsPtr, &dummyNsPtr, &dummyNsPtr,
02464                     &simpleName);
02465             if ((realNsPtr != NULL) && (simpleName != NULL)
02466                     && !(realNsPtr->flags & NS_DYING)) {
02467                 entryPtr = Tcl_FindHashEntry(&realNsPtr->cmdTable, simpleName);
02468                 if (entryPtr != NULL) {
02469                     cmdPtr = Tcl_GetHashValue(entryPtr);
02470                 }
02471             }
02472         }
02473     } else {
02474         Namespace *nsPtr[2];
02475         register int search;
02476 
02477         TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr,
02478                 flags, &nsPtr[0], &nsPtr[1], &cxtNsPtr, &simpleName);
02479 
02480         /*
02481          * Look for the command in the command table of its namespace. Be sure
02482          * to check both possible search paths: from the specified namespace
02483          * context and from the global namespace.
02484          */
02485 
02486         for (search = 0;  (search < 2) && (cmdPtr == NULL);  search++) {
02487             if ((nsPtr[search] != NULL) && (simpleName != NULL)) {
02488                 entryPtr = Tcl_FindHashEntry(&nsPtr[search]->cmdTable,
02489                         simpleName);
02490                 if (entryPtr != NULL) {
02491                     cmdPtr = Tcl_GetHashValue(entryPtr);
02492                 }
02493             }
02494         }
02495     }
02496 
02497     if (cmdPtr != NULL) {
02498         return (Tcl_Command) cmdPtr;
02499     }
02500 
02501     if (flags & TCL_LEAVE_ERR_MSG) {
02502         Tcl_ResetResult(interp);
02503         Tcl_AppendResult(interp, "unknown command \"", name, "\"", NULL);
02504         Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", name, NULL);
02505     }
02506     return NULL;
02507 }
02508 
02509 /*
02510  *----------------------------------------------------------------------
02511  *
02512  * TclResetShadowedCmdRefs --
02513  *
02514  *      Called when a command is added to a namespace to check for existing
02515  *      command references that the new command may invalidate. Consider the
02516  *      following cases that could happen when you add a command "foo" to a
02517  *      namespace "b":
02518  *         1. It could shadow a command named "foo" at the global scope. If
02519  *            it does, all command references in the namespace "b" are
02520  *            suspect.
02521  *         2. Suppose the namespace "b" resides in a namespace "a". Then to
02522  *            "a" the new command "b::foo" could shadow another command
02523  *            "b::foo" in the global namespace. If so, then all command
02524  *            references in "a" * are suspect.
02525  *      The same checks are applied to all parent namespaces, until we reach
02526  *      the global :: namespace.
02527  *
02528  * Results:
02529  *      None.
02530  *
02531  * Side effects:
02532  *      If the new command shadows an existing command, the cmdRefEpoch
02533  *      counter is incremented in each namespace that sees the shadow. This
02534  *      invalidates all command references that were previously cached in that
02535  *      namespace. The next time the commands are used, they are resolved from
02536  *      scratch.
02537  *
02538  *----------------------------------------------------------------------
02539  */
02540 
02541 void
02542 TclResetShadowedCmdRefs(
02543     Tcl_Interp *interp,         /* Interpreter containing the new command. */
02544     Command *newCmdPtr)         /* Points to the new command. */
02545 {
02546     char *cmdName;
02547     Tcl_HashEntry *hPtr;
02548     register Namespace *nsPtr;
02549     Namespace *trailNsPtr, *shadowNsPtr;
02550     Namespace *globalNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
02551     int found, i;
02552     int trailFront = -1;
02553     int trailSize = 5;          /* Formerly NUM_TRAIL_ELEMS. */
02554     Namespace **trailPtr = (Namespace **)
02555             TclStackAlloc(interp, trailSize * sizeof(Namespace *));
02556 
02557     /*
02558      * Start at the namespace containing the new command, and work up through
02559      * the list of parents. Stop just before the global namespace, since the
02560      * global namespace can't "shadow" its own entries.
02561      *
02562      * The namespace "trail" list we build consists of the names of each
02563      * namespace that encloses the new command, in order from outermost to
02564      * innermost: for example, "a" then "b". Each iteration of this loop
02565      * eventually extends the trail upwards by one namespace, nsPtr. We use
02566      * this trail list to see if nsPtr (e.g. "a" in 2. above) could have
02567      * now-invalid cached command references. This will happen if nsPtr
02568      * (e.g. "a") contains a sequence of child namespaces (e.g. "b") such that
02569      * there is a identically-named sequence of child namespaces starting from
02570      * :: (e.g. "::b") whose tail namespace contains a command also named
02571      * cmdName.
02572      */
02573 
02574     cmdName = Tcl_GetHashKey(newCmdPtr->hPtr->tablePtr, newCmdPtr->hPtr);
02575     for (nsPtr=newCmdPtr->nsPtr ; (nsPtr!=NULL) && (nsPtr!=globalNsPtr) ;
02576             nsPtr=nsPtr->parentPtr) {
02577         /*
02578          * Find the maximal sequence of child namespaces contained in nsPtr
02579          * such that there is a identically-named sequence of child namespaces
02580          * starting from ::. shadowNsPtr will be the tail of this sequence, or
02581          * the deepest namespace under :: that might contain a command now
02582          * shadowed by cmdName. We check below if shadowNsPtr actually
02583          * contains a command cmdName.
02584          */
02585 
02586         found = 1;
02587         shadowNsPtr = globalNsPtr;
02588 
02589         for (i = trailFront;  i >= 0;  i--) {
02590             trailNsPtr = trailPtr[i];
02591             hPtr = Tcl_FindHashEntry(&shadowNsPtr->childTable,
02592                     trailNsPtr->name);
02593             if (hPtr != NULL) {
02594                 shadowNsPtr = Tcl_GetHashValue(hPtr);
02595             } else {
02596                 found = 0;
02597                 break;
02598             }
02599         }
02600 
02601         /*
02602          * If shadowNsPtr contains a command named cmdName, we invalidate all
02603          * of the command refs cached in nsPtr. As a boundary case,
02604          * shadowNsPtr is initially :: and we check for case 1. above.
02605          */
02606 
02607         if (found) {
02608             hPtr = Tcl_FindHashEntry(&shadowNsPtr->cmdTable, cmdName);
02609             if (hPtr != NULL) {
02610                 nsPtr->cmdRefEpoch++;
02611                 TclInvalidateNsPath(nsPtr);
02612 
02613                 /*
02614                  * If the shadowed command was compiled to bytecodes, we
02615                  * invalidate all the bytecodes in nsPtr, to force a new
02616                  * compilation. We use the resolverEpoch to signal the need
02617                  * for a fresh compilation of every bytecode.
02618                  */
02619 
02620                 if (((Command *)Tcl_GetHashValue(hPtr))->compileProc != NULL) {
02621                     nsPtr->resolverEpoch++;
02622                 }
02623             }
02624         }
02625 
02626         /*
02627          * Insert nsPtr at the front of the trail list: i.e., at the end of
02628          * the trailPtr array.
02629          */
02630 
02631         trailFront++;
02632         if (trailFront == trailSize) {
02633             int newSize = 2 * trailSize;
02634             trailPtr = (Namespace **) TclStackRealloc(interp,
02635                     trailPtr, newSize * sizeof(Namespace *));
02636             trailSize = newSize;
02637         }
02638         trailPtr[trailFront] = nsPtr;
02639     }
02640     TclStackFree(interp, trailPtr);
02641 }
02642 
02643 /*
02644  *----------------------------------------------------------------------
02645  *
02646  * TclGetNamespaceFromObj, GetNamespaceFromObj --
02647  *
02648  *      Gets the namespace specified by the name in a Tcl_Obj.
02649  *
02650  * Results:
02651  *      Returns TCL_OK if the namespace was resolved successfully, and stores
02652  *      a pointer to the namespace in the location specified by nsPtrPtr. If
02653  *      the namespace can't be found, or anything else goes wrong, this
02654  *      function returns TCL_ERROR and writes an error message to interp,
02655  *      if non-NULL.
02656  *
02657  * Side effects:
02658  *      May update the internal representation for the object, caching the
02659  *      namespace reference. The next time this function is called, the
02660  *      namespace value can be found quickly.
02661  *
02662  *----------------------------------------------------------------------
02663  */
02664 
02665 int
02666 TclGetNamespaceFromObj(
02667     Tcl_Interp *interp,         /* The current interpreter. */
02668     Tcl_Obj *objPtr,            /* The object to be resolved as the name of a
02669                                  * namespace. */
02670     Tcl_Namespace **nsPtrPtr)   /* Result namespace pointer goes here. */
02671 {
02672     if (GetNamespaceFromObj(interp, objPtr, nsPtrPtr) == TCL_ERROR) {
02673         const char *name = TclGetString(objPtr);
02674 
02675         if ((name[0] == ':') && (name[1] == ':')) {
02676             Tcl_SetObjResult(interp, Tcl_ObjPrintf(
02677                     "namespace \"%s\" not found", name));
02678         } else {
02679             /*
02680              * Get the current namespace name.
02681              */
02682 
02683             NamespaceCurrentCmd(NULL, interp, 2, NULL);
02684             Tcl_SetObjResult(interp, Tcl_ObjPrintf(
02685                     "namespace \"%s\" not found in \"%s\"", name,
02686                     Tcl_GetStringResult(interp)));
02687         }
02688         Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", name, NULL);
02689         return TCL_ERROR;
02690     }
02691     return TCL_OK;
02692 }
02693 
02694 static int
02695 GetNamespaceFromObj(
02696     Tcl_Interp *interp,         /* The current interpreter. */
02697     Tcl_Obj *objPtr,            /* The object to be resolved as the name of a
02698                                  * namespace. */
02699     Tcl_Namespace **nsPtrPtr)   /* Result namespace pointer goes here. */
02700 {
02701     ResolvedNsName *resNamePtr;
02702     Namespace *nsPtr;
02703 
02704     if (objPtr->typePtr == &nsNameType) {
02705         /*
02706          * Check that the ResolvedNsName is still valid.
02707          */
02708 
02709         resNamePtr = (ResolvedNsName *) objPtr->internalRep.twoPtrValue.ptr1;
02710         nsPtr = resNamePtr->nsPtr;
02711         if (!(nsPtr->flags & NS_DYING)
02712                 && ((resNamePtr->refNsPtr == NULL) || (resNamePtr->refNsPtr
02713                 == (Namespace *) Tcl_GetCurrentNamespace(interp)))) {
02714             *nsPtrPtr = (Tcl_Namespace *) nsPtr;
02715             return TCL_OK;
02716         }
02717     }
02718     if (SetNsNameFromAny(interp, objPtr) == TCL_OK) {
02719         resNamePtr = (ResolvedNsName *) objPtr->internalRep.twoPtrValue.ptr1;
02720         *nsPtrPtr = (Tcl_Namespace *) resNamePtr->nsPtr;
02721         return TCL_OK;
02722     }
02723     return TCL_ERROR;
02724 }
02725 
02726 /*
02727  *----------------------------------------------------------------------
02728  *
02729  * Tcl_NamespaceObjCmd --
02730  *
02731  *      Invoked to implement the "namespace" command that creates, deletes, or
02732  *      manipulates Tcl namespaces. Handles the following syntax:
02733  *
02734  *          namespace children ?name? ?pattern?
02735  *          namespace code arg
02736  *          namespace current
02737  *          namespace delete ?name name...?
02738  *          namespace ensemble subcommand ?arg...?
02739  *          namespace eval name arg ?arg...?
02740  *          namespace exists name
02741  *          namespace export ?-clear? ?pattern pattern...?
02742  *          namespace forget ?pattern pattern...?
02743  *          namespace import ?-force? ?pattern pattern...?
02744  *          namespace inscope name arg ?arg...?
02745  *          namespace origin name
02746  *          namespace parent ?name?
02747  *          namespace qualifiers string
02748  *          namespace tail string
02749  *          namespace which ?-command? ?-variable? name
02750  *
02751  * Results:
02752  *      Returns TCL_OK if the command is successful. Returns TCL_ERROR if
02753  *      anything goes wrong.
02754  *
02755  * Side effects:
02756  *      Based on the subcommand name (e.g., "import"), this function
02757  *      dispatches to a corresponding function NamespaceXXXCmd defined
02758  *      statically in this file. This function's side effects depend on
02759  *      whatever that subcommand function does. If there is an error, this
02760  *      function returns an error message in the interpreter's result object.
02761  *      Otherwise it may return a result in the interpreter's result object.
02762  *
02763  *----------------------------------------------------------------------
02764  */
02765 
02766 int
02767 Tcl_NamespaceObjCmd(
02768     ClientData clientData,      /* Arbitrary value passed to cmd. */
02769     Tcl_Interp *interp,         /* Current interpreter. */
02770     int objc,                   /* Number of arguments. */
02771     Tcl_Obj *const objv[])      /* Argument objects. */
02772 {
02773     static const char *subCmds[] = {
02774         "children", "code", "current", "delete", "ensemble",
02775         "eval", "exists", "export", "forget", "import",
02776         "inscope", "origin", "parent", "path", "qualifiers",
02777         "tail", "unknown", "upvar", "which", NULL
02778     };
02779     enum NSSubCmdIdx {
02780         NSChildrenIdx, NSCodeIdx, NSCurrentIdx, NSDeleteIdx, NSEnsembleIdx,
02781         NSEvalIdx, NSExistsIdx, NSExportIdx, NSForgetIdx, NSImportIdx,
02782         NSInscopeIdx, NSOriginIdx, NSParentIdx, NSPathIdx, NSQualifiersIdx,
02783         NSTailIdx, NSUnknownIdx, NSUpvarIdx, NSWhichIdx
02784     };
02785     int index, result;
02786 
02787     if (objc < 2) {
02788         Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?arg ...?");
02789         return TCL_ERROR;
02790     }
02791 
02792     /*
02793      * Return an index reflecting the particular subcommand.
02794      */
02795 
02796     result = Tcl_GetIndexFromObj((Tcl_Interp *) interp, objv[1], subCmds,
02797             "option", /*flags*/ 0, (int *) &index);
02798     if (result != TCL_OK) {
02799         return result;
02800     }
02801 
02802     switch (index) {
02803     case NSChildrenIdx:
02804         result = NamespaceChildrenCmd(clientData, interp, objc, objv);
02805         break;
02806     case NSCodeIdx:
02807         result = NamespaceCodeCmd(clientData, interp, objc, objv);
02808         break;
02809     case NSCurrentIdx:
02810         result = NamespaceCurrentCmd(clientData, interp, objc, objv);
02811         break;
02812     case NSDeleteIdx:
02813         result = NamespaceDeleteCmd(clientData, interp, objc, objv);
02814         break;
02815     case NSEnsembleIdx:
02816         result = NamespaceEnsembleCmd(clientData, interp, objc, objv);
02817         break;
02818     case NSEvalIdx:
02819         result = NamespaceEvalCmd(clientData, interp, objc, objv);
02820         break;
02821     case NSExistsIdx:
02822         result = NamespaceExistsCmd(clientData, interp, objc, objv);
02823         break;
02824     case NSExportIdx:
02825         result = NamespaceExportCmd(clientData, interp, objc, objv);
02826         break;
02827     case NSForgetIdx:
02828         result = NamespaceForgetCmd(clientData, interp, objc, objv);
02829         break;
02830     case NSImportIdx:
02831         result = NamespaceImportCmd(clientData, interp, objc, objv);
02832         break;
02833     case NSInscopeIdx:
02834         result = NamespaceInscopeCmd(clientData, interp, objc, objv);
02835         break;
02836     case NSOriginIdx:
02837         result = NamespaceOriginCmd(clientData, interp, objc, objv);
02838         break;
02839     case NSParentIdx:
02840         result = NamespaceParentCmd(clientData, interp, objc, objv);
02841         break;
02842     case NSPathIdx:
02843         result = NamespacePathCmd(clientData, interp, objc, objv);
02844         break;
02845     case NSQualifiersIdx:
02846         result = NamespaceQualifiersCmd(clientData, interp, objc, objv);
02847         break;
02848     case NSTailIdx:
02849         result = NamespaceTailCmd(clientData, interp, objc, objv);
02850         break;
02851     case NSUpvarIdx:
02852         result = NamespaceUpvarCmd(clientData, interp, objc, objv);
02853         break;
02854     case NSUnknownIdx:
02855         result = NamespaceUnknownCmd(clientData, interp, objc, objv);
02856         break;
02857     case NSWhichIdx:
02858         result = NamespaceWhichCmd(clientData, interp, objc, objv);
02859         break;
02860     }
02861     return result;
02862 }
02863 
02864 /*
02865  *----------------------------------------------------------------------
02866  *
02867  * NamespaceChildrenCmd --
02868  *
02869  *      Invoked to implement the "namespace children" command that returns a
02870  *      list containing the fully-qualified names of the child namespaces of a
02871  *      given namespace. Handles the following syntax:
02872  *
02873  *          namespace children ?name? ?pattern?
02874  *
02875  * Results:
02876  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
02877  *
02878  * Side effects:
02879  *      Returns a result in the interpreter's result object. If anything goes
02880  *      wrong, the result is an error message.
02881  *
02882  *----------------------------------------------------------------------
02883  */
02884 
02885 static int
02886 NamespaceChildrenCmd(
02887     ClientData dummy,           /* Not used. */
02888     Tcl_Interp *interp,         /* Current interpreter. */
02889     int objc,                   /* Number of arguments. */
02890     Tcl_Obj *const objv[])      /* Argument objects. */
02891 {
02892     Tcl_Namespace *namespacePtr;
02893     Namespace *nsPtr, *childNsPtr;
02894     Namespace *globalNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
02895     char *pattern = NULL;
02896     Tcl_DString buffer;
02897     register Tcl_HashEntry *entryPtr;
02898     Tcl_HashSearch search;
02899     Tcl_Obj *listPtr, *elemPtr;
02900 
02901     /*
02902      * Get a pointer to the specified namespace, or the current namespace.
02903      */
02904 
02905     if (objc == 2) {
02906         nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
02907     } else if ((objc == 3) || (objc == 4)) {
02908         if (TclGetNamespaceFromObj(interp, objv[2], &namespacePtr) != TCL_OK) {
02909             return TCL_ERROR;
02910         }
02911         nsPtr = (Namespace *) namespacePtr;
02912     } else {
02913         Tcl_WrongNumArgs(interp, 2, objv, "?name? ?pattern?");
02914         return TCL_ERROR;
02915     }
02916 
02917     /*
02918      * Get the glob-style pattern, if any, used to narrow the search.
02919      */
02920 
02921     Tcl_DStringInit(&buffer);
02922     if (objc == 4) {
02923         char *name = TclGetString(objv[3]);
02924 
02925         if ((*name == ':') && (*(name+1) == ':')) {
02926             pattern = name;
02927         } else {
02928             Tcl_DStringAppend(&buffer, nsPtr->fullName, -1);
02929             if (nsPtr != globalNsPtr) {
02930                 Tcl_DStringAppend(&buffer, "::", 2);
02931             }
02932             Tcl_DStringAppend(&buffer, name, -1);
02933             pattern = Tcl_DStringValue(&buffer);
02934         }
02935     }
02936 
02937     /*
02938      * Create a list containing the full names of all child namespaces whose
02939      * names match the specified pattern, if any.
02940      */
02941 
02942     listPtr = Tcl_NewListObj(0, NULL);
02943     if ((pattern != NULL) && TclMatchIsTrivial(pattern)) {
02944         unsigned int length = strlen(nsPtr->fullName);
02945 
02946         if (strncmp(pattern, nsPtr->fullName, length) != 0) {
02947             goto searchDone;
02948         }
02949         if (Tcl_FindHashEntry(&nsPtr->childTable, pattern+length) != NULL) {
02950             Tcl_ListObjAppendElement(interp, listPtr,
02951                     Tcl_NewStringObj(pattern, -1));
02952         }
02953         goto searchDone;
02954     }
02955     entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search);
02956     while (entryPtr != NULL) {
02957         childNsPtr = Tcl_GetHashValue(entryPtr);
02958         if ((pattern == NULL)
02959                 || Tcl_StringMatch(childNsPtr->fullName, pattern)) {
02960             elemPtr = Tcl_NewStringObj(childNsPtr->fullName, -1);
02961             Tcl_ListObjAppendElement(interp, listPtr, elemPtr);
02962         }
02963         entryPtr = Tcl_NextHashEntry(&search);
02964     }
02965 
02966   searchDone:
02967     Tcl_SetObjResult(interp, listPtr);
02968     Tcl_DStringFree(&buffer);
02969     return TCL_OK;
02970 }
02971 
02972 /*
02973  *----------------------------------------------------------------------
02974  *
02975  * NamespaceCodeCmd --
02976  *
02977  *      Invoked to implement the "namespace code" command to capture the
02978  *      namespace context of a command. Handles the following syntax:
02979  *
02980  *          namespace code arg
02981  *
02982  *      Here "arg" can be a list. "namespace code arg" produces a result
02983  *      equivalent to that produced by the command
02984  *
02985  *          list ::namespace inscope [namespace current] $arg
02986  *
02987  *      However, if "arg" is itself a scoped value starting with "::namespace
02988  *      inscope", then the result is just "arg".
02989  *
02990  * Results:
02991  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
02992  *
02993  * Side effects:
02994  *      If anything goes wrong, this function returns an error message as the
02995  *      result in the interpreter's result object.
02996  *
02997  *----------------------------------------------------------------------
02998  */
02999 
03000 static int
03001 NamespaceCodeCmd(
03002     ClientData dummy,           /* Not used. */
03003     Tcl_Interp *interp,         /* Current interpreter. */
03004     int objc,                   /* Number of arguments. */
03005     Tcl_Obj *const objv[])      /* Argument objects. */
03006 {
03007     Namespace *currNsPtr;
03008     Tcl_Obj *listPtr, *objPtr;
03009     register char *arg, *p;
03010     int length;
03011 
03012     if (objc != 3) {
03013         Tcl_WrongNumArgs(interp, 2, objv, "arg");
03014         return TCL_ERROR;
03015     }
03016 
03017     /*
03018      * If "arg" is already a scoped value, then return it directly.
03019      */
03020 
03021     arg = TclGetStringFromObj(objv[2], &length);
03022     while (*arg == ':') {
03023         arg++;
03024         length--;
03025     }
03026     if (*arg=='n' && length>17 && strncmp(arg, "namespace", 9)==0) {
03027         for (p=arg+9 ; isspace(UCHAR(*p)) ; p++) {
03028             /* empty body: skip over whitespace */
03029         }
03030         if (*p=='i' && (p+7 <= arg+length) && strncmp(p, "inscope", 7)==0) {
03031             Tcl_SetObjResult(interp, objv[2]);
03032             return TCL_OK;
03033         }
03034     }
03035 
03036     /*
03037      * Otherwise, construct a scoped command by building a list with
03038      * "namespace inscope", the full name of the current namespace, and the
03039      * argument "arg". By constructing a list, we ensure that scoped commands
03040      * are interpreted properly when they are executed later, by the
03041      * "namespace inscope" command.
03042      */
03043 
03044     TclNewObj(listPtr);
03045     TclNewLiteralStringObj(objPtr, "::namespace");
03046     Tcl_ListObjAppendElement(interp, listPtr, objPtr);
03047     TclNewLiteralStringObj(objPtr, "inscope");
03048     Tcl_ListObjAppendElement(interp, listPtr, objPtr);
03049 
03050     currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
03051     if (currNsPtr == (Namespace *) TclGetGlobalNamespace(interp)) {
03052         TclNewLiteralStringObj(objPtr, "::");
03053     } else {
03054         objPtr = Tcl_NewStringObj(currNsPtr->fullName, -1);
03055     }
03056     Tcl_ListObjAppendElement(interp, listPtr, objPtr);
03057 
03058     Tcl_ListObjAppendElement(interp, listPtr, objv[2]);
03059 
03060     Tcl_SetObjResult(interp, listPtr);
03061     return TCL_OK;
03062 }
03063 
03064 /*
03065  *----------------------------------------------------------------------
03066  *
03067  * NamespaceCurrentCmd --
03068  *
03069  *      Invoked to implement the "namespace current" command which returns the
03070  *      fully-qualified name of the current namespace. Handles the following
03071  *      syntax:
03072  *
03073  *          namespace current
03074  *
03075  * Results:
03076  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
03077  *
03078  * Side effects:
03079  *      Returns a result in the interpreter's result object. If anything goes
03080  *      wrong, the result is an error message.
03081  *
03082  *----------------------------------------------------------------------
03083  */
03084 
03085 static int
03086 NamespaceCurrentCmd(
03087     ClientData dummy,           /* Not used. */
03088     Tcl_Interp *interp,         /* Current interpreter. */
03089     int objc,                   /* Number of arguments. */
03090     Tcl_Obj *const objv[])      /* Argument objects. */
03091 {
03092     register Namespace *currNsPtr;
03093 
03094     if (objc != 2) {
03095         Tcl_WrongNumArgs(interp, 2, objv, NULL);
03096         return TCL_ERROR;
03097     }
03098 
03099     /*
03100      * The "real" name of the global namespace ("::") is the null string, but
03101      * we return "::" for it as a convenience to programmers. Note that "" and
03102      * "::" are treated as synonyms by the namespace code so that it is still
03103      * easy to do things like:
03104      *
03105      *    namespace [namespace current]::bar { ... }
03106      */
03107 
03108     currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
03109     if (currNsPtr == (Namespace *) TclGetGlobalNamespace(interp)) {
03110         Tcl_SetObjResult(interp, Tcl_NewStringObj("::", 2));
03111     } else {
03112         Tcl_SetObjResult(interp, Tcl_NewStringObj(currNsPtr->fullName, -1));
03113     }
03114     return TCL_OK;
03115 }
03116 
03117 /*
03118  *----------------------------------------------------------------------
03119  *
03120  * NamespaceDeleteCmd --
03121  *
03122  *      Invoked to implement the "namespace delete" command to delete
03123  *      namespace(s). Handles the following syntax:
03124  *
03125  *          namespace delete ?name name...?
03126  *
03127  *      Each name identifies a namespace. It may include a sequence of
03128  *      namespace qualifiers separated by "::"s. If a namespace is found, it
03129  *      is deleted: all variables and procedures contained in that namespace
03130  *      are deleted. If that namespace is being used on the call stack, it is
03131  *      kept alive (but logically deleted) until it is removed from the call
03132  *      stack: that is, it can no longer be referenced by name but any
03133  *      currently executing procedure that refers to it is allowed to do so
03134  *      until the procedure returns. If the namespace can't be found, this
03135  *      function returns an error. If no namespaces are specified, this
03136  *      command does nothing.
03137  *
03138  * Results:
03139  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
03140  *
03141  * Side effects:
03142  *      Deletes the specified namespaces. If anything goes wrong, this
03143  *      function returns an error message in the interpreter's result object.
03144  *
03145  *----------------------------------------------------------------------
03146  */
03147 
03148 static int
03149 NamespaceDeleteCmd(
03150     ClientData dummy,           /* Not used. */
03151     Tcl_Interp *interp,         /* Current interpreter. */
03152     int objc,                   /* Number of arguments. */
03153     Tcl_Obj *const objv[])      /* Argument objects. */
03154 {
03155     Tcl_Namespace *namespacePtr;
03156     char *name;
03157     register int i;
03158 
03159     if (objc < 2) {
03160         Tcl_WrongNumArgs(interp, 2, objv, "?name name...?");
03161         return TCL_ERROR;
03162     }
03163 
03164     /*
03165      * Destroying one namespace may cause another to be destroyed. Break this
03166      * into two passes: first check to make sure that all namespaces on the
03167      * command line are valid, and report any errors.
03168      */
03169 
03170     for (i = 2;  i < objc;  i++) {
03171         name = TclGetString(objv[i]);
03172         namespacePtr = Tcl_FindNamespace(interp, name, NULL, /*flags*/ 0);
03173         if ((namespacePtr == NULL)
03174                 || (((Namespace *)namespacePtr)->flags & NS_KILLED)) {
03175             Tcl_AppendResult(interp, "unknown namespace \"",
03176                     TclGetString(objv[i]),
03177                     "\" in namespace delete command", NULL);
03178             Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE",
03179                     TclGetString(objv[i]), NULL);
03180             return TCL_ERROR;
03181         }
03182     }
03183 
03184     /*
03185      * Okay, now delete each namespace.
03186      */
03187 
03188     for (i = 2;  i < objc;  i++) {
03189         name = TclGetString(objv[i]);
03190         namespacePtr = Tcl_FindNamespace(interp, name, NULL, /* flags */ 0);
03191         if (namespacePtr) {
03192             Tcl_DeleteNamespace(namespacePtr);
03193         }
03194     }
03195     return TCL_OK;
03196 }
03197 
03198 /*
03199  *----------------------------------------------------------------------
03200  *
03201  * NamespaceEvalCmd --
03202  *
03203  *      Invoked to implement the "namespace eval" command. Executes commands
03204  *      in a namespace. If the namespace does not already exist, it is
03205  *      created. Handles the following syntax:
03206  *
03207  *          namespace eval name arg ?arg...?
03208  *
03209  *      If more than one arg argument is specified, the command that is
03210  *      executed is the result of concatenating the arguments together with a
03211  *      space between each argument.
03212  *
03213  * Results:
03214  *      Returns TCL_OK if the namespace is found and the commands are executed
03215  *      successfully. Returns TCL_ERROR if anything goes wrong.
03216  *
03217  * Side effects:
03218  *      Returns the result of the command in the interpreter's result object.
03219  *      If anything goes wrong, this function returns an error message as the
03220  *      result.
03221  *
03222  *----------------------------------------------------------------------
03223  */
03224 
03225 static int
03226 NamespaceEvalCmd(
03227     ClientData dummy,           /* Not used. */
03228     Tcl_Interp *interp,         /* Current interpreter. */
03229     int objc,                   /* Number of arguments. */
03230     Tcl_Obj *const objv[])      /* Argument objects. */
03231 {
03232     Tcl_Namespace *namespacePtr;
03233     CallFrame *framePtr, **framePtrPtr;
03234     Tcl_Obj *objPtr;
03235     int result;
03236 
03237     if (objc < 4) {
03238         Tcl_WrongNumArgs(interp, 2, objv, "name arg ?arg...?");
03239         return TCL_ERROR;
03240     }
03241 
03242     /*
03243      * Try to resolve the namespace reference, caching the result in the
03244      * namespace object along the way.
03245      */
03246 
03247     result = GetNamespaceFromObj(interp, objv[2], &namespacePtr);
03248 
03249     /*
03250      * If the namespace wasn't found, try to create it.
03251      */
03252 
03253     if (result == TCL_ERROR) {
03254         char *name = TclGetString(objv[2]);
03255 
03256         namespacePtr = Tcl_CreateNamespace(interp, name, NULL, NULL);
03257         if (namespacePtr == NULL) {
03258             return TCL_ERROR;
03259         }
03260     }
03261 
03262     /*
03263      * Make the specified namespace the current namespace and evaluate the
03264      * command(s).
03265      */
03266 
03267     /* This is needed to satisfy GCC 3.3's strict aliasing rules */
03268     framePtrPtr = &framePtr;
03269     result = TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
03270             namespacePtr, /*isProcCallFrame*/ 0);
03271     if (result != TCL_OK) {
03272         return TCL_ERROR;
03273     }
03274 
03275     framePtr->objc = objc;
03276     framePtr->objv = objv;
03277 
03278     if (objc == 4) {
03279         /*
03280          * TIP #280: Make invoker available to eval'd script.
03281          */
03282 
03283         Interp *iPtr = (Interp *) interp;
03284 
03285         result = TclEvalObjEx(interp, objv[3], 0, iPtr->cmdFramePtr, 3);
03286     } else {
03287         /*
03288          * More than one argument: concatenate them together with spaces
03289          * between, then evaluate the result. Tcl_EvalObjEx will delete the
03290          * object when it decrements its refcount after eval'ing it.
03291          */
03292 
03293         objPtr = Tcl_ConcatObj(objc-3, objv+3);
03294 
03295         /*
03296          * TIP #280: Make invoking context available to eval'd script.
03297          */
03298 
03299         result = TclEvalObjEx(interp, objPtr, TCL_EVAL_DIRECT, NULL, 0);
03300     }
03301 
03302     if (result == TCL_ERROR) {
03303         int length = strlen(namespacePtr->fullName);
03304         int limit = 200;
03305         int overflow = (length > limit);
03306 
03307         Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
03308                 "\n    (in namespace eval \"%.*s%s\" script line %d)",
03309                 (overflow ? limit : length), namespacePtr->fullName,
03310                 (overflow ? "..." : ""), interp->errorLine));
03311     }
03312 
03313     /*
03314      * Restore the previous "current" namespace.
03315      */
03316 
03317     TclPopStackFrame(interp);
03318     return result;
03319 }
03320 
03321 /*
03322  *----------------------------------------------------------------------
03323  *
03324  * NamespaceExistsCmd --
03325  *
03326  *      Invoked to implement the "namespace exists" command that returns true
03327  *      if the given namespace currently exists, and false otherwise. Handles
03328  *      the following syntax:
03329  *
03330  *          namespace exists name
03331  *
03332  * Results:
03333  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
03334  *
03335  * Side effects:
03336  *      Returns a result in the interpreter's result object. If anything goes
03337  *      wrong, the result is an error message.
03338  *
03339  *----------------------------------------------------------------------
03340  */
03341 
03342 static int
03343 NamespaceExistsCmd(
03344     ClientData dummy,           /* Not used. */
03345     Tcl_Interp *interp,         /* Current interpreter. */
03346     int objc,                   /* Number of arguments. */
03347     Tcl_Obj *const objv[])      /* Argument objects. */
03348 {
03349     Tcl_Namespace *namespacePtr;
03350 
03351     if (objc != 3) {
03352         Tcl_WrongNumArgs(interp, 2, objv, "name");
03353         return TCL_ERROR;
03354     }
03355 
03356     Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
03357             GetNamespaceFromObj(interp, objv[2], &namespacePtr) == TCL_OK));
03358     return TCL_OK;
03359 }
03360 
03361 /*
03362  *----------------------------------------------------------------------
03363  *
03364  * NamespaceExportCmd --
03365  *
03366  *      Invoked to implement the "namespace export" command that specifies
03367  *      which commands are exported from a namespace. The exported commands
03368  *      are those that can be imported into another namespace using "namespace
03369  *      import". Both commands defined in a namespace and commands the
03370  *      namespace has imported can be exported by a namespace. This command
03371  *      has the following syntax:
03372  *
03373  *          namespace export ?-clear? ?pattern pattern...?
03374  *
03375  *      Each pattern may contain "string match"-style pattern matching special
03376  *      characters, but the pattern may not include any namespace qualifiers:
03377  *      that is, the pattern must specify commands in the current (exporting)
03378  *      namespace. The specified patterns are appended onto the namespace's
03379  *      list of export patterns.
03380  *
03381  *      To reset the namespace's export pattern list, specify the "-clear"
03382  *      flag.
03383  *
03384  *      If there are no export patterns and the "-clear" flag isn't given,
03385  *      this command returns the namespace's current export list.
03386  *
03387  * Results:
03388  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
03389  *
03390  * Side effects:
03391  *      Returns a result in the interpreter's result object. If anything goes
03392  *      wrong, the result is an error message.
03393  *
03394  *----------------------------------------------------------------------
03395  */
03396 
03397 static int
03398 NamespaceExportCmd(
03399     ClientData dummy,           /* Not used. */
03400     Tcl_Interp *interp,         /* Current interpreter. */
03401     int objc,                   /* Number of arguments. */
03402     Tcl_Obj *const objv[])      /* Argument objects. */
03403 {
03404     Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
03405     char *pattern, *string;
03406     int resetListFirst = 0;
03407     int firstArg, patternCt, i, result;
03408 
03409     if (objc < 2) {
03410         Tcl_WrongNumArgs(interp, 2, objv, "?-clear? ?pattern pattern...?");
03411         return TCL_ERROR;
03412     }
03413 
03414     /*
03415      * Process the optional "-clear" argument.
03416      */
03417 
03418     firstArg = 2;
03419     if (firstArg < objc) {
03420         string = TclGetString(objv[firstArg]);
03421         if (strcmp(string, "-clear") == 0) {
03422             resetListFirst = 1;
03423             firstArg++;
03424         }
03425     }
03426 
03427     /*
03428      * If no pattern arguments are given, and "-clear" isn't specified, return
03429      * the namespace's current export pattern list.
03430      */
03431 
03432     patternCt = (objc - firstArg);
03433     if (patternCt == 0) {
03434         if (firstArg > 2) {
03435             return TCL_OK;
03436         } else {
03437             /*
03438              * Create list with export patterns.
03439              */
03440 
03441             Tcl_Obj *listPtr = Tcl_NewListObj(0, NULL);
03442             result = Tcl_AppendExportList(interp, (Tcl_Namespace *) currNsPtr,
03443                     listPtr);
03444             if (result != TCL_OK) {
03445                 return result;
03446             }
03447             Tcl_SetObjResult(interp, listPtr);
03448             return TCL_OK;
03449         }
03450     }
03451 
03452     /*
03453      * Add each pattern to the namespace's export pattern list.
03454      */
03455 
03456     for (i = firstArg;  i < objc;  i++) {
03457         pattern = TclGetString(objv[i]);
03458         result = Tcl_Export(interp, (Tcl_Namespace *) currNsPtr, pattern,
03459                 ((i == firstArg)? resetListFirst : 0));
03460         if (result != TCL_OK) {
03461             return result;
03462         }
03463     }
03464     return TCL_OK;
03465 }
03466 
03467 /*
03468  *----------------------------------------------------------------------
03469  *
03470  * NamespaceForgetCmd --
03471  *
03472  *      Invoked to implement the "namespace forget" command to remove imported
03473  *      commands from a namespace. Handles the following syntax:
03474  *
03475  *          namespace forget ?pattern pattern...?
03476  *
03477  *      Each pattern is a name like "foo::*" or "a::b::x*". That is, the
03478  *      pattern may include the special pattern matching characters recognized
03479  *      by the "string match" command, but only in the command name at the end
03480  *      of the qualified name; the special pattern characters may not appear
03481  *      in a namespace name. All of the commands that match that pattern are
03482  *      checked to see if they have an imported command in the current
03483  *      namespace that refers to the matched command. If there is an alias, it
03484  *      is removed.
03485  *
03486  * Results:
03487  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
03488  *
03489  * Side effects:
03490  *      Imported commands are removed from the current namespace. If anything
03491  *      goes wrong, this function returns an error message in the
03492  *      interpreter's result object.
03493  *
03494  *----------------------------------------------------------------------
03495  */
03496 
03497 static int
03498 NamespaceForgetCmd(
03499     ClientData dummy,           /* Not used. */
03500     Tcl_Interp *interp,         /* Current interpreter. */
03501     int objc,                   /* Number of arguments. */
03502     Tcl_Obj *const objv[])      /* Argument objects. */
03503 {
03504     char *pattern;
03505     register int i, result;
03506 
03507     if (objc < 2) {
03508         Tcl_WrongNumArgs(interp, 2, objv, "?pattern pattern...?");
03509         return TCL_ERROR;
03510     }
03511 
03512     for (i = 2;  i < objc;  i++) {
03513         pattern = TclGetString(objv[i]);
03514         result = Tcl_ForgetImport(interp, NULL, pattern);
03515         if (result != TCL_OK) {
03516             return result;
03517         }
03518     }
03519     return TCL_OK;
03520 }
03521 
03522 /*
03523  *----------------------------------------------------------------------
03524  *
03525  * NamespaceImportCmd --
03526  *
03527  *      Invoked to implement the "namespace import" command that imports
03528  *      commands into a namespace. Handles the following syntax:
03529  *
03530  *          namespace import ?-force? ?pattern pattern...?
03531  *
03532  *      Each pattern is a namespace-qualified name like "foo::*", "a::b::x*",
03533  *      or "bar::p". That is, the pattern may include the special pattern
03534  *      matching characters recognized by the "string match" command, but only
03535  *      in the command name at the end of the qualified name; the special
03536  *      pattern characters may not appear in a namespace name. All of the
03537  *      commands that match the pattern and which are exported from their
03538  *      namespace are made accessible from the current namespace context. This
03539  *      is done by creating a new "imported command" in the current namespace
03540  *      that points to the real command in its original namespace; when the
03541  *      imported command is called, it invokes the real command.
03542  *
03543  *      If an imported command conflicts with an existing command, it is
03544  *      treated as an error. But if the "-force" option is included, then
03545  *      existing commands are overwritten by the imported commands.
03546  *
03547  *      If there are no pattern arguments and the "-force" flag isn't given,
03548  *      this command returns the list of commands currently imported in
03549  *      the current namespace.
03550  *
03551  * Results:
03552  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
03553  *
03554  * Side effects:
03555  *      Adds imported commands to the current namespace. If anything goes
03556  *      wrong, this function returns an error message in the interpreter's
03557  *      result object.
03558  *
03559  *----------------------------------------------------------------------
03560  */
03561 
03562 static int
03563 NamespaceImportCmd(
03564     ClientData dummy,           /* Not used. */
03565     Tcl_Interp *interp,         /* Current interpreter. */
03566     int objc,                   /* Number of arguments. */
03567     Tcl_Obj *const objv[])      /* Argument objects. */
03568 {
03569     int allowOverwrite = 0;
03570     char *string, *pattern;
03571     register int i, result;
03572     int firstArg;
03573 
03574     if (objc < 2) {
03575         Tcl_WrongNumArgs(interp, 2, objv, "?-force? ?pattern pattern...?");
03576         return TCL_ERROR;
03577     }
03578 
03579     /*
03580      * Skip over the optional "-force" as the first argument.
03581      */
03582 
03583     firstArg = 2;
03584     if (firstArg < objc) {
03585         string = TclGetString(objv[firstArg]);
03586         if ((*string == '-') && (strcmp(string, "-force") == 0)) {
03587             allowOverwrite = 1;
03588             firstArg++;
03589         }
03590     } else {
03591         /*
03592          * When objc == 2, command is just [namespace import]. Introspection
03593          * form to return list of imported commands.
03594          */
03595 
03596         Tcl_HashEntry *hPtr;
03597         Tcl_HashSearch search;
03598         Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
03599         Tcl_Obj *listPtr;
03600 
03601         TclNewObj(listPtr);
03602         for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
03603                 hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
03604             Command *cmdPtr = Tcl_GetHashValue(hPtr);
03605 
03606             if (cmdPtr->deleteProc == DeleteImportedCmd) {
03607                 Tcl_ListObjAppendElement(NULL, listPtr, Tcl_NewStringObj(
03608                         Tcl_GetHashKey(&nsPtr->cmdTable, hPtr) ,-1));
03609             }
03610         }
03611         Tcl_SetObjResult(interp, listPtr);
03612         return TCL_OK;
03613     }
03614 
03615     /*
03616      * Handle the imports for each of the patterns.
03617      */
03618 
03619     for (i = firstArg;  i < objc;  i++) {
03620         pattern = TclGetString(objv[i]);
03621         result = Tcl_Import(interp, NULL, pattern, allowOverwrite);
03622         if (result != TCL_OK) {
03623             return result;
03624         }
03625     }
03626     return TCL_OK;
03627 }
03628 
03629 /*
03630  *----------------------------------------------------------------------
03631  *
03632  * NamespaceInscopeCmd --
03633  *
03634  *      Invoked to implement the "namespace inscope" command that executes a
03635  *      script in the context of a particular namespace. This command is not
03636  *      expected to be used directly by programmers; calls to it are generated
03637  *      implicitly when programs use "namespace code" commands to register
03638  *      callback scripts. Handles the following syntax:
03639  *
03640  *          namespace inscope name arg ?arg...?
03641  *
03642  *      The "namespace inscope" command is much like the "namespace eval"
03643  *      command except that it has lappend semantics and the namespace must
03644  *      already exist. It treats the first argument as a list, and appends any
03645  *      arguments after the first onto the end as proper list elements. For
03646  *      example,
03647  *
03648  *          namespace inscope ::foo {a b} c d e
03649  *
03650  *      is equivalent to
03651  *
03652  *          namespace eval ::foo [concat {a b} [list c d e]]
03653  *
03654  *      This lappend semantics is important because many callback scripts are
03655  *      actually prefixes.
03656  *
03657  * Results:
03658  *      Returns TCL_OK to indicate success, or TCL_ERROR to indicate failure.
03659  *
03660  * Side effects:
03661  *      Returns a result in the Tcl interpreter's result object.
03662  *
03663  *----------------------------------------------------------------------
03664  */
03665 
03666 static int
03667 NamespaceInscopeCmd(
03668     ClientData dummy,           /* Not used. */
03669     Tcl_Interp *interp,         /* Current interpreter. */
03670     int objc,                   /* Number of arguments. */
03671     Tcl_Obj *const objv[])      /* Argument objects. */
03672 {
03673     Tcl_Namespace *namespacePtr;
03674     CallFrame *framePtr, **framePtrPtr;
03675     int i, result;
03676 
03677     if (objc < 4) {
03678         Tcl_WrongNumArgs(interp, 2, objv, "name arg ?arg...?");
03679         return TCL_ERROR;
03680     }
03681 
03682     /*
03683      * Resolve the namespace reference.
03684      */
03685 
03686     if (TclGetNamespaceFromObj(interp, objv[2], &namespacePtr) != TCL_OK) {
03687         return TCL_ERROR;
03688     }
03689 
03690     /*
03691      * Make the specified namespace the current namespace.
03692      */
03693 
03694     framePtrPtr = &framePtr;            /* This is needed to satisfy GCC's
03695                                          * strict aliasing rules. */
03696     result = TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
03697             namespacePtr, /*isProcCallFrame*/ 0);
03698     if (result != TCL_OK) {
03699         return result;
03700     }
03701 
03702     framePtr->objc = objc;
03703     framePtr->objv = objv;
03704 
03705     /*
03706      * Execute the command. If there is just one argument, just treat it as a
03707      * script and evaluate it. Otherwise, create a list from the arguments
03708      * after the first one, then concatenate the first argument and the list
03709      * of extra arguments to form the command to evaluate.
03710      */
03711 
03712     if (objc == 4) {
03713         result = Tcl_EvalObjEx(interp, objv[3], 0);
03714     } else {
03715         Tcl_Obj *concatObjv[2];
03716         register Tcl_Obj *listPtr, *cmdObjPtr;
03717 
03718         listPtr = Tcl_NewListObj(0, NULL);
03719         for (i = 4;  i < objc;  i++) {
03720             if (Tcl_ListObjAppendElement(interp, listPtr, objv[i]) != TCL_OK) {
03721                 Tcl_DecrRefCount(listPtr);      /* Free unneeded obj. */
03722                 return TCL_ERROR;
03723             }
03724         }
03725 
03726         concatObjv[0] = objv[3];
03727         concatObjv[1] = listPtr;
03728         cmdObjPtr = Tcl_ConcatObj(2, concatObjv);
03729         result = Tcl_EvalObjEx(interp, cmdObjPtr, TCL_EVAL_DIRECT);
03730         Tcl_DecrRefCount(listPtr);    /* We're done with the list object. */
03731     }
03732 
03733     if (result == TCL_ERROR) {
03734         int length = strlen(namespacePtr->fullName);
03735         int limit = 200;
03736         int overflow = (length > limit);
03737 
03738         Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
03739                 "\n    (in namespace inscope \"%.*s%s\" script line %d)",
03740                 (overflow ? limit : length), namespacePtr->fullName,
03741                 (overflow ? "..." : ""), interp->errorLine));
03742     }
03743 
03744     /*
03745      * Restore the previous "current" namespace.
03746      */
03747 
03748     TclPopStackFrame(interp);
03749     return result;
03750 }
03751 
03752 /*
03753  *----------------------------------------------------------------------
03754  *
03755  * NamespaceOriginCmd --
03756  *
03757  *      Invoked to implement the "namespace origin" command to return the
03758  *      fully-qualified name of the "real" command to which the specified
03759  *      "imported command" refers. Handles the following syntax:
03760  *
03761  *          namespace origin name
03762  *
03763  * Results:
03764  *      An imported command is created in an namespace when that namespace
03765  *      imports a command from another namespace. If a command is imported
03766  *      into a sequence of namespaces a, b,...,n where each successive
03767  *      namespace just imports the command from the previous namespace, this
03768  *      command returns the fully-qualified name of the original command in
03769  *      the first namespace, a. If "name" does not refer to an alias, its
03770  *      fully-qualified name is returned. The returned name is stored in the
03771  *      interpreter's result object. This function returns TCL_OK if
03772  *      successful, and TCL_ERROR if anything goes wrong.
03773  *
03774  * Side effects:
03775  *      If anything goes wrong, this function returns an error message in the
03776  *      interpreter's result object.
03777  *
03778  *----------------------------------------------------------------------
03779  */
03780 
03781 static int
03782 NamespaceOriginCmd(
03783     ClientData dummy,           /* Not used. */
03784     Tcl_Interp *interp,         /* Current interpreter. */
03785     int objc,                   /* Number of arguments. */
03786     Tcl_Obj *const objv[])      /* Argument objects. */
03787 {
03788     Tcl_Command command, origCommand;
03789     Tcl_Obj *resultPtr;
03790 
03791     if (objc != 3) {
03792         Tcl_WrongNumArgs(interp, 2, objv, "name");
03793         return TCL_ERROR;
03794     }
03795 
03796     command = Tcl_GetCommandFromObj(interp, objv[2]);
03797     if (command == NULL) {
03798         Tcl_AppendResult(interp, "invalid command name \"",
03799                 TclGetString(objv[2]), "\"", NULL);
03800         Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND",
03801                 TclGetString(objv[2]), NULL);
03802         return TCL_ERROR;
03803     }
03804     origCommand = TclGetOriginalCommand(command);
03805     TclNewObj(resultPtr);
03806     if (origCommand == NULL) {
03807         /*
03808          * The specified command isn't an imported command. Return the
03809          * command's name qualified by the full name of the namespace it was
03810          * defined in.
03811          */
03812 
03813         Tcl_GetCommandFullName(interp, command, resultPtr);
03814     } else {
03815         Tcl_GetCommandFullName(interp, origCommand, resultPtr);
03816     }
03817     Tcl_SetObjResult(interp, resultPtr);
03818     return TCL_OK;
03819 }
03820 
03821 /*
03822  *----------------------------------------------------------------------
03823  *
03824  * NamespaceParentCmd --
03825  *
03826  *      Invoked to implement the "namespace parent" command that returns the
03827  *      fully-qualified name of the parent namespace for a specified
03828  *      namespace. Handles the following syntax:
03829  *
03830  *          namespace parent ?name?
03831  *
03832  * Results:
03833  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
03834  *
03835  * Side effects:
03836  *      Returns a result in the interpreter's result object. If anything goes
03837  *      wrong, the result is an error message.
03838  *
03839  *----------------------------------------------------------------------
03840  */
03841 
03842 static int
03843 NamespaceParentCmd(
03844     ClientData dummy,           /* Not used. */
03845     Tcl_Interp *interp,         /* Current interpreter. */
03846     int objc,                   /* Number of arguments. */
03847     Tcl_Obj *const objv[])      /* Argument objects. */
03848 {
03849     Tcl_Namespace *nsPtr;
03850 
03851     if (objc == 2) {
03852         nsPtr = TclGetCurrentNamespace(interp);
03853     } else if (objc == 3) {
03854         if (TclGetNamespaceFromObj(interp, objv[2], &nsPtr) != TCL_OK) {
03855             return TCL_ERROR;
03856         }
03857     } else {
03858         Tcl_WrongNumArgs(interp, 2, objv, "?name?");
03859         return TCL_ERROR;
03860     }
03861 
03862     /*
03863      * Report the parent of the specified namespace.
03864      */
03865 
03866     if (nsPtr->parentPtr != NULL) {
03867         Tcl_SetObjResult(interp, Tcl_NewStringObj(
03868                 nsPtr->parentPtr->fullName, -1));
03869     }
03870     return TCL_OK;
03871 }
03872 
03873 /*
03874  *----------------------------------------------------------------------
03875  *
03876  * NamespacePathCmd --
03877  *
03878  *      Invoked to implement the "namespace path" command that reads and
03879  *      writes the current namespace's command resolution path. Has one
03880  *      optional argument: if present, it is a list of named namespaces to set
03881  *      the path to, and if absent, the current path should be returned.
03882  *      Handles the following syntax:
03883  *
03884  *          namespace path ?nsList?
03885  *
03886  * Results:
03887  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong
03888  *      (most notably if the namespace list contains the name of something
03889  *      other than a namespace). In the successful-exit case, may set the
03890  *      interpreter result to the list of names of the namespaces on the
03891  *      current namespace's path.
03892  *
03893  * Side effects:
03894  *      May update the namespace path (triggering a recomputing of all command
03895  *      names that depend on the namespace for resolution).
03896  *
03897  *----------------------------------------------------------------------
03898  */
03899 
03900 static int
03901 NamespacePathCmd(
03902     ClientData dummy,           /* Not used. */
03903     Tcl_Interp *interp,         /* Current interpreter. */
03904     int objc,                   /* Number of arguments. */
03905     Tcl_Obj *const objv[])      /* Argument objects. */
03906 {
03907     Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
03908     int i, nsObjc, result = TCL_ERROR;
03909     Tcl_Obj **nsObjv;
03910     Tcl_Namespace **namespaceList = NULL;
03911 
03912     if (objc > 3) {
03913         Tcl_WrongNumArgs(interp, 2, objv, "?pathList?");
03914         return TCL_ERROR;
03915     }
03916 
03917     /*
03918      * If no path is given, return the current path.
03919      */
03920 
03921     if (objc == 2) {
03922         /*
03923          * Not a very fast way to compute this, but easy to get right.
03924          */
03925 
03926         for (i=0 ; i<nsPtr->commandPathLength ; i++) {
03927             if (nsPtr->commandPathArray[i].nsPtr != NULL) {
03928                 Tcl_AppendElement(interp,
03929                         nsPtr->commandPathArray[i].nsPtr->fullName);
03930             }
03931         }
03932         return TCL_OK;
03933     }
03934 
03935     /*
03936      * There is a path given, so parse it into an array of namespace pointers.
03937      */
03938 
03939     if (TclListObjGetElements(interp, objv[2], &nsObjc, &nsObjv) != TCL_OK) {
03940         goto badNamespace;
03941     }
03942     if (nsObjc != 0) {
03943         namespaceList = (Tcl_Namespace **)
03944                 TclStackAlloc(interp, sizeof(Tcl_Namespace *) * nsObjc);
03945 
03946         for (i=0 ; i<nsObjc ; i++) {
03947             if (TclGetNamespaceFromObj(interp, nsObjv[i],
03948                     &namespaceList[i]) != TCL_OK) {
03949                 goto badNamespace;
03950             }
03951         }
03952     }
03953 
03954     /*
03955      * Now we have the list of valid namespaces, install it as the path.
03956      */
03957 
03958     TclSetNsPath(nsPtr, nsObjc, namespaceList);
03959 
03960     result = TCL_OK;
03961   badNamespace:
03962     if (namespaceList != NULL) {
03963         TclStackFree(interp, namespaceList);
03964     }
03965     return result;
03966 }
03967 
03968 /*
03969  *----------------------------------------------------------------------
03970  *
03971  * TclSetNsPath --
03972  *
03973  *      Sets the namespace command name resolution path to the given list of
03974  *      namespaces. If the list is empty (of zero length) the path is set to
03975  *      empty and the default old-style behaviour of command name resolution
03976  *      is used.
03977  *
03978  * Results:
03979  *      nothing
03980  *
03981  * Side effects:
03982  *      Invalidates the command name resolution caches for any command
03983  *      resolved in the given namespace.
03984  *
03985  *----------------------------------------------------------------------
03986  */
03987 
03988 void
03989 TclSetNsPath(
03990     Namespace *nsPtr,           /* Namespace whose path is to be set. */
03991     int pathLength,             /* Length of pathAry. */
03992     Tcl_Namespace *pathAry[])   /* Array of namespaces that are the path. */
03993 {
03994     if (pathLength != 0) {
03995         NamespacePathEntry *tmpPathArray = (NamespacePathEntry *)
03996                 ckalloc(sizeof(NamespacePathEntry) * pathLength);
03997         int i;
03998 
03999         for (i=0 ; i<pathLength ; i++) {
04000             tmpPathArray[i].nsPtr = (Namespace *) pathAry[i];
04001             tmpPathArray[i].creatorNsPtr = nsPtr;
04002             tmpPathArray[i].prevPtr = NULL;
04003             tmpPathArray[i].nextPtr =
04004                     tmpPathArray[i].nsPtr->commandPathSourceList;
04005             if (tmpPathArray[i].nextPtr != NULL) {
04006                 tmpPathArray[i].nextPtr->prevPtr = &tmpPathArray[i];
04007             }
04008             tmpPathArray[i].nsPtr->commandPathSourceList = &tmpPathArray[i];
04009         }
04010         if (nsPtr->commandPathLength != 0) {
04011             UnlinkNsPath(nsPtr);
04012         }
04013         nsPtr->commandPathArray = tmpPathArray;
04014     } else {
04015         if (nsPtr->commandPathLength != 0) {
04016             UnlinkNsPath(nsPtr);
04017         }
04018     }
04019 
04020     nsPtr->commandPathLength = pathLength;
04021     nsPtr->cmdRefEpoch++;
04022     nsPtr->resolverEpoch++;
04023 }
04024 
04025 /*
04026  *----------------------------------------------------------------------
04027  *
04028  * UnlinkNsPath --
04029  *
04030  *      Delete the given namespace's command name resolution path. Only call
04031  *      if the path is non-empty. Caller must reset the counter containing the
04032  *      path size.
04033  *
04034  * Results:
04035  *      nothing
04036  *
04037  * Side effects:
04038  *      Deletes the array of path entries and unlinks those path entries from
04039  *      the target namespace's list of interested namespaces.
04040  *
04041  *----------------------------------------------------------------------
04042  */
04043 
04044 static void
04045 UnlinkNsPath(
04046     Namespace *nsPtr)
04047 {
04048     int i;
04049     for (i=0 ; i<nsPtr->commandPathLength ; i++) {
04050         NamespacePathEntry *nsPathPtr = &nsPtr->commandPathArray[i];
04051         if (nsPathPtr->prevPtr != NULL) {
04052             nsPathPtr->prevPtr->nextPtr = nsPathPtr->nextPtr;
04053         }
04054         if (nsPathPtr->nextPtr != NULL) {
04055             nsPathPtr->nextPtr->prevPtr = nsPathPtr->prevPtr;
04056         }
04057         if (nsPathPtr->nsPtr != NULL) {
04058             if (nsPathPtr->nsPtr->commandPathSourceList == nsPathPtr) {
04059                 nsPathPtr->nsPtr->commandPathSourceList = nsPathPtr->nextPtr;
04060             }
04061         }
04062     }
04063     ckfree((char *) nsPtr->commandPathArray);
04064 }
04065 
04066 /*
04067  *----------------------------------------------------------------------
04068  *
04069  * TclInvalidateNsPath --
04070  *
04071  *      Invalidate the name resolution caches for all names looked up in
04072  *      namespaces whose name path includes the given namespace.
04073  *
04074  * Results:
04075  *      nothing
04076  *
04077  * Side effects:
04078  *      Increments the command reference epoch in each namespace whose path
04079  *      includes the given namespace. This causes any cached resolved names
04080  *      whose root cacheing context starts at that namespace to be recomputed
04081  *      the next time they are used.
04082  *
04083  *----------------------------------------------------------------------
04084  */
04085 
04086 void
04087 TclInvalidateNsPath(
04088     Namespace *nsPtr)
04089 {
04090     NamespacePathEntry *nsPathPtr = nsPtr->commandPathSourceList;
04091     while (nsPathPtr != NULL) {
04092         if (nsPathPtr->nsPtr != NULL) {
04093             nsPathPtr->creatorNsPtr->cmdRefEpoch++;
04094         }
04095         nsPathPtr = nsPathPtr->nextPtr;
04096     }
04097 }
04098 
04099 /*
04100  *----------------------------------------------------------------------
04101  *
04102  * NamespaceQualifiersCmd --
04103  *
04104  *      Invoked to implement the "namespace qualifiers" command that returns
04105  *      any leading namespace qualifiers in a string. These qualifiers are
04106  *      namespace names separated by "::"s. For example, for "::foo::p" this
04107  *      command returns "::foo", and for "::" it returns "". This command is
04108  *      the complement of the "namespace tail" command. Note that this command
04109  *      does not check whether the "namespace" names are, in fact, the names
04110  *      of currently defined namespaces. Handles the following syntax:
04111  *
04112  *          namespace qualifiers string
04113  *
04114  * Results:
04115  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
04116  *
04117  * Side effects:
04118  *      Returns a result in the interpreter's result object. If anything goes
04119  *      wrong, the result is an error message.
04120  *
04121  *----------------------------------------------------------------------
04122  */
04123 
04124 static int
04125 NamespaceQualifiersCmd(
04126     ClientData dummy,           /* Not used. */
04127     Tcl_Interp *interp,         /* Current interpreter. */
04128     int objc,                   /* Number of arguments. */
04129     Tcl_Obj *const objv[])      /* Argument objects. */
04130 {
04131     register char *name, *p;
04132     int length;
04133 
04134     if (objc != 3) {
04135         Tcl_WrongNumArgs(interp, 2, objv, "string");
04136         return TCL_ERROR;
04137     }
04138 
04139     /*
04140      * Find the end of the string, then work backward and find the start of
04141      * the last "::" qualifier.
04142      */
04143 
04144     name = TclGetString(objv[2]);
04145     for (p = name;  *p != '\0';  p++) {
04146         /* empty body */
04147     }
04148     while (--p >= name) {
04149         if ((*p == ':') && (p > name) && (*(p-1) == ':')) {
04150             p -= 2;                     /* Back up over the :: */
04151             while ((p >= name) && (*p == ':')) {
04152                 p--;                    /* Back up over the preceeding : */
04153             }
04154             break;
04155         }
04156     }
04157 
04158     if (p >= name) {
04159         length = p-name+1;
04160         Tcl_SetObjResult(interp, Tcl_NewStringObj(name, length));
04161     }
04162     return TCL_OK;
04163 }
04164 
04165 /*
04166  *----------------------------------------------------------------------
04167  *
04168  * NamespaceUnknownCmd --
04169  *
04170  *      Invoked to implement the "namespace unknown" command (TIP 181) that
04171  *      sets or queries a per-namespace unknown command handler. This handler
04172  *      is called when command lookup fails (current and global ns). The
04173  *      default handler for the global namespace is ::unknown. The default
04174  *      handler for other namespaces is to call the global namespace unknown
04175  *      handler. Passing an empty list results in resetting the handler to its
04176  *      default.
04177  *
04178  *          namespace unknown ?handler?
04179  *
04180  * Results:
04181  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
04182  *
04183  * Side effects:
04184  *      If no handler is specified, returns a result in the interpreter's
04185  *      result object, otherwise it sets the unknown handler pointer in the
04186  *      current namespace to the script fragment provided. If anything goes
04187  *      wrong, the result is an error message.
04188  *
04189  *----------------------------------------------------------------------
04190  */
04191 
04192 static int
04193 NamespaceUnknownCmd(
04194     ClientData dummy,           /* Not used. */
04195     Tcl_Interp *interp,         /* Current interpreter. */
04196     int objc,                   /* Number of arguments. */
04197     Tcl_Obj *const objv[])      /* Argument objects. */
04198 {
04199     Tcl_Namespace *currNsPtr;
04200     Tcl_Obj *resultPtr;
04201     int rc;
04202 
04203     if (objc > 3) {
04204         Tcl_WrongNumArgs(interp, 2, objv, "?script?");
04205         return TCL_ERROR;
04206     }
04207 
04208     currNsPtr = TclGetCurrentNamespace(interp);
04209 
04210     if (objc == 2) {
04211         /*
04212          * Introspection - return the current namespace handler.
04213          */
04214 
04215         resultPtr = Tcl_GetNamespaceUnknownHandler(interp, currNsPtr);
04216         if (resultPtr == NULL) {
04217             TclNewObj(resultPtr);
04218         }
04219         Tcl_SetObjResult(interp, resultPtr);
04220     } else {
04221         rc = Tcl_SetNamespaceUnknownHandler(interp, currNsPtr, objv[2]);
04222         if (rc == TCL_OK) {
04223             Tcl_SetObjResult(interp, objv[2]);
04224         }
04225         return rc;
04226     }
04227     return TCL_OK;
04228 }
04229 
04230 /*
04231  *----------------------------------------------------------------------
04232  *
04233  * Tcl_GetNamespaceUnknownHandler --
04234  *
04235  *      Returns the unknown command handler registered for the given
04236  *      namespace.
04237  *
04238  * Results:
04239  *      Returns the current unknown command handler, or NULL if none exists
04240  *      for the namespace.
04241  *
04242  * Side effects:
04243  *      None.
04244  *
04245  *----------------------------------------------------------------------
04246  */
04247 
04248 Tcl_Obj *
04249 Tcl_GetNamespaceUnknownHandler(
04250     Tcl_Interp *interp,         /* The interpreter in which the namespace
04251                                  * exists. */
04252     Tcl_Namespace *nsPtr)       /* The namespace. */
04253 {
04254     Namespace *currNsPtr = (Namespace *)nsPtr;
04255 
04256     if (currNsPtr->unknownHandlerPtr == NULL &&
04257             currNsPtr == ((Interp *)interp)->globalNsPtr) {
04258         /*
04259          * Default handler for global namespace is "::unknown". For all other
04260          * namespaces, it is NULL (which falls back on the global unknown
04261          * handler).
04262          */
04263 
04264         TclNewLiteralStringObj(currNsPtr->unknownHandlerPtr, "::unknown");
04265         Tcl_IncrRefCount(currNsPtr->unknownHandlerPtr);
04266     }
04267     return currNsPtr->unknownHandlerPtr;
04268 }
04269 
04270 /*
04271  *----------------------------------------------------------------------
04272  *
04273  * Tcl_SetNamespaceUnknownHandler --
04274  *
04275  *      Sets the unknown command handler for the given namespace to the
04276  *      command prefix passed.
04277  *
04278  * Results:
04279  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
04280  *
04281  * Side effects:
04282  *      Sets the namespace unknown command handler. If the passed in handler
04283  *      is NULL or an empty list, then the handler is reset to its default. If
04284  *      an error occurs, then an error message is left in the interpreter
04285  *      result.
04286  *
04287  *----------------------------------------------------------------------
04288  */
04289 
04290 int
04291 Tcl_SetNamespaceUnknownHandler(
04292     Tcl_Interp *interp,         /* Interpreter in which the namespace
04293                                  * exists. */
04294     Tcl_Namespace *nsPtr,       /* Namespace which is being updated. */
04295     Tcl_Obj *handlerPtr)        /* The new handler, or NULL to reset. */
04296 {
04297     int lstlen;
04298     Namespace *currNsPtr = (Namespace *)nsPtr;
04299 
04300     if (currNsPtr->unknownHandlerPtr != NULL) {
04301         /*
04302          * Remove old handler first.
04303          */
04304 
04305         Tcl_DecrRefCount(currNsPtr->unknownHandlerPtr);
04306         currNsPtr->unknownHandlerPtr = NULL;
04307     }
04308 
04309     /*
04310      * If NULL or an empty list is passed, then reset to the default
04311      * handler.
04312      */
04313 
04314     if (handlerPtr == NULL) {
04315         currNsPtr->unknownHandlerPtr = NULL;
04316     } else if (TclListObjLength(interp, handlerPtr, &lstlen) != TCL_OK) {
04317         /*
04318          * Not a list.
04319          */
04320 
04321         return TCL_ERROR;
04322     } else if (lstlen == 0) {
04323         /*
04324          * Empty list - reset to default.
04325          */
04326 
04327         currNsPtr->unknownHandlerPtr = NULL;
04328     } else {
04329         /*
04330          * Increment ref count and store. The reference count is decremented
04331          * either in the code above, or when the namespace is deleted.
04332          */
04333 
04334         Tcl_IncrRefCount(handlerPtr);
04335         currNsPtr->unknownHandlerPtr = handlerPtr;
04336     }
04337     return TCL_OK;
04338 }
04339 
04340 /*
04341  *----------------------------------------------------------------------
04342  *
04343  * NamespaceTailCmd --
04344  *
04345  *      Invoked to implement the "namespace tail" command that returns the
04346  *      trailing name at the end of a string with "::" namespace qualifiers.
04347  *      These qualifiers are namespace names separated by "::"s. For example,
04348  *      for "::foo::p" this command returns "p", and for "::" it returns "".
04349  *      This command is the complement of the "namespace qualifiers" command.
04350  *      Note that this command does not check whether the "namespace" names
04351  *      are, in fact, the names of currently defined namespaces. Handles the
04352  *      following syntax:
04353  *
04354  *          namespace tail string
04355  *
04356  * Results:
04357  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
04358  *
04359  * Side effects:
04360  *      Returns a result in the interpreter's result object. If anything goes
04361  *      wrong, the result is an error message.
04362  *
04363  *----------------------------------------------------------------------
04364  */
04365 
04366 static int
04367 NamespaceTailCmd(
04368     ClientData dummy,           /* Not used. */
04369     Tcl_Interp *interp,         /* Current interpreter. */
04370     int objc,                   /* Number of arguments. */
04371     Tcl_Obj *const objv[])      /* Argument objects. */
04372 {
04373     register char *name, *p;
04374 
04375     if (objc != 3) {
04376         Tcl_WrongNumArgs(interp, 2, objv, "string");
04377         return TCL_ERROR;
04378     }
04379 
04380     /*
04381      * Find the end of the string, then work backward and find the last "::"
04382      * qualifier.
04383      */
04384 
04385     name = TclGetString(objv[2]);
04386     for (p = name;  *p != '\0';  p++) {
04387         /* empty body */
04388     }
04389     while (--p > name) {
04390         if ((*p == ':') && (*(p-1) == ':')) {
04391             p++;                        /* Just after the last "::" */
04392             break;
04393         }
04394     }
04395 
04396     if (p >= name) {
04397         Tcl_SetObjResult(interp, Tcl_NewStringObj(p, -1));
04398     }
04399     return TCL_OK;
04400 }
04401 
04402 /*
04403  *----------------------------------------------------------------------
04404  *
04405  * NamespaceUpvarCmd --
04406  *
04407  *      Invoked to implement the "namespace upvar" command, that creates
04408  *      variables in the current scope linked to variables in another
04409  *      namespace. Handles the following syntax:
04410  *
04411  *          namespace upvar ns otherVar myVar ?otherVar myVar ...?
04412  *
04413  * Results:
04414  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
04415  *
04416  * Side effects:
04417  *      Creates new variables in the current scope, linked to the
04418  *      corresponding variables in the stipulated nmamespace. If anything goes
04419  *      wrong, the result is an error message.
04420  *
04421  *----------------------------------------------------------------------
04422  */
04423 
04424 static int
04425 NamespaceUpvarCmd(
04426     ClientData dummy,           /* Not used. */
04427     Tcl_Interp *interp,         /* Current interpreter. */
04428     int objc,                   /* Number of arguments. */
04429     Tcl_Obj *const objv[])      /* Argument objects. */
04430 {
04431     Interp *iPtr = (Interp *) interp;
04432     Tcl_Namespace *nsPtr, *savedNsPtr;
04433     Var *otherPtr, *arrayPtr;
04434     char *myName;
04435 
04436     if (objc < 5 || !(objc & 1)) {
04437         Tcl_WrongNumArgs(interp, 2, objv,
04438                 "ns otherVar myVar ?otherVar myVar ...?");
04439         return TCL_ERROR;
04440     }
04441 
04442     if (TclGetNamespaceFromObj(interp, objv[2], &nsPtr) != TCL_OK) {
04443         return TCL_ERROR;
04444     }
04445 
04446     objc -= 3;
04447     objv += 3;
04448 
04449     for (; objc>0 ; objc-=2, objv+=2) {
04450         /*
04451          * Locate the other variable
04452          */
04453 
04454         savedNsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
04455         iPtr->varFramePtr->nsPtr = (Namespace *) nsPtr;
04456         otherPtr = TclObjLookupVarEx(interp, objv[0], NULL,
04457                 (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
04458                 /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
04459         iPtr->varFramePtr->nsPtr = (Namespace *) savedNsPtr;
04460         if (otherPtr == NULL) {
04461             return TCL_ERROR;
04462         }
04463 
04464         /*
04465          * Create the new variable and link it to otherPtr.
04466          */
04467 
04468         myName = TclGetString(objv[1]);
04469         if (TclPtrMakeUpvar(interp, otherPtr, myName, 0, -1) != TCL_OK) {
04470             return TCL_ERROR;
04471         }
04472     }
04473 
04474     return TCL_OK;
04475 }
04476 
04477 /*
04478  *----------------------------------------------------------------------
04479  *
04480  * NamespaceWhichCmd --
04481  *
04482  *      Invoked to implement the "namespace which" command that returns the
04483  *      fully-qualified name of a command or variable. If the specified
04484  *      command or variable does not exist, it returns "". Handles the
04485  *      following syntax:
04486  *
04487  *          namespace which ?-command? ?-variable? name
04488  *
04489  * Results:
04490  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
04491  *
04492  * Side effects:
04493  *      Returns a result in the interpreter's result object. If anything goes
04494  *      wrong, the result is an error message.
04495  *
04496  *----------------------------------------------------------------------
04497  */
04498 
04499 static int
04500 NamespaceWhichCmd(
04501     ClientData dummy,           /* Not used. */
04502     Tcl_Interp *interp,         /* Current interpreter. */
04503     int objc,                   /* Number of arguments. */
04504     Tcl_Obj *const objv[])      /* Argument objects. */
04505 {
04506     static const char *opts[] = {
04507         "-command", "-variable", NULL
04508     };
04509     int lookupType = 0;
04510     Tcl_Obj *resultPtr;
04511 
04512     if (objc < 3 || objc > 4) {
04513     badArgs:
04514         Tcl_WrongNumArgs(interp, 2, objv, "?-command? ?-variable? name");
04515         return TCL_ERROR;
04516     } else if (objc == 4) {
04517         /*
04518          * Look for a flag controlling the lookup.
04519          */
04520 
04521         if (Tcl_GetIndexFromObj(interp, objv[2], opts, "option", 0,
04522                 &lookupType) != TCL_OK) {
04523             /*
04524              * Preserve old style of error message!
04525              */
04526 
04527             Tcl_ResetResult(interp);
04528             goto badArgs;
04529         }
04530     }
04531 
04532     TclNewObj(resultPtr);
04533     switch (lookupType) {
04534     case 0: {                           /* -command */
04535         Tcl_Command cmd = Tcl_GetCommandFromObj(interp, objv[objc-1]);
04536 
04537         if (cmd != NULL) {
04538             Tcl_GetCommandFullName(interp, cmd, resultPtr);
04539         }
04540         break;
04541     }
04542     case 1: {                           /* -variable */
04543         Tcl_Var var = Tcl_FindNamespaceVar(interp,
04544                 TclGetString(objv[objc-1]), NULL, /*flags*/ 0);
04545 
04546         if (var != NULL) {
04547             Tcl_GetVariableFullName(interp, var, resultPtr);
04548         }
04549         break;
04550     }
04551     }
04552     Tcl_SetObjResult(interp, resultPtr);
04553     return TCL_OK;
04554 }
04555 
04556 /*
04557  *----------------------------------------------------------------------
04558  *
04559  * FreeNsNameInternalRep --
04560  *
04561  *      Frees the resources associated with a nsName object's internal
04562  *      representation.
04563  *
04564  * Results:
04565  *      None.
04566  *
04567  * Side effects:
04568  *      Decrements the ref count of any Namespace structure pointed to by the
04569  *      nsName's internal representation. If there are no more references to
04570  *      the namespace, it's structure will be freed.
04571  *
04572  *----------------------------------------------------------------------
04573  */
04574 
04575 static void
04576 FreeNsNameInternalRep(
04577     register Tcl_Obj *objPtr)   /* nsName object with internal representation
04578                                  * to free. */
04579 {
04580     register ResolvedNsName *resNamePtr = (ResolvedNsName *)
04581             objPtr->internalRep.twoPtrValue.ptr1;
04582     Namespace *nsPtr;
04583 
04584     /*
04585      * Decrement the reference count of the namespace. If there are no more
04586      * references, free it up.
04587      */
04588 
04589     resNamePtr->refCount--;
04590     if (resNamePtr->refCount == 0) {
04591 
04592         /*
04593          * Decrement the reference count for the cached namespace. If the
04594          * namespace is dead, and there are no more references to it, free
04595          * it.
04596          */
04597 
04598         nsPtr = resNamePtr->nsPtr;
04599         nsPtr->refCount--;
04600         if ((nsPtr->refCount == 0) && (nsPtr->flags & NS_DEAD)) {
04601             NamespaceFree(nsPtr);
04602         }
04603         ckfree((char *) resNamePtr);
04604     }
04605 }
04606 
04607 /*
04608  *----------------------------------------------------------------------
04609  *
04610  * DupNsNameInternalRep --
04611  *
04612  *      Initializes the internal representation of a nsName object to a copy
04613  *      of the internal representation of another nsName object.
04614  *
04615  * Results:
04616  *      None.
04617  *
04618  * Side effects:
04619  *      copyPtr's internal rep is set to refer to the same namespace
04620  *      referenced by srcPtr's internal rep. Increments the ref count of the
04621  *      ResolvedNsName structure used to hold the namespace reference.
04622  *
04623  *----------------------------------------------------------------------
04624  */
04625 
04626 static void
04627 DupNsNameInternalRep(
04628     Tcl_Obj *srcPtr,            /* Object with internal rep to copy. */
04629     register Tcl_Obj *copyPtr)  /* Object with internal rep to set. */
04630 {
04631     register ResolvedNsName *resNamePtr = (ResolvedNsName *)
04632             srcPtr->internalRep.twoPtrValue.ptr1;
04633 
04634     copyPtr->internalRep.twoPtrValue.ptr1 = resNamePtr;
04635     resNamePtr->refCount++;
04636     copyPtr->typePtr = &nsNameType;
04637 }
04638 
04639 /*
04640  *----------------------------------------------------------------------
04641  *
04642  * SetNsNameFromAny --
04643  *
04644  *      Attempt to generate a nsName internal representation for a Tcl object.
04645  *
04646  * Results:
04647  *      Returns TCL_OK if the value could be converted to a proper namespace
04648  *      reference. Otherwise, it returns TCL_ERROR, along with an error
04649  *      message in the interpreter's result object.
04650  *
04651  * Side effects:
04652  *      If successful, the object is made a nsName object. Its internal rep is
04653  *      set to point to a ResolvedNsName, which contains a cached pointer to
04654  *      the Namespace. Reference counts are kept on both the ResolvedNsName
04655  *      and the Namespace, so we can keep track of their usage and free them
04656  *      when appropriate.
04657  *
04658  *----------------------------------------------------------------------
04659  */
04660 
04661 static int
04662 SetNsNameFromAny(
04663     Tcl_Interp *interp,         /* Points to the namespace in which to resolve
04664                                  * name. Also used for error reporting if not
04665                                  * NULL. */
04666     register Tcl_Obj *objPtr)   /* The object to convert. */
04667 {
04668     const char *dummy;
04669     Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr;
04670     register ResolvedNsName *resNamePtr;
04671     const char *name = TclGetString(objPtr);
04672 
04673     TclGetNamespaceForQualName(interp, name, NULL, TCL_FIND_ONLY_NS,
04674              &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy);
04675 
04676     /*
04677      * If we found a namespace, then create a new ResolvedNsName structure
04678      * that holds a reference to it.
04679      */
04680 
04681     if ((nsPtr == NULL) || (nsPtr->flags & NS_DYING)) {
04682         /*
04683          * Our failed lookup proves any previously cached nsName intrep is no
04684          * longer valid. Get rid of it so we no longer waste memory storing
04685          * it, nor time determining its invalidity again and again.
04686          */
04687 
04688         if (objPtr->typePtr == &nsNameType) {
04689             TclFreeIntRep(objPtr);
04690             objPtr->typePtr = NULL;
04691         }
04692         return TCL_ERROR;
04693     }
04694 
04695     nsPtr->refCount++;
04696     resNamePtr = (ResolvedNsName *) ckalloc(sizeof(ResolvedNsName));
04697     resNamePtr->nsPtr = nsPtr;
04698     if ((name[0] == ':') && (name[1] == ':')) {
04699         resNamePtr->refNsPtr = NULL;
04700     } else {
04701         resNamePtr->refNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
04702     }
04703     resNamePtr->refCount = 1;
04704     TclFreeIntRep(objPtr);
04705     objPtr->internalRep.twoPtrValue.ptr1 = resNamePtr;
04706     objPtr->typePtr = &nsNameType;
04707     return TCL_OK;
04708 }
04709 
04710 /*
04711  *----------------------------------------------------------------------
04712  *
04713  * NamespaceEnsembleCmd --
04714  *
04715  *      Invoked to implement the "namespace ensemble" command that creates and
04716  *      manipulates ensembles built on top of namespaces. Handles the
04717  *      following syntax:
04718  *
04719  *          namespace ensemble name ?dictionary?
04720  *
04721  * Results:
04722  *      Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
04723  *
04724  * Side effects:
04725  *      Creates the ensemble for the namespace if one did not previously
04726  *      exist. Alternatively, alters the way that the ensemble's subcommand =>
04727  *      implementation prefix is configured.
04728  *
04729  *----------------------------------------------------------------------
04730  */
04731 
04732 static int
04733 NamespaceEnsembleCmd(
04734     ClientData dummy,
04735     Tcl_Interp *interp,
04736     int objc,
04737     Tcl_Obj *const objv[])
04738 {
04739     Namespace *nsPtr;
04740     Tcl_Command token;
04741     static const char *subcommands[] = {
04742         "configure", "create", "exists", NULL
04743     };
04744     enum EnsSubcmds {
04745         ENS_CONFIG, ENS_CREATE, ENS_EXISTS
04746     };
04747     static const char *createOptions[] = {
04748         "-command", "-map", "-prefixes", "-subcommands", "-unknown", NULL
04749     };
04750     enum EnsCreateOpts {
04751         CRT_CMD, CRT_MAP, CRT_PREFIX, CRT_SUBCMDS, CRT_UNKNOWN
04752     };
04753     static const char *configOptions[] = {
04754         "-map", "-namespace", "-prefixes", "-subcommands", "-unknown", NULL
04755     };
04756     enum EnsConfigOpts {
04757         CONF_MAP, CONF_NAMESPACE, CONF_PREFIX, CONF_SUBCMDS, CONF_UNKNOWN
04758     };
04759     int index;
04760 
04761     nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
04762     if (nsPtr == NULL || nsPtr->flags & NS_DYING) {
04763         if (!Tcl_InterpDeleted(interp)) {
04764             Tcl_AppendResult(interp,
04765                     "tried to manipulate ensemble of deleted namespace", NULL);
04766         }
04767         return TCL_ERROR;
04768     }
04769 
04770     if (objc < 3) {
04771         Tcl_WrongNumArgs(interp, 2, objv, "subcommand ?arg ...?");
04772         return TCL_ERROR;
04773     }
04774     if (Tcl_GetIndexFromObj(interp, objv[2], subcommands, "subcommand", 0,
04775             &index) != TCL_OK) {
04776         return TCL_ERROR;
04777     }
04778 
04779     switch ((enum EnsSubcmds) index) {
04780     case ENS_CREATE: {
04781         char *name;
04782         Tcl_DictSearch search;
04783         Tcl_Obj *listObj;
04784         int done, len, allocatedMapFlag = 0;
04785         /*
04786          * Defaults
04787          */
04788         Tcl_Obj *subcmdObj = NULL;
04789         Tcl_Obj *mapObj = NULL;
04790         int permitPrefix = 1;
04791         Tcl_Obj *unknownObj = NULL;
04792 
04793         objv += 3;
04794         objc -= 3;
04795 
04796         /*
04797          * Work out what name to use for the command to create. If supplied,
04798          * it is either fully specified or relative to the current namespace.
04799          * If not supplied, it is exactly the name of the current namespace.
04800          */
04801 
04802         name = nsPtr->fullName;
04803 
04804         /*
04805          * Parse the option list, applying type checks as we go. Note that we
04806          * are not incrementing any reference counts in the objects at this
04807          * stage, so the presence of an option multiple times won't cause any
04808          * memory leaks.
04809          */
04810 
04811         for (; objc>1 ; objc-=2,objv+=2 ) {
04812             if (Tcl_GetIndexFromObj(interp, objv[0], createOptions, "option",
04813                     0, &index) != TCL_OK) {
04814                 if (allocatedMapFlag) {
04815                     Tcl_DecrRefCount(mapObj);
04816                 }
04817                 return TCL_ERROR;
04818             }
04819             switch ((enum EnsCreateOpts) index) {
04820             case CRT_CMD:
04821                 name = TclGetString(objv[1]);
04822                 continue;
04823             case CRT_SUBCMDS:
04824                 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
04825                     if (allocatedMapFlag) {
04826                         Tcl_DecrRefCount(mapObj);
04827                     }
04828                     return TCL_ERROR;
04829                 }
04830                 subcmdObj = (len > 0 ? objv[1] : NULL);
04831                 continue;
04832             case CRT_MAP: {
04833                 Tcl_Obj *patchedDict = NULL, *subcmdObj;
04834 
04835                 /*
04836                  * Verify that the map is sensible.
04837                  */
04838 
04839                 if (Tcl_DictObjFirst(interp, objv[1], &search,
04840                         &subcmdObj, &listObj, &done) != TCL_OK) {
04841                     if (allocatedMapFlag) {
04842                         Tcl_DecrRefCount(mapObj);
04843                     }
04844                     return TCL_ERROR;
04845                 }
04846                 if (done) {
04847                     mapObj = NULL;
04848                     continue;
04849                 }
04850                 do {
04851                     Tcl_Obj **listv;
04852                     char *cmd;
04853 
04854                     if (TclListObjGetElements(interp, listObj, &len,
04855                             &listv) != TCL_OK) {
04856                         Tcl_DictObjDone(&search);
04857                         if (patchedDict) {
04858                             Tcl_DecrRefCount(patchedDict);
04859                         }
04860                         if (allocatedMapFlag) {
04861                             Tcl_DecrRefCount(mapObj);
04862                         }
04863                         return TCL_ERROR;
04864                     }
04865                     if (len < 1) {
04866                         Tcl_SetResult(interp,
04867                                 "ensemble subcommand implementations "
04868                                 "must be non-empty lists", TCL_STATIC);
04869                         Tcl_DictObjDone(&search);
04870                         if (patchedDict) {
04871                             Tcl_DecrRefCount(patchedDict);
04872                         }
04873                         if (allocatedMapFlag) {
04874                             Tcl_DecrRefCount(mapObj);
04875                         }
04876                         return TCL_ERROR;
04877                     }
04878                     cmd = TclGetString(listv[0]);
04879                     if (!(cmd[0] == ':' && cmd[1] == ':')) {
04880                         Tcl_Obj *newList = Tcl_NewListObj(len, listv);
04881                         Tcl_Obj *newCmd = Tcl_NewStringObj(nsPtr->fullName,-1);
04882 
04883                         if (nsPtr->parentPtr) {
04884                             Tcl_AppendStringsToObj(newCmd, "::", NULL);
04885                         }
04886                         Tcl_AppendObjToObj(newCmd, listv[0]);
04887                         Tcl_ListObjReplace(NULL, newList, 0, 1, 1, &newCmd);
04888                         if (patchedDict == NULL) {
04889                             patchedDict = Tcl_DuplicateObj(objv[1]);
04890                         }
04891                         Tcl_DictObjPut(NULL, patchedDict, subcmdObj, newList);
04892                     }
04893                     Tcl_DictObjNext(&search, &subcmdObj, &listObj, &done);
04894                 } while (!done);
04895 
04896                 if (allocatedMapFlag) {
04897                     Tcl_DecrRefCount(mapObj);
04898                 }
04899                 mapObj = (patchedDict ? patchedDict : objv[1]);
04900                 if (patchedDict) {
04901                     allocatedMapFlag = 1;
04902                 }
04903                 continue;
04904             }
04905             case CRT_PREFIX:
04906                 if (Tcl_GetBooleanFromObj(interp, objv[1],
04907                         &permitPrefix) != TCL_OK) {
04908                     if (allocatedMapFlag) {
04909                         Tcl_DecrRefCount(mapObj);
04910                     }
04911                     return TCL_ERROR;
04912                 }
04913                 continue;
04914             case CRT_UNKNOWN:
04915                 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
04916                     if (allocatedMapFlag) {
04917                         Tcl_DecrRefCount(mapObj);
04918                     }
04919                     return TCL_ERROR;
04920                 }
04921                 unknownObj = (len > 0 ? objv[1] : NULL);
04922                 continue;
04923             }
04924         }
04925 
04926         /*
04927          * Create the ensemble. Note that this might delete another ensemble
04928          * linked to the same namespace, so we must be careful. However, we
04929          * should be OK because we only link the namespace into the list once
04930          * we've created it (and after any deletions have occurred.)
04931          */
04932 
04933         token = Tcl_CreateEnsemble(interp, name, NULL,
04934                 (permitPrefix ? TCL_ENSEMBLE_PREFIX : 0));
04935         Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj);
04936         Tcl_SetEnsembleMappingDict(interp, token, mapObj);
04937         Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj);
04938 
04939         /*
04940          * Tricky! Must ensure that the result is not shared (command delete
04941          * traces could have corrupted the pristine object that we started
04942          * with). [Snit test rename-1.5]
04943          */
04944 
04945         Tcl_ResetResult(interp);
04946         Tcl_GetCommandFullName(interp, token, Tcl_GetObjResult(interp));
04947         return TCL_OK;
04948     }
04949 
04950     case ENS_EXISTS:
04951         if (objc != 4) {
04952             Tcl_WrongNumArgs(interp, 3, objv, "cmdname");
04953             return TCL_ERROR;
04954         }
04955         Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
04956                 Tcl_FindEnsemble(interp, objv[3], 0) != NULL));
04957         return TCL_OK;
04958 
04959     case ENS_CONFIG:
04960         if (objc < 4 || (objc != 5 && objc & 1)) {
04961             Tcl_WrongNumArgs(interp, 3, objv, "cmdname ?opt? ?value? ...");
04962             return TCL_ERROR;
04963         }
04964         token = Tcl_FindEnsemble(interp, objv[3], TCL_LEAVE_ERR_MSG);
04965         if (token == NULL) {
04966             return TCL_ERROR;
04967         }
04968 
04969         if (objc == 5) {
04970             Tcl_Obj *resultObj = NULL;          /* silence gcc 4 warning */
04971 
04972             if (Tcl_GetIndexFromObj(interp, objv[4], configOptions, "option",
04973                     0, &index) != TCL_OK) {
04974                 return TCL_ERROR;
04975             }
04976             switch ((enum EnsConfigOpts) index) {
04977             case CONF_SUBCMDS:
04978                 Tcl_GetEnsembleSubcommandList(NULL, token, &resultObj);
04979                 if (resultObj != NULL) {
04980                     Tcl_SetObjResult(interp, resultObj);
04981                 }
04982                 break;
04983             case CONF_MAP:
04984                 Tcl_GetEnsembleMappingDict(NULL, token, &resultObj);
04985                 if (resultObj != NULL) {
04986                     Tcl_SetObjResult(interp, resultObj);
04987                 }
04988                 break;
04989             case CONF_NAMESPACE: {
04990                 Tcl_Namespace *namespacePtr = NULL; /* silence gcc 4 warning */
04991 
04992                 Tcl_GetEnsembleNamespace(NULL, token, &namespacePtr);
04993                 Tcl_SetResult(interp, ((Namespace *)namespacePtr)->fullName,
04994                         TCL_VOLATILE);
04995                 break;
04996             }
04997             case CONF_PREFIX: {
04998                 int flags = 0;                  /* silence gcc 4 warning */
04999 
05000                 Tcl_GetEnsembleFlags(NULL, token, &flags);
05001                 Tcl_SetObjResult(interp,
05002                         Tcl_NewBooleanObj(flags & TCL_ENSEMBLE_PREFIX));
05003                 break;
05004             }
05005             case CONF_UNKNOWN:
05006                 Tcl_GetEnsembleUnknownHandler(NULL, token, &resultObj);
05007                 if (resultObj != NULL) {
05008                     Tcl_SetObjResult(interp, resultObj);
05009                 }
05010                 break;
05011             }
05012             return TCL_OK;
05013 
05014         } else if (objc == 4) {
05015             /*
05016              * Produce list of all information.
05017              */
05018 
05019             Tcl_Obj *resultObj, *tmpObj = NULL; /* silence gcc 4 warning */
05020             Tcl_Namespace *namespacePtr = NULL; /* silence gcc 4 warning */
05021             int flags = 0;                      /* silence gcc 4 warning */
05022 
05023             TclNewObj(resultObj);
05024 
05025             /* -map option */
05026             Tcl_ListObjAppendElement(NULL, resultObj,
05027                     Tcl_NewStringObj(configOptions[CONF_MAP], -1));
05028             Tcl_GetEnsembleMappingDict(NULL, token, &tmpObj);
05029             Tcl_ListObjAppendElement(NULL, resultObj,
05030                     (tmpObj != NULL) ? tmpObj : Tcl_NewObj());
05031 
05032             /* -namespace option */
05033             Tcl_ListObjAppendElement(NULL, resultObj,
05034                     Tcl_NewStringObj(configOptions[CONF_NAMESPACE], -1));
05035             Tcl_GetEnsembleNamespace(NULL, token, &namespacePtr);
05036             Tcl_ListObjAppendElement(NULL, resultObj,
05037                     Tcl_NewStringObj(((Namespace *)namespacePtr)->fullName,
05038                     -1));
05039 
05040             /* -prefix option */
05041             Tcl_ListObjAppendElement(NULL, resultObj,
05042                     Tcl_NewStringObj(configOptions[CONF_PREFIX], -1));
05043             Tcl_GetEnsembleFlags(NULL, token, &flags);
05044             Tcl_ListObjAppendElement(NULL, resultObj,
05045                     Tcl_NewBooleanObj(flags & TCL_ENSEMBLE_PREFIX));
05046 
05047             /* -subcommands option */
05048             Tcl_ListObjAppendElement(NULL, resultObj,
05049                     Tcl_NewStringObj(configOptions[CONF_SUBCMDS], -1));
05050             Tcl_GetEnsembleSubcommandList(NULL, token, &tmpObj);
05051             Tcl_ListObjAppendElement(NULL, resultObj,
05052                     (tmpObj != NULL) ? tmpObj : Tcl_NewObj());
05053 
05054             /* -unknown option */
05055             Tcl_ListObjAppendElement(NULL, resultObj,
05056                     Tcl_NewStringObj(configOptions[CONF_UNKNOWN], -1));
05057             Tcl_GetEnsembleUnknownHandler(NULL, token, &tmpObj);
05058             Tcl_ListObjAppendElement(NULL, resultObj,
05059                     (tmpObj != NULL) ? tmpObj : Tcl_NewObj());
05060 
05061             Tcl_SetObjResult(interp, resultObj);
05062             return TCL_OK;
05063         } else {
05064             Tcl_DictSearch search;
05065             Tcl_Obj *listObj;
05066             int done, len, allocatedMapFlag = 0;
05067             Tcl_Obj *subcmdObj = NULL, *mapObj = NULL,
05068                     *unknownObj = NULL; /* Defaults, silence gcc 4 warnings */
05069             int permitPrefix, flags = 0;        /* silence gcc 4 warning */
05070 
05071             Tcl_GetEnsembleSubcommandList(NULL, token, &subcmdObj);
05072             Tcl_GetEnsembleMappingDict(NULL, token, &mapObj);
05073             Tcl_GetEnsembleUnknownHandler(NULL, token, &unknownObj);
05074             Tcl_GetEnsembleFlags(NULL, token, &flags);
05075             permitPrefix = (flags & TCL_ENSEMBLE_PREFIX) != 0;
05076 
05077             objv += 4;
05078             objc -= 4;
05079 
05080             /*
05081              * Parse the option list, applying type checks as we go. Note that
05082              * we are not incrementing any reference counts in the objects at
05083              * this stage, so the presence of an option multiple times won't
05084              * cause any memory leaks.
05085              */
05086 
05087             for (; objc>0 ; objc-=2,objv+=2 ) {
05088                 if (Tcl_GetIndexFromObj(interp, objv[0], configOptions,
05089                         "option", 0, &index) != TCL_OK) {
05090                     if (allocatedMapFlag) {
05091                         Tcl_DecrRefCount(mapObj);
05092                     }
05093                     return TCL_ERROR;
05094                 }
05095                 switch ((enum EnsConfigOpts) index) {
05096                 case CONF_SUBCMDS:
05097                     if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
05098                         if (allocatedMapFlag) {
05099                             Tcl_DecrRefCount(mapObj);
05100                         }
05101                         return TCL_ERROR;
05102                     }
05103                     subcmdObj = (len > 0 ? objv[1] : NULL);
05104                     continue;
05105                 case CONF_MAP: {
05106                     Tcl_Obj *patchedDict = NULL, *subcmdObj;
05107 
05108                     /*
05109                      * Verify that the map is sensible.
05110                      */
05111 
05112                     if (Tcl_DictObjFirst(interp, objv[1], &search,
05113                             &subcmdObj, &listObj, &done) != TCL_OK) {
05114                         if (allocatedMapFlag) {
05115                             Tcl_DecrRefCount(mapObj);
05116                         }
05117                         return TCL_ERROR;
05118                     }
05119                     if (done) {
05120                         mapObj = NULL;
05121                         continue;
05122                     }
05123                     do {
05124                         Tcl_Obj **listv;
05125                         char *cmd;
05126 
05127                         if (TclListObjGetElements(interp, listObj, &len,
05128                                 &listv) != TCL_OK) {
05129                             Tcl_DictObjDone(&search);
05130                             if (patchedDict) {
05131                                 Tcl_DecrRefCount(patchedDict);
05132                             }
05133                             if (allocatedMapFlag) {
05134                                 Tcl_DecrRefCount(mapObj);
05135                             }
05136                             return TCL_ERROR;
05137                         }
05138                         if (len < 1) {
05139                             Tcl_SetResult(interp,
05140                                     "ensemble subcommand implementations "
05141                                     "must be non-empty lists", TCL_STATIC);
05142                             Tcl_DictObjDone(&search);
05143                             if (patchedDict) {
05144                                 Tcl_DecrRefCount(patchedDict);
05145                             }
05146                             if (allocatedMapFlag) {
05147                                 Tcl_DecrRefCount(mapObj);
05148                             }
05149                             return TCL_ERROR;
05150                         }
05151                         cmd = TclGetString(listv[0]);
05152                         if (!(cmd[0] == ':' && cmd[1] == ':')) {
05153                             Tcl_Obj *newList = Tcl_NewListObj(len, listv);
05154                             Tcl_Obj *newCmd =
05155                                     Tcl_NewStringObj(nsPtr->fullName, -1);
05156                             if (nsPtr->parentPtr) {
05157                                 Tcl_AppendStringsToObj(newCmd, "::", NULL);
05158                             }
05159                             Tcl_AppendObjToObj(newCmd, listv[0]);
05160                             Tcl_ListObjReplace(NULL, newList, 0,1, 1,&newCmd);
05161                             if (patchedDict == NULL) {
05162                                 patchedDict = Tcl_DuplicateObj(objv[1]);
05163                             }
05164                             Tcl_DictObjPut(NULL, patchedDict, subcmdObj,
05165                                     newList);
05166                         }
05167                         Tcl_DictObjNext(&search, &subcmdObj, &listObj, &done);
05168                     } while (!done);
05169                     if (allocatedMapFlag) {
05170                         Tcl_DecrRefCount(mapObj);
05171                     }
05172                     mapObj = (patchedDict ? patchedDict : objv[1]);
05173                     if (patchedDict) {
05174                         allocatedMapFlag = 1;
05175                     }
05176                     continue;
05177                 }
05178                 case CONF_NAMESPACE:
05179                     if (allocatedMapFlag) {
05180                         Tcl_DecrRefCount(mapObj);
05181                     }
05182                     Tcl_AppendResult(interp, "option -namespace is read-only",
05183                             NULL);
05184                     return TCL_ERROR;
05185                 case CONF_PREFIX:
05186                     if (Tcl_GetBooleanFromObj(interp, objv[1],
05187                             &permitPrefix) != TCL_OK) {
05188                         if (allocatedMapFlag) {
05189                             Tcl_DecrRefCount(mapObj);
05190                         }
05191                         return TCL_ERROR;
05192                     }
05193                     continue;
05194                 case CONF_UNKNOWN:
05195                     if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
05196                         if (allocatedMapFlag) {
05197                             Tcl_DecrRefCount(mapObj);
05198                         }
05199                         return TCL_ERROR;
05200                     }
05201                     unknownObj = (len > 0 ? objv[1] : NULL);
05202                     continue;
05203                 }
05204             }
05205 
05206             /*
05207              * Update the namespace now that we've finished the parsing stage.
05208              */
05209 
05210             flags = (permitPrefix ? flags|TCL_ENSEMBLE_PREFIX
05211                     : flags&~TCL_ENSEMBLE_PREFIX);
05212             Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj);
05213             Tcl_SetEnsembleMappingDict(interp, token, mapObj);
05214             Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj);
05215             Tcl_SetEnsembleFlags(interp, token, flags);
05216             return TCL_OK;
05217         }
05218 
05219     default:
05220         Tcl_Panic("unexpected ensemble command");
05221     }
05222     return TCL_OK;
05223 }
05224 
05225 /*
05226  *----------------------------------------------------------------------
05227  *
05228  * Tcl_CreateEnsemble --
05229  *
05230  *      Create a simple ensemble attached to the given namespace.
05231  *
05232  * Results:
05233  *      The token for the command created.
05234  *
05235  * Side effects:
05236  *      The ensemble is created and marked for compilation.
05237  *
05238  *----------------------------------------------------------------------
05239  */
05240 
05241 Tcl_Command
05242 Tcl_CreateEnsemble(
05243     Tcl_Interp *interp,
05244     const char *name,
05245     Tcl_Namespace *namespacePtr,
05246     int flags)
05247 {
05248     Namespace *nsPtr = (Namespace *) namespacePtr;
05249     EnsembleConfig *ensemblePtr = (EnsembleConfig *)
05250             ckalloc(sizeof(EnsembleConfig));
05251     Tcl_Obj *nameObj = NULL;
05252 
05253     if (nsPtr == NULL) {
05254         nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
05255     }
05256 
05257     /*
05258      * Make the name of the ensemble into a fully qualified name. This might
05259      * allocate a temporary object.
05260      */
05261 
05262     if (!(name[0] == ':' && name[1] == ':')) {
05263         nameObj = Tcl_NewStringObj(nsPtr->fullName, -1);
05264         if (nsPtr->parentPtr == NULL) {
05265             Tcl_AppendStringsToObj(nameObj, name, NULL);
05266         } else {
05267             Tcl_AppendStringsToObj(nameObj, "::", name, NULL);
05268         }
05269         Tcl_IncrRefCount(nameObj);
05270         name = TclGetString(nameObj);
05271     }
05272 
05273     ensemblePtr->nsPtr = nsPtr;
05274     ensemblePtr->epoch = 0;
05275     Tcl_InitHashTable(&ensemblePtr->subcommandTable, TCL_STRING_KEYS);
05276     ensemblePtr->subcommandArrayPtr = NULL;
05277     ensemblePtr->subcmdList = NULL;
05278     ensemblePtr->subcommandDict = NULL;
05279     ensemblePtr->flags = flags;
05280     ensemblePtr->unknownHandler = NULL;
05281     ensemblePtr->token = Tcl_CreateObjCommand(interp, name,
05282             NsEnsembleImplementationCmd, ensemblePtr, DeleteEnsembleConfig);
05283     ensemblePtr->next = (EnsembleConfig *) nsPtr->ensembles;
05284     nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr;
05285 
05286     /*
05287      * Trigger an eventual recomputation of the ensemble command set. Note
05288      * that this is slightly tricky, as it means that we are not actually
05289      * counting the number of namespace export actions, but it is the simplest
05290      * way to go!
05291      */
05292 
05293     nsPtr->exportLookupEpoch++;
05294 
05295     if (flags & ENSEMBLE_COMPILE) {
05296         ((Command *) ensemblePtr->token)->compileProc = TclCompileEnsemble;
05297     }
05298 
05299     if (nameObj != NULL) {
05300         TclDecrRefCount(nameObj);
05301     }
05302     return ensemblePtr->token;
05303 }
05304 
05305 /*
05306  *----------------------------------------------------------------------
05307  *
05308  * Tcl_SetEnsembleSubcommandList --
05309  *
05310  *      Set the subcommand list for a particular ensemble.
05311  *
05312  * Results:
05313  *      Tcl result code (error if command token does not indicate an ensemble
05314  *      or the subcommand list - if non-NULL - is not a list).
05315  *
05316  * Side effects:
05317  *      The ensemble is updated and marked for recompilation.
05318  *
05319  *----------------------------------------------------------------------
05320  */
05321 
05322 int
05323 Tcl_SetEnsembleSubcommandList(
05324     Tcl_Interp *interp,
05325     Tcl_Command token,
05326     Tcl_Obj *subcmdList)
05327 {
05328     Command *cmdPtr = (Command *) token;
05329     EnsembleConfig *ensemblePtr;
05330     Tcl_Obj *oldList;
05331 
05332     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05333         Tcl_AppendResult(interp, "command is not an ensemble", NULL);
05334         return TCL_ERROR;
05335     }
05336     if (subcmdList != NULL) {
05337         int length;
05338 
05339         if (TclListObjLength(interp, subcmdList, &length) != TCL_OK) {
05340             return TCL_ERROR;
05341         }
05342         if (length < 1) {
05343             subcmdList = NULL;
05344         }
05345     }
05346 
05347     ensemblePtr = cmdPtr->objClientData;
05348     oldList = ensemblePtr->subcmdList;
05349     ensemblePtr->subcmdList = subcmdList;
05350     if (subcmdList != NULL) {
05351         Tcl_IncrRefCount(subcmdList);
05352     }
05353     if (oldList != NULL) {
05354         TclDecrRefCount(oldList);
05355     }
05356 
05357     /*
05358      * Trigger an eventual recomputation of the ensemble command set. Note
05359      * that this is slightly tricky, as it means that we are not actually
05360      * counting the number of namespace export actions, but it is the simplest
05361      * way to go!
05362      */
05363 
05364     ensemblePtr->nsPtr->exportLookupEpoch++;
05365 
05366     /*
05367      * Special hack to make compiling of [info exists] work when the
05368      * dictionary is modified.
05369      */
05370 
05371     if (cmdPtr->compileProc != NULL) {
05372         ((Interp *)interp)->compileEpoch++;
05373     }
05374 
05375     return TCL_OK;
05376 }
05377 
05378 /*
05379  *----------------------------------------------------------------------
05380  *
05381  * Tcl_SetEnsembleMappingDict --
05382  *
05383  *      Set the mapping dictionary for a particular ensemble.
05384  *
05385  * Results:
05386  *      Tcl result code (error if command token does not indicate an ensemble
05387  *      or the mapping - if non-NULL - is not a dict).
05388  *
05389  * Side effects:
05390  *      The ensemble is updated and marked for recompilation.
05391  *
05392  *----------------------------------------------------------------------
05393  */
05394 
05395 int
05396 Tcl_SetEnsembleMappingDict(
05397     Tcl_Interp *interp,
05398     Tcl_Command token,
05399     Tcl_Obj *mapDict)
05400 {
05401     Command *cmdPtr = (Command *) token;
05402     EnsembleConfig *ensemblePtr;
05403     Tcl_Obj *oldDict;
05404 
05405     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05406         Tcl_AppendResult(interp, "command is not an ensemble", NULL);
05407         return TCL_ERROR;
05408     }
05409     if (mapDict != NULL) {
05410         int size, done;
05411         Tcl_DictSearch search;
05412         Tcl_Obj *valuePtr;
05413 
05414         if (Tcl_DictObjSize(interp, mapDict, &size) != TCL_OK) {
05415             return TCL_ERROR;
05416         }
05417 
05418         for (Tcl_DictObjFirst(NULL, mapDict, &search, NULL, &valuePtr, &done);
05419                 !done; Tcl_DictObjNext(&search, NULL, &valuePtr, &done)) {
05420             Tcl_Obj *cmdPtr;
05421             const char *bytes;
05422 
05423             if (Tcl_ListObjIndex(interp, valuePtr, 0, &cmdPtr) != TCL_OK) {
05424                 Tcl_DictObjDone(&search);
05425                 return TCL_ERROR;
05426             }
05427             bytes = TclGetString(cmdPtr);
05428             if (bytes[0] != ':' || bytes[1] != ':') {
05429                 Tcl_AppendResult(interp,
05430                         "ensemble target is not a fully-qualified command",
05431                         NULL);
05432                 Tcl_DictObjDone(&search);
05433                 return TCL_ERROR;
05434             }
05435         }
05436 
05437         if (size < 1) {
05438             mapDict = NULL;
05439         }
05440     }
05441 
05442     ensemblePtr = cmdPtr->objClientData;
05443     oldDict = ensemblePtr->subcommandDict;
05444     ensemblePtr->subcommandDict = mapDict;
05445     if (mapDict != NULL) {
05446         Tcl_IncrRefCount(mapDict);
05447     }
05448     if (oldDict != NULL) {
05449         TclDecrRefCount(oldDict);
05450     }
05451 
05452     /*
05453      * Trigger an eventual recomputation of the ensemble command set. Note
05454      * that this is slightly tricky, as it means that we are not actually
05455      * counting the number of namespace export actions, but it is the simplest
05456      * way to go!
05457      */
05458 
05459     ensemblePtr->nsPtr->exportLookupEpoch++;
05460 
05461     /*
05462      * Special hack to make compiling of [info exists] work when the
05463      * dictionary is modified.
05464      */
05465 
05466     if (cmdPtr->compileProc != NULL) {
05467         ((Interp *)interp)->compileEpoch++;
05468     }
05469 
05470     return TCL_OK;
05471 }
05472 
05473 /*
05474  *----------------------------------------------------------------------
05475  *
05476  * Tcl_SetEnsembleUnknownHandler --
05477  *
05478  *      Set the unknown handler for a particular ensemble.
05479  *
05480  * Results:
05481  *      Tcl result code (error if command token does not indicate an ensemble
05482  *      or the unknown handler - if non-NULL - is not a list).
05483  *
05484  * Side effects:
05485  *      The ensemble is updated and marked for recompilation.
05486  *
05487  *----------------------------------------------------------------------
05488  */
05489 
05490 int
05491 Tcl_SetEnsembleUnknownHandler(
05492     Tcl_Interp *interp,
05493     Tcl_Command token,
05494     Tcl_Obj *unknownList)
05495 {
05496     Command *cmdPtr = (Command *) token;
05497     EnsembleConfig *ensemblePtr;
05498     Tcl_Obj *oldList;
05499 
05500     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05501         Tcl_AppendResult(interp, "command is not an ensemble", NULL);
05502         return TCL_ERROR;
05503     }
05504     if (unknownList != NULL) {
05505         int length;
05506 
05507         if (TclListObjLength(interp, unknownList, &length) != TCL_OK) {
05508             return TCL_ERROR;
05509         }
05510         if (length < 1) {
05511             unknownList = NULL;
05512         }
05513     }
05514 
05515     ensemblePtr = cmdPtr->objClientData;
05516     oldList = ensemblePtr->unknownHandler;
05517     ensemblePtr->unknownHandler = unknownList;
05518     if (unknownList != NULL) {
05519         Tcl_IncrRefCount(unknownList);
05520     }
05521     if (oldList != NULL) {
05522         TclDecrRefCount(oldList);
05523     }
05524 
05525     /*
05526      * Trigger an eventual recomputation of the ensemble command set. Note
05527      * that this is slightly tricky, as it means that we are not actually
05528      * counting the number of namespace export actions, but it is the simplest
05529      * way to go!
05530      */
05531 
05532     ensemblePtr->nsPtr->exportLookupEpoch++;
05533 
05534     return TCL_OK;
05535 }
05536 
05537 /*
05538  *----------------------------------------------------------------------
05539  *
05540  * Tcl_SetEnsembleFlags --
05541  *
05542  *      Set the flags for a particular ensemble.
05543  *
05544  * Results:
05545  *      Tcl result code (error if command token does not indicate an
05546  *      ensemble).
05547  *
05548  * Side effects:
05549  *      The ensemble is updated and marked for recompilation.
05550  *
05551  *----------------------------------------------------------------------
05552  */
05553 
05554 int
05555 Tcl_SetEnsembleFlags(
05556     Tcl_Interp *interp,
05557     Tcl_Command token,
05558     int flags)
05559 {
05560     Command *cmdPtr = (Command *) token;
05561     EnsembleConfig *ensemblePtr;
05562     int wasCompiled;
05563 
05564     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05565         Tcl_AppendResult(interp, "command is not an ensemble", NULL);
05566         return TCL_ERROR;
05567     }
05568 
05569     ensemblePtr = cmdPtr->objClientData;
05570     wasCompiled = ensemblePtr->flags & ENSEMBLE_COMPILE;
05571 
05572     /*
05573      * This API refuses to set the ENS_DEAD flag...
05574      */
05575 
05576     ensemblePtr->flags &= ENS_DEAD;
05577     ensemblePtr->flags |= flags & ~ENS_DEAD;
05578 
05579     /*
05580      * Trigger an eventual recomputation of the ensemble command set. Note
05581      * that this is slightly tricky, as it means that we are not actually
05582      * counting the number of namespace export actions, but it is the simplest
05583      * way to go!
05584      */
05585 
05586     ensemblePtr->nsPtr->exportLookupEpoch++;
05587 
05588     /*
05589      * If the ENSEMBLE_COMPILE flag status was changed, install or remove the
05590      * compiler function and bump the interpreter's compilation epoch so that
05591      * bytecode gets regenerated.
05592      */
05593 
05594     if (flags & ENSEMBLE_COMPILE) {
05595         if (!wasCompiled) {
05596             ((Command*) ensemblePtr->token)->compileProc = TclCompileEnsemble;
05597             ((Interp *) interp)->compileEpoch++;
05598         }
05599     } else {
05600         if (wasCompiled) {
05601             ((Command*) ensemblePtr->token)->compileProc = NULL;
05602             ((Interp *) interp)->compileEpoch++;
05603         }
05604     }
05605 
05606     return TCL_OK;
05607 }
05608 
05609 /*
05610  *----------------------------------------------------------------------
05611  *
05612  * Tcl_GetEnsembleSubcommandList --
05613  *
05614  *      Get the list of subcommands associated with a particular ensemble.
05615  *
05616  * Results:
05617  *      Tcl result code (error if command token does not indicate an
05618  *      ensemble). The list of subcommands is returned by updating the
05619  *      variable pointed to by the last parameter (NULL if this is to be
05620  *      derived from the mapping dictionary or the associated namespace's
05621  *      exported commands).
05622  *
05623  * Side effects:
05624  *      None
05625  *
05626  *----------------------------------------------------------------------
05627  */
05628 
05629 int
05630 Tcl_GetEnsembleSubcommandList(
05631     Tcl_Interp *interp,
05632     Tcl_Command token,
05633     Tcl_Obj **subcmdListPtr)
05634 {
05635     Command *cmdPtr = (Command *) token;
05636     EnsembleConfig *ensemblePtr;
05637 
05638     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05639         if (interp != NULL) {
05640             Tcl_AppendResult(interp, "command is not an ensemble", NULL);
05641         }
05642         return TCL_ERROR;
05643     }
05644 
05645     ensemblePtr = cmdPtr->objClientData;
05646     *subcmdListPtr = ensemblePtr->subcmdList;
05647     return TCL_OK;
05648 }
05649 
05650 /*
05651  *----------------------------------------------------------------------
05652  *
05653  * Tcl_GetEnsembleMappingDict --
05654  *
05655  *      Get the command mapping dictionary associated with a particular
05656  *      ensemble.
05657  *
05658  * Results:
05659  *      Tcl result code (error if command token does not indicate an
05660  *      ensemble). The mapping dict is returned by updating the variable
05661  *      pointed to by the last parameter (NULL if none is installed).
05662  *
05663  * Side effects:
05664  *      None
05665  *
05666  *----------------------------------------------------------------------
05667  */
05668 
05669 int
05670 Tcl_GetEnsembleMappingDict(
05671     Tcl_Interp *interp,
05672     Tcl_Command token,
05673     Tcl_Obj **mapDictPtr)
05674 {
05675     Command *cmdPtr = (Command *) token;
05676     EnsembleConfig *ensemblePtr;
05677 
05678     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05679         if (interp != NULL) {
05680             Tcl_AppendResult(interp, "command is not an ensemble", NULL);
05681         }
05682         return TCL_ERROR;
05683     }
05684 
05685     ensemblePtr = cmdPtr->objClientData;
05686     *mapDictPtr = ensemblePtr->subcommandDict;
05687     return TCL_OK;
05688 }
05689 
05690 /*
05691  *----------------------------------------------------------------------
05692  *
05693  * Tcl_GetEnsembleUnknownHandler --
05694  *
05695  *      Get the unknown handler associated with a particular ensemble.
05696  *
05697  * Results:
05698  *      Tcl result code (error if command token does not indicate an
05699  *      ensemble). The unknown handler is returned by updating the variable
05700  *      pointed to by the last parameter (NULL if no handler is installed).
05701  *
05702  * Side effects:
05703  *      None
05704  *
05705  *----------------------------------------------------------------------
05706  */
05707 
05708 int
05709 Tcl_GetEnsembleUnknownHandler(
05710     Tcl_Interp *interp,
05711     Tcl_Command token,
05712     Tcl_Obj **unknownListPtr)
05713 {
05714     Command *cmdPtr = (Command *) token;
05715     EnsembleConfig *ensemblePtr;
05716 
05717     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05718         if (interp != NULL) {
05719             Tcl_AppendResult(interp, "command is not an ensemble", NULL);
05720         }
05721         return TCL_ERROR;
05722     }
05723 
05724     ensemblePtr = cmdPtr->objClientData;
05725     *unknownListPtr = ensemblePtr->unknownHandler;
05726     return TCL_OK;
05727 }
05728 
05729 /*
05730  *----------------------------------------------------------------------
05731  *
05732  * Tcl_GetEnsembleFlags --
05733  *
05734  *      Get the flags for a particular ensemble.
05735  *
05736  * Results:
05737  *      Tcl result code (error if command token does not indicate an
05738  *      ensemble). The flags are returned by updating the variable pointed to
05739  *      by the last parameter.
05740  *
05741  * Side effects:
05742  *      None
05743  *
05744  *----------------------------------------------------------------------
05745  */
05746 
05747 int
05748 Tcl_GetEnsembleFlags(
05749     Tcl_Interp *interp,
05750     Tcl_Command token,
05751     int *flagsPtr)
05752 {
05753     Command *cmdPtr = (Command *) token;
05754     EnsembleConfig *ensemblePtr;
05755 
05756     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05757         if (interp != NULL) {
05758             Tcl_AppendResult(interp, "command is not an ensemble", NULL);
05759         }
05760         return TCL_ERROR;
05761     }
05762 
05763     ensemblePtr = cmdPtr->objClientData;
05764     *flagsPtr = ensemblePtr->flags;
05765     return TCL_OK;
05766 }
05767 
05768 /*
05769  *----------------------------------------------------------------------
05770  *
05771  * Tcl_GetEnsembleNamespace --
05772  *
05773  *      Get the namespace associated with a particular ensemble.
05774  *
05775  * Results:
05776  *      Tcl result code (error if command token does not indicate an
05777  *      ensemble). Namespace is returned by updating the variable pointed to
05778  *      by the last parameter.
05779  *
05780  * Side effects:
05781  *      None
05782  *
05783  *----------------------------------------------------------------------
05784  */
05785 
05786 int
05787 Tcl_GetEnsembleNamespace(
05788     Tcl_Interp *interp,
05789     Tcl_Command token,
05790     Tcl_Namespace **namespacePtrPtr)
05791 {
05792     Command *cmdPtr = (Command *) token;
05793     EnsembleConfig *ensemblePtr;
05794 
05795     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05796         if (interp != NULL) {
05797             Tcl_AppendResult(interp, "command is not an ensemble", NULL);
05798         }
05799         return TCL_ERROR;
05800     }
05801 
05802     ensemblePtr = cmdPtr->objClientData;
05803     *namespacePtrPtr = (Tcl_Namespace *) ensemblePtr->nsPtr;
05804     return TCL_OK;
05805 }
05806 
05807 /*
05808  *----------------------------------------------------------------------
05809  *
05810  * Tcl_FindEnsemble --
05811  *
05812  *      Given a command name, get the ensemble token for it, allowing for
05813  *      [namespace import]s. [Bug 1017022]
05814  *
05815  * Results:
05816  *      The token for the ensemble command with the given name, or NULL if the
05817  *      command either does not exist or is not an ensemble (when an error
05818  *      message will be written into the interp if thats non-NULL).
05819  *
05820  * Side effects:
05821  *      None
05822  *
05823  *----------------------------------------------------------------------
05824  */
05825 
05826 Tcl_Command
05827 Tcl_FindEnsemble(
05828     Tcl_Interp *interp,         /* Where to do the lookup, and where to write
05829                                  * the errors if TCL_LEAVE_ERR_MSG is set in
05830                                  * the flags. */
05831     Tcl_Obj *cmdNameObj,        /* Name of command to look up. */
05832     int flags)                  /* Either 0 or TCL_LEAVE_ERR_MSG; other flags
05833                                  * are probably not useful. */
05834 {
05835     Command *cmdPtr;
05836 
05837     cmdPtr = (Command *)
05838             Tcl_FindCommand(interp, TclGetString(cmdNameObj), NULL, flags);
05839     if (cmdPtr == NULL) {
05840         return NULL;
05841     }
05842 
05843     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
05844         /*
05845          * Reuse existing infrastructure for following import link chains
05846          * rather than duplicating it.
05847          */
05848 
05849         cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
05850 
05851         if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd) {
05852             if (flags & TCL_LEAVE_ERR_MSG) {
05853                 Tcl_AppendResult(interp, "\"", TclGetString(cmdNameObj),
05854                         "\" is not an ensemble command", NULL);
05855                 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE",
05856                         TclGetString(cmdNameObj), NULL);
05857             }
05858             return NULL;
05859         }
05860     }
05861 
05862     return (Tcl_Command) cmdPtr;
05863 }
05864 
05865 /*
05866  *----------------------------------------------------------------------
05867  *
05868  * Tcl_IsEnsemble --
05869  *
05870  *      Simple test for ensemble-hood that takes into account imported
05871  *      ensemble commands as well.
05872  *
05873  * Results:
05874  *      Boolean value
05875  *
05876  * Side effects:
05877  *      None
05878  *
05879  *----------------------------------------------------------------------
05880  */
05881 
05882 int
05883 Tcl_IsEnsemble(
05884     Tcl_Command token)
05885 {
05886     Command *cmdPtr = (Command *) token;
05887     if (cmdPtr->objProc == NsEnsembleImplementationCmd) {
05888         return 1;
05889     }
05890     cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
05891     if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd) {
05892         return 0;
05893     }
05894     return 1;
05895 }
05896 
05897 /*
05898  *----------------------------------------------------------------------
05899  *
05900  * TclMakeEnsemble --
05901  *
05902  *      Create an ensemble from a table of implementation commands. The
05903  *      ensemble will be subject to (limited) compilation if any of the
05904  *      implementation commands are compilable.
05905  *
05906  * Results:
05907  *      Handle for the ensemble, or NULL if creation of it fails.
05908  *
05909  * Side effects:
05910  *      May advance bytecode compilation epoch.
05911  *
05912  *----------------------------------------------------------------------
05913  */
05914 
05915 Tcl_Command
05916 TclMakeEnsemble(
05917     Tcl_Interp *interp,
05918     const char *name,
05919     const EnsembleImplMap map[])
05920 {
05921     Tcl_Command ensemble;       /* The overall ensemble. */
05922     Tcl_Namespace *tclNsPtr;    /* Reference to the "::tcl" namespace. */
05923     Tcl_DString buf;
05924 
05925     tclNsPtr = Tcl_FindNamespace(interp, "::tcl", NULL,
05926             TCL_CREATE_NS_IF_UNKNOWN);
05927     if (tclNsPtr == NULL) {
05928         Tcl_Panic("unable to find or create ::tcl namespace!");
05929     }
05930     Tcl_DStringInit(&buf);
05931     Tcl_DStringAppend(&buf, "::tcl::", -1);
05932     Tcl_DStringAppend(&buf, name, -1);
05933     tclNsPtr = Tcl_FindNamespace(interp, Tcl_DStringValue(&buf), NULL,
05934             TCL_CREATE_NS_IF_UNKNOWN);
05935     if (tclNsPtr == NULL) {
05936         Tcl_Panic("unable to find or create %s namespace!",
05937                 Tcl_DStringValue(&buf));
05938     }
05939     ensemble = Tcl_CreateEnsemble(interp, Tcl_DStringValue(&buf)+5, tclNsPtr,
05940             TCL_ENSEMBLE_PREFIX);
05941     Tcl_DStringAppend(&buf, "::", -1);
05942     if (ensemble != NULL) {
05943         Tcl_Obj *mapDict;
05944         int i, compile = 0;
05945 
05946         TclNewObj(mapDict);
05947         for (i=0 ; map[i].name != NULL ; i++) {
05948             Tcl_Obj *fromObj, *toObj;
05949             Command *cmdPtr;
05950 
05951             fromObj = Tcl_NewStringObj(map[i].name, -1);
05952             TclNewStringObj(toObj, Tcl_DStringValue(&buf),
05953                     Tcl_DStringLength(&buf));
05954             Tcl_AppendToObj(toObj, map[i].name, -1);
05955             Tcl_DictObjPut(NULL, mapDict, fromObj, toObj);
05956             cmdPtr = (Command *) Tcl_CreateObjCommand(interp,
05957                     TclGetString(toObj), map[i].proc, NULL, NULL);
05958             cmdPtr->compileProc = map[i].compileProc;
05959             compile |= (map[i].compileProc != NULL);
05960         }
05961         Tcl_SetEnsembleMappingDict(interp, ensemble, mapDict);
05962         if (compile) {
05963             Tcl_SetEnsembleFlags(interp, ensemble,
05964                     TCL_ENSEMBLE_PREFIX | ENSEMBLE_COMPILE);
05965         }
05966     }
05967     Tcl_DStringFree(&buf);
05968 
05969     return ensemble;
05970 }
05971 
05972 /*
05973  *----------------------------------------------------------------------
05974  *
05975  * NsEnsembleImplementationCmd --
05976  *
05977  *      Implements an ensemble of commands (being those exported by a
05978  *      namespace other than the global namespace) as a command with the same
05979  *      (short) name as the namespace in the parent namespace.
05980  *
05981  * Results:
05982  *      A standard Tcl result code. Will be TCL_ERROR if the command is not an
05983  *      unambiguous prefix of any command exported by the ensemble's
05984  *      namespace.
05985  *
05986  * Side effects:
05987  *      Depends on the command within the namespace that gets executed. If the
05988  *      ensemble itself returns TCL_ERROR, a descriptive error message will be
05989  *      placed in the interpreter's result.
05990  *
05991  *----------------------------------------------------------------------
05992  */
05993 
05994 static int
05995 NsEnsembleImplementationCmd(
05996     ClientData clientData,
05997     Tcl_Interp *interp,
05998     int objc,
05999     Tcl_Obj *const objv[])
06000 {
06001     EnsembleConfig *ensemblePtr = clientData;
06002                                 /* The ensemble itself. */
06003     Tcl_Obj **tempObjv;         /* Space used to construct the list of
06004                                  * arguments to pass to the command that
06005                                  * implements the ensemble subcommand. */
06006     int result;                 /* The result of the subcommand execution. */
06007     Tcl_Obj *prefixObj;         /* An object containing the prefix words of
06008                                  * the command that implements the
06009                                  * subcommand. */
06010     Tcl_HashEntry *hPtr;        /* Used for efficient lookup of fully
06011                                  * specified but not yet cached command
06012                                  * names. */
06013     Tcl_Obj **prefixObjv;       /* The list of objects to substitute in as the
06014                                  * target command prefix. */
06015     int prefixObjc;             /* Size of prefixObjv of course! */
06016     int reparseCount = 0;       /* Number of reparses. */
06017 
06018     if (objc < 2) {
06019         Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?argument ...?");
06020         return TCL_ERROR;
06021     }
06022 
06023   restartEnsembleParse:
06024     if (ensemblePtr->nsPtr->flags & NS_DYING) {
06025         /*
06026          * Don't know how we got here, but make things give up quickly.
06027          */
06028 
06029         if (!Tcl_InterpDeleted(interp)) {
06030             Tcl_AppendResult(interp,
06031                     "ensemble activated for deleted namespace", NULL);
06032         }
06033         return TCL_ERROR;
06034     }
06035 
06036     /*
06037      * Determine if the table of subcommands is right. If so, we can just look
06038      * up in there and go straight to dispatch.
06039      */
06040 
06041     if (ensemblePtr->epoch == ensemblePtr->nsPtr->exportLookupEpoch) {
06042         /*
06043          * Table of subcommands is still valid; therefore there might be a
06044          * valid cache of discovered information which we can reuse. Do the
06045          * check here, and if we're still valid, we can jump straight to the
06046          * part where we do the invocation of the subcommand.
06047          */
06048 
06049         if (objv[1]->typePtr == &tclEnsembleCmdType) {
06050             EnsembleCmdRep *ensembleCmd = objv[1]->internalRep.otherValuePtr;
06051 
06052             if (ensembleCmd->nsPtr == ensemblePtr->nsPtr &&
06053                     ensembleCmd->epoch == ensemblePtr->epoch &&
06054                     ensembleCmd->token == ensemblePtr->token) {
06055                 prefixObj = ensembleCmd->realPrefixObj;
06056                 Tcl_IncrRefCount(prefixObj);
06057                 goto runResultingSubcommand;
06058             }
06059         }
06060     } else {
06061         BuildEnsembleConfig(ensemblePtr);
06062         ensemblePtr->epoch = ensemblePtr->nsPtr->exportLookupEpoch;
06063     }
06064 
06065     /*
06066      * Look in the hashtable for the subcommand name; this is the fastest way
06067      * of all.
06068      */
06069 
06070     hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable,
06071             TclGetString(objv[1]));
06072     if (hPtr != NULL) {
06073         char *fullName = Tcl_GetHashKey(&ensemblePtr->subcommandTable, hPtr);
06074 
06075         prefixObj = Tcl_GetHashValue(hPtr);
06076 
06077         /*
06078          * Cache for later in the subcommand object.
06079          */
06080 
06081         MakeCachedEnsembleCommand(objv[1], ensemblePtr, fullName, prefixObj);
06082     } else if (!(ensemblePtr->flags & TCL_ENSEMBLE_PREFIX)) {
06083         /*
06084          * Could not map, no prefixing, go to unknown/error handling.
06085          */
06086 
06087         goto unknownOrAmbiguousSubcommand;
06088     } else {
06089         /*
06090          * If we've not already confirmed the command with the hash as part of
06091          * building our export table, we need to scan the sorted array for
06092          * matches.
06093          */
06094 
06095         char *subcmdName;       /* Name of the subcommand, or unique prefix of
06096                                  * it (will be an error for a non-unique
06097                                  * prefix). */
06098         char *fullName = NULL;  /* Full name of the subcommand. */
06099         int stringLength, i;
06100         int tableLength = ensemblePtr->subcommandTable.numEntries;
06101 
06102         subcmdName = TclGetString(objv[1]);
06103         stringLength = objv[1]->length;
06104         for (i=0 ; i<tableLength ; i++) {
06105             register int cmp = strncmp(subcmdName,
06106                     ensemblePtr->subcommandArrayPtr[i],
06107                     (unsigned) stringLength);
06108 
06109             if (cmp == 0) {
06110                 if (fullName != NULL) {
06111                     /*
06112                      * Since there's never the exact-match case to worry about
06113                      * (hash search filters this), getting here indicates that
06114                      * our subcommand is an ambiguous prefix of (at least) two
06115                      * exported subcommands, which is an error case.
06116                      */
06117 
06118                     goto unknownOrAmbiguousSubcommand;
06119                 }
06120                 fullName = ensemblePtr->subcommandArrayPtr[i];
06121             } else if (cmp < 0) {
06122                 /*
06123                  * Because we are searching a sorted table, we can now stop
06124                  * searching because we have gone past anything that could
06125                  * possibly match.
06126                  */
06127 
06128                 break;
06129             }
06130         }
06131         if (fullName == NULL) {
06132             /*
06133              * The subcommand is not a prefix of anything, so bail out!
06134              */
06135 
06136             goto unknownOrAmbiguousSubcommand;
06137         }
06138         hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable, fullName);
06139         if (hPtr == NULL) {
06140             Tcl_Panic("full name %s not found in supposedly synchronized hash",
06141                     fullName);
06142         }
06143         prefixObj = Tcl_GetHashValue(hPtr);
06144 
06145         /*
06146          * Cache for later in the subcommand object.
06147          */
06148 
06149         MakeCachedEnsembleCommand(objv[1], ensemblePtr, fullName, prefixObj);
06150     }
06151 
06152     Tcl_IncrRefCount(prefixObj);
06153   runResultingSubcommand:
06154 
06155     /*
06156      * Do the real work of execution of the subcommand by building an array of
06157      * objects (note that this is potentially not the same length as the
06158      * number of arguments to this ensemble command), populating it and then
06159      * feeding it back through the main command-lookup engine. In theory, we
06160      * could look up the command in the namespace ourselves, as we already
06161      * have the namespace in which it is guaranteed to exist, but we don't do
06162      * that (the cacheing of the command object used should help with that.)
06163      */
06164 
06165     {
06166         Interp *iPtr = (Interp *) interp;
06167         int isRootEnsemble;
06168         Tcl_Obj *copyObj;
06169 
06170         /*
06171          * Get the prefix that we're rewriting to. To do this we need to
06172          * ensure that the internal representation of the list does not change
06173          * so that we can safely keep the internal representations of the
06174          * elements in the list.
06175          */
06176 
06177         copyObj = TclListObjCopy(NULL, prefixObj);
06178         TclListObjGetElements(NULL, copyObj, &prefixObjc, &prefixObjv);
06179 
06180         /*
06181          * Record what arguments the script sent in so that things like
06182          * Tcl_WrongNumArgs can give the correct error message.
06183          */
06184 
06185         isRootEnsemble = (iPtr->ensembleRewrite.sourceObjs == NULL);
06186         if (isRootEnsemble) {
06187             iPtr->ensembleRewrite.sourceObjs = objv;
06188             iPtr->ensembleRewrite.numRemovedObjs = 2;
06189             iPtr->ensembleRewrite.numInsertedObjs = prefixObjc;
06190         } else {
06191             int ni = iPtr->ensembleRewrite.numInsertedObjs;
06192 
06193             if (ni < 2) {
06194                 iPtr->ensembleRewrite.numRemovedObjs += 2 - ni;
06195                 iPtr->ensembleRewrite.numInsertedObjs += prefixObjc-1;
06196             } else {
06197                 iPtr->ensembleRewrite.numInsertedObjs += prefixObjc-2;
06198             }
06199         }
06200 
06201         /*
06202          * Allocate a workspace and build the list of arguments to pass to the
06203          * target command in it.
06204          */
06205 
06206         tempObjv = (Tcl_Obj **) TclStackAlloc(interp,
06207                 (int) sizeof(Tcl_Obj *) * (objc - 2 + prefixObjc));
06208         memcpy(tempObjv, prefixObjv, sizeof(Tcl_Obj *) * prefixObjc);
06209         memcpy(tempObjv+prefixObjc, objv+2, sizeof(Tcl_Obj *) * (objc-2));
06210 
06211         /*
06212          * Hand off to the target command.
06213          */
06214 
06215         result = Tcl_EvalObjv(interp, objc-2+prefixObjc, tempObjv,
06216                 TCL_EVAL_INVOKE);
06217 
06218         /*
06219          * Clean up.
06220          */
06221 
06222         TclStackFree(interp, tempObjv);
06223         Tcl_DecrRefCount(copyObj);
06224         if (isRootEnsemble) {
06225             iPtr->ensembleRewrite.sourceObjs = NULL;
06226             iPtr->ensembleRewrite.numRemovedObjs = 0;
06227             iPtr->ensembleRewrite.numInsertedObjs = 0;
06228         }
06229     }
06230     Tcl_DecrRefCount(prefixObj);
06231     return result;
06232 
06233   unknownOrAmbiguousSubcommand:
06234     /*
06235      * Have not been able to match the subcommand asked for with a real
06236      * subcommand that we export. See whether a handler has been registered
06237      * for dealing with this situation. Will only call (at most) once for any
06238      * particular ensemble invocation.
06239      */
06240 
06241     if (ensemblePtr->unknownHandler != NULL && reparseCount++ < 1) {
06242         int paramc, i;
06243         Tcl_Obj **paramv, *unknownCmd, *ensObj;
06244 
06245         unknownCmd = Tcl_DuplicateObj(ensemblePtr->unknownHandler);
06246         TclNewObj(ensObj);
06247         Tcl_GetCommandFullName(interp, ensemblePtr->token, ensObj);
06248         Tcl_ListObjAppendElement(NULL, unknownCmd, ensObj);
06249         for (i=1 ; i<objc ; i++) {
06250             Tcl_ListObjAppendElement(NULL, unknownCmd, objv[i]);
06251         }
06252         TclListObjGetElements(NULL, unknownCmd, &paramc, &paramv);
06253         Tcl_Preserve(ensemblePtr);
06254         Tcl_IncrRefCount(unknownCmd);
06255         result = Tcl_EvalObjv(interp, paramc, paramv, 0);
06256         if (result == TCL_OK) {
06257             prefixObj = Tcl_GetObjResult(interp);
06258             Tcl_IncrRefCount(prefixObj);
06259             Tcl_DecrRefCount(unknownCmd);
06260             Tcl_Release(ensemblePtr);
06261             Tcl_ResetResult(interp);
06262             if (ensemblePtr->flags & ENS_DEAD) {
06263                 Tcl_DecrRefCount(prefixObj);
06264                 Tcl_SetResult(interp,
06265                         "unknown subcommand handler deleted its ensemble",
06266                         TCL_STATIC);
06267                 return TCL_ERROR;
06268             }
06269 
06270             /*
06271              * Namespace is still there. Check if the result is a valid list.
06272              * If it is, and it is non-empty, that list is what we are using
06273              * as our replacement.
06274              */
06275 
06276             if (TclListObjLength(interp, prefixObj, &prefixObjc) != TCL_OK) {
06277                 Tcl_DecrRefCount(prefixObj);
06278                 Tcl_AddErrorInfo(interp, "\n    while parsing result of "
06279                         "ensemble unknown subcommand handler");
06280                 return TCL_ERROR;
06281             }
06282             if (prefixObjc > 0) {
06283                 goto runResultingSubcommand;
06284             }
06285 
06286             /*
06287              * Namespace alive & empty result => reparse.
06288              */
06289 
06290             Tcl_DecrRefCount(prefixObj);
06291             goto restartEnsembleParse;
06292         }
06293         if (!Tcl_InterpDeleted(interp)) {
06294             if (result != TCL_ERROR) {
06295                 char buf[TCL_INTEGER_SPACE];
06296 
06297                 Tcl_ResetResult(interp);
06298                 Tcl_SetResult(interp,
06299                         "unknown subcommand handler returned bad code: ",
06300                         TCL_STATIC);
06301                 switch (result) {
06302                 case TCL_RETURN:
06303                     Tcl_AppendResult(interp, "return", NULL);
06304                     break;
06305                 case TCL_BREAK:
06306                     Tcl_AppendResult(interp, "break", NULL);
06307                     break;
06308                 case TCL_CONTINUE:
06309                     Tcl_AppendResult(interp, "continue", NULL);
06310                     break;
06311                 default:
06312                     sprintf(buf, "%d", result);
06313                     Tcl_AppendResult(interp, buf, NULL);
06314                 }
06315                 Tcl_AddErrorInfo(interp, "\n    result of "
06316                         "ensemble unknown subcommand handler: ");
06317                 Tcl_AddErrorInfo(interp, TclGetString(unknownCmd));
06318             } else {
06319                 Tcl_AddErrorInfo(interp,
06320                         "\n    (ensemble unknown subcommand handler)");
06321             }
06322         }
06323         Tcl_DecrRefCount(unknownCmd);
06324         Tcl_Release(ensemblePtr);
06325         return TCL_ERROR;
06326     }
06327 
06328     /*
06329      * We cannot determine what subcommand to hand off to, so generate a
06330      * (standard) failure message. Note the one odd case compared with
06331      * standard ensemble-like command, which is where a namespace has no
06332      * exported commands at all...
06333      */
06334 
06335     Tcl_ResetResult(interp);
06336     Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE",
06337             TclGetString(objv[1]), NULL);
06338     if (ensemblePtr->subcommandTable.numEntries == 0) {
06339         Tcl_AppendResult(interp, "unknown subcommand \"",TclGetString(objv[1]),
06340                 "\": namespace ", ensemblePtr->nsPtr->fullName,
06341                 " does not export any commands", NULL);
06342         Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND",
06343                 TclGetString(objv[1]), NULL);
06344         return TCL_ERROR;
06345     }
06346     Tcl_AppendResult(interp, "unknown ",
06347             (ensemblePtr->flags & TCL_ENSEMBLE_PREFIX ? "or ambiguous " : ""),
06348             "subcommand \"", TclGetString(objv[1]), "\": must be ", NULL);
06349     if (ensemblePtr->subcommandTable.numEntries == 1) {
06350         Tcl_AppendResult(interp, ensemblePtr->subcommandArrayPtr[0], NULL);
06351     } else {
06352         int i;
06353 
06354         for (i=0 ; i<ensemblePtr->subcommandTable.numEntries-1 ; i++) {
06355             Tcl_AppendResult(interp,
06356                     ensemblePtr->subcommandArrayPtr[i], ", ", NULL);
06357         }
06358         Tcl_AppendResult(interp, "or ",
06359                 ensemblePtr->subcommandArrayPtr[i], NULL);
06360     }
06361     Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND",
06362             TclGetString(objv[1]), NULL);
06363     return TCL_ERROR;
06364 }
06365 
06366 /*
06367  *----------------------------------------------------------------------
06368  *
06369  * MakeCachedEnsembleCommand --
06370  *
06371  *      Cache what we've computed so far; it's not nice to repeatedly copy
06372  *      strings about. Note that to do this, we start by deleting any old
06373  *      representation that there was (though if it was an out of date
06374  *      ensemble rep, we can skip some of the deallocation process.)
06375  *
06376  * Results:
06377  *      None
06378  *
06379  * Side effects:
06380  *      Alters the internal representation of the first object parameter.
06381  *
06382  *----------------------------------------------------------------------
06383  */
06384 
06385 static void
06386 MakeCachedEnsembleCommand(
06387     Tcl_Obj *objPtr,
06388     EnsembleConfig *ensemblePtr,
06389     const char *subcommandName,
06390     Tcl_Obj *prefixObjPtr)
06391 {
06392     register EnsembleCmdRep *ensembleCmd;
06393     int length;
06394 
06395     if (objPtr->typePtr == &tclEnsembleCmdType) {
06396         ensembleCmd = objPtr->internalRep.otherValuePtr;
06397         Tcl_DecrRefCount(ensembleCmd->realPrefixObj);
06398         ensembleCmd->nsPtr->refCount--;
06399         if ((ensembleCmd->nsPtr->refCount == 0)
06400                 && (ensembleCmd->nsPtr->flags & NS_DEAD)) {
06401             NamespaceFree(ensembleCmd->nsPtr);
06402         }
06403         ckfree(ensembleCmd->fullSubcmdName);
06404     } else {
06405         /*
06406          * Kill the old internal rep, and replace it with a brand new one of
06407          * our own.
06408          */
06409 
06410         TclFreeIntRep(objPtr);
06411         ensembleCmd = (EnsembleCmdRep *) ckalloc(sizeof(EnsembleCmdRep));
06412         objPtr->internalRep.otherValuePtr = ensembleCmd;
06413         objPtr->typePtr = &tclEnsembleCmdType;
06414     }
06415 
06416     /*
06417      * Populate the internal rep.
06418      */
06419 
06420     ensembleCmd->nsPtr = ensemblePtr->nsPtr;
06421     ensembleCmd->epoch = ensemblePtr->epoch;
06422     ensembleCmd->token = ensemblePtr->token;
06423     ensemblePtr->nsPtr->refCount++;
06424     ensembleCmd->realPrefixObj = prefixObjPtr;
06425     length = strlen(subcommandName)+1;
06426     ensembleCmd->fullSubcmdName = ckalloc((unsigned) length);
06427     memcpy(ensembleCmd->fullSubcmdName, subcommandName, (unsigned) length);
06428     Tcl_IncrRefCount(ensembleCmd->realPrefixObj);
06429 }
06430 
06431 /*
06432  *----------------------------------------------------------------------
06433  *
06434  * DeleteEnsembleConfig --
06435  *
06436  *      Destroys the data structure used to represent an ensemble. This is
06437  *      called when the ensemble's command is deleted (which happens
06438  *      automatically if the ensemble's namespace is deleted.) Maintainers
06439  *      should note that ensembles should be deleted by deleting their
06440  *      commands.
06441  *
06442  * Results:
06443  *      None.
06444  *
06445  * Side effects:
06446  *      Memory is (eventually) deallocated.
06447  *
06448  *----------------------------------------------------------------------
06449  */
06450 
06451 static void
06452 DeleteEnsembleConfig(
06453     ClientData clientData)
06454 {
06455     EnsembleConfig *ensemblePtr = clientData;
06456     Namespace *nsPtr = ensemblePtr->nsPtr;
06457     Tcl_HashSearch search;
06458     Tcl_HashEntry *hEnt;
06459 
06460     /*
06461      * Unlink from the ensemble chain if it has not been marked as having been
06462      * done already.
06463      */
06464 
06465     if (ensemblePtr->next != ensemblePtr) {
06466         EnsembleConfig *ensPtr = (EnsembleConfig *) nsPtr->ensembles;
06467         if (ensPtr == ensemblePtr) {
06468             nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr->next;
06469         } else {
06470             while (ensPtr != NULL) {
06471                 if (ensPtr->next == ensemblePtr) {
06472                     ensPtr->next = ensemblePtr->next;
06473                     break;
06474                 }
06475                 ensPtr = ensPtr->next;
06476             }
06477         }
06478     }
06479 
06480     /*
06481      * Mark the namespace as dead so code that uses Tcl_Preserve() can tell
06482      * whether disaster happened anyway.
06483      */
06484 
06485     ensemblePtr->flags |= ENS_DEAD;
06486 
06487     /*
06488      * Kill the pointer-containing fields.
06489      */
06490 
06491     if (ensemblePtr->subcommandTable.numEntries != 0) {
06492         ckfree((char *) ensemblePtr->subcommandArrayPtr);
06493     }
06494     hEnt = Tcl_FirstHashEntry(&ensemblePtr->subcommandTable, &search);
06495     while (hEnt != NULL) {
06496         Tcl_Obj *prefixObj = Tcl_GetHashValue(hEnt);
06497 
06498         Tcl_DecrRefCount(prefixObj);
06499         hEnt = Tcl_NextHashEntry(&search);
06500     }
06501     Tcl_DeleteHashTable(&ensemblePtr->subcommandTable);
06502     if (ensemblePtr->subcmdList != NULL) {
06503         Tcl_DecrRefCount(ensemblePtr->subcmdList);
06504     }
06505     if (ensemblePtr->subcommandDict != NULL) {
06506         Tcl_DecrRefCount(ensemblePtr->subcommandDict);
06507     }
06508     if (ensemblePtr->unknownHandler != NULL) {
06509         Tcl_DecrRefCount(ensemblePtr->unknownHandler);
06510     }
06511 
06512     /*
06513      * Arrange for the structure to be reclaimed. Note that this is complex
06514      * because we have to make sure that we can react sensibly when an
06515      * ensemble is deleted during the process of initialising the ensemble
06516      * (especially the unknown callback.)
06517      */
06518 
06519     Tcl_EventuallyFree(ensemblePtr, TCL_DYNAMIC);
06520 }
06521 
06522 /*
06523  *----------------------------------------------------------------------
06524  *
06525  * BuildEnsembleConfig --
06526  *
06527  *      Create the internal data structures that describe how an ensemble
06528  *      looks, being a hash mapping from the full command name to the Tcl list
06529  *      that describes the implementation prefix words, and a sorted array of
06530  *      all the full command names to allow for reasonably efficient
06531  *      unambiguous prefix handling.
06532  *
06533  * Results:
06534  *      None.
06535  *
06536  * Side effects:
06537  *      Reallocates and rebuilds the hash table and array stored at the
06538  *      ensemblePtr argument. For large ensembles or large namespaces, this is
06539  *      a potentially expensive operation.
06540  *
06541  *----------------------------------------------------------------------
06542  */
06543 
06544 static void
06545 BuildEnsembleConfig(
06546     EnsembleConfig *ensemblePtr)
06547 {
06548     Tcl_HashSearch search;      /* Used for scanning the set of commands in
06549                                  * the namespace that backs up this
06550                                  * ensemble. */
06551     int i, j, isNew;
06552     Tcl_HashTable *hash = &ensemblePtr->subcommandTable;
06553     Tcl_HashEntry *hPtr;
06554 
06555     if (hash->numEntries != 0) {
06556         /*
06557          * Remove pre-existing table.
06558          */
06559 
06560         Tcl_HashSearch search;
06561 
06562         ckfree((char *) ensemblePtr->subcommandArrayPtr);
06563         hPtr = Tcl_FirstHashEntry(hash, &search);
06564         while (hPtr != NULL) {
06565             Tcl_Obj *prefixObj = Tcl_GetHashValue(hPtr);
06566             Tcl_DecrRefCount(prefixObj);
06567             hPtr = Tcl_NextHashEntry(&search);
06568         }
06569         Tcl_DeleteHashTable(hash);
06570         Tcl_InitHashTable(hash, TCL_STRING_KEYS);
06571     }
06572 
06573     /*
06574      * See if we've got an export list. If so, we will only export exactly
06575      * those commands, which may be either implemented by the prefix in the
06576      * subcommandDict or mapped directly onto the namespace's commands.
06577      */
06578 
06579     if (ensemblePtr->subcmdList != NULL) {
06580         Tcl_Obj **subcmdv, *target, *cmdObj, *cmdPrefixObj;
06581         int subcmdc;
06582 
06583         TclListObjGetElements(NULL, ensemblePtr->subcmdList, &subcmdc,
06584                 &subcmdv);
06585         for (i=0 ; i<subcmdc ; i++) {
06586             char *name = TclGetString(subcmdv[i]);
06587 
06588             hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
06589 
06590             /*
06591              * Skip non-unique cases.
06592              */
06593 
06594             if (!isNew) {
06595                 continue;
06596             }
06597 
06598             /*
06599              * Look in our dictionary (if present) for the command.
06600              */
06601 
06602             if (ensemblePtr->subcommandDict != NULL) {
06603                 Tcl_DictObjGet(NULL, ensemblePtr->subcommandDict, subcmdv[i],
06604                         &target);
06605                 if (target != NULL) {
06606                     Tcl_SetHashValue(hPtr, target);
06607                     Tcl_IncrRefCount(target);
06608                     continue;
06609                 }
06610             }
06611 
06612             /*
06613              * Not there, so map onto the namespace. Note in this case that we
06614              * do not guarantee that the command is actually there; that is
06615              * the programmer's responsibility (or [::unknown] of course).
06616              */
06617 
06618             cmdObj = Tcl_NewStringObj(ensemblePtr->nsPtr->fullName, -1);
06619             if (ensemblePtr->nsPtr->parentPtr != NULL) {
06620                 Tcl_AppendStringsToObj(cmdObj, "::", name, NULL);
06621             } else {
06622                 Tcl_AppendStringsToObj(cmdObj, name, NULL);
06623             }
06624             cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
06625             Tcl_SetHashValue(hPtr, cmdPrefixObj);
06626             Tcl_IncrRefCount(cmdPrefixObj);
06627         }
06628     } else if (ensemblePtr->subcommandDict != NULL) {
06629         /*
06630          * No subcmd list, but we do have a mapping dictionary so we should
06631          * use the keys of that. Convert the dictionary's contents into the
06632          * form required for the ensemble's internal hashtable.
06633          */
06634 
06635         Tcl_DictSearch dictSearch;
06636         Tcl_Obj *keyObj, *valueObj;
06637         int done;
06638 
06639         Tcl_DictObjFirst(NULL, ensemblePtr->subcommandDict, &dictSearch,
06640                 &keyObj, &valueObj, &done);
06641         while (!done) {
06642             char *name = TclGetString(keyObj);
06643 
06644             hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
06645             Tcl_SetHashValue(hPtr, valueObj);
06646             Tcl_IncrRefCount(valueObj);
06647             Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done);
06648         }
06649     } else {
06650         /*
06651          * Discover what commands are actually exported by the namespace.
06652          * What we have is an array of patterns and a hash table whose keys
06653          * are the command names exported by the namespace (the contents do
06654          * not matter here.) We must find out what commands are actually
06655          * exported by filtering each command in the namespace against each of
06656          * the patterns in the export list. Note that we use an intermediate
06657          * hash table to make memory management easier, and because that makes
06658          * exact matching far easier too.
06659          *
06660          * Suggestion for future enhancement: compute the unique prefixes and
06661          * place them in the hash too, which should make for even faster
06662          * matching.
06663          */
06664 
06665         hPtr = Tcl_FirstHashEntry(&ensemblePtr->nsPtr->cmdTable, &search);
06666         for (; hPtr!= NULL ; hPtr=Tcl_NextHashEntry(&search)) {
06667             char *nsCmdName =           /* Name of command in namespace. */
06668                     Tcl_GetHashKey(&ensemblePtr->nsPtr->cmdTable, hPtr);
06669 
06670             for (i=0 ; i<ensemblePtr->nsPtr->numExportPatterns ; i++) {
06671                 if (Tcl_StringMatch(nsCmdName,
06672                         ensemblePtr->nsPtr->exportArrayPtr[i])) {
06673                     hPtr = Tcl_CreateHashEntry(hash, nsCmdName, &isNew);
06674 
06675                     /*
06676                      * Remember, hash entries have a full reference to the
06677                      * substituted part of the command (as a list) as their
06678                      * content!
06679                      */
06680 
06681                     if (isNew) {
06682                         Tcl_Obj *cmdObj, *cmdPrefixObj;
06683 
06684                         TclNewObj(cmdObj);
06685                         Tcl_AppendStringsToObj(cmdObj,
06686                                 ensemblePtr->nsPtr->fullName,
06687                                 (ensemblePtr->nsPtr->parentPtr ? "::" : ""),
06688                                 nsCmdName, NULL);
06689                         cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
06690                         Tcl_SetHashValue(hPtr, cmdPrefixObj);
06691                         Tcl_IncrRefCount(cmdPrefixObj);
06692                     }
06693                     break;
06694                 }
06695             }
06696         }
06697     }
06698 
06699     if (hash->numEntries == 0) {
06700         ensemblePtr->subcommandArrayPtr = NULL;
06701         return;
06702     }
06703 
06704     /*
06705      * Create a sorted array of all subcommands in the ensemble; hash tables
06706      * are all very well for a quick look for an exact match, but they can't
06707      * determine things like whether a string is a prefix of another (not
06708      * without lots of preparation anyway) and they're no good for when we're
06709      * generating the error message either.
06710      *
06711      * We do this by filling an array with the names (we use the hash keys
06712      * directly to save a copy, since any time we change the array we change
06713      * the hash too, and vice versa) and running quicksort over the array.
06714      */
06715 
06716     ensemblePtr->subcommandArrayPtr = (char **)
06717             ckalloc(sizeof(char *) * hash->numEntries);
06718 
06719     /*
06720      * Fill array from both ends as this makes us less likely to end up with
06721      * performance problems in qsort(), which is good. Note that doing this
06722      * makes this code much more opaque, but the naive alternatve:
06723      *
06724      * for (hPtr=Tcl_FirstHashEntry(hash,&search),i=0 ;
06725      *         hPtr!=NULL ; hPtr=Tcl_NextHashEntry(&search),i++) {
06726      *     ensemblePtr->subcommandArrayPtr[i] = Tcl_GetHashKey(hash, &hPtr);
06727      * }
06728      *
06729      * can produce long runs of precisely ordered table entries when the
06730      * commands in the namespace are declared in a sorted fashion (an ordering
06731      * some people like) and the hashing functions (or the command names
06732      * themselves) are fairly unfortunate. By filling from both ends, it
06733      * requires active malice (and probably a debugger) to get qsort() to have
06734      * awful runtime behaviour.
06735      */
06736 
06737     i = 0;
06738     j = hash->numEntries;
06739     hPtr = Tcl_FirstHashEntry(hash, &search);
06740     while (hPtr != NULL) {
06741         ensemblePtr->subcommandArrayPtr[i++] = Tcl_GetHashKey(hash, hPtr);
06742         hPtr = Tcl_NextHashEntry(&search);
06743         if (hPtr == NULL) {
06744             break;
06745         }
06746         ensemblePtr->subcommandArrayPtr[--j] = Tcl_GetHashKey(hash, hPtr);
06747         hPtr = Tcl_NextHashEntry(&search);
06748     }
06749     if (hash->numEntries > 1) {
06750         qsort(ensemblePtr->subcommandArrayPtr, (unsigned)hash->numEntries,
06751                 sizeof(char *), NsEnsembleStringOrder);
06752     }
06753 }
06754 
06755 /*
06756  *----------------------------------------------------------------------
06757  *
06758  * NsEnsembleStringOrder --
06759  *
06760  *      Helper function to compare two pointers to two strings for use with
06761  *      qsort().
06762  *
06763  * Results:
06764  *      -1 if the first string is smaller, 1 if the second string is smaller,
06765  *      and 0 if they are equal.
06766  *
06767  * Side effects:
06768  *      None.
06769  *
06770  *----------------------------------------------------------------------
06771  */
06772 
06773 static int
06774 NsEnsembleStringOrder(
06775     const void *strPtr1,
06776     const void *strPtr2)
06777 {
06778     return strcmp(*(const char **)strPtr1, *(const char **)strPtr2);
06779 }
06780 
06781 /*
06782  *----------------------------------------------------------------------
06783  *
06784  * FreeEnsembleCmdRep --
06785  *
06786  *      Destroys the internal representation of a Tcl_Obj that has been
06787  *      holding information about a command in an ensemble.
06788  *
06789  * Results:
06790  *      None.
06791  *
06792  * Side effects:
06793  *      Memory is deallocated. If this held the last reference to a
06794  *      namespace's main structure, that main structure will also be
06795  *      destroyed.
06796  *
06797  *----------------------------------------------------------------------
06798  */
06799 
06800 static void
06801 FreeEnsembleCmdRep(
06802     Tcl_Obj *objPtr)
06803 {
06804     EnsembleCmdRep *ensembleCmd = objPtr->internalRep.otherValuePtr;
06805 
06806     Tcl_DecrRefCount(ensembleCmd->realPrefixObj);
06807     ckfree(ensembleCmd->fullSubcmdName);
06808     ensembleCmd->nsPtr->refCount--;
06809     if ((ensembleCmd->nsPtr->refCount == 0)
06810             && (ensembleCmd->nsPtr->flags & NS_DEAD)) {
06811         NamespaceFree(ensembleCmd->nsPtr);
06812     }
06813     ckfree((char *) ensembleCmd);
06814 }
06815 
06816 /*
06817  *----------------------------------------------------------------------
06818  *
06819  * DupEnsembleCmdRep --
06820  *
06821  *      Makes one Tcl_Obj into a copy of another that is a subcommand of an
06822  *      ensemble.
06823  *
06824  * Results:
06825  *      None.
06826  *
06827  * Side effects:
06828  *      Memory is allocated, and the namespace that the ensemble is built on
06829  *      top of gains another reference.
06830  *
06831  *----------------------------------------------------------------------
06832  */
06833 
06834 static void
06835 DupEnsembleCmdRep(
06836     Tcl_Obj *objPtr,
06837     Tcl_Obj *copyPtr)
06838 {
06839     EnsembleCmdRep *ensembleCmd = objPtr->internalRep.otherValuePtr;
06840     EnsembleCmdRep *ensembleCopy = (EnsembleCmdRep *)
06841             ckalloc(sizeof(EnsembleCmdRep));
06842     int length = strlen(ensembleCmd->fullSubcmdName);
06843 
06844     copyPtr->typePtr = &tclEnsembleCmdType;
06845     copyPtr->internalRep.otherValuePtr = ensembleCopy;
06846     ensembleCopy->nsPtr = ensembleCmd->nsPtr;
06847     ensembleCopy->epoch = ensembleCmd->epoch;
06848     ensembleCopy->token = ensembleCmd->token;
06849     ensembleCopy->nsPtr->refCount++;
06850     ensembleCopy->realPrefixObj = ensembleCmd->realPrefixObj;
06851     Tcl_IncrRefCount(ensembleCopy->realPrefixObj);
06852     ensembleCopy->fullSubcmdName = ckalloc((unsigned) length+1);
06853     memcpy(ensembleCopy->fullSubcmdName, ensembleCmd->fullSubcmdName,
06854             (unsigned) length+1);
06855 }
06856 
06857 /*
06858  *----------------------------------------------------------------------
06859  *
06860  * StringOfEnsembleCmdRep --
06861  *
06862  *      Creates a string representation of a Tcl_Obj that holds a subcommand
06863  *      of an ensemble.
06864  *
06865  * Results:
06866  *      None.
06867  *
06868  * Side effects:
06869  *      The object gains a string (UTF-8) representation.
06870  *
06871  *----------------------------------------------------------------------
06872  */
06873 
06874 static void
06875 StringOfEnsembleCmdRep(
06876     Tcl_Obj *objPtr)
06877 {
06878     EnsembleCmdRep *ensembleCmd = objPtr->internalRep.otherValuePtr;
06879     int length = strlen(ensembleCmd->fullSubcmdName);
06880 
06881     objPtr->length = length;
06882     objPtr->bytes = ckalloc((unsigned) length+1);
06883     memcpy(objPtr->bytes, ensembleCmd->fullSubcmdName, (unsigned) length+1);
06884 }
06885 
06886 /*
06887  *----------------------------------------------------------------------
06888  *
06889  * Tcl_LogCommandInfo --
06890  *
06891  *      This function is invoked after an error occurs in an interpreter. It
06892  *      adds information to iPtr->errorInfo field to describe the command that
06893  *      was being executed when the error occurred.
06894  *
06895  * Results:
06896  *      None.
06897  *
06898  * Side effects:
06899  *      Information about the command is added to errorInfo and the line
06900  *      number stored internally in the interpreter is set.
06901  *
06902  *----------------------------------------------------------------------
06903  */
06904 
06905 void
06906 Tcl_LogCommandInfo(
06907     Tcl_Interp *interp,         /* Interpreter in which to log information. */
06908     const char *script,         /* First character in script containing
06909                                  * command (must be <= command). */
06910     const char *command,        /* First character in command that generated
06911                                  * the error. */
06912     int length)                 /* Number of bytes in command (-1 means use
06913                                  * all bytes up to first null byte). */
06914 {
06915     register const char *p;
06916     Interp *iPtr = (Interp *) interp;
06917     int overflow, limit = 150;
06918     Var *varPtr, *arrayPtr;
06919 
06920     if (iPtr->flags & ERR_ALREADY_LOGGED) {
06921         /*
06922          * Someone else has already logged error information for this command;
06923          * we shouldn't add anything more.
06924          */
06925 
06926         return;
06927     }
06928 
06929     /*
06930      * Compute the line number where the error occurred.
06931      */
06932 
06933     iPtr->errorLine = 1;
06934     for (p = script; p != command; p++) {
06935         if (*p == '\n') {
06936             iPtr->errorLine++;
06937         }
06938     }
06939 
06940     overflow = (length > limit);
06941     Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
06942             "\n    %s\n\"%.*s%s\"", ((iPtr->errorInfo == NULL)
06943             ? "while executing" : "invoked from within"),
06944             (overflow ? limit : length), command, (overflow ? "..." : "")));
06945 
06946     varPtr = TclObjLookupVarEx(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY,
06947             NULL, 0, 0, &arrayPtr);
06948     if ((varPtr == NULL) || !TclIsVarTraced(varPtr)) {
06949         /*
06950          * Should not happen.
06951          */
06952 
06953         return;
06954     } else {
06955         Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&iPtr->varTraces,
06956                 (char *) varPtr);
06957         VarTrace *tracePtr = Tcl_GetHashValue(hPtr);
06958 
06959         if (tracePtr->traceProc != EstablishErrorInfoTraces) {
06960             /*
06961              * The most recent trace set on ::errorInfo is not the one the
06962              * core itself puts on last. This means some other code is tracing
06963              * the variable, and the additional trace(s) might be write traces
06964              * that expect the timing of writes to ::errorInfo that existed
06965              * Tcl releases before 8.5. To satisfy that compatibility need, we
06966              * write the current -errorinfo value to the ::errorInfo variable.
06967              */
06968 
06969             Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, iPtr->errorInfo,
06970                     TCL_GLOBAL_ONLY);
06971         }
06972     }
06973 }
06974 
06975 /*
06976  * Local Variables:
06977  * mode: c
06978  * c-basic-offset: 4
06979  * fill-column: 78
06980  * End:
06981  */



Generated on Wed Mar 12 12:18:19 2008 by  doxygen 1.5.1