summaryrefslogtreecommitdiffstats
path: root/tcl8.6/generic/tclNamesp.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-12-21 22:47:21 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-12-21 22:47:21 (GMT)
commit5514e37335c012cc70f5b9aee3cedfe3d57f583f (patch)
tree4ba7d8aad13735e52f59bdce7ca5ba3151ebd7e3 /tcl8.6/generic/tclNamesp.c
parent768f87f613cc9789fcf8073018fa02178c8c91df (diff)
downloadblt-5514e37335c012cc70f5b9aee3cedfe3d57f583f.zip
blt-5514e37335c012cc70f5b9aee3cedfe3d57f583f.tar.gz
blt-5514e37335c012cc70f5b9aee3cedfe3d57f583f.tar.bz2
undo subtree
Diffstat (limited to 'tcl8.6/generic/tclNamesp.c')
-rw-r--r--tcl8.6/generic/tclNamesp.c5101
1 files changed, 0 insertions, 5101 deletions
diff --git a/tcl8.6/generic/tclNamesp.c b/tcl8.6/generic/tclNamesp.c
deleted file mode 100644
index 5930859..0000000
--- a/tcl8.6/generic/tclNamesp.c
+++ /dev/null
@@ -1,5101 +0,0 @@
-/*
- * tclNamesp.c --
- *
- * Contains support for namespaces, which provide a separate context of
- * commands and global variables. The global :: namespace is the
- * traditional Tcl "global" scope. Other namespaces are created as
- * children of the global namespace. These other namespaces contain
- * special-purpose commands and variables for packages.
- *
- * Copyright (c) 1993-1997 Lucent Technologies.
- * Copyright (c) 1997 Sun Microsystems, Inc.
- * Copyright (c) 1998-1999 by Scriptics Corporation.
- * Copyright (c) 2002-2005 Donal K. Fellows.
- * Copyright (c) 2006 Neil Madden.
- * Contributions from Don Porter, NIST, 2007. (not subject to US copyright)
- *
- * Originally implemented by
- * Michael J. McLennan
- * Bell Labs Innovations for Lucent Technologies
- * mmclennan@lucent.com
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-#include "tclInt.h"
-#include "tclCompile.h" /* for TclLogCommandInfo visibility */
-
-/*
- * Thread-local storage used to avoid having a global lock on data that is not
- * limited to a single interpreter.
- */
-
-typedef struct ThreadSpecificData {
- long numNsCreated; /* Count of the number of namespaces created
- * within the thread. This value is used as a
- * unique id for each namespace. Cannot be
- * per-interp because the nsId is used to
- * distinguish objects which can be passed
- * around between interps in the same thread,
- * but does not need to be global because
- * object internal reps are always per-thread
- * anyway. */
-} ThreadSpecificData;
-
-static Tcl_ThreadDataKey dataKey;
-
-/*
- * This structure contains a cached pointer to a namespace that is the result
- * of resolving the namespace's name in some other namespace. It is the
- * internal representation for a nsName object. It contains the pointer along
- * with some information that is used to check the cached pointer's validity.
- */
-
-typedef struct ResolvedNsName {
- Namespace *nsPtr; /* A cached pointer to the Namespace that the
- * name resolved to. */
- Namespace *refNsPtr; /* Points to the namespace context in which
- * the name was resolved. NULL if the name is
- * fully qualified and thus the resolution
- * does not depend on the context. */
- int refCount; /* Reference count: 1 for each nsName object
- * that has a pointer to this ResolvedNsName
- * structure as its internal rep. This
- * structure can be freed when refCount
- * becomes zero. */
-} ResolvedNsName;
-
-/*
- * Declarations for functions local to this file:
- */
-
-static void DeleteImportedCmd(ClientData clientData);
-static int DoImport(Tcl_Interp *interp,
- Namespace *nsPtr, Tcl_HashEntry *hPtr,
- const char *cmdName, const char *pattern,
- Namespace *importNsPtr, int allowOverwrite);
-static void DupNsNameInternalRep(Tcl_Obj *objPtr,Tcl_Obj *copyPtr);
-static char * ErrorCodeRead(ClientData clientData,Tcl_Interp *interp,
- const char *name1, const char *name2, int flags);
-static char * ErrorInfoRead(ClientData clientData,Tcl_Interp *interp,
- const char *name1, const char *name2, int flags);
-static char * EstablishErrorCodeTraces(ClientData clientData,
- Tcl_Interp *interp, const char *name1,
- const char *name2, int flags);
-static char * EstablishErrorInfoTraces(ClientData clientData,
- Tcl_Interp *interp, const char *name1,
- const char *name2, int flags);
-static void FreeNsNameInternalRep(Tcl_Obj *objPtr);
-static int GetNamespaceFromObj(Tcl_Interp *interp,
- Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr);
-static int InvokeImportedCmd(ClientData clientData,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
-static int InvokeImportedNRCmd(ClientData clientData,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
-static int NamespaceChildrenCmd(ClientData dummy,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
-static int NamespaceCodeCmd(ClientData dummy, Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespaceCurrentCmd(ClientData dummy,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
-static int NamespaceDeleteCmd(ClientData dummy,Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespaceEvalCmd(ClientData dummy, Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NRNamespaceEvalCmd(ClientData dummy,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
-static int NamespaceExistsCmd(ClientData dummy,Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespaceExportCmd(ClientData dummy,Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespaceForgetCmd(ClientData dummy,Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static void NamespaceFree(Namespace *nsPtr);
-static int NamespaceImportCmd(ClientData dummy,Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespaceInscopeCmd(ClientData dummy,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
-static int NRNamespaceInscopeCmd(ClientData dummy,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
-static int NamespaceOriginCmd(ClientData dummy,Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespaceParentCmd(ClientData dummy,Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespacePathCmd(ClientData dummy, Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespaceQualifiersCmd(ClientData dummy,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
-static int NamespaceTailCmd(ClientData dummy, Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespaceUpvarCmd(ClientData dummy, Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int NamespaceUnknownCmd(ClientData dummy,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
-static int NamespaceWhichCmd(ClientData dummy, Tcl_Interp *interp,
- int objc, Tcl_Obj *const objv[]);
-static int SetNsNameFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
-static void UnlinkNsPath(Namespace *nsPtr);
-
-static Tcl_NRPostProc NsEval_Callback;
-
-/*
- * This structure defines a Tcl object type that contains a namespace
- * reference. It is used in commands that take the name of a namespace as an
- * argument. The namespace reference is resolved, and the result in cached in
- * the object.
- */
-
-static const Tcl_ObjType nsNameType = {
- "nsName", /* the type's name */
- FreeNsNameInternalRep, /* freeIntRepProc */
- DupNsNameInternalRep, /* dupIntRepProc */
- NULL, /* updateStringProc */
- SetNsNameFromAny /* setFromAnyProc */
-};
-
-/*
- * Array of values describing how to implement each standard subcommand of the
- * "namespace" command.
- */
-
-static const EnsembleImplMap defaultNamespaceMap[] = {
- {"children", NamespaceChildrenCmd, TclCompileBasic0To2ArgCmd, NULL, NULL, 0},
- {"code", NamespaceCodeCmd, TclCompileNamespaceCodeCmd, NULL, NULL, 0},
- {"current", NamespaceCurrentCmd, TclCompileNamespaceCurrentCmd, NULL, NULL, 0},
- {"delete", NamespaceDeleteCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0},
- {"ensemble", TclNamespaceEnsembleCmd, NULL, NULL, NULL, 0},
- {"eval", NamespaceEvalCmd, NULL, NRNamespaceEvalCmd, NULL, 0},
- {"exists", NamespaceExistsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
- {"export", NamespaceExportCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0},
- {"forget", NamespaceForgetCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0},
- {"import", NamespaceImportCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0},
- {"inscope", NamespaceInscopeCmd, NULL, NRNamespaceInscopeCmd, NULL, 0},
- {"origin", NamespaceOriginCmd, TclCompileNamespaceOriginCmd, NULL, NULL, 0},
- {"parent", NamespaceParentCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
- {"path", NamespacePathCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
- {"qualifiers", NamespaceQualifiersCmd, TclCompileNamespaceQualifiersCmd, NULL, NULL, 0},
- {"tail", NamespaceTailCmd, TclCompileNamespaceTailCmd, NULL, NULL, 0},
- {"unknown", NamespaceUnknownCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
- {"upvar", NamespaceUpvarCmd, TclCompileNamespaceUpvarCmd, NULL, NULL, 0},
- {"which", NamespaceWhichCmd, TclCompileNamespaceWhichCmd, NULL, NULL, 0},
- {NULL, NULL, NULL, NULL, NULL, 0}
-};
-
-/*
- *----------------------------------------------------------------------
- *
- * TclInitNamespaceSubsystem --
- *
- * This function is called to initialize all the structures that are used
- * by namespaces on a per-process basis.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclInitNamespaceSubsystem(void)
-{
- /*
- * Does nothing for now.
- */
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_GetCurrentNamespace --
- *
- * Returns a pointer to an interpreter's currently active namespace.
- *
- * Results:
- * Returns a pointer to the interpreter's current namespace.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Namespace *
-Tcl_GetCurrentNamespace(
- register Tcl_Interp *interp)/* Interpreter whose current namespace is
- * being queried. */
-{
- return TclGetCurrentNamespace(interp);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_GetGlobalNamespace --
- *
- * Returns a pointer to an interpreter's global :: namespace.
- *
- * Results:
- * Returns a pointer to the specified interpreter's global namespace.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Namespace *
-Tcl_GetGlobalNamespace(
- register Tcl_Interp *interp)/* Interpreter whose global namespace should
- * be returned. */
-{
- return TclGetGlobalNamespace(interp);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_PushCallFrame --
- *
- * Pushes a new call frame onto the interpreter's Tcl call stack. Called
- * when executing a Tcl procedure or a "namespace eval" or "namespace
- * inscope" command.
- *
- * Results:
- * Returns TCL_OK if successful, or TCL_ERROR (along with an error
- * message in the interpreter's result object) if something goes wrong.
- *
- * Side effects:
- * Modifies the interpreter's Tcl call stack.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_PushCallFrame(
- Tcl_Interp *interp, /* Interpreter in which the new call frame is
- * to be pushed. */
- Tcl_CallFrame *callFramePtr,/* Points to a call frame structure to push.
- * Storage for this has already been allocated
- * by the caller; typically this is the
- * address of a CallFrame structure allocated
- * on the caller's C stack. The call frame
- * will be initialized by this function. The
- * caller can pop the frame later with
- * Tcl_PopCallFrame, and it is responsible for
- * freeing the frame's storage. */
- Tcl_Namespace *namespacePtr,/* Points to the namespace in which the frame
- * will execute. If NULL, the interpreter's
- * current namespace will be used. */
- int isProcCallFrame) /* If nonzero, the frame represents a called
- * Tcl procedure and may have local vars. Vars
- * will ordinarily be looked up in the frame.
- * If new variables are created, they will be
- * created in the frame. If 0, the frame is
- * for a "namespace eval" or "namespace
- * inscope" command and var references are
- * treated as references to namespace
- * variables. */
-{
- Interp *iPtr = (Interp *) interp;
- register CallFrame *framePtr = (CallFrame *) callFramePtr;
- register Namespace *nsPtr;
-
- if (namespacePtr == NULL) {
- nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- } else {
- nsPtr = (Namespace *) namespacePtr;
-
- /*
- * TODO: Examine whether it would be better to guard based on NS_DYING
- * or NS_KILLED. It appears that these are not tested because they can
- * be set in a global interp that has been [namespace delete]d, but
- * which never really completely goes away because of lingering global
- * things like ::errorInfo and [::unknown] and hidden commands.
- * Review of those designs might permit stricter checking here.
- */
-
- if (nsPtr->flags & NS_DEAD) {
- Tcl_Panic("Trying to push call frame for dead namespace");
- /*NOTREACHED*/
- }
- }
-
- nsPtr->activationCount++;
- framePtr->nsPtr = nsPtr;
- framePtr->isProcCallFrame = isProcCallFrame;
- framePtr->objc = 0;
- framePtr->objv = NULL;
- framePtr->callerPtr = iPtr->framePtr;
- framePtr->callerVarPtr = iPtr->varFramePtr;
- if (iPtr->varFramePtr != NULL) {
- framePtr->level = (iPtr->varFramePtr->level + 1);
- } else {
- framePtr->level = 0;
- }
- framePtr->procPtr = NULL; /* no called procedure */
- framePtr->varTablePtr = NULL; /* and no local variables */
- framePtr->numCompiledLocals = 0;
- framePtr->compiledLocals = NULL;
- framePtr->clientData = NULL;
- framePtr->localCachePtr = NULL;
- framePtr->tailcallPtr = NULL;
-
- /*
- * Push the new call frame onto the interpreter's stack of procedure call
- * frames making it the current frame.
- */
-
- iPtr->framePtr = framePtr;
- iPtr->varFramePtr = framePtr;
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_PopCallFrame --
- *
- * Removes a call frame from the Tcl call stack for the interpreter.
- * Called to remove a frame previously pushed by Tcl_PushCallFrame.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Modifies the call stack of the interpreter. Resets various fields of
- * the popped call frame. If a namespace has been deleted and has no more
- * activations on the call stack, the namespace is destroyed.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_PopCallFrame(
- Tcl_Interp *interp) /* Interpreter with call frame to pop. */
-{
- register Interp *iPtr = (Interp *) interp;
- register CallFrame *framePtr = iPtr->framePtr;
- Namespace *nsPtr;
-
- /*
- * It's important to remove the call frame from the interpreter's stack of
- * call frames before deleting local variables, so that traces invoked by
- * the variable deletion don't see the partially-deleted frame.
- */
-
- if (framePtr->callerPtr) {
- iPtr->framePtr = framePtr->callerPtr;
- iPtr->varFramePtr = framePtr->callerVarPtr;
- } else {
- /* Tcl_PopCallFrame: trying to pop rootCallFrame! */
- }
-
- if (framePtr->varTablePtr != NULL) {
- TclDeleteVars(iPtr, framePtr->varTablePtr);
- ckfree(framePtr->varTablePtr);
- framePtr->varTablePtr = NULL;
- }
- if (framePtr->numCompiledLocals > 0) {
- TclDeleteCompiledLocalVars(iPtr, framePtr);
- if (--framePtr->localCachePtr->refCount == 0) {
- TclFreeLocalCache(interp, framePtr->localCachePtr);
- }
- framePtr->localCachePtr = NULL;
- }
-
- /*
- * Decrement the namespace's count of active call frames. If the namespace
- * is "dying" and there are no more active call frames, call
- * Tcl_DeleteNamespace to destroy it.
- */
-
- nsPtr = framePtr->nsPtr;
- nsPtr->activationCount--;
- if ((nsPtr->flags & NS_DYING)
- && (nsPtr->activationCount - (nsPtr == iPtr->globalNsPtr) == 0)) {
- Tcl_DeleteNamespace((Tcl_Namespace *) nsPtr);
- }
- framePtr->nsPtr = NULL;
-
- if (framePtr->tailcallPtr) {
- TclSetTailcall(interp, framePtr->tailcallPtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclPushStackFrame --
- *
- * Allocates a new call frame in the interpreter's execution stack, then
- * pushes it onto the interpreter's Tcl call stack. Called when executing
- * a Tcl procedure or a "namespace eval" or "namespace inscope" command.
- *
- * Results:
- * Returns TCL_OK if successful, or TCL_ERROR (along with an error
- * message in the interpreter's result object) if something goes wrong.
- *
- * Side effects:
- * Modifies the interpreter's Tcl call stack.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclPushStackFrame(
- Tcl_Interp *interp, /* Interpreter in which the new call frame is
- * to be pushed. */
- Tcl_CallFrame **framePtrPtr,/* Place to store a pointer to the stack
- * allocated call frame. */
- Tcl_Namespace *namespacePtr,/* Points to the namespace in which the frame
- * will execute. If NULL, the interpreter's
- * current namespace will be used. */
- int isProcCallFrame) /* If nonzero, the frame represents a called
- * Tcl procedure and may have local vars. Vars
- * will ordinarily be looked up in the frame.
- * If new variables are created, they will be
- * created in the frame. If 0, the frame is
- * for a "namespace eval" or "namespace
- * inscope" command and var references are
- * treated as references to namespace
- * variables. */
-{
- *framePtrPtr = TclStackAlloc(interp, sizeof(CallFrame));
- return Tcl_PushCallFrame(interp, *framePtrPtr, namespacePtr,
- isProcCallFrame);
-}
-
-void
-TclPopStackFrame(
- Tcl_Interp *interp) /* Interpreter with call frame to pop. */
-{
- CallFrame *freePtr = ((Interp *) interp)->framePtr;
-
- Tcl_PopCallFrame(interp);
- TclStackFree(interp, freePtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * EstablishErrorCodeTraces --
- *
- * Creates traces on the ::errorCode variable to keep its value
- * consistent with the expectations of legacy code.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Read and unset traces are established on ::errorCode.
- *
- *----------------------------------------------------------------------
- */
-
-static char *
-EstablishErrorCodeTraces(
- ClientData clientData,
- Tcl_Interp *interp,
- const char *name1,
- const char *name2,
- int flags)
-{
- Tcl_TraceVar2(interp, "errorCode", NULL, TCL_GLOBAL_ONLY|TCL_TRACE_READS,
- ErrorCodeRead, NULL);
- Tcl_TraceVar2(interp, "errorCode", NULL, TCL_GLOBAL_ONLY|TCL_TRACE_UNSETS,
- EstablishErrorCodeTraces, NULL);
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ErrorCodeRead --
- *
- * Called when the ::errorCode variable is read. Copies the current value
- * of the interp's errorCode field into ::errorCode.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static char *
-ErrorCodeRead(
- ClientData clientData,
- Tcl_Interp *interp,
- const char *name1,
- const char *name2,
- int flags)
-{
- Interp *iPtr = (Interp *) interp;
-
- if (Tcl_InterpDeleted(interp) || !(iPtr->flags & ERR_LEGACY_COPY)) {
- return NULL;
- }
- if (iPtr->errorCode) {
- Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL,
- iPtr->errorCode, TCL_GLOBAL_ONLY);
- return NULL;
- }
- if (NULL == Tcl_ObjGetVar2(interp, iPtr->ecVar, NULL, TCL_GLOBAL_ONLY)) {
- Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL,
- Tcl_NewObj(), TCL_GLOBAL_ONLY);
- }
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * EstablishErrorInfoTraces --
- *
- * Creates traces on the ::errorInfo variable to keep its value
- * consistent with the expectations of legacy code.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Read and unset traces are established on ::errorInfo.
- *
- *----------------------------------------------------------------------
- */
-
-static char *
-EstablishErrorInfoTraces(
- ClientData clientData,
- Tcl_Interp *interp,
- const char *name1,
- const char *name2,
- int flags)
-{
- Tcl_TraceVar2(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY|TCL_TRACE_READS,
- ErrorInfoRead, NULL);
- Tcl_TraceVar2(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY|TCL_TRACE_UNSETS,
- EstablishErrorInfoTraces, NULL);
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ErrorInfoRead --
- *
- * Called when the ::errorInfo variable is read. Copies the current value
- * of the interp's errorInfo field into ::errorInfo.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static char *
-ErrorInfoRead(
- ClientData clientData,
- Tcl_Interp *interp,
- const char *name1,
- const char *name2,
- int flags)
-{
- Interp *iPtr = (Interp *) interp;
-
- if (Tcl_InterpDeleted(interp) || !(iPtr->flags & ERR_LEGACY_COPY)) {
- return NULL;
- }
- if (iPtr->errorInfo) {
- Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL,
- iPtr->errorInfo, TCL_GLOBAL_ONLY);
- return NULL;
- }
- if (NULL == Tcl_ObjGetVar2(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY)) {
- Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL,
- Tcl_NewObj(), TCL_GLOBAL_ONLY);
- }
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_CreateNamespace --
- *
- * Creates a new namespace with the given name. If there is no active
- * namespace (i.e., the interpreter is being initialized), the global ::
- * namespace is created and returned.
- *
- * Results:
- * Returns a pointer to the new namespace if successful. If the namespace
- * already exists or if another error occurs, this routine returns NULL,
- * along with an error message in the interpreter's result object.
- *
- * Side effects:
- * If the name contains "::" qualifiers and a parent namespace does not
- * already exist, it is automatically created.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Namespace *
-Tcl_CreateNamespace(
- Tcl_Interp *interp, /* Interpreter in which a new namespace is
- * being created. Also used for error
- * reporting. */
- const char *name, /* Name for the new namespace. May be a
- * qualified name with names of ancestor
- * namespaces separated by "::"s. */
- ClientData clientData, /* One-word value to store with namespace. */
- Tcl_NamespaceDeleteProc *deleteProc)
- /* Function called to delete client data when
- * the namespace is deleted. NULL if no
- * function should be called. */
-{
- Interp *iPtr = (Interp *) interp;
- register Namespace *nsPtr, *ancestorPtr;
- Namespace *parentPtr, *dummy1Ptr, *dummy2Ptr;
- Namespace *globalNsPtr = iPtr->globalNsPtr;
- const char *simpleName;
- Tcl_HashEntry *entryPtr;
- Tcl_DString buffer1, buffer2;
- Tcl_DString *namePtr, *buffPtr;
- int newEntry, nameLen;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- const char *nameStr;
- Tcl_DString tmpBuffer;
-
- Tcl_DStringInit(&tmpBuffer);
-
- /*
- * If there is no active namespace, the interpreter is being initialized.
- */
-
- if ((globalNsPtr == NULL) && (iPtr->varFramePtr == NULL)) {
- /*
- * Treat this namespace as the global namespace, and avoid looking for
- * a parent.
- */
-
- parentPtr = NULL;
- simpleName = "";
- goto doCreate;
- }
-
- /*
- * Ensure that there are no trailing colons as that causes chaos when a
- * deleteProc is specified. [Bug d614d63989]
- */
-
- if (deleteProc != NULL) {
- nameStr = name + strlen(name) - 2;
- if (nameStr >= name && nameStr[1] == ':' && nameStr[0] == ':') {
- Tcl_DStringAppend(&tmpBuffer, name, -1);
- while ((nameLen = Tcl_DStringLength(&tmpBuffer)) > 0
- && Tcl_DStringValue(&tmpBuffer)[nameLen-1] == ':') {
- Tcl_DStringSetLength(&tmpBuffer, nameLen-1);
- }
- name = Tcl_DStringValue(&tmpBuffer);
- }
- }
-
- /*
- * If we've ended up with an empty string now, we're attempting to create
- * the global namespace despite the global namespace existing. That's
- * naughty!
- */
-
- if (*name == '\0') {
- Tcl_SetObjResult(interp, Tcl_NewStringObj("can't create namespace"
- " \"\": only global namespace can have empty name", -1));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE",
- "CREATEGLOBAL", NULL);
- Tcl_DStringFree(&tmpBuffer);
- return NULL;
- }
-
- /*
- * Find the parent for the new namespace.
- */
-
- TclGetNamespaceForQualName(interp, name, NULL, TCL_CREATE_NS_IF_UNKNOWN,
- &parentPtr, &dummy1Ptr, &dummy2Ptr, &simpleName);
-
- /*
- * If the unqualified name at the end is empty, there were trailing "::"s
- * after the namespace's name which we ignore. The new namespace was
- * already (recursively) created and is pointed to by parentPtr.
- */
-
- if (*simpleName == '\0') {
- Tcl_DStringFree(&tmpBuffer);
- return (Tcl_Namespace *) parentPtr;
- }
-
- /*
- * Check for a bad namespace name and make sure that the name does not
- * already exist in the parent namespace.
- */
-
- if (
-#ifndef BREAK_NAMESPACE_COMPAT
- Tcl_FindHashEntry(&parentPtr->childTable, simpleName) != NULL
-#else
- parentPtr->childTablePtr != NULL &&
- Tcl_FindHashEntry(parentPtr->childTablePtr, simpleName) != NULL
-#endif
- ) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't create namespace \"%s\": already exists", name));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE",
- "CREATEEXISTING", NULL);
- Tcl_DStringFree(&tmpBuffer);
- return NULL;
- }
-
- /*
- * Create the new namespace and root it in its parent. Increment the count
- * of namespaces created.
- */
-
- doCreate:
- nsPtr = ckalloc(sizeof(Namespace));
- nameLen = strlen(simpleName) + 1;
- nsPtr->name = ckalloc(nameLen);
- memcpy(nsPtr->name, simpleName, nameLen);
- nsPtr->fullName = NULL; /* Set below. */
- nsPtr->clientData = clientData;
- nsPtr->deleteProc = deleteProc;
- nsPtr->parentPtr = parentPtr;
-#ifndef BREAK_NAMESPACE_COMPAT
- Tcl_InitHashTable(&nsPtr->childTable, TCL_STRING_KEYS);
-#else
- nsPtr->childTablePtr = NULL;
-#endif
- nsPtr->nsId = ++(tsdPtr->numNsCreated);
- nsPtr->interp = interp;
- nsPtr->flags = 0;
- nsPtr->activationCount = 0;
- nsPtr->refCount = 0;
- Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS);
- TclInitVarHashTable(&nsPtr->varTable, nsPtr);
- nsPtr->exportArrayPtr = NULL;
- nsPtr->numExportPatterns = 0;
- nsPtr->maxExportPatterns = 0;
- nsPtr->cmdRefEpoch = 0;
- nsPtr->resolverEpoch = 0;
- nsPtr->cmdResProc = NULL;
- nsPtr->varResProc = NULL;
- nsPtr->compiledVarResProc = NULL;
- nsPtr->exportLookupEpoch = 0;
- nsPtr->ensembles = NULL;
- nsPtr->unknownHandlerPtr = NULL;
- nsPtr->commandPathLength = 0;
- nsPtr->commandPathArray = NULL;
- nsPtr->commandPathSourceList = NULL;
- nsPtr->earlyDeleteProc = NULL;
-
- if (parentPtr != NULL) {
- entryPtr = Tcl_CreateHashEntry(
- TclGetNamespaceChildTable((Tcl_Namespace *) parentPtr),
- simpleName, &newEntry);
- Tcl_SetHashValue(entryPtr, nsPtr);
- } else {
- /*
- * In the global namespace create traces to maintain the ::errorInfo
- * and ::errorCode variables.
- */
-
- iPtr->globalNsPtr = nsPtr;
- EstablishErrorInfoTraces(NULL, interp, NULL, NULL, 0);
- EstablishErrorCodeTraces(NULL, interp, NULL, NULL, 0);
- }
-
- /*
- * Build the fully qualified name for this namespace.
- */
-
- Tcl_DStringInit(&buffer1);
- Tcl_DStringInit(&buffer2);
- namePtr = &buffer1;
- buffPtr = &buffer2;
- for (ancestorPtr = nsPtr; ancestorPtr != NULL;
- ancestorPtr = ancestorPtr->parentPtr) {
- if (ancestorPtr != globalNsPtr) {
- register Tcl_DString *tempPtr = namePtr;
-
- TclDStringAppendLiteral(buffPtr, "::");
- Tcl_DStringAppend(buffPtr, ancestorPtr->name, -1);
- TclDStringAppendDString(buffPtr, namePtr);
-
- /*
- * Clear the unwanted buffer or we end up appending to previous
- * results, making the namespace fullNames of nested namespaces
- * very wrong (and strange).
- */
-
- TclDStringClear(namePtr);
-
- /*
- * Now swap the buffer pointers so that we build in the other
- * buffer. This is faster than repeated copying back and forth
- * between buffers.
- */
-
- namePtr = buffPtr;
- buffPtr = tempPtr;
- }
- }
-
- name = Tcl_DStringValue(namePtr);
- nameLen = Tcl_DStringLength(namePtr);
- nsPtr->fullName = ckalloc(nameLen + 1);
- memcpy(nsPtr->fullName, name, (unsigned) nameLen + 1);
-
- Tcl_DStringFree(&buffer1);
- Tcl_DStringFree(&buffer2);
- Tcl_DStringFree(&tmpBuffer);
-
- /*
- * If compilation of commands originating from the parent NS is
- * suppressed, suppress it for commands originating in this one too.
- */
-
- if (nsPtr->parentPtr != NULL &&
- nsPtr->parentPtr->flags & NS_SUPPRESS_COMPILATION) {
- nsPtr->flags |= NS_SUPPRESS_COMPILATION;
- }
-
- /*
- * Return a pointer to the new namespace.
- */
-
- return (Tcl_Namespace *) nsPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_DeleteNamespace --
- *
- * Deletes a namespace and all of the commands, variables, and other
- * namespaces within it.
- *
- * Results:
- * None.
- *
- * Side effects:
- * When a namespace is deleted, it is automatically removed as a child of
- * its parent namespace. Also, all its commands, variables and child
- * namespaces are deleted.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_DeleteNamespace(
- Tcl_Namespace *namespacePtr)/* Points to the namespace to delete. */
-{
- register Namespace *nsPtr = (Namespace *) namespacePtr;
- Interp *iPtr = (Interp *) nsPtr->interp;
- Namespace *globalNsPtr = (Namespace *)
- TclGetGlobalNamespace((Tcl_Interp *) iPtr);
- Tcl_HashEntry *entryPtr;
- Tcl_HashSearch search;
- Command *cmdPtr;
-
- /*
- * Give anyone interested - notably TclOO - a chance to use this namespace
- * normally despite the fact that the namespace is going to go. Allows the
- * calling of destructors. Will only be called once (unless re-established
- * by the called function). [Bug 2950259]
- *
- * Note that setting this field requires access to the internal definition
- * of namespaces, so it should only be accessed by code that knows about
- * being careful with reentrancy.
- */
-
- if (nsPtr->earlyDeleteProc != NULL) {
- Tcl_NamespaceDeleteProc *earlyDeleteProc = nsPtr->earlyDeleteProc;
-
- nsPtr->earlyDeleteProc = NULL;
- nsPtr->activationCount++;
- earlyDeleteProc(nsPtr->clientData);
- nsPtr->activationCount--;
- }
-
- /*
- * Delete all coroutine commands now: break the circular ref cycle between
- * the namespace and the coroutine command [Bug 2724403]. This code is
- * essentially duplicated in TclTeardownNamespace() for all other
- * commands. Don't optimize to Tcl_NextHashEntry() because of traces.
- *
- * NOTE: we could avoid traversing the ns's command list by keeping a
- * separate list of coros.
- */
-
- for (entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
- entryPtr != NULL;) {
- cmdPtr = Tcl_GetHashValue(entryPtr);
- if (cmdPtr->nreProc == TclNRInterpCoroutine) {
- Tcl_DeleteCommandFromToken((Tcl_Interp *) iPtr,
- (Tcl_Command) cmdPtr);
- entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
- } else {
- entryPtr = Tcl_NextHashEntry(&search);
- }
- }
-
- /*
- * If the namespace has associated ensemble commands, delete them first.
- * This leaves the actual contents of the namespace alone (unless they are
- * linked ensemble commands, of course). Note that this code is actually
- * reentrant so command delete traces won't purturb things badly.
- */
-
- while (nsPtr->ensembles != NULL) {
- EnsembleConfig *ensemblePtr = (EnsembleConfig *) nsPtr->ensembles;
-
- /*
- * Splice out and link to indicate that we've already been killed.
- */
-
- nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr->next;
- ensemblePtr->next = ensemblePtr;
- Tcl_DeleteCommandFromToken(nsPtr->interp, ensemblePtr->token);
- }
-
- /*
- * If the namespace has a registered unknown handler (TIP 181), then free
- * it here.
- */
-
- if (nsPtr->unknownHandlerPtr != NULL) {
- Tcl_DecrRefCount(nsPtr->unknownHandlerPtr);
- nsPtr->unknownHandlerPtr = NULL;
- }
-
- /*
- * If the namespace is on the call frame stack, it is marked as "dying"
- * (NS_DYING is OR'd into its flags): the namespace can't be looked up by
- * name but its commands and variables are still usable by those active
- * call frames. When all active call frames referring to the namespace
- * have been popped from the Tcl stack, Tcl_PopCallFrame will call this
- * function again to delete everything in the namespace. If no nsName
- * objects refer to the namespace (i.e., if its refCount is zero), its
- * commands and variables are deleted and the storage for its namespace
- * structure is freed. Otherwise, if its refCount is nonzero, the
- * namespace's commands and variables are deleted but the structure isn't
- * freed. Instead, NS_DEAD is OR'd into the structure's flags to allow the
- * namespace resolution code to recognize that the namespace is "deleted".
- * The structure's storage is freed by FreeNsNameInternalRep when its
- * refCount reaches 0.
- */
-
- if (nsPtr->activationCount - (nsPtr == globalNsPtr) > 0) {
- nsPtr->flags |= NS_DYING;
- if (nsPtr->parentPtr != NULL) {
- entryPtr = Tcl_FindHashEntry(
- TclGetNamespaceChildTable((Tcl_Namespace *)
- nsPtr->parentPtr), nsPtr->name);
- if (entryPtr != NULL) {
- Tcl_DeleteHashEntry(entryPtr);
- }
- }
- nsPtr->parentPtr = NULL;
- } else if (!(nsPtr->flags & NS_KILLED)) {
- /*
- * Delete the namespace and everything in it. If this is the global
- * namespace, then clear it but don't free its storage unless the
- * interpreter is being torn down. Set the NS_KILLED flag to avoid
- * recursive calls here - if the namespace is really in the process of
- * being deleted, ignore any second call.
- */
-
- nsPtr->flags |= (NS_DYING|NS_KILLED);
-
- TclTeardownNamespace(nsPtr);
-
- if ((nsPtr != globalNsPtr) || (iPtr->flags & DELETED)) {
- /*
- * If this is the global namespace, then it may have residual
- * "errorInfo" and "errorCode" variables for errors that occurred
- * while it was being torn down. Try to clear the variable list
- * one last time.
- */
-
- TclDeleteNamespaceVars(nsPtr);
-
-#ifndef BREAK_NAMESPACE_COMPAT
- Tcl_DeleteHashTable(&nsPtr->childTable);
-#else
- if (nsPtr->childTablePtr != NULL) {
- Tcl_DeleteHashTable(nsPtr->childTablePtr);
- ckfree(nsPtr->childTablePtr);
- }
-#endif
- Tcl_DeleteHashTable(&nsPtr->cmdTable);
-
- /*
- * If the reference count is 0, then discard the namespace.
- * Otherwise, mark it as "dead" so that it can't be used.
- */
-
- if (nsPtr->refCount == 0) {
- NamespaceFree(nsPtr);
- } else {
- nsPtr->flags |= NS_DEAD;
- }
- } else {
- /*
- * Restore the ::errorInfo and ::errorCode traces.
- */
-
- EstablishErrorInfoTraces(NULL, nsPtr->interp, NULL, NULL, 0);
- EstablishErrorCodeTraces(NULL, nsPtr->interp, NULL, NULL, 0);
-
- /*
- * We didn't really kill it, so remove the KILLED marks, so it can
- * get killed later, avoiding mem leaks.
- */
-
- nsPtr->flags &= ~(NS_DYING|NS_KILLED);
- }
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclTeardownNamespace --
- *
- * Used internally to dismantle and unlink a namespace when it is
- * deleted. Divorces the namespace from its parent, and deletes all
- * commands, variables, and child namespaces.
- *
- * This is kept separate from Tcl_DeleteNamespace so that the global
- * namespace can be handled specially.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Removes this namespace from its parent's child namespace hashtable.
- * Deletes all commands, variables and namespaces in this namespace.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclTeardownNamespace(
- register Namespace *nsPtr) /* Points to the namespace to be dismantled
- * and unlinked from its parent. */
-{
- Interp *iPtr = (Interp *) nsPtr->interp;
- register Tcl_HashEntry *entryPtr;
- Tcl_HashSearch search;
- int i;
-
- /*
- * Start by destroying the namespace's variable table, since variables
- * might trigger traces. Variable table should be cleared but not freed!
- * TclDeleteNamespaceVars frees it, so we reinitialize it afterwards.
- */
-
- TclDeleteNamespaceVars(nsPtr);
- TclInitVarHashTable(&nsPtr->varTable, nsPtr);
-
- /*
- * Delete all commands in this namespace. Be careful when traversing the
- * hash table: when each command is deleted, it removes itself from the
- * command table. Because of traces (and the desire to avoid the quadratic
- * problems of just using Tcl_FirstHashEntry over and over, [Bug
- * f97d4ee020]) we copy to a temporary array and then delete all those
- * commands.
- */
-
- while (nsPtr->cmdTable.numEntries > 0) {
- int length = nsPtr->cmdTable.numEntries;
- Command **cmds = TclStackAlloc((Tcl_Interp *) iPtr,
- sizeof(Command *) * length);
-
- i = 0;
- for (entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
- entryPtr != NULL;
- entryPtr = Tcl_NextHashEntry(&search)) {
- cmds[i] = Tcl_GetHashValue(entryPtr);
- cmds[i]->refCount++;
- i++;
- }
- for (i = 0 ; i < length ; i++) {
- Tcl_DeleteCommandFromToken((Tcl_Interp *) iPtr,
- (Tcl_Command) cmds[i]);
- TclCleanupCommandMacro(cmds[i]);
- }
- TclStackFree((Tcl_Interp *) iPtr, cmds);
- }
- Tcl_DeleteHashTable(&nsPtr->cmdTable);
- Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS);
-
- /*
- * Remove the namespace from its parent's child hashtable.
- */
-
- if (nsPtr->parentPtr != NULL) {
- entryPtr = Tcl_FindHashEntry(
- TclGetNamespaceChildTable((Tcl_Namespace *)
- nsPtr->parentPtr), nsPtr->name);
- if (entryPtr != NULL) {
- Tcl_DeleteHashEntry(entryPtr);
- }
- }
- nsPtr->parentPtr = NULL;
-
- /*
- * Delete the namespace path if one is installed.
- */
-
- if (nsPtr->commandPathLength != 0) {
- UnlinkNsPath(nsPtr);
- nsPtr->commandPathLength = 0;
- }
- if (nsPtr->commandPathSourceList != NULL) {
- NamespacePathEntry *nsPathPtr = nsPtr->commandPathSourceList;
-
- do {
- if (nsPathPtr->nsPtr != NULL && nsPathPtr->creatorNsPtr != NULL) {
- nsPathPtr->creatorNsPtr->cmdRefEpoch++;
- }
- nsPathPtr->nsPtr = NULL;
- nsPathPtr = nsPathPtr->nextPtr;
- } while (nsPathPtr != NULL);
- nsPtr->commandPathSourceList = NULL;
- }
-
- /*
- * Delete all the child namespaces.
- *
- * BE CAREFUL: When each child is deleted, it will divorce itself from its
- * parent. You can't traverse a hash table properly if its elements are
- * being deleted. Because of traces (and the desire to avoid the
- * quadratic problems of just using Tcl_FirstHashEntry over and over, [Bug
- * f97d4ee020]) we copy to a temporary array and then delete all those
- * namespaces.
- *
- * Important: leave the hash table itself still live.
- */
-
-#ifndef BREAK_NAMESPACE_COMPAT
- while (nsPtr->childTable.numEntries > 0) {
- int length = nsPtr->childTable.numEntries;
- Namespace **children = TclStackAlloc((Tcl_Interp *) iPtr,
- sizeof(Namespace *) * length);
-
- i = 0;
- for (entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search);
- entryPtr != NULL;
- entryPtr = Tcl_NextHashEntry(&search)) {
- children[i] = Tcl_GetHashValue(entryPtr);
- children[i]->refCount++;
- i++;
- }
- for (i = 0 ; i < length ; i++) {
- Tcl_DeleteNamespace((Tcl_Namespace *) children[i]);
- TclNsDecrRefCount(children[i]);
- }
- TclStackFree((Tcl_Interp *) iPtr, children);
- }
-#else
- if (nsPtr->childTablePtr != NULL) {
- while (nsPtr->childTablePtr->numEntries > 0) {
- int length = nsPtr->childTablePtr->numEntries;
- Namespace **children = TclStackAlloc((Tcl_Interp *) iPtr,
- sizeof(Namespace *) * length);
-
- i = 0;
- for (entryPtr = Tcl_FirstHashEntry(nsPtr->childTablePtr, &search);
- entryPtr != NULL;
- entryPtr = Tcl_NextHashEntry(&search)) {
- children[i] = Tcl_GetHashValue(entryPtr);
- children[i]->refCount++;
- i++;
- }
- for (i = 0 ; i < length ; i++) {
- Tcl_DeleteNamespace((Tcl_Namespace *) children[i]);
- TclNsDecrRefCount(children[i]);
- }
- TclStackFree((Tcl_Interp *) iPtr, children);
- }
- }
-#endif
-
- /*
- * Free the namespace's export pattern array.
- */
-
- if (nsPtr->exportArrayPtr != NULL) {
- for (i = 0; i < nsPtr->numExportPatterns; i++) {
- ckfree(nsPtr->exportArrayPtr[i]);
- }
- ckfree(nsPtr->exportArrayPtr);
- nsPtr->exportArrayPtr = NULL;
- nsPtr->numExportPatterns = 0;
- nsPtr->maxExportPatterns = 0;
- }
-
- /*
- * Free any client data associated with the namespace.
- */
-
- if (nsPtr->deleteProc != NULL) {
- nsPtr->deleteProc(nsPtr->clientData);
- }
- nsPtr->deleteProc = NULL;
- nsPtr->clientData = NULL;
-
- /*
- * Reset the namespace's id field to ensure that this namespace won't be
- * interpreted as valid by, e.g., the cache validation code for cached
- * command references in Tcl_GetCommandFromObj.
- */
-
- nsPtr->nsId = 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceFree --
- *
- * Called after a namespace has been deleted, when its reference count
- * reaches 0. Frees the data structure representing the namespace.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-NamespaceFree(
- register Namespace *nsPtr) /* Points to the namespace to free. */
-{
- /*
- * Most of the namespace's contents are freed when the namespace is
- * deleted by Tcl_DeleteNamespace. All that remains is to free its names
- * (for error messages), and the structure itself.
- */
-
- ckfree(nsPtr->name);
- ckfree(nsPtr->fullName);
- ckfree(nsPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclNsDecrRefCount --
- *
- * Drops a reference to a namespace and frees it if the namespace has
- * been deleted and the last reference has just been dropped.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclNsDecrRefCount(
- Namespace *nsPtr)
-{
- nsPtr->refCount--;
- if ((nsPtr->refCount == 0) && (nsPtr->flags & NS_DEAD)) {
- NamespaceFree(nsPtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_Export --
- *
- * Makes all the commands matching a pattern available to later be
- * imported from the namespace specified by namespacePtr (or the current
- * namespace if namespacePtr is NULL). The specified pattern is appended
- * onto the namespace's export pattern list, which is optionally cleared
- * beforehand.
- *
- * Results:
- * Returns TCL_OK if successful, or TCL_ERROR (along with an error
- * message in the interpreter's result) if something goes wrong.
- *
- * Side effects:
- * Appends the export pattern onto the namespace's export list.
- * Optionally reset the namespace's export pattern list.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_Export(
- Tcl_Interp *interp, /* Current interpreter. */
- Tcl_Namespace *namespacePtr,/* Points to the namespace from which commands
- * are to be exported. NULL for the current
- * namespace. */
- const char *pattern, /* String pattern indicating which commands to
- * export. This pattern may not include any
- * namespace qualifiers; only commands in the
- * specified namespace may be exported. */
- int resetListFirst) /* If nonzero, resets the namespace's export
- * list before appending. */
-{
-#define INIT_EXPORT_PATTERNS 5
- Namespace *nsPtr, *exportNsPtr, *dummyPtr;
- Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- const char *simplePattern;
- char *patternCpy;
- int neededElems, len, i;
-
- /*
- * If the specified namespace is NULL, use the current namespace.
- */
-
- if (namespacePtr == NULL) {
- nsPtr = (Namespace *) currNsPtr;
- } else {
- nsPtr = (Namespace *) namespacePtr;
- }
-
- /*
- * If resetListFirst is true (nonzero), clear the namespace's export
- * pattern list.
- */
-
- if (resetListFirst) {
- if (nsPtr->exportArrayPtr != NULL) {
- for (i = 0; i < nsPtr->numExportPatterns; i++) {
- ckfree(nsPtr->exportArrayPtr[i]);
- }
- ckfree(nsPtr->exportArrayPtr);
- nsPtr->exportArrayPtr = NULL;
- TclInvalidateNsCmdLookup(nsPtr);
- nsPtr->numExportPatterns = 0;
- nsPtr->maxExportPatterns = 0;
- }
- }
-
- /*
- * Check that the pattern doesn't have namespace qualifiers.
- */
-
- TclGetNamespaceForQualName(interp, pattern, nsPtr, TCL_NAMESPACE_ONLY,
- &exportNsPtr, &dummyPtr, &dummyPtr, &simplePattern);
-
- if ((exportNsPtr != nsPtr) || (strcmp(pattern, simplePattern) != 0)) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid export pattern"
- " \"%s\": pattern can't specify a namespace", pattern));
- Tcl_SetErrorCode(interp, "TCL", "EXPORT", "INVALID", NULL);
- return TCL_ERROR;
- }
-
- /*
- * Make sure that we don't already have the pattern in the array
- */
-
- if (nsPtr->exportArrayPtr != NULL) {
- for (i = 0; i < nsPtr->numExportPatterns; i++) {
- if (strcmp(pattern, nsPtr->exportArrayPtr[i]) == 0) {
- /*
- * The pattern already exists in the list.
- */
-
- return TCL_OK;
- }
- }
- }
-
- /*
- * Make sure there is room in the namespace's pattern array for the new
- * pattern.
- */
-
- neededElems = nsPtr->numExportPatterns + 1;
- if (neededElems > nsPtr->maxExportPatterns) {
- nsPtr->maxExportPatterns = nsPtr->maxExportPatterns ?
- 2 * nsPtr->maxExportPatterns : INIT_EXPORT_PATTERNS;
- nsPtr->exportArrayPtr = ckrealloc(nsPtr->exportArrayPtr,
- sizeof(char *) * nsPtr->maxExportPatterns);
- }
-
- /*
- * Add the pattern to the namespace's array of export patterns.
- */
-
- len = strlen(pattern);
- patternCpy = ckalloc(len + 1);
- memcpy(patternCpy, pattern, (unsigned) len + 1);
-
- nsPtr->exportArrayPtr[nsPtr->numExportPatterns] = patternCpy;
- nsPtr->numExportPatterns++;
-
- /*
- * The list of commands actually exported from the namespace might have
- * changed (probably will have!) However, we do not need to recompute this
- * just yet; next time we need the info will be soon enough.
- */
-
- TclInvalidateNsCmdLookup(nsPtr);
-
- return TCL_OK;
-#undef INIT_EXPORT_PATTERNS
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_AppendExportList --
- *
- * Appends onto the argument object the list of export patterns for the
- * specified namespace.
- *
- * Results:
- * The return value is normally TCL_OK; in this case the object
- * referenced by objPtr has each export pattern appended to it. If an
- * error occurs, TCL_ERROR is returned and the interpreter's result holds
- * an error message.
- *
- * Side effects:
- * If necessary, the object referenced by objPtr is converted into a list
- * object.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_AppendExportList(
- Tcl_Interp *interp, /* Interpreter used for error reporting. */
- Tcl_Namespace *namespacePtr,/* Points to the namespace whose export
- * pattern list is appended onto objPtr. NULL
- * for the current namespace. */
- Tcl_Obj *objPtr) /* Points to the Tcl object onto which the
- * export pattern list is appended. */
-{
- Namespace *nsPtr;
- int i, result;
-
- /*
- * If the specified namespace is NULL, use the current namespace.
- */
-
- if (namespacePtr == NULL) {
- nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- } else {
- nsPtr = (Namespace *) namespacePtr;
- }
-
- /*
- * Append the export pattern list onto objPtr.
- */
-
- for (i = 0; i < nsPtr->numExportPatterns; i++) {
- result = Tcl_ListObjAppendElement(interp, objPtr,
- Tcl_NewStringObj(nsPtr->exportArrayPtr[i], -1));
- if (result != TCL_OK) {
- return result;
- }
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_Import --
- *
- * Imports all of the commands matching a pattern into the namespace
- * specified by namespacePtr (or the current namespace if contextNsPtr is
- * NULL). This is done by creating a new command (the "imported command")
- * that points to the real command in its original namespace.
- *
- * If matching commands are on the autoload path but haven't been loaded
- * yet, this command forces them to be loaded, then creates the links to
- * them.
- *
- * Results:
- * Returns TCL_OK if successful, or TCL_ERROR (along with an error
- * message in the interpreter's result) if something goes wrong.
- *
- * Side effects:
- * Creates new commands in the importing namespace. These indirect calls
- * back to the real command and are deleted if the real commands are
- * deleted.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_Import(
- Tcl_Interp *interp, /* Current interpreter. */
- Tcl_Namespace *namespacePtr,/* Points to the namespace into which the
- * commands are to be imported. NULL for the
- * current namespace. */
- const char *pattern, /* String pattern indicating which commands to
- * import. This pattern should be qualified by
- * the name of the namespace from which to
- * import the command(s). */
- int allowOverwrite) /* If nonzero, allow existing commands to be
- * overwritten by imported commands. If 0,
- * return an error if an imported cmd
- * conflicts with an existing one. */
-{
- Namespace *nsPtr, *importNsPtr, *dummyPtr;
- const char *simplePattern;
- register Tcl_HashEntry *hPtr;
- Tcl_HashSearch search;
-
- /*
- * If the specified namespace is NULL, use the current namespace.
- */
-
- if (namespacePtr == NULL) {
- nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- } else {
- nsPtr = (Namespace *) namespacePtr;
- }
-
- /*
- * First, invoke the "auto_import" command with the pattern being
- * imported. This command is part of the Tcl library. It looks for
- * imported commands in autoloaded libraries and loads them in. That way,
- * they will be found when we try to create links below.
- *
- * Note that we don't just call Tcl_EvalObjv() directly because we do not
- * want absence of the command to be a failure case.
- */
-
- if (Tcl_FindCommand(interp,"auto_import",NULL,TCL_GLOBAL_ONLY) != NULL) {
- Tcl_Obj *objv[2];
- int result;
-
- TclNewLiteralStringObj(objv[0], "auto_import");
- objv[1] = Tcl_NewStringObj(pattern, -1);
-
- Tcl_IncrRefCount(objv[0]);
- Tcl_IncrRefCount(objv[1]);
- result = Tcl_EvalObjv(interp, 2, objv, TCL_GLOBAL_ONLY);
- Tcl_DecrRefCount(objv[0]);
- Tcl_DecrRefCount(objv[1]);
-
- if (result != TCL_OK) {
- return TCL_ERROR;
- }
- Tcl_ResetResult(interp);
- }
-
- /*
- * From the pattern, find the namespace from which we are importing and
- * get the simple pattern (no namespace qualifiers or ::'s) at the end.
- */
-
- if (strlen(pattern) == 0) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj("empty import pattern",-1));
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "EMPTY", NULL);
- return TCL_ERROR;
- }
- TclGetNamespaceForQualName(interp, pattern, nsPtr, TCL_NAMESPACE_ONLY,
- &importNsPtr, &dummyPtr, &dummyPtr, &simplePattern);
-
- if (importNsPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unknown namespace in import pattern \"%s\"", pattern));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", pattern, NULL);
- return TCL_ERROR;
- }
- if (importNsPtr == nsPtr) {
- if (pattern == simplePattern) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "no namespace specified in import pattern \"%s\"",
- pattern));
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "ORIGIN", NULL);
- } else {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "import pattern \"%s\" tries to import from namespace"
- " \"%s\" into itself", pattern, importNsPtr->name));
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "SELF", NULL);
- }
- return TCL_ERROR;
- }
-
- /*
- * Scan through the command table in the source namespace and look for
- * exported commands that match the string pattern. Create an "imported
- * command" in the current namespace for each imported command; these
- * commands redirect their invocations to the "real" command.
- */
-
- if ((simplePattern != NULL) && TclMatchIsTrivial(simplePattern)) {
- hPtr = Tcl_FindHashEntry(&importNsPtr->cmdTable, simplePattern);
- if (hPtr == NULL) {
- return TCL_OK;
- }
- return DoImport(interp, nsPtr, hPtr, simplePattern, pattern,
- importNsPtr, allowOverwrite);
- }
- for (hPtr = Tcl_FirstHashEntry(&importNsPtr->cmdTable, &search);
- (hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) {
- char *cmdName = Tcl_GetHashKey(&importNsPtr->cmdTable, hPtr);
-
- if (Tcl_StringMatch(cmdName, simplePattern) &&
- DoImport(interp, nsPtr, hPtr, cmdName, pattern, importNsPtr,
- allowOverwrite) == TCL_ERROR) {
- return TCL_ERROR;
- }
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DoImport --
- *
- * Import a particular command from one namespace into another. Helper
- * for Tcl_Import().
- *
- * Results:
- * Standard Tcl result code. If TCL_ERROR, appends an error message to
- * the interpreter result.
- *
- * Side effects:
- * A new command is created in the target namespace unless this is a
- * reimport of exactly the same command as before.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-DoImport(
- Tcl_Interp *interp,
- Namespace *nsPtr,
- Tcl_HashEntry *hPtr,
- const char *cmdName,
- const char *pattern,
- Namespace *importNsPtr,
- int allowOverwrite)
-{
- int i = 0, exported = 0;
- Tcl_HashEntry *found;
-
- /*
- * The command cmdName in the source namespace matches the pattern. Check
- * whether it was exported. If it wasn't, we ignore it.
- */
-
- while (!exported && (i < importNsPtr->numExportPatterns)) {
- exported |= Tcl_StringMatch(cmdName,
- importNsPtr->exportArrayPtr[i++]);
- }
- if (!exported) {
- return TCL_OK;
- }
-
- /*
- * Unless there is a name clash, create an imported command in the current
- * namespace that refers to cmdPtr.
- */
-
- found = Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName);
- if ((found == NULL) || allowOverwrite) {
- /*
- * Create the imported command and its client data. To create the new
- * command in the current namespace, generate a fully qualified name
- * for it.
- */
-
- Tcl_DString ds;
- Tcl_Command importedCmd;
- ImportedCmdData *dataPtr;
- Command *cmdPtr;
- ImportRef *refPtr;
-
- Tcl_DStringInit(&ds);
- Tcl_DStringAppend(&ds, nsPtr->fullName, -1);
- if (nsPtr != ((Interp *) interp)->globalNsPtr) {
- TclDStringAppendLiteral(&ds, "::");
- }
- Tcl_DStringAppend(&ds, cmdName, -1);
-
- /*
- * Check whether creating the new imported command in the current
- * namespace would create a cycle of imported command references.
- */
-
- cmdPtr = Tcl_GetHashValue(hPtr);
- if (found != NULL && cmdPtr->deleteProc == DeleteImportedCmd) {
- Command *overwrite = Tcl_GetHashValue(found);
- Command *linkCmd = cmdPtr;
-
- while (linkCmd->deleteProc == DeleteImportedCmd) {
- dataPtr = linkCmd->objClientData;
- linkCmd = dataPtr->realCmdPtr;
- if (overwrite == linkCmd) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "import pattern \"%s\" would create a loop"
- " containing command \"%s\"",
- pattern, Tcl_DStringValue(&ds)));
- Tcl_DStringFree(&ds);
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "LOOP", NULL);
- return TCL_ERROR;
- }
- }
- }
-
- dataPtr = ckalloc(sizeof(ImportedCmdData));
- importedCmd = Tcl_NRCreateCommand(interp, Tcl_DStringValue(&ds),
- InvokeImportedCmd, InvokeImportedNRCmd, dataPtr,
- DeleteImportedCmd);
- dataPtr->realCmdPtr = cmdPtr;
- dataPtr->selfPtr = (Command *) importedCmd;
- dataPtr->selfPtr->compileProc = cmdPtr->compileProc;
- Tcl_DStringFree(&ds);
-
- /*
- * Create an ImportRef structure describing this new import command
- * and add it to the import ref list in the "real" command.
- */
-
- refPtr = ckalloc(sizeof(ImportRef));
- refPtr->importedCmdPtr = (Command *) importedCmd;
- refPtr->nextPtr = cmdPtr->importRefPtr;
- cmdPtr->importRefPtr = refPtr;
- } else {
- Command *overwrite = Tcl_GetHashValue(found);
-
- if (overwrite->deleteProc == DeleteImportedCmd) {
- ImportedCmdData *dataPtr = overwrite->objClientData;
-
- if (dataPtr->realCmdPtr == Tcl_GetHashValue(hPtr)) {
- /*
- * Repeated import of same command is acceptable.
- */
-
- return TCL_OK;
- }
- }
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't import command \"%s\": already exists", cmdName));
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "OVERWRITE", NULL);
- return TCL_ERROR;
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_ForgetImport --
- *
- * Deletes commands previously imported into the namespace indicated.
- * The by namespacePtr, or the current namespace of interp, when
- * namespacePtr is NULL. The pattern controls which imported commands are
- * deleted. A simple pattern, one without namespace separators, matches
- * the current command names of imported commands in the namespace.
- * Matching imported commands are deleted. A qualified pattern is
- * interpreted as deletion selection on the basis of where the command is
- * imported from. The original command and "first link" command for each
- * imported command are determined, and they are matched against the
- * pattern. A match leads to deletion of the imported command.
- *
- * Results:
- * Returns TCL_ERROR and records an error message in the interp result if
- * a namespace qualified pattern refers to a namespace that does not
- * exist. Otherwise, returns TCL_OK.
- *
- * Side effects:
- * May delete commands.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_ForgetImport(
- Tcl_Interp *interp, /* Current interpreter. */
- Tcl_Namespace *namespacePtr,/* Points to the namespace from which
- * previously imported commands should be
- * removed. NULL for current namespace. */
- const char *pattern) /* String pattern indicating which imported
- * commands to remove. */
-{
- Namespace *nsPtr, *sourceNsPtr, *dummyPtr;
- const char *simplePattern;
- char *cmdName;
- register Tcl_HashEntry *hPtr;
- Tcl_HashSearch search;
-
- /*
- * If the specified namespace is NULL, use the current namespace.
- */
-
- if (namespacePtr == NULL) {
- nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- } else {
- nsPtr = (Namespace *) namespacePtr;
- }
-
- /*
- * Parse the pattern into its namespace-qualification (if any) and the
- * simple pattern.
- */
-
- TclGetNamespaceForQualName(interp, pattern, nsPtr, TCL_NAMESPACE_ONLY,
- &sourceNsPtr, &dummyPtr, &dummyPtr, &simplePattern);
-
- if (sourceNsPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unknown namespace in namespace forget pattern \"%s\"",
- pattern));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", pattern, NULL);
- return TCL_ERROR;
- }
-
- if (strcmp(pattern, simplePattern) == 0) {
- /*
- * The pattern is simple. Delete any imported commands that match it.
- */
-
- if (TclMatchIsTrivial(simplePattern)) {
- hPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simplePattern);
- if (hPtr != NULL) {
- Command *cmdPtr = Tcl_GetHashValue(hPtr);
-
- if (cmdPtr && (cmdPtr->deleteProc == DeleteImportedCmd)) {
- Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
- }
- }
- return TCL_OK;
- }
- for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
- (hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) {
- Command *cmdPtr = Tcl_GetHashValue(hPtr);
-
- if (cmdPtr->deleteProc != DeleteImportedCmd) {
- continue;
- }
- cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, hPtr);
- if (Tcl_StringMatch(cmdName, simplePattern)) {
- Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
- }
- }
- return TCL_OK;
- }
-
- /*
- * The pattern was namespace-qualified.
- */
-
- for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); (hPtr != NULL);
- hPtr = Tcl_NextHashEntry(&search)) {
- Tcl_CmdInfo info;
- Tcl_Command token = Tcl_GetHashValue(hPtr);
- Tcl_Command origin = TclGetOriginalCommand(token);
-
- if (Tcl_GetCommandInfoFromToken(origin, &info) == 0) {
- continue; /* Not an imported command. */
- }
- if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) {
- /*
- * Original not in namespace we're matching. Check the first link
- * in the import chain.
- */
-
- Command *cmdPtr = (Command *) token;
- ImportedCmdData *dataPtr = cmdPtr->objClientData;
- Tcl_Command firstToken = (Tcl_Command) dataPtr->realCmdPtr;
-
- if (firstToken == origin) {
- continue;
- }
- Tcl_GetCommandInfoFromToken(firstToken, &info);
- if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) {
- continue;
- }
- origin = firstToken;
- }
- if (Tcl_StringMatch(Tcl_GetCommandName(NULL, origin), simplePattern)){
- Tcl_DeleteCommandFromToken(interp, token);
- }
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclGetOriginalCommand --
- *
- * An imported command is created in an namespace when a "real" command
- * is imported from another namespace. If the specified command is an
- * imported command, this function returns the original command it refers
- * to.
- *
- * Results:
- * If the command was imported into a sequence of namespaces a, b,...,n
- * where each successive namespace just imports the command from the
- * previous namespace, this function returns the Tcl_Command token in the
- * first namespace, a. Otherwise, if the specified command is not an
- * imported command, the function returns NULL.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Command
-TclGetOriginalCommand(
- Tcl_Command command) /* The imported command for which the original
- * command should be returned. */
-{
- register Command *cmdPtr = (Command *) command;
- ImportedCmdData *dataPtr;
-
- if (cmdPtr->deleteProc != DeleteImportedCmd) {
- return NULL;
- }
-
- while (cmdPtr->deleteProc == DeleteImportedCmd) {
- dataPtr = cmdPtr->objClientData;
- cmdPtr = dataPtr->realCmdPtr;
- }
- return (Tcl_Command) cmdPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * InvokeImportedCmd --
- *
- * Invoked by Tcl whenever the user calls an imported command that was
- * created by Tcl_Import. Finds the "real" command (in another
- * namespace), and passes control to it.
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns a result in the interpreter's result object. If anything goes
- * wrong, the result object is set to an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-InvokeImportedNRCmd(
- ClientData clientData, /* Points to the imported command's
- * ImportedCmdData structure. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* The argument objects. */
-{
- ImportedCmdData *dataPtr = clientData;
- Command *realCmdPtr = dataPtr->realCmdPtr;
-
- TclSkipTailcall(interp);
- return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NOERR, realCmdPtr);
-}
-
-static int
-InvokeImportedCmd(
- ClientData clientData, /* Points to the imported command's
- * ImportedCmdData structure. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* The argument objects. */
-{
- return Tcl_NRCallObjProc(interp, InvokeImportedNRCmd, clientData,
- objc, objv);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DeleteImportedCmd --
- *
- * Invoked by Tcl whenever an imported command is deleted. The "real"
- * command keeps a list of all the imported commands that refer to it, so
- * those imported commands can be deleted when the real command is
- * deleted. This function removes the imported command reference from the
- * real command's list, and frees up the memory associated with the
- * imported command.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Removes the imported command from the real command's import list.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-DeleteImportedCmd(
- ClientData clientData) /* Points to the imported command's
- * ImportedCmdData structure. */
-{
- ImportedCmdData *dataPtr = clientData;
- Command *realCmdPtr = dataPtr->realCmdPtr;
- Command *selfPtr = dataPtr->selfPtr;
- register ImportRef *refPtr, *prevPtr;
-
- prevPtr = NULL;
- for (refPtr = realCmdPtr->importRefPtr; refPtr != NULL;
- refPtr = refPtr->nextPtr) {
- if (refPtr->importedCmdPtr == selfPtr) {
- /*
- * Remove *refPtr from real command's list of imported commands
- * that refer to it.
- */
-
- if (prevPtr == NULL) { /* refPtr is first in list. */
- realCmdPtr->importRefPtr = refPtr->nextPtr;
- } else {
- prevPtr->nextPtr = refPtr->nextPtr;
- }
- ckfree(refPtr);
- ckfree(dataPtr);
- return;
- }
- prevPtr = refPtr;
- }
-
- Tcl_Panic("DeleteImportedCmd: did not find cmd in real cmd's list of import references");
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclGetNamespaceForQualName --
- *
- * Given a qualified name specifying a command, variable, or namespace,
- * and a namespace in which to resolve the name, this function returns a
- * pointer to the namespace that contains the item. A qualified name
- * consists of the "simple" name of an item qualified by the names of an
- * arbitrary number of containing namespace separated by "::"s. If the
- * qualified name starts with "::", it is interpreted absolutely from the
- * global namespace. Otherwise, it is interpreted relative to the
- * namespace specified by cxtNsPtr if it is non-NULL. If cxtNsPtr is
- * NULL, the name is interpreted relative to the current namespace.
- *
- * A relative name like "foo::bar::x" can be found starting in either the
- * current namespace or in the global namespace. So each search usually
- * follows two tracks, and two possible namespaces are returned. If the
- * function sets either *nsPtrPtr or *altNsPtrPtr to NULL, then that path
- * failed.
- *
- * If "flags" contains TCL_GLOBAL_ONLY, the relative qualified name is
- * sought only in the global :: namespace. The alternate search (also)
- * starting from the global namespace is ignored and *altNsPtrPtr is set
- * NULL.
- *
- * If "flags" contains TCL_NAMESPACE_ONLY, the relative qualified name is
- * sought only in the namespace specified by cxtNsPtr. The alternate
- * search starting from the global namespace is ignored and *altNsPtrPtr
- * is set NULL. If both TCL_GLOBAL_ONLY and TCL_NAMESPACE_ONLY are
- * specified, TCL_GLOBAL_ONLY is ignored and the search starts from the
- * namespace specified by cxtNsPtr.
- *
- * If "flags" contains TCL_CREATE_NS_IF_UNKNOWN, all namespace components
- * of the qualified name that cannot be found are automatically created
- * within their specified parent. This makes sure that functions like
- * Tcl_CreateCommand always succeed. There is no alternate search path,
- * so *altNsPtrPtr is set NULL.
- *
- * If "flags" contains TCL_FIND_ONLY_NS, the qualified name is treated as
- * a reference to a namespace, and the entire qualified name is followed.
- * If the name is relative, the namespace is looked up only in the
- * current namespace. A pointer to the namespace is stored in *nsPtrPtr
- * and NULL is stored in *simpleNamePtr. Otherwise, if TCL_FIND_ONLY_NS
- * is not specified, only the leading components are treated as namespace
- * names, and a pointer to the simple name of the final component is
- * stored in *simpleNamePtr.
- *
- * Results:
- * It sets *nsPtrPtr and *altNsPtrPtr to point to the two possible
- * namespaces which represent the last (containing) namespace in the
- * qualified name. If the function sets either *nsPtrPtr or *altNsPtrPtr
- * to NULL, then the search along that path failed. The function also
- * stores a pointer to the simple name of the final component in
- * *simpleNamePtr. If the qualified name is "::" or was treated as a
- * namespace reference (TCL_FIND_ONLY_NS), the function stores a pointer
- * to the namespace in *nsPtrPtr, NULL in *altNsPtrPtr, and sets
- * *simpleNamePtr to point to an empty string.
- *
- * If there is an error, this function returns TCL_ERROR. If "flags"
- * contains TCL_LEAVE_ERR_MSG, an error message is returned in the
- * interpreter's result object. Otherwise, the interpreter's result
- * object is left unchanged.
- *
- * *actualCxtPtrPtr is set to the actual context namespace. It is set to
- * the input context namespace pointer in cxtNsPtr. If cxtNsPtr is NULL,
- * it is set to the current namespace context.
- *
- * For backwards compatibility with the TclPro byte code loader, this
- * function always returns TCL_OK.
- *
- * Side effects:
- * If "flags" contains TCL_CREATE_NS_IF_UNKNOWN, new namespaces may be
- * created.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclGetNamespaceForQualName(
- Tcl_Interp *interp, /* Interpreter in which to find the namespace
- * containing qualName. */
- const char *qualName, /* A namespace-qualified name of an command,
- * variable, or namespace. */
- Namespace *cxtNsPtr, /* The namespace in which to start the search
- * for qualName's namespace. If NULL start
- * from the current namespace. Ignored if
- * TCL_GLOBAL_ONLY is set. */
- int flags, /* Flags controlling the search: an OR'd
- * combination of TCL_GLOBAL_ONLY,
- * TCL_NAMESPACE_ONLY, TCL_FIND_ONLY_NS, and
- * TCL_CREATE_NS_IF_UNKNOWN. */
- Namespace **nsPtrPtr, /* Address where function stores a pointer to
- * containing namespace if qualName is found
- * starting from *cxtNsPtr or, if
- * TCL_GLOBAL_ONLY is set, if qualName is
- * found in the global :: namespace. NULL is
- * stored otherwise. */
- Namespace **altNsPtrPtr, /* Address where function stores a pointer to
- * containing namespace if qualName is found
- * starting from the global :: namespace.
- * NULL is stored if qualName isn't found
- * starting from :: or if the TCL_GLOBAL_ONLY,
- * TCL_NAMESPACE_ONLY, TCL_FIND_ONLY_NS,
- * TCL_CREATE_NS_IF_UNKNOWN flag is set. */
- Namespace **actualCxtPtrPtr,/* Address where function stores a pointer to
- * the actual namespace from which the search
- * started. This is either cxtNsPtr, the ::
- * namespace if TCL_GLOBAL_ONLY was specified,
- * or the current namespace if cxtNsPtr was
- * NULL. */
- const char **simpleNamePtr) /* Address where function stores the simple
- * name at end of the qualName, or NULL if
- * qualName is "::" or the flag
- * TCL_FIND_ONLY_NS was specified. */
-{
- Interp *iPtr = (Interp *) interp;
- Namespace *nsPtr = cxtNsPtr;
- Namespace *altNsPtr;
- Namespace *globalNsPtr = iPtr->globalNsPtr;
- const char *start, *end;
- const char *nsName;
- Tcl_HashEntry *entryPtr;
- Tcl_DString buffer;
- int len;
-
- /*
- * Determine the context namespace nsPtr in which to start the primary
- * search. If the qualName name starts with a "::" or TCL_GLOBAL_ONLY was
- * specified, search from the global namespace. Otherwise, use the
- * namespace given in cxtNsPtr, or if that is NULL, use the current
- * namespace context. Note that we always treat two or more adjacent ":"s
- * as a namespace separator.
- */
-
- if (flags & TCL_GLOBAL_ONLY) {
- nsPtr = globalNsPtr;
- } else if (nsPtr == NULL) {
- nsPtr = iPtr->varFramePtr->nsPtr;
- }
-
- start = qualName; /* Points to start of qualifying
- * namespace. */
- if ((*qualName == ':') && (*(qualName+1) == ':')) {
- start = qualName+2; /* Skip over the initial :: */
- while (*start == ':') {
- start++; /* Skip over a subsequent : */
- }
- nsPtr = globalNsPtr;
- if (*start == '\0') { /* qualName is just two or more
- * ":"s. */
- *nsPtrPtr = globalNsPtr;
- *altNsPtrPtr = NULL;
- *actualCxtPtrPtr = globalNsPtr;
- *simpleNamePtr = start; /* Points to empty string. */
- return TCL_OK;
- }
- }
- *actualCxtPtrPtr = nsPtr;
-
- /*
- * Start an alternate search path starting with the global namespace.
- * However, if the starting context is the global namespace, or if the
- * flag is set to search only the namespace *cxtNsPtr, ignore the
- * alternate search path.
- */
-
- altNsPtr = globalNsPtr;
- if ((nsPtr == globalNsPtr)
- || (flags & (TCL_NAMESPACE_ONLY | TCL_FIND_ONLY_NS))) {
- altNsPtr = NULL;
- }
-
- /*
- * Loop to resolve each namespace qualifier in qualName.
- */
-
- Tcl_DStringInit(&buffer);
- end = start;
- while (*start != '\0') {
- /*
- * Find the next namespace qualifier (i.e., a name ending in "::") or
- * the end of the qualified name (i.e., a name ending in "\0"). Set
- * len to the number of characters, starting from start, in the name;
- * set end to point after the "::"s or at the "\0".
- */
-
- len = 0;
- for (end = start; *end != '\0'; end++) {
- if ((*end == ':') && (*(end+1) == ':')) {
- end += 2; /* Skip over the initial :: */
- while (*end == ':') {
- end++; /* Skip over the subsequent : */
- }
- break; /* Exit for loop; end is after ::'s */
- }
- len++;
- }
-
- if (*end=='\0' && !(end-start>=2 && *(end-1)==':' && *(end-2)==':')) {
- /*
- * qualName ended with a simple name at start. If TCL_FIND_ONLY_NS
- * was specified, look this up as a namespace. Otherwise, start is
- * the name of a cmd or var and we are done.
- */
-
- if (flags & TCL_FIND_ONLY_NS) {
- nsName = start;
- } else {
- *nsPtrPtr = nsPtr;
- *altNsPtrPtr = altNsPtr;
- *simpleNamePtr = start;
- Tcl_DStringFree(&buffer);
- return TCL_OK;
- }
- } else {
- /*
- * start points to the beginning of a namespace qualifier ending
- * in "::". end points to the start of a name in that namespace
- * that might be empty. Copy the namespace qualifier to a buffer
- * so it can be null terminated. We can't modify the incoming
- * qualName since it may be a string constant.
- */
-
- TclDStringClear(&buffer);
- Tcl_DStringAppend(&buffer, start, len);
- nsName = Tcl_DStringValue(&buffer);
- }
-
- /*
- * Look up the namespace qualifier nsName in the current namespace
- * context. If it isn't found but TCL_CREATE_NS_IF_UNKNOWN is set,
- * create that qualifying namespace. This is needed for functions like
- * Tcl_CreateCommand that cannot fail.
- */
-
- if (nsPtr != NULL) {
-#ifndef BREAK_NAMESPACE_COMPAT
- entryPtr = Tcl_FindHashEntry(&nsPtr->childTable, nsName);
-#else
- if (nsPtr->childTablePtr == NULL) {
- entryPtr = NULL;
- } else {
- entryPtr = Tcl_FindHashEntry(nsPtr->childTablePtr, nsName);
- }
-#endif
- if (entryPtr != NULL) {
- nsPtr = Tcl_GetHashValue(entryPtr);
- } else if (flags & TCL_CREATE_NS_IF_UNKNOWN) {
- Tcl_CallFrame *framePtr;
-
- (void) TclPushStackFrame(interp, &framePtr,
- (Tcl_Namespace *) nsPtr, /*isProcCallFrame*/ 0);
-
- nsPtr = (Namespace *)
- Tcl_CreateNamespace(interp, nsName, NULL, NULL);
- TclPopStackFrame(interp);
-
- if (nsPtr == NULL) {
- Tcl_Panic("Could not create namespace '%s'", nsName);
- }
- } else { /* Namespace not found and was not
- * created. */
- nsPtr = NULL;
- }
- }
-
- /*
- * Look up the namespace qualifier in the alternate search path too.
- */
-
- if (altNsPtr != NULL) {
-#ifndef BREAK_NAMESPACE_COMPAT
- entryPtr = Tcl_FindHashEntry(&altNsPtr->childTable, nsName);
-#else
- if (altNsPtr->childTablePtr != NULL) {
- entryPtr = Tcl_FindHashEntry(altNsPtr->childTablePtr, nsName);
- } else {
- entryPtr = NULL;
- }
-#endif
- if (entryPtr != NULL) {
- altNsPtr = Tcl_GetHashValue(entryPtr);
- } else {
- altNsPtr = NULL;
- }
- }
-
- /*
- * If both search paths have failed, return NULL results.
- */
-
- if ((nsPtr == NULL) && (altNsPtr == NULL)) {
- *nsPtrPtr = NULL;
- *altNsPtrPtr = NULL;
- *simpleNamePtr = NULL;
- Tcl_DStringFree(&buffer);
- return TCL_OK;
- }
-
- start = end;
- }
-
- /*
- * We ignore trailing "::"s in a namespace name, but in a command or
- * variable name, trailing "::"s refer to the cmd or var named {}.
- */
-
- if ((flags & TCL_FIND_ONLY_NS) || (end>start && *(end-1)!=':')) {
- *simpleNamePtr = NULL; /* Found namespace name. */
- } else {
- *simpleNamePtr = end; /* Found cmd/var: points to empty
- * string. */
- }
-
- /*
- * As a special case, if we are looking for a namespace and qualName is ""
- * and the current active namespace (nsPtr) is not the global namespace,
- * return NULL (no namespace was found). This is because namespaces can
- * not have empty names except for the global namespace.
- */
-
- if ((flags & TCL_FIND_ONLY_NS) && (*qualName == '\0')
- && (nsPtr != globalNsPtr)) {
- nsPtr = NULL;
- }
-
- *nsPtrPtr = nsPtr;
- *altNsPtrPtr = altNsPtr;
- Tcl_DStringFree(&buffer);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_FindNamespace --
- *
- * Searches for a namespace.
- *
- * Results:
- * Returns a pointer to the namespace if it is found. Otherwise, returns
- * NULL and leaves an error message in the interpreter's result object if
- * "flags" contains TCL_LEAVE_ERR_MSG.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Namespace *
-Tcl_FindNamespace(
- Tcl_Interp *interp, /* The interpreter in which to find the
- * namespace. */
- const char *name, /* Namespace name. If it starts with "::",
- * will be looked up in global namespace.
- * Else, looked up first in contextNsPtr
- * (current namespace if contextNsPtr is
- * NULL), then in global namespace. */
- Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag is set or
- * if the name starts with "::". Otherwise,
- * points to namespace in which to resolve
- * name; if NULL, look up name in the current
- * namespace. */
- register int flags) /* Flags controlling namespace lookup: an OR'd
- * combination of TCL_GLOBAL_ONLY and
- * TCL_LEAVE_ERR_MSG flags. */
-{
- Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr;
- const char *dummy;
-
- /*
- * Find the namespace(s) that contain the specified namespace name. Add
- * the TCL_FIND_ONLY_NS flag to resolve the name all the way down to its
- * last component, a namespace.
- */
-
- TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr,
- flags|TCL_FIND_ONLY_NS, &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy);
-
- if (nsPtr != NULL) {
- return (Tcl_Namespace *) nsPtr;
- }
-
- if (flags & TCL_LEAVE_ERR_MSG) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unknown namespace \"%s\"", name));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", name, NULL);
- }
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_FindCommand --
- *
- * Searches for a command.
- *
- * Results:
- * Returns a token for the command if it is found. Otherwise, if it can't
- * be found or there is an error, returns NULL and leaves an error
- * message in the interpreter's result object if "flags" contains
- * TCL_LEAVE_ERR_MSG.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Command
-Tcl_FindCommand(
- Tcl_Interp *interp, /* The interpreter in which to find the
- * command and to report errors. */
- const char *name, /* Command's name. If it starts with "::",
- * will be looked up in global namespace.
- * Else, looked up first in contextNsPtr
- * (current namespace if contextNsPtr is
- * NULL), then in global namespace. */
- Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag set.
- * Otherwise, points to namespace in which to
- * resolve name. If NULL, look up name in the
- * current namespace. */
- int flags) /* An OR'd combination of flags:
- * TCL_GLOBAL_ONLY (look up name only in
- * global namespace), TCL_NAMESPACE_ONLY (look
- * up only in contextNsPtr, or the current
- * namespace if contextNsPtr is NULL), and
- * TCL_LEAVE_ERR_MSG. If both TCL_GLOBAL_ONLY
- * and TCL_NAMESPACE_ONLY are given,
- * TCL_GLOBAL_ONLY is ignored. */
-{
- Interp *iPtr = (Interp *) interp;
- Namespace *cxtNsPtr;
- register Tcl_HashEntry *entryPtr;
- register Command *cmdPtr;
- const char *simpleName;
- int result;
-
- /*
- * If this namespace has a command resolver, then give it first crack at
- * the command resolution. If the interpreter has any command resolvers,
- * consult them next. The command resolver functions may return a
- * Tcl_Command value, they may signal to continue onward, or they may
- * signal an error.
- */
-
- if ((flags & TCL_GLOBAL_ONLY) || !strncmp(name, "::", 2)) {
- cxtNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
- } else if (contextNsPtr != NULL) {
- cxtNsPtr = (Namespace *) contextNsPtr;
- } else {
- cxtNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- }
-
- if (cxtNsPtr->cmdResProc != NULL || iPtr->resolverPtr != NULL) {
- ResolverScheme *resPtr = iPtr->resolverPtr;
- Tcl_Command cmd;
-
- if (cxtNsPtr->cmdResProc) {
- result = cxtNsPtr->cmdResProc(interp, name,
- (Tcl_Namespace *) cxtNsPtr, flags, &cmd);
- } else {
- result = TCL_CONTINUE;
- }
-
- while (result == TCL_CONTINUE && resPtr) {
- if (resPtr->cmdResProc) {
- result = resPtr->cmdResProc(interp, name,
- (Tcl_Namespace *) cxtNsPtr, flags, &cmd);
- }
- resPtr = resPtr->nextPtr;
- }
-
- if (result == TCL_OK) {
- return cmd;
- } else if (result != TCL_CONTINUE) {
- return NULL;
- }
- }
-
- /*
- * Find the namespace(s) that contain the command.
- */
-
- cmdPtr = NULL;
- if (cxtNsPtr->commandPathLength!=0 && strncmp(name, "::", 2)
- && !(flags & TCL_NAMESPACE_ONLY)) {
- int i;
- Namespace *pathNsPtr, *realNsPtr, *dummyNsPtr;
-
- (void) TclGetNamespaceForQualName(interp, name, cxtNsPtr,
- TCL_NAMESPACE_ONLY, &realNsPtr, &dummyNsPtr, &dummyNsPtr,
- &simpleName);
- if ((realNsPtr != NULL) && (simpleName != NULL)) {
- if ((cxtNsPtr == realNsPtr)
- || !(realNsPtr->flags & NS_DYING)) {
- entryPtr = Tcl_FindHashEntry(&realNsPtr->cmdTable, simpleName);
- if (entryPtr != NULL) {
- cmdPtr = Tcl_GetHashValue(entryPtr);
- }
- }
- }
-
- /*
- * Next, check along the path.
- */
-
- for (i=0 ; i<cxtNsPtr->commandPathLength && cmdPtr==NULL ; i++) {
- pathNsPtr = cxtNsPtr->commandPathArray[i].nsPtr;
- if (pathNsPtr == NULL) {
- continue;
- }
- (void) TclGetNamespaceForQualName(interp, name, pathNsPtr,
- TCL_NAMESPACE_ONLY, &realNsPtr, &dummyNsPtr, &dummyNsPtr,
- &simpleName);
- if ((realNsPtr != NULL) && (simpleName != NULL)
- && !(realNsPtr->flags & NS_DYING)) {
- entryPtr = Tcl_FindHashEntry(&realNsPtr->cmdTable, simpleName);
- if (entryPtr != NULL) {
- cmdPtr = Tcl_GetHashValue(entryPtr);
- }
- }
- }
-
- /*
- * If we've still not found the command, look in the global namespace
- * as a last resort.
- */
-
- if (cmdPtr == NULL) {
- (void) TclGetNamespaceForQualName(interp, name, NULL,
- TCL_GLOBAL_ONLY, &realNsPtr, &dummyNsPtr, &dummyNsPtr,
- &simpleName);
- if ((realNsPtr != NULL) && (simpleName != NULL)
- && !(realNsPtr->flags & NS_DYING)) {
- entryPtr = Tcl_FindHashEntry(&realNsPtr->cmdTable, simpleName);
- if (entryPtr != NULL) {
- cmdPtr = Tcl_GetHashValue(entryPtr);
- }
- }
- }
- } else {
- Namespace *nsPtr[2];
- register int search;
-
- TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr,
- flags, &nsPtr[0], &nsPtr[1], &cxtNsPtr, &simpleName);
-
- /*
- * Look for the command in the command table of its namespace. Be sure
- * to check both possible search paths: from the specified namespace
- * context and from the global namespace.
- */
-
- for (search = 0; (search < 2) && (cmdPtr == NULL); search++) {
- if ((nsPtr[search] != NULL) && (simpleName != NULL)) {
- entryPtr = Tcl_FindHashEntry(&nsPtr[search]->cmdTable,
- simpleName);
- if (entryPtr != NULL) {
- cmdPtr = Tcl_GetHashValue(entryPtr);
- }
- }
- }
- }
-
- if (cmdPtr != NULL) {
- return (Tcl_Command) cmdPtr;
- }
-
- if (flags & TCL_LEAVE_ERR_MSG) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unknown command \"%s\"", name));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", name, NULL);
- }
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclResetShadowedCmdRefs --
- *
- * Called when a command is added to a namespace to check for existing
- * command references that the new command may invalidate. Consider the
- * following cases that could happen when you add a command "foo" to a
- * namespace "b":
- * 1. It could shadow a command named "foo" at the global scope. If
- * it does, all command references in the namespace "b" are
- * suspect.
- * 2. Suppose the namespace "b" resides in a namespace "a". Then to
- * "a" the new command "b::foo" could shadow another command
- * "b::foo" in the global namespace. If so, then all command
- * references in "a" * are suspect.
- * The same checks are applied to all parent namespaces, until we reach
- * the global :: namespace.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If the new command shadows an existing command, the cmdRefEpoch
- * counter is incremented in each namespace that sees the shadow. This
- * invalidates all command references that were previously cached in that
- * namespace. The next time the commands are used, they are resolved from
- * scratch.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclResetShadowedCmdRefs(
- Tcl_Interp *interp, /* Interpreter containing the new command. */
- Command *newCmdPtr) /* Points to the new command. */
-{
- char *cmdName;
- Tcl_HashEntry *hPtr;
- register Namespace *nsPtr;
- Namespace *trailNsPtr, *shadowNsPtr;
- Namespace *globalNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
- int found, i;
- int trailFront = -1;
- int trailSize = 5; /* Formerly NUM_TRAIL_ELEMS. */
- Namespace **trailPtr = TclStackAlloc(interp,
- trailSize * sizeof(Namespace *));
-
- /*
- * Start at the namespace containing the new command, and work up through
- * the list of parents. Stop just before the global namespace, since the
- * global namespace can't "shadow" its own entries.
- *
- * The namespace "trail" list we build consists of the names of each
- * namespace that encloses the new command, in order from outermost to
- * innermost: for example, "a" then "b". Each iteration of this loop
- * eventually extends the trail upwards by one namespace, nsPtr. We use
- * this trail list to see if nsPtr (e.g. "a" in 2. above) could have
- * now-invalid cached command references. This will happen if nsPtr
- * (e.g. "a") contains a sequence of child namespaces (e.g. "b") such that
- * there is a identically-named sequence of child namespaces starting from
- * :: (e.g. "::b") whose tail namespace contains a command also named
- * cmdName.
- */
-
- cmdName = Tcl_GetHashKey(newCmdPtr->hPtr->tablePtr, newCmdPtr->hPtr);
- for (nsPtr=newCmdPtr->nsPtr ; (nsPtr!=NULL) && (nsPtr!=globalNsPtr) ;
- nsPtr=nsPtr->parentPtr) {
- /*
- * Find the maximal sequence of child namespaces contained in nsPtr
- * such that there is a identically-named sequence of child namespaces
- * starting from ::. shadowNsPtr will be the tail of this sequence, or
- * the deepest namespace under :: that might contain a command now
- * shadowed by cmdName. We check below if shadowNsPtr actually
- * contains a command cmdName.
- */
-
- found = 1;
- shadowNsPtr = globalNsPtr;
-
- for (i = trailFront; i >= 0; i--) {
- trailNsPtr = trailPtr[i];
-#ifndef BREAK_NAMESPACE_COMPAT
- hPtr = Tcl_FindHashEntry(&shadowNsPtr->childTable,
- trailNsPtr->name);
-#else
- if (shadowNsPtr->childTablePtr != NULL) {
- hPtr = Tcl_FindHashEntry(shadowNsPtr->childTablePtr,
- trailNsPtr->name);
- } else {
- hPtr = NULL;
- }
-#endif
- if (hPtr != NULL) {
- shadowNsPtr = Tcl_GetHashValue(hPtr);
- } else {
- found = 0;
- break;
- }
- }
-
- /*
- * If shadowNsPtr contains a command named cmdName, we invalidate all
- * of the command refs cached in nsPtr. As a boundary case,
- * shadowNsPtr is initially :: and we check for case 1. above.
- */
-
- if (found) {
- hPtr = Tcl_FindHashEntry(&shadowNsPtr->cmdTable, cmdName);
- if (hPtr != NULL) {
- nsPtr->cmdRefEpoch++;
- TclInvalidateNsPath(nsPtr);
-
- /*
- * If the shadowed command was compiled to bytecodes, we
- * invalidate all the bytecodes in nsPtr, to force a new
- * compilation. We use the resolverEpoch to signal the need
- * for a fresh compilation of every bytecode.
- */
-
- if (((Command *)Tcl_GetHashValue(hPtr))->compileProc != NULL){
- nsPtr->resolverEpoch++;
- }
- }
- }
-
- /*
- * Insert nsPtr at the front of the trail list: i.e., at the end of
- * the trailPtr array.
- */
-
- trailFront++;
- if (trailFront == trailSize) {
- int newSize = 2 * trailSize;
-
- trailPtr = TclStackRealloc(interp, trailPtr,
- newSize * sizeof(Namespace *));
- trailSize = newSize;
- }
- trailPtr[trailFront] = nsPtr;
- }
- TclStackFree(interp, trailPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclGetNamespaceFromObj, GetNamespaceFromObj --
- *
- * Gets the namespace specified by the name in a Tcl_Obj.
- *
- * Results:
- * Returns TCL_OK if the namespace was resolved successfully, and stores
- * a pointer to the namespace in the location specified by nsPtrPtr. If
- * the namespace can't be found, or anything else goes wrong, this
- * function returns TCL_ERROR and writes an error message to interp,
- * if non-NULL.
- *
- * Side effects:
- * May update the internal representation for the object, caching the
- * namespace reference. The next time this function is called, the
- * namespace value can be found quickly.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclGetNamespaceFromObj(
- Tcl_Interp *interp, /* The current interpreter. */
- Tcl_Obj *objPtr, /* The object to be resolved as the name of a
- * namespace. */
- Tcl_Namespace **nsPtrPtr) /* Result namespace pointer goes here. */
-{
- if (GetNamespaceFromObj(interp, objPtr, nsPtrPtr) == TCL_ERROR) {
- const char *name = TclGetString(objPtr);
-
- if ((name[0] == ':') && (name[1] == ':')) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "namespace \"%s\" not found", name));
- } else {
- /*
- * Get the current namespace name.
- */
-
- NamespaceCurrentCmd(NULL, interp, 1, NULL);
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "namespace \"%s\" not found in \"%s\"", name,
- Tcl_GetStringResult(interp)));
- }
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", name, NULL);
- return TCL_ERROR;
- }
- return TCL_OK;
-}
-
-static int
-GetNamespaceFromObj(
- Tcl_Interp *interp, /* The current interpreter. */
- Tcl_Obj *objPtr, /* The object to be resolved as the name of a
- * namespace. */
- Tcl_Namespace **nsPtrPtr) /* Result namespace pointer goes here. */
-{
- ResolvedNsName *resNamePtr;
- Namespace *nsPtr, *refNsPtr;
-
- if (objPtr->typePtr == &nsNameType) {
- /*
- * Check that the ResolvedNsName is still valid; avoid letting the ref
- * cross interps.
- */
-
- resNamePtr = objPtr->internalRep.twoPtrValue.ptr1;
- nsPtr = resNamePtr->nsPtr;
- refNsPtr = resNamePtr->refNsPtr;
- if (!(nsPtr->flags & NS_DYING) && (interp == nsPtr->interp) &&
- (!refNsPtr || ((interp == refNsPtr->interp) &&
- (refNsPtr== (Namespace *) Tcl_GetCurrentNamespace(interp))))){
- *nsPtrPtr = (Tcl_Namespace *) nsPtr;
- return TCL_OK;
- }
- }
- if (SetNsNameFromAny(interp, objPtr) == TCL_OK) {
- resNamePtr = objPtr->internalRep.twoPtrValue.ptr1;
- *nsPtrPtr = (Tcl_Namespace *) resNamePtr->nsPtr;
- return TCL_OK;
- }
- return TCL_ERROR;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclInitNamespaceCmd --
- *
- * This function is called to create the "namespace" Tcl command. See the
- * user documentation for details on what it does.
- *
- * Results:
- * Handle for the namespace command, or NULL on failure.
- *
- * Side effects:
- * none
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Command
-TclInitNamespaceCmd(
- Tcl_Interp *interp) /* Current interpreter. */
-{
- return TclMakeEnsemble(interp, "namespace", defaultNamespaceMap);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceChildrenCmd --
- *
- * Invoked to implement the "namespace children" command that returns a
- * list containing the fully-qualified names of the child namespaces of a
- * given namespace. Handles the following syntax:
- *
- * namespace children ?name? ?pattern?
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns a result in the interpreter's result object. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceChildrenCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Tcl_Namespace *namespacePtr;
- Namespace *nsPtr, *childNsPtr;
- Namespace *globalNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
- const char *pattern = NULL;
- Tcl_DString buffer;
- register Tcl_HashEntry *entryPtr;
- Tcl_HashSearch search;
- Tcl_Obj *listPtr, *elemPtr;
-
- /*
- * Get a pointer to the specified namespace, or the current namespace.
- */
-
- if (objc == 1) {
- nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- } else if ((objc == 2) || (objc == 3)) {
- if (TclGetNamespaceFromObj(interp, objv[1], &namespacePtr) != TCL_OK){
- return TCL_ERROR;
- }
- nsPtr = (Namespace *) namespacePtr;
- } else {
- Tcl_WrongNumArgs(interp, 1, objv, "?name? ?pattern?");
- return TCL_ERROR;
- }
-
- /*
- * Get the glob-style pattern, if any, used to narrow the search.
- */
-
- Tcl_DStringInit(&buffer);
- if (objc == 3) {
- const char *name = TclGetString(objv[2]);
-
- if ((*name == ':') && (*(name+1) == ':')) {
- pattern = name;
- } else {
- Tcl_DStringAppend(&buffer, nsPtr->fullName, -1);
- if (nsPtr != globalNsPtr) {
- TclDStringAppendLiteral(&buffer, "::");
- }
- Tcl_DStringAppend(&buffer, name, -1);
- pattern = Tcl_DStringValue(&buffer);
- }
- }
-
- /*
- * Create a list containing the full names of all child namespaces whose
- * names match the specified pattern, if any.
- */
-
- listPtr = Tcl_NewListObj(0, NULL);
- if ((pattern != NULL) && TclMatchIsTrivial(pattern)) {
- unsigned int length = strlen(nsPtr->fullName);
-
- if (strncmp(pattern, nsPtr->fullName, length) != 0) {
- goto searchDone;
- }
- if (
-#ifndef BREAK_NAMESPACE_COMPAT
- Tcl_FindHashEntry(&nsPtr->childTable, pattern+length) != NULL
-#else
- nsPtr->childTablePtr != NULL &&
- Tcl_FindHashEntry(nsPtr->childTablePtr, pattern+length) != NULL
-#endif
- ) {
- Tcl_ListObjAppendElement(interp, listPtr,
- Tcl_NewStringObj(pattern, -1));
- }
- goto searchDone;
- }
-#ifndef BREAK_NAMESPACE_COMPAT
- entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search);
-#else
- if (nsPtr->childTablePtr == NULL) {
- goto searchDone;
- }
- entryPtr = Tcl_FirstHashEntry(nsPtr->childTablePtr, &search);
-#endif
- while (entryPtr != NULL) {
- childNsPtr = Tcl_GetHashValue(entryPtr);
- if ((pattern == NULL)
- || Tcl_StringMatch(childNsPtr->fullName, pattern)) {
- elemPtr = Tcl_NewStringObj(childNsPtr->fullName, -1);
- Tcl_ListObjAppendElement(interp, listPtr, elemPtr);
- }
- entryPtr = Tcl_NextHashEntry(&search);
- }
-
- searchDone:
- Tcl_SetObjResult(interp, listPtr);
- Tcl_DStringFree(&buffer);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceCodeCmd --
- *
- * Invoked to implement the "namespace code" command to capture the
- * namespace context of a command. Handles the following syntax:
- *
- * namespace code arg
- *
- * Here "arg" can be a list. "namespace code arg" produces a result
- * equivalent to that produced by the command
- *
- * list ::namespace inscope [namespace current] $arg
- *
- * However, if "arg" is itself a scoped value starting with "::namespace
- * inscope", then the result is just "arg".
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * If anything goes wrong, this function returns an error message as the
- * result in the interpreter's result object.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceCodeCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Namespace *currNsPtr;
- Tcl_Obj *listPtr, *objPtr;
- register const char *arg;
- int length;
-
- if (objc != 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "arg");
- return TCL_ERROR;
- }
-
- /*
- * If "arg" is already a scoped value, then return it directly.
- * Take care to only check for scoping in precisely the style that
- * [::namespace code] generates it. Anything more forgiving can have
- * the effect of failing in namespaces that contain their own custom
- " "namespace" command. [Bug 3202171].
- */
-
- arg = TclGetStringFromObj(objv[1], &length);
- if (*arg==':' && length > 20
- && strncmp(arg, "::namespace inscope ", 20) == 0) {
- Tcl_SetObjResult(interp, objv[1]);
- return TCL_OK;
- }
-
- /*
- * Otherwise, construct a scoped command by building a list with
- * "namespace inscope", the full name of the current namespace, and the
- * argument "arg". By constructing a list, we ensure that scoped commands
- * are interpreted properly when they are executed later, by the
- * "namespace inscope" command.
- */
-
- TclNewObj(listPtr);
- TclNewLiteralStringObj(objPtr, "::namespace");
- Tcl_ListObjAppendElement(interp, listPtr, objPtr);
- TclNewLiteralStringObj(objPtr, "inscope");
- Tcl_ListObjAppendElement(interp, listPtr, objPtr);
-
- currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- if (currNsPtr == (Namespace *) TclGetGlobalNamespace(interp)) {
- TclNewLiteralStringObj(objPtr, "::");
- } else {
- objPtr = Tcl_NewStringObj(currNsPtr->fullName, -1);
- }
- Tcl_ListObjAppendElement(interp, listPtr, objPtr);
-
- Tcl_ListObjAppendElement(interp, listPtr, objv[1]);
-
- Tcl_SetObjResult(interp, listPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceCurrentCmd --
- *
- * Invoked to implement the "namespace current" command which returns the
- * fully-qualified name of the current namespace. Handles the following
- * syntax:
- *
- * namespace current
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns a result in the interpreter's result object. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceCurrentCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- register Namespace *currNsPtr;
-
- if (objc != 1) {
- Tcl_WrongNumArgs(interp, 1, objv, NULL);
- return TCL_ERROR;
- }
-
- /*
- * The "real" name of the global namespace ("::") is the null string, but
- * we return "::" for it as a convenience to programmers. Note that "" and
- * "::" are treated as synonyms by the namespace code so that it is still
- * easy to do things like:
- *
- * namespace [namespace current]::bar { ... }
- */
-
- currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- if (currNsPtr == (Namespace *) TclGetGlobalNamespace(interp)) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj("::", 2));
- } else {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(currNsPtr->fullName, -1));
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceDeleteCmd --
- *
- * Invoked to implement the "namespace delete" command to delete
- * namespace(s). Handles the following syntax:
- *
- * namespace delete ?name name...?
- *
- * Each name identifies a namespace. It may include a sequence of
- * namespace qualifiers separated by "::"s. If a namespace is found, it
- * is deleted: all variables and procedures contained in that namespace
- * are deleted. If that namespace is being used on the call stack, it is
- * kept alive (but logically deleted) until it is removed from the call
- * stack: that is, it can no longer be referenced by name but any
- * currently executing procedure that refers to it is allowed to do so
- * until the procedure returns. If the namespace can't be found, this
- * function returns an error. If no namespaces are specified, this
- * command does nothing.
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Deletes the specified namespaces. If anything goes wrong, this
- * function returns an error message in the interpreter's result object.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceDeleteCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Tcl_Namespace *namespacePtr;
- const char *name;
- register int i;
-
- if (objc < 1) {
- Tcl_WrongNumArgs(interp, 1, objv, "?name name...?");
- return TCL_ERROR;
- }
-
- /*
- * Destroying one namespace may cause another to be destroyed. Break this
- * into two passes: first check to make sure that all namespaces on the
- * command line are valid, and report any errors.
- */
-
- for (i = 1; i < objc; i++) {
- name = TclGetString(objv[i]);
- namespacePtr = Tcl_FindNamespace(interp, name, NULL, /*flags*/ 0);
- if ((namespacePtr == NULL)
- || (((Namespace *) namespacePtr)->flags & NS_KILLED)) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unknown namespace \"%s\" in namespace delete command",
- TclGetString(objv[i])));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE",
- TclGetString(objv[i]), NULL);
- return TCL_ERROR;
- }
- }
-
- /*
- * Okay, now delete each namespace.
- */
-
- for (i = 1; i < objc; i++) {
- name = TclGetString(objv[i]);
- namespacePtr = Tcl_FindNamespace(interp, name, NULL, /* flags */ 0);
- if (namespacePtr) {
- Tcl_DeleteNamespace(namespacePtr);
- }
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceEvalCmd --
- *
- * Invoked to implement the "namespace eval" command. Executes commands
- * in a namespace. If the namespace does not already exist, it is
- * created. Handles the following syntax:
- *
- * namespace eval name arg ?arg...?
- *
- * If more than one arg argument is specified, the command that is
- * executed is the result of concatenating the arguments together with a
- * space between each argument.
- *
- * Results:
- * Returns TCL_OK if the namespace is found and the commands are executed
- * successfully. Returns TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns the result of the command in the interpreter's result object.
- * If anything goes wrong, this function returns an error message as the
- * result.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceEvalCmd(
- ClientData clientData, /* Arbitrary value passed to cmd. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- return Tcl_NRCallObjProc(interp, NRNamespaceEvalCmd, clientData, objc,
- objv);
-}
-
-static int
-NRNamespaceEvalCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Interp *iPtr = (Interp *) interp;
- CmdFrame *invoker;
- int word;
- Tcl_Namespace *namespacePtr;
- CallFrame *framePtr, **framePtrPtr;
- Tcl_Obj *objPtr;
- int result;
-
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 1, objv, "name arg ?arg...?");
- return TCL_ERROR;
- }
-
- /*
- * Try to resolve the namespace reference, caching the result in the
- * namespace object along the way.
- */
-
- result = GetNamespaceFromObj(interp, objv[1], &namespacePtr);
-
- /*
- * If the namespace wasn't found, try to create it.
- */
-
- if (result == TCL_ERROR) {
- const char *name = TclGetString(objv[1]);
-
- namespacePtr = Tcl_CreateNamespace(interp, name, NULL, NULL);
- if (namespacePtr == NULL) {
- return TCL_ERROR;
- }
- }
-
- /*
- * Make the specified namespace the current namespace and evaluate the
- * command(s).
- */
-
- /* This is needed to satisfy GCC 3.3's strict aliasing rules */
- framePtrPtr = &framePtr;
- (void) TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
- namespacePtr, /*isProcCallFrame*/ 0);
-
- framePtr->objv = TclFetchEnsembleRoot(interp, objv, objc, &framePtr->objc);
-
- if (objc == 3) {
- /*
- * TIP #280: Make actual argument location available to eval'd script.
- */
-
- objPtr = objv[2];
- invoker = iPtr->cmdFramePtr;
- word = 3;
- TclArgumentGet(interp, objPtr, &invoker, &word);
- } else {
- /*
- * More than one argument: concatenate them together with spaces
- * between, then evaluate the result. Tcl_EvalObjEx will delete the
- * object when it decrements its refcount after eval'ing it.
- */
-
- objPtr = Tcl_ConcatObj(objc-2, objv+2);
- invoker = NULL;
- word = 0;
- }
-
- /*
- * TIP #280: Make invoking context available to eval'd script.
- */
-
- TclNRAddCallback(interp, NsEval_Callback, namespacePtr, "eval",
- NULL, NULL);
- return TclNREvalObjEx(interp, objPtr, 0, invoker, word);
-}
-
-static int
-NsEval_Callback(
- ClientData data[],
- Tcl_Interp *interp,
- int result)
-{
- Tcl_Namespace *namespacePtr = data[0];
-
- if (result == TCL_ERROR) {
- int length = strlen(namespacePtr->fullName);
- int limit = 200;
- int overflow = (length > limit);
- char *cmd = data[1];
-
- Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
- "\n (in namespace %s \"%.*s%s\" script line %d)",
- cmd,
- (overflow ? limit : length), namespacePtr->fullName,
- (overflow ? "..." : ""), Tcl_GetErrorLine(interp)));
- }
-
- /*
- * Restore the previous "current" namespace.
- */
-
- TclPopStackFrame(interp);
- return result;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceExistsCmd --
- *
- * Invoked to implement the "namespace exists" command that returns true
- * if the given namespace currently exists, and false otherwise. Handles
- * the following syntax:
- *
- * namespace exists name
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns a result in the interpreter's result object. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceExistsCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Tcl_Namespace *namespacePtr;
-
- if (objc != 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "name");
- return TCL_ERROR;
- }
-
- Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
- GetNamespaceFromObj(interp, objv[1], &namespacePtr) == TCL_OK));
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceExportCmd --
- *
- * Invoked to implement the "namespace export" command that specifies
- * which commands are exported from a namespace. The exported commands
- * are those that can be imported into another namespace using "namespace
- * import". Both commands defined in a namespace and commands the
- * namespace has imported can be exported by a namespace. This command
- * has the following syntax:
- *
- * namespace export ?-clear? ?pattern pattern...?
- *
- * Each pattern may contain "string match"-style pattern matching special
- * characters, but the pattern may not include any namespace qualifiers:
- * that is, the pattern must specify commands in the current (exporting)
- * namespace. The specified patterns are appended onto the namespace's
- * list of export patterns.
- *
- * To reset the namespace's export pattern list, specify the "-clear"
- * flag.
- *
- * If there are no export patterns and the "-clear" flag isn't given,
- * this command returns the namespace's current export list.
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns a result in the interpreter's result object. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceExportCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- int firstArg, i;
-
- if (objc < 1) {
- Tcl_WrongNumArgs(interp, 1, objv, "?-clear? ?pattern pattern...?");
- return TCL_ERROR;
- }
-
- /*
- * If no pattern arguments are given, and "-clear" isn't specified, return
- * the namespace's current export pattern list.
- */
-
- if (objc == 1) {
- Tcl_Obj *listPtr = Tcl_NewObj();
-
- (void) Tcl_AppendExportList(interp, NULL, listPtr);
- Tcl_SetObjResult(interp, listPtr);
- return TCL_OK;
- }
-
- /*
- * Process the optional "-clear" argument.
- */
-
- firstArg = 1;
- if (strcmp("-clear", Tcl_GetString(objv[firstArg])) == 0) {
- Tcl_Export(interp, NULL, "::", 1);
- Tcl_ResetResult(interp);
- firstArg++;
- }
-
- /*
- * Add each pattern to the namespace's export pattern list.
- */
-
- for (i = firstArg; i < objc; i++) {
- int result = Tcl_Export(interp, NULL, Tcl_GetString(objv[i]), 0);
- if (result != TCL_OK) {
- return result;
- }
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceForgetCmd --
- *
- * Invoked to implement the "namespace forget" command to remove imported
- * commands from a namespace. Handles the following syntax:
- *
- * namespace forget ?pattern pattern...?
- *
- * Each pattern is a name like "foo::*" or "a::b::x*". That is, the
- * pattern may include the special pattern matching characters recognized
- * by the "string match" command, but only in the command name at the end
- * of the qualified name; the special pattern characters may not appear
- * in a namespace name. All of the commands that match that pattern are
- * checked to see if they have an imported command in the current
- * namespace that refers to the matched command. If there is an alias, it
- * is removed.
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Imported commands are removed from the current namespace. If anything
- * goes wrong, this function returns an error message in the
- * interpreter's result object.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceForgetCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- const char *pattern;
- register int i, result;
-
- if (objc < 1) {
- Tcl_WrongNumArgs(interp, 1, objv, "?pattern pattern...?");
- return TCL_ERROR;
- }
-
- for (i = 1; i < objc; i++) {
- pattern = TclGetString(objv[i]);
- result = Tcl_ForgetImport(interp, NULL, pattern);
- if (result != TCL_OK) {
- return result;
- }
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceImportCmd --
- *
- * Invoked to implement the "namespace import" command that imports
- * commands into a namespace. Handles the following syntax:
- *
- * namespace import ?-force? ?pattern pattern...?
- *
- * Each pattern is a namespace-qualified name like "foo::*", "a::b::x*",
- * or "bar::p". That is, the pattern may include the special pattern
- * matching characters recognized by the "string match" command, but only
- * in the command name at the end of the qualified name; the special
- * pattern characters may not appear in a namespace name. All of the
- * commands that match the pattern and which are exported from their
- * namespace are made accessible from the current namespace context. This
- * is done by creating a new "imported command" in the current namespace
- * that points to the real command in its original namespace; when the
- * imported command is called, it invokes the real command.
- *
- * If an imported command conflicts with an existing command, it is
- * treated as an error. But if the "-force" option is included, then
- * existing commands are overwritten by the imported commands.
- *
- * If there are no pattern arguments and the "-force" flag isn't given,
- * this command returns the list of commands currently imported in
- * the current namespace.
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Adds imported commands to the current namespace. If anything goes
- * wrong, this function returns an error message in the interpreter's
- * result object.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceImportCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- int allowOverwrite = 0;
- const char *string, *pattern;
- register int i, result;
- int firstArg;
-
- if (objc < 1) {
- Tcl_WrongNumArgs(interp, 1, objv, "?-force? ?pattern pattern...?");
- return TCL_ERROR;
- }
-
- /*
- * Skip over the optional "-force" as the first argument.
- */
-
- firstArg = 1;
- if (firstArg < objc) {
- string = TclGetString(objv[firstArg]);
- if ((*string == '-') && (strcmp(string, "-force") == 0)) {
- allowOverwrite = 1;
- firstArg++;
- }
- } else {
- /*
- * When objc == 1, command is just [namespace import]. Introspection
- * form to return list of imported commands.
- */
-
- Tcl_HashEntry *hPtr;
- Tcl_HashSearch search;
- Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- Tcl_Obj *listPtr;
-
- TclNewObj(listPtr);
- for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
- hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
- Command *cmdPtr = Tcl_GetHashValue(hPtr);
-
- if (cmdPtr->deleteProc == DeleteImportedCmd) {
- Tcl_ListObjAppendElement(NULL, listPtr, Tcl_NewStringObj(
- Tcl_GetHashKey(&nsPtr->cmdTable, hPtr) ,-1));
- }
- }
- Tcl_SetObjResult(interp, listPtr);
- return TCL_OK;
- }
-
- /*
- * Handle the imports for each of the patterns.
- */
-
- for (i = firstArg; i < objc; i++) {
- pattern = TclGetString(objv[i]);
- result = Tcl_Import(interp, NULL, pattern, allowOverwrite);
- if (result != TCL_OK) {
- return result;
- }
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceInscopeCmd --
- *
- * Invoked to implement the "namespace inscope" command that executes a
- * script in the context of a particular namespace. This command is not
- * expected to be used directly by programmers; calls to it are generated
- * implicitly when programs use "namespace code" commands to register
- * callback scripts. Handles the following syntax:
- *
- * namespace inscope name arg ?arg...?
- *
- * The "namespace inscope" command is much like the "namespace eval"
- * command except that it has lappend semantics and the namespace must
- * already exist. It treats the first argument as a list, and appends any
- * arguments after the first onto the end as proper list elements. For
- * example,
- *
- * namespace inscope ::foo {a b} c d e
- *
- * is equivalent to
- *
- * namespace eval ::foo [concat {a b} [list c d e]]
- *
- * This lappend semantics is important because many callback scripts are
- * actually prefixes.
- *
- * Results:
- * Returns TCL_OK to indicate success, or TCL_ERROR to indicate failure.
- *
- * Side effects:
- * Returns a result in the Tcl interpreter's result object.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceInscopeCmd(
- ClientData clientData, /* Arbitrary value passed to cmd. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- return Tcl_NRCallObjProc(interp, NRNamespaceInscopeCmd, clientData, objc,
- objv);
-}
-
-static int
-NRNamespaceInscopeCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Tcl_Namespace *namespacePtr;
- CallFrame *framePtr, **framePtrPtr;
- int i;
- Tcl_Obj *cmdObjPtr;
-
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 1, objv, "name arg ?arg...?");
- return TCL_ERROR;
- }
-
- /*
- * Resolve the namespace reference.
- */
-
- if (TclGetNamespaceFromObj(interp, objv[1], &namespacePtr) != TCL_OK) {
- return TCL_ERROR;
- }
-
- /*
- * Make the specified namespace the current namespace.
- */
-
- framePtrPtr = &framePtr; /* This is needed to satisfy GCC's
- * strict aliasing rules. */
- (void) TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
- namespacePtr, /*isProcCallFrame*/ 0);
-
- framePtr->objv = TclFetchEnsembleRoot(interp, objv, objc, &framePtr->objc);
-
- /*
- * Execute the command. If there is just one argument, just treat it as a
- * script and evaluate it. Otherwise, create a list from the arguments
- * after the first one, then concatenate the first argument and the list
- * of extra arguments to form the command to evaluate.
- */
-
- if (objc == 3) {
- cmdObjPtr = objv[2];
- } else {
- Tcl_Obj *concatObjv[2];
- register Tcl_Obj *listPtr;
-
- listPtr = Tcl_NewListObj(0, NULL);
- for (i = 3; i < objc; i++) {
- if (Tcl_ListObjAppendElement(interp, listPtr, objv[i]) != TCL_OK){
- Tcl_DecrRefCount(listPtr); /* Free unneeded obj. */
- return TCL_ERROR;
- }
- }
-
- concatObjv[0] = objv[2];
- concatObjv[1] = listPtr;
- cmdObjPtr = Tcl_ConcatObj(2, concatObjv);
- Tcl_DecrRefCount(listPtr); /* We're done with the list object. */
- }
-
- TclNRAddCallback(interp, NsEval_Callback, namespacePtr, "inscope",
- NULL, NULL);
- return TclNREvalObjEx(interp, cmdObjPtr, 0, NULL, 0);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceOriginCmd --
- *
- * Invoked to implement the "namespace origin" command to return the
- * fully-qualified name of the "real" command to which the specified
- * "imported command" refers. Handles the following syntax:
- *
- * namespace origin name
- *
- * Results:
- * An imported command is created in an namespace when that namespace
- * imports a command from another namespace. If a command is imported
- * into a sequence of namespaces a, b,...,n where each successive
- * namespace just imports the command from the previous namespace, this
- * command returns the fully-qualified name of the original command in
- * the first namespace, a. If "name" does not refer to an alias, its
- * fully-qualified name is returned. The returned name is stored in the
- * interpreter's result object. This function returns TCL_OK if
- * successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * If anything goes wrong, this function returns an error message in the
- * interpreter's result object.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceOriginCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Tcl_Command command, origCommand;
- Tcl_Obj *resultPtr;
-
- if (objc != 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "name");
- return TCL_ERROR;
- }
-
- command = Tcl_GetCommandFromObj(interp, objv[1]);
- if (command == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "invalid command name \"%s\"", TclGetString(objv[1])));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND",
- TclGetString(objv[1]), NULL);
- return TCL_ERROR;
- }
- origCommand = TclGetOriginalCommand(command);
- TclNewObj(resultPtr);
- if (origCommand == NULL) {
- /*
- * The specified command isn't an imported command. Return the
- * command's name qualified by the full name of the namespace it was
- * defined in.
- */
-
- Tcl_GetCommandFullName(interp, command, resultPtr);
- } else {
- Tcl_GetCommandFullName(interp, origCommand, resultPtr);
- }
- Tcl_SetObjResult(interp, resultPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceParentCmd --
- *
- * Invoked to implement the "namespace parent" command that returns the
- * fully-qualified name of the parent namespace for a specified
- * namespace. Handles the following syntax:
- *
- * namespace parent ?name?
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns a result in the interpreter's result object. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceParentCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Tcl_Namespace *nsPtr;
-
- if (objc == 1) {
- nsPtr = TclGetCurrentNamespace(interp);
- } else if (objc == 2) {
- if (TclGetNamespaceFromObj(interp, objv[1], &nsPtr) != TCL_OK) {
- return TCL_ERROR;
- }
- } else {
- Tcl_WrongNumArgs(interp, 1, objv, "?name?");
- return TCL_ERROR;
- }
-
- /*
- * Report the parent of the specified namespace.
- */
-
- if (nsPtr->parentPtr != NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- nsPtr->parentPtr->fullName, -1));
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespacePathCmd --
- *
- * Invoked to implement the "namespace path" command that reads and
- * writes the current namespace's command resolution path. Has one
- * optional argument: if present, it is a list of named namespaces to set
- * the path to, and if absent, the current path should be returned.
- * Handles the following syntax:
- *
- * namespace path ?nsList?
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong
- * (most notably if the namespace list contains the name of something
- * other than a namespace). In the successful-exit case, may set the
- * interpreter result to the list of names of the namespaces on the
- * current namespace's path.
- *
- * Side effects:
- * May update the namespace path (triggering a recomputing of all command
- * names that depend on the namespace for resolution).
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespacePathCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
- int i, nsObjc, result = TCL_ERROR;
- Tcl_Obj **nsObjv;
- Tcl_Namespace **namespaceList = NULL;
-
- if (objc > 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "?pathList?");
- return TCL_ERROR;
- }
-
- /*
- * If no path is given, return the current path.
- */
-
- if (objc == 1) {
- Tcl_Obj *resultObj = Tcl_NewObj();
-
- for (i=0 ; i<nsPtr->commandPathLength ; i++) {
- if (nsPtr->commandPathArray[i].nsPtr != NULL) {
- Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj(
- nsPtr->commandPathArray[i].nsPtr->fullName, -1));
- }
- }
- Tcl_SetObjResult(interp, resultObj);
- return TCL_OK;
- }
-
- /*
- * There is a path given, so parse it into an array of namespace pointers.
- */
-
- if (TclListObjGetElements(interp, objv[1], &nsObjc, &nsObjv) != TCL_OK) {
- goto badNamespace;
- }
- if (nsObjc != 0) {
- namespaceList = TclStackAlloc(interp,
- sizeof(Tcl_Namespace *) * nsObjc);
-
- for (i=0 ; i<nsObjc ; i++) {
- if (TclGetNamespaceFromObj(interp, nsObjv[i],
- &namespaceList[i]) != TCL_OK) {
- goto badNamespace;
- }
- }
- }
-
- /*
- * Now we have the list of valid namespaces, install it as the path.
- */
-
- TclSetNsPath(nsPtr, nsObjc, namespaceList);
-
- result = TCL_OK;
- badNamespace:
- if (namespaceList != NULL) {
- TclStackFree(interp, namespaceList);
- }
- return result;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclSetNsPath --
- *
- * Sets the namespace command name resolution path to the given list of
- * namespaces. If the list is empty (of zero length) the path is set to
- * empty and the default old-style behaviour of command name resolution
- * is used.
- *
- * Results:
- * nothing
- *
- * Side effects:
- * Invalidates the command name resolution caches for any command
- * resolved in the given namespace.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclSetNsPath(
- Namespace *nsPtr, /* Namespace whose path is to be set. */
- int pathLength, /* Length of pathAry. */
- Tcl_Namespace *pathAry[]) /* Array of namespaces that are the path. */
-{
- if (pathLength != 0) {
- NamespacePathEntry *tmpPathArray =
- ckalloc(sizeof(NamespacePathEntry) * pathLength);
- int i;
-
- for (i=0 ; i<pathLength ; i++) {
- tmpPathArray[i].nsPtr = (Namespace *) pathAry[i];
- tmpPathArray[i].creatorNsPtr = nsPtr;
- tmpPathArray[i].prevPtr = NULL;
- tmpPathArray[i].nextPtr =
- tmpPathArray[i].nsPtr->commandPathSourceList;
- if (tmpPathArray[i].nextPtr != NULL) {
- tmpPathArray[i].nextPtr->prevPtr = &tmpPathArray[i];
- }
- tmpPathArray[i].nsPtr->commandPathSourceList = &tmpPathArray[i];
- }
- if (nsPtr->commandPathLength != 0) {
- UnlinkNsPath(nsPtr);
- }
- nsPtr->commandPathArray = tmpPathArray;
- } else {
- if (nsPtr->commandPathLength != 0) {
- UnlinkNsPath(nsPtr);
- }
- }
-
- nsPtr->commandPathLength = pathLength;
- nsPtr->cmdRefEpoch++;
- nsPtr->resolverEpoch++;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * UnlinkNsPath --
- *
- * Delete the given namespace's command name resolution path. Only call
- * if the path is non-empty. Caller must reset the counter containing the
- * path size.
- *
- * Results:
- * nothing
- *
- * Side effects:
- * Deletes the array of path entries and unlinks those path entries from
- * the target namespace's list of interested namespaces.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-UnlinkNsPath(
- Namespace *nsPtr)
-{
- int i;
- for (i=0 ; i<nsPtr->commandPathLength ; i++) {
- NamespacePathEntry *nsPathPtr = &nsPtr->commandPathArray[i];
-
- if (nsPathPtr->prevPtr != NULL) {
- nsPathPtr->prevPtr->nextPtr = nsPathPtr->nextPtr;
- }
- if (nsPathPtr->nextPtr != NULL) {
- nsPathPtr->nextPtr->prevPtr = nsPathPtr->prevPtr;
- }
- if (nsPathPtr->nsPtr != NULL) {
- if (nsPathPtr->nsPtr->commandPathSourceList == nsPathPtr) {
- nsPathPtr->nsPtr->commandPathSourceList = nsPathPtr->nextPtr;
- }
- }
- }
- ckfree(nsPtr->commandPathArray);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclInvalidateNsPath --
- *
- * Invalidate the name resolution caches for all names looked up in
- * namespaces whose name path includes the given namespace.
- *
- * Results:
- * nothing
- *
- * Side effects:
- * Increments the command reference epoch in each namespace whose path
- * includes the given namespace. This causes any cached resolved names
- * whose root cacheing context starts at that namespace to be recomputed
- * the next time they are used.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclInvalidateNsPath(
- Namespace *nsPtr)
-{
- NamespacePathEntry *nsPathPtr = nsPtr->commandPathSourceList;
-
- while (nsPathPtr != NULL) {
- if (nsPathPtr->nsPtr != NULL) {
- nsPathPtr->creatorNsPtr->cmdRefEpoch++;
- }
- nsPathPtr = nsPathPtr->nextPtr;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceQualifiersCmd --
- *
- * Invoked to implement the "namespace qualifiers" command that returns
- * any leading namespace qualifiers in a string. These qualifiers are
- * namespace names separated by "::"s. For example, for "::foo::p" this
- * command returns "::foo", and for "::" it returns "". This command is
- * the complement of the "namespace tail" command. Note that this command
- * does not check whether the "namespace" names are, in fact, the names
- * of currently defined namespaces. Handles the following syntax:
- *
- * namespace qualifiers string
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns a result in the interpreter's result object. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceQualifiersCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- register const char *name, *p;
- int length;
-
- if (objc != 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "string");
- return TCL_ERROR;
- }
-
- /*
- * Find the end of the string, then work backward and find the start of
- * the last "::" qualifier.
- */
-
- name = TclGetString(objv[1]);
- for (p = name; *p != '\0'; p++) {
- /* empty body */
- }
- while (--p >= name) {
- if ((*p == ':') && (p > name) && (*(p-1) == ':')) {
- p -= 2; /* Back up over the :: */
- while ((p >= name) && (*p == ':')) {
- p--; /* Back up over the preceeding : */
- }
- break;
- }
- }
-
- if (p >= name) {
- length = p-name+1;
- Tcl_SetObjResult(interp, Tcl_NewStringObj(name, length));
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceUnknownCmd --
- *
- * Invoked to implement the "namespace unknown" command (TIP 181) that
- * sets or queries a per-namespace unknown command handler. This handler
- * is called when command lookup fails (current and global ns). The
- * default handler for the global namespace is ::unknown. The default
- * handler for other namespaces is to call the global namespace unknown
- * handler. Passing an empty list results in resetting the handler to its
- * default.
- *
- * namespace unknown ?handler?
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * If no handler is specified, returns a result in the interpreter's
- * result object, otherwise it sets the unknown handler pointer in the
- * current namespace to the script fragment provided. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceUnknownCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Tcl_Namespace *currNsPtr;
- Tcl_Obj *resultPtr;
- int rc;
-
- if (objc > 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "?script?");
- return TCL_ERROR;
- }
-
- currNsPtr = TclGetCurrentNamespace(interp);
-
- if (objc == 1) {
- /*
- * Introspection - return the current namespace handler.
- */
-
- resultPtr = Tcl_GetNamespaceUnknownHandler(interp, currNsPtr);
- if (resultPtr == NULL) {
- TclNewObj(resultPtr);
- }
- Tcl_SetObjResult(interp, resultPtr);
- } else {
- rc = Tcl_SetNamespaceUnknownHandler(interp, currNsPtr, objv[1]);
- if (rc == TCL_OK) {
- Tcl_SetObjResult(interp, objv[1]);
- }
- return rc;
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_GetNamespaceUnknownHandler --
- *
- * Returns the unknown command handler registered for the given
- * namespace.
- *
- * Results:
- * Returns the current unknown command handler, or NULL if none exists
- * for the namespace.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Obj *
-Tcl_GetNamespaceUnknownHandler(
- Tcl_Interp *interp, /* The interpreter in which the namespace
- * exists. */
- Tcl_Namespace *nsPtr) /* The namespace. */
-{
- Namespace *currNsPtr = (Namespace *) nsPtr;
-
- if (currNsPtr->unknownHandlerPtr == NULL &&
- currNsPtr == ((Interp *) interp)->globalNsPtr) {
- /*
- * Default handler for global namespace is "::unknown". For all other
- * namespaces, it is NULL (which falls back on the global unknown
- * handler).
- */
-
- TclNewLiteralStringObj(currNsPtr->unknownHandlerPtr, "::unknown");
- Tcl_IncrRefCount(currNsPtr->unknownHandlerPtr);
- }
- return currNsPtr->unknownHandlerPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_SetNamespaceUnknownHandler --
- *
- * Sets the unknown command handler for the given namespace to the
- * command prefix passed.
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Sets the namespace unknown command handler. If the passed in handler
- * is NULL or an empty list, then the handler is reset to its default. If
- * an error occurs, then an error message is left in the interpreter
- * result.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_SetNamespaceUnknownHandler(
- Tcl_Interp *interp, /* Interpreter in which the namespace
- * exists. */
- Tcl_Namespace *nsPtr, /* Namespace which is being updated. */
- Tcl_Obj *handlerPtr) /* The new handler, or NULL to reset. */
-{
- int lstlen = 0;
- Namespace *currNsPtr = (Namespace *) nsPtr;
-
- /*
- * Ensure that we check for errors *first* before we change anything.
- */
-
- if (handlerPtr != NULL) {
- if (TclListObjLength(interp, handlerPtr, &lstlen) != TCL_OK) {
- /*
- * Not a list.
- */
-
- return TCL_ERROR;
- }
- if (lstlen > 0) {
- /*
- * We are going to be saving this handler. Increment the reference
- * count before decrementing the refcount on the previous handler,
- * so that nothing strange can happen if we are told to set the
- * handler to the previous value.
- */
-
- Tcl_IncrRefCount(handlerPtr);
- }
- }
-
- /*
- * Remove old handler next.
- */
-
- if (currNsPtr->unknownHandlerPtr != NULL) {
- Tcl_DecrRefCount(currNsPtr->unknownHandlerPtr);
- }
-
- /*
- * Install the new handler.
- */
-
- if (lstlen > 0) {
- /*
- * Just store the handler. It already has the correct reference count.
- */
-
- currNsPtr->unknownHandlerPtr = handlerPtr;
- } else {
- /*
- * If NULL or an empty list is passed, this resets to the default
- * handler.
- */
-
- currNsPtr->unknownHandlerPtr = NULL;
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceTailCmd --
- *
- * Invoked to implement the "namespace tail" command that returns the
- * trailing name at the end of a string with "::" namespace qualifiers.
- * These qualifiers are namespace names separated by "::"s. For example,
- * for "::foo::p" this command returns "p", and for "::" it returns "".
- * This command is the complement of the "namespace qualifiers" command.
- * Note that this command does not check whether the "namespace" names
- * are, in fact, the names of currently defined namespaces. Handles the
- * following syntax:
- *
- * namespace tail string
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns a result in the interpreter's result object. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceTailCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- register const char *name, *p;
-
- if (objc != 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "string");
- return TCL_ERROR;
- }
-
- /*
- * Find the end of the string, then work backward and find the last "::"
- * qualifier.
- */
-
- name = TclGetString(objv[1]);
- for (p = name; *p != '\0'; p++) {
- /* empty body */
- }
- while (--p > name) {
- if ((*p == ':') && (*(p-1) == ':')) {
- p++; /* Just after the last "::" */
- break;
- }
- }
-
- if (p >= name) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(p, -1));
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceUpvarCmd --
- *
- * Invoked to implement the "namespace upvar" command, that creates
- * variables in the current scope linked to variables in another
- * namespace. Handles the following syntax:
- *
- * namespace upvar ns otherVar myVar ?otherVar myVar ...?
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Creates new variables in the current scope, linked to the
- * corresponding variables in the stipulated nmamespace. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceUpvarCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- Interp *iPtr = (Interp *) interp;
- Tcl_Namespace *nsPtr, *savedNsPtr;
- Var *otherPtr, *arrayPtr;
- const char *myName;
-
- if (objc < 2 || (objc & 1)) {
- Tcl_WrongNumArgs(interp, 1, objv, "ns ?otherVar myVar ...?");
- return TCL_ERROR;
- }
-
- if (TclGetNamespaceFromObj(interp, objv[1], &nsPtr) != TCL_OK) {
- return TCL_ERROR;
- }
-
- objc -= 2;
- objv += 2;
-
- for (; objc>0 ; objc-=2, objv+=2) {
- /*
- * Locate the other variable.
- */
-
- savedNsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
- iPtr->varFramePtr->nsPtr = (Namespace *) nsPtr;
- otherPtr = TclObjLookupVarEx(interp, objv[0], NULL,
- (TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG|TCL_AVOID_RESOLVERS),
- "access", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
- iPtr->varFramePtr->nsPtr = (Namespace *) savedNsPtr;
- if (otherPtr == NULL) {
- return TCL_ERROR;
- }
-
- /*
- * Create the new variable and link it to otherPtr.
- */
-
- myName = TclGetString(objv[1]);
- if (TclPtrMakeUpvar(interp, otherPtr, myName, 0, -1) != TCL_OK) {
- return TCL_ERROR;
- }
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NamespaceWhichCmd --
- *
- * Invoked to implement the "namespace which" command that returns the
- * fully-qualified name of a command or variable. If the specified
- * command or variable does not exist, it returns "". Handles the
- * following syntax:
- *
- * namespace which ?-command? ?-variable? name
- *
- * Results:
- * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
- *
- * Side effects:
- * Returns a result in the interpreter's result object. If anything goes
- * wrong, the result is an error message.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NamespaceWhichCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- static const char *const opts[] = {
- "-command", "-variable", NULL
- };
- int lookupType = 0;
- Tcl_Obj *resultPtr;
-
- if (objc < 2 || objc > 3) {
- badArgs:
- Tcl_WrongNumArgs(interp, 1, objv, "?-command? ?-variable? name");
- return TCL_ERROR;
- } else if (objc == 3) {
- /*
- * Look for a flag controlling the lookup.
- */
-
- if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0,
- &lookupType) != TCL_OK) {
- /*
- * Preserve old style of error message!
- */
-
- Tcl_ResetResult(interp);
- goto badArgs;
- }
- }
-
- TclNewObj(resultPtr);
- switch (lookupType) {
- case 0: { /* -command */
- Tcl_Command cmd = Tcl_GetCommandFromObj(interp, objv[objc-1]);
-
- if (cmd != NULL) {
- Tcl_GetCommandFullName(interp, cmd, resultPtr);
- }
- break;
- }
- case 1: { /* -variable */
- Tcl_Var var = Tcl_FindNamespaceVar(interp,
- TclGetString(objv[objc-1]), NULL, /*flags*/ 0);
-
- if (var != NULL) {
- Tcl_GetVariableFullName(interp, var, resultPtr);
- }
- break;
- }
- }
- Tcl_SetObjResult(interp, resultPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * FreeNsNameInternalRep --
- *
- * Frees the resources associated with a nsName object's internal
- * representation.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Decrements the ref count of any Namespace structure pointed to by the
- * nsName's internal representation. If there are no more references to
- * the namespace, it's structure will be freed.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-FreeNsNameInternalRep(
- register Tcl_Obj *objPtr) /* nsName object with internal representation
- * to free. */
-{
- ResolvedNsName *resNamePtr = objPtr->internalRep.twoPtrValue.ptr1;
-
- /*
- * Decrement the reference count of the namespace. If there are no more
- * references, free it up.
- */
-
- resNamePtr->refCount--;
- if (resNamePtr->refCount == 0) {
- /*
- * Decrement the reference count for the cached namespace. If the
- * namespace is dead, and there are no more references to it, free
- * it.
- */
-
- TclNsDecrRefCount(resNamePtr->nsPtr);
- ckfree(resNamePtr);
- }
- objPtr->typePtr = NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DupNsNameInternalRep --
- *
- * Initializes the internal representation of a nsName object to a copy
- * of the internal representation of another nsName object.
- *
- * Results:
- * None.
- *
- * Side effects:
- * copyPtr's internal rep is set to refer to the same namespace
- * referenced by srcPtr's internal rep. Increments the ref count of the
- * ResolvedNsName structure used to hold the namespace reference.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-DupNsNameInternalRep(
- Tcl_Obj *srcPtr, /* Object with internal rep to copy. */
- register Tcl_Obj *copyPtr) /* Object with internal rep to set. */
-{
- ResolvedNsName *resNamePtr = srcPtr->internalRep.twoPtrValue.ptr1;
-
- copyPtr->internalRep.twoPtrValue.ptr1 = resNamePtr;
- resNamePtr->refCount++;
- copyPtr->typePtr = &nsNameType;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * SetNsNameFromAny --
- *
- * Attempt to generate a nsName internal representation for a Tcl object.
- *
- * Results:
- * Returns TCL_OK if the value could be converted to a proper namespace
- * reference. Otherwise, it returns TCL_ERROR, along with an error
- * message in the interpreter's result object.
- *
- * Side effects:
- * If successful, the object is made a nsName object. Its internal rep is
- * set to point to a ResolvedNsName, which contains a cached pointer to
- * the Namespace. Reference counts are kept on both the ResolvedNsName
- * and the Namespace, so we can keep track of their usage and free them
- * when appropriate.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-SetNsNameFromAny(
- Tcl_Interp *interp, /* Points to the namespace in which to resolve
- * name. Also used for error reporting if not
- * NULL. */
- register Tcl_Obj *objPtr) /* The object to convert. */
-{
- const char *dummy;
- Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr;
- register ResolvedNsName *resNamePtr;
- const char *name;
-
- if (interp == NULL) {
- return TCL_ERROR;
- }
-
- name = TclGetString(objPtr);
- TclGetNamespaceForQualName(interp, name, NULL, TCL_FIND_ONLY_NS,
- &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy);
-
- /*
- * If we found a namespace, then create a new ResolvedNsName structure
- * that holds a reference to it.
- */
-
- if ((nsPtr == NULL) || (nsPtr->flags & NS_DYING)) {
- /*
- * Our failed lookup proves any previously cached nsName intrep is no
- * longer valid. Get rid of it so we no longer waste memory storing
- * it, nor time determining its invalidity again and again.
- */
-
- if (objPtr->typePtr == &nsNameType) {
- TclFreeIntRep(objPtr);
- }
- return TCL_ERROR;
- }
-
- nsPtr->refCount++;
- resNamePtr = ckalloc(sizeof(ResolvedNsName));
- resNamePtr->nsPtr = nsPtr;
- if ((name[0] == ':') && (name[1] == ':')) {
- resNamePtr->refNsPtr = NULL;
- } else {
- resNamePtr->refNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
- }
- resNamePtr->refCount = 1;
- TclFreeIntRep(objPtr);
- objPtr->internalRep.twoPtrValue.ptr1 = resNamePtr;
- objPtr->typePtr = &nsNameType;
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclGetNamespaceCommandTable --
- *
- * Returns the hash table of commands.
- *
- * Results:
- * Pointer to the hash table.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_HashTable *
-TclGetNamespaceCommandTable(
- Tcl_Namespace *nsPtr)
-{
- return &((Namespace *) nsPtr)->cmdTable;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclGetNamespaceChildTable --
- *
- * Returns the hash table of child namespaces.
- *
- * Results:
- * Pointer to the hash table.
- *
- * Side effects:
- * Might allocate memory.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_HashTable *
-TclGetNamespaceChildTable(
- Tcl_Namespace *nsPtr)
-{
- Namespace *nPtr = (Namespace *) nsPtr;
-#ifndef BREAK_NAMESPACE_COMPAT
- return &nPtr->childTable;
-#else
- if (nPtr->childTablePtr == NULL) {
- nPtr->childTablePtr = ckalloc(sizeof(Tcl_HashTable));
- Tcl_InitHashTable(nPtr->childTablePtr, TCL_STRING_KEYS);
- }
- return nPtr->childTablePtr;
-#endif
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclLogCommandInfo --
- *
- * This function is invoked after an error occurs in an interpreter. It
- * adds information to iPtr->errorInfo/errorStack fields to describe the
- * command that was being executed when the error occurred. When pc and
- * tosPtr are non-NULL, conveying a bytecode execution "inner context",
- * and the offending instruction is suitable, that inner context is
- * recorded in errorStack.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Information about the command is added to errorInfo/errorStack and the
- * line number stored internally in the interpreter is set.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclLogCommandInfo(
- Tcl_Interp *interp, /* Interpreter in which to log information. */
- const char *script, /* First character in script containing
- * command (must be <= command). */
- const char *command, /* First character in command that generated
- * the error. */
- int length, /* Number of bytes in command (-1 means use
- * all bytes up to first null byte). */
- const unsigned char *pc, /* Current pc of bytecode execution context */
- Tcl_Obj **tosPtr) /* Current stack of bytecode execution
- * context */
-{
- register const char *p;
- Interp *iPtr = (Interp *) interp;
- int overflow, limit = 150;
- Var *varPtr, *arrayPtr;
-
- if (iPtr->flags & ERR_ALREADY_LOGGED) {
- /*
- * Someone else has already logged error information for this command;
- * we shouldn't add anything more.
- */
-
- return;
- }
-
- if (command != NULL) {
- /*
- * Compute the line number where the error occurred.
- */
-
- iPtr->errorLine = 1;
- for (p = script; p != command; p++) {
- if (*p == '\n') {
- iPtr->errorLine++;
- }
- }
-
- if (length < 0) {
- length = strlen(command);
- }
- overflow = (length > limit);
- Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
- "\n %s\n\"%.*s%s\"", ((iPtr->errorInfo == NULL)
- ? "while executing" : "invoked from within"),
- (overflow ? limit : length), command,
- (overflow ? "..." : "")));
-
- varPtr = TclObjLookupVarEx(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY,
- NULL, 0, 0, &arrayPtr);
- if ((varPtr == NULL) || !TclIsVarTraced(varPtr)) {
- /*
- * Should not happen.
- */
-
- return;
- } else {
- Tcl_HashEntry *hPtr
- = Tcl_FindHashEntry(&iPtr->varTraces, (char *) varPtr);
- VarTrace *tracePtr = Tcl_GetHashValue(hPtr);
-
- if (tracePtr->traceProc != EstablishErrorInfoTraces) {
- /*
- * The most recent trace set on ::errorInfo is not the one the
- * core itself puts on last. This means some other code is
- * tracing the variable, and the additional trace(s) might be
- * write traces that expect the timing of writes to
- * ::errorInfo that existed Tcl releases before 8.5. To
- * satisfy that compatibility need, we write the current
- * -errorinfo value to the ::errorInfo variable.
- */
-
- Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, iPtr->errorInfo,
- TCL_GLOBAL_ONLY);
- }
- }
- }
-
- /*
- * TIP #348
- */
-
- if (Tcl_IsShared(iPtr->errorStack)) {
- Tcl_Obj *newObj;
-
- newObj = Tcl_DuplicateObj(iPtr->errorStack);
- Tcl_DecrRefCount(iPtr->errorStack);
- Tcl_IncrRefCount(newObj);
- iPtr->errorStack = newObj;
- }
- if (iPtr->resetErrorStack) {
- int len;
-
- iPtr->resetErrorStack = 0;
- Tcl_ListObjLength(interp, iPtr->errorStack, &len);
-
- /*
- * Reset while keeping the list intrep as much as possible.
- */
-
- Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
- if (pc != NULL) {
- Tcl_Obj *innerContext;
-
- innerContext = TclGetInnerContext(interp, pc, tosPtr);
- if (innerContext != NULL) {
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
- iPtr->innerLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, innerContext);
- }
- } else if (command != NULL) {
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
- iPtr->innerLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
- Tcl_NewStringObj(command, length));
- }
- }
-
- if (!iPtr->framePtr->objc) {
- /*
- * Special frame, nothing to report.
- */
- } else if (iPtr->varFramePtr != iPtr->framePtr) {
- /*
- * uplevel case, [lappend errorstack UP $relativelevel]
- */
-
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->upLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewIntObj(
- iPtr->framePtr->level - iPtr->varFramePtr->level));
- } else if (iPtr->framePtr != iPtr->rootFramePtr) {
- /*
- * normal case, [lappend errorstack CALL [info level 0]]
- */
-
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->callLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewListObj(
- iPtr->framePtr->objc, iPtr->framePtr->objv));
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclErrorStackResetIf --
- *
- * The TIP 348 reset/no-bc part of TLCI, for specific use by
- * TclCompileSyntaxError.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Reset errorstack if it needs be, and in that case remember the
- * passed-in error message as inner context.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclErrorStackResetIf(
- Tcl_Interp *interp,
- const char *msg,
- int length)
-{
- Interp *iPtr = (Interp *) interp;
-
- if (Tcl_IsShared(iPtr->errorStack)) {
- Tcl_Obj *newObj;
-
- newObj = Tcl_DuplicateObj(iPtr->errorStack);
- Tcl_DecrRefCount(iPtr->errorStack);
- Tcl_IncrRefCount(newObj);
- iPtr->errorStack = newObj;
- }
- if (iPtr->resetErrorStack) {
- int len;
-
- iPtr->resetErrorStack = 0;
- Tcl_ListObjLength(interp, iPtr->errorStack, &len);
-
- /*
- * Reset while keeping the list intrep as much as possible.
- */
-
- Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
- Tcl_NewStringObj(msg, length));
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_LogCommandInfo --
- *
- * This function is invoked after an error occurs in an interpreter. It
- * adds information to iPtr->errorInfo/errorStack fields to describe the
- * command that was being executed when the error occurred.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Information about the command is added to errorInfo/errorStack and the
- * line number stored internally in the interpreter is set.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_LogCommandInfo(
- Tcl_Interp *interp, /* Interpreter in which to log information. */
- const char *script, /* First character in script containing
- * command (must be <= command). */
- const char *command, /* First character in command that generated
- * the error. */
- int length) /* Number of bytes in command (-1 means use
- * all bytes up to first null byte). */
-{
- TclLogCommandInfo(interp, script, command, length, NULL, NULL);
-}
-
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * tab-width: 8
- * End:
- */