Attachment "tip181-4.patch" to
ticket [958222ffff]
added by
tallniel
2005-06-14 05:08:22.
Index: doc/Namespace.3
===================================================================
RCS file: /cvsroot/tcl/tcl/doc/Namespace.3,v
retrieving revision 1.7
diff -u -r1.7 Namespace.3
--- doc/Namespace.3 7 Oct 2004 15:15:38 -0000 1.7
+++ doc/Namespace.3 13 Jun 2005 22:04:45 -0000
@@ -13,7 +13,7 @@
.TH Tcl_Namespace 3 8.5 Tcl "Tcl Library Procedures"
.BS
.SH NAME
-Tcl_AppendExportList, Tcl_CreateNamespace, Tcl_DeleteNamespace, Tcl_Export, Tcl_FindCommand, Tcl_FindNamespace, Tcl_ForgetImport, Tcl_GetCurrentNamespace, Tcl_GetGloblaNamespace, Tcl_Import \- manipulate namespaces
+Tcl_AppendExportList, Tcl_CreateNamespace, Tcl_DeleteNamespace, Tcl_Export, Tcl_FindCommand, Tcl_FindNamespace, Tcl_ForgetImport, Tcl_GetCurrentNamespace, Tcl_GetGloblaNamespace, Tcl_GetNamespaceUnknownHandler, Tcl_Import, Tcl_SetNamespaceUnknownHandler \- manipulate namespaces
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
@@ -46,6 +46,12 @@
.sp
Tcl_Command
\fBTcl_FindCommand\fR(\fIinterp, name, contextNsPtr, flags\fR)
+.sp
+Tcl_Obj *
+\fBTcl_GetNamespaceUnknownHandler(\fIinterp, nsPtr\fR)
+.sp
+int
+\fBTcl_SetNamespaceUnknownHandler(\fIinterp, nsPtr, handlerPtr\fR)
.SH ARGUMENTS
.AS Tcl_NamespaceDeleteProc allowOverwrite in/out
.AP Tcl_Interp *interp in/out
@@ -87,6 +93,9 @@
indicates that the search is always to be conducted relative to the
context namespace), and \fBTCL_LEAVE_ERR_MSG\fR (indicates that an error
message should be left in the interpreter if the search fails.)
+.AP Tcl_Obj *handlerPtr in
+A script fragment to be installed as the unknown command handler for the
+namespace, or NULL to reset the handler to its default.
.BE
.SH DESCRIPTION
@@ -143,6 +152,13 @@
\fBTcl_FindCommand\fR searches for a command named \fIname\fR within
the context of the namespace \fIcontextNsPtr\fR. If the command
cannot be found, NULL is returned.
+.PP
+\fBTcl_GetNamespaceUnknownHandler\fR returns the unknown command handler
+for the namespace, or NULL if none is set.
+.PP
+\fBTcl_SetNamespaceUnknownHandler\fR sets the unknown command handler for
+the namespace. If \fIhandlerPtr\fR is NULL, then the handler is reset to
+its default.
.SH "SEE ALSO"
Tcl_CreateCommand, Tcl_ListObjAppendElements, Tcl_SetVar
Index: doc/namespace.n
===================================================================
RCS file: /cvsroot/tcl/tcl/doc/namespace.n,v
retrieving revision 1.18
diff -u -r1.18 namespace.n
--- doc/namespace.n 30 May 2005 00:04:45 -0000 1.18
+++ doc/namespace.n 13 Jun 2005 22:04:47 -0000
@@ -249,6 +249,17 @@
It does not check whether the namespace names are, in fact,
the names of currently defined namespaces.
.TP
+\fBnamespace unknown\fR ?\fIscript\fR?
+Sets or returns the unknown command handler for the current namespace.
+The handler is invoked when a command called from within the namespace
+cannot be found (in either the current namespace or the global namespace).
+The \fIscript\fR argument, if given, should be a well
+formed list representing a command name and optional arguments. When
+the handler is invoked, the full invocation line will be appended to the
+script and the result evaluated in the context of the namespace. The
+default handler for all namespaces is \fB::unknown\fR. If no argument
+is given, it returns the handler for the current namespace.
+.TP
\fBnamespace which\fR ?\-\fBcommand\fR? ?\-\fBvariable\fR? \fIname\fR
Looks up \fIname\fR as either a command or variable
and returns its fully-qualified name.
Index: doc/unknown.n
===================================================================
RCS file: /cvsroot/tcl/tcl/doc/unknown.n,v
retrieving revision 1.5
diff -u -r1.5 unknown.n
--- doc/unknown.n 30 May 2004 14:13:52 -0000 1.5
+++ doc/unknown.n 13 Jun 2005 22:04:48 -0000
@@ -23,15 +23,18 @@
tries to invoke a command that doesn't exist. The default implementation
of \fBunknown\fR is a library procedure defined when Tcl initializes an
interpreter. You can override the default \fBunknown\fR to change its
-functionality. Note that there is no default implementation of
-\fBunknown\fR in a safe interpreter.
+functionality, or you can register a new handler for individual namespaces
+using the \fBnamespace unknown\fR command. Note that there is no default
+implementation of \fBunknown\fR in a safe interpreter.
.PP
If the Tcl interpreter encounters a command name for which there
-is not a defined command, then Tcl checks for the existence of
-a command named \fBunknown\fR.
-If there is no such command, then the interpreter returns an
-error.
-If the \fBunknown\fR command exists, then it is invoked with
+is not a defined command (in either the current namespace, or the
+global namespace), then Tcl checks for the existence of
+an unknown handler for the current namespace. By default, this
+handler is a command named \fB::unknown\fR. If there is no such
+command, then the interpreter returns an error.
+If the \fBunknown\fR command exists (or a new handler has been
+registered for the current namespace), then it is invoked with
arguments consisting of the fully-substituted name and arguments
for the original non-existent command.
The \fBunknown\fR command typically does things like searching
@@ -87,7 +90,7 @@
.CE
.SH "SEE ALSO"
-info(n), proc(n), interp(n), library(n)
+info(n), proc(n), interp(n), library(n), namespace(n)
.SH KEYWORDS
error, non-existent command
Index: generic/tcl.decls
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tcl.decls,v
retrieving revision 1.112
diff -u -r1.112 tcl.decls
--- generic/tcl.decls 6 Jun 2005 23:45:42 -0000 1.112
+++ generic/tcl.decls 13 Jun 2005 22:04:50 -0000
@@ -2013,6 +2013,18 @@
Tcl_ChannelType *chanTypePtr)
}
+# TIP #181:
+declare 561 generic {
+ Tcl_Obj *Tcl_GetNamespaceUnknownHandler(Tcl_Interp *interp,
+ Tcl_Namespace *nsPtr)
+}
+declare 562 generic {
+ int Tcl_SetNamespaceUnknownHandler(
+ Tcl_Interp *interp, Tcl_Namespace *nsPtr,
+ Tcl_Obj *handlerPtr)
+}
+
+
##############################################################################
# Define the platform specific public Tcl interface. These functions are
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.160
diff -u -r1.160 tclBasic.c
--- generic/tclBasic.c 6 Jun 2005 23:45:43 -0000 1.160
+++ generic/tclBasic.c 13 Jun 2005 22:04:58 -0000
@@ -3222,6 +3222,10 @@
int i;
CallFrame *savedVarFramePtr; /* Saves old copy of iPtr->varFramePtr
* in case TCL_EVAL_GLOBAL was set. */
+ Namespace *currNsPtr = NULL; /* Used to check for, and invoke any
+ * registered unknown commmand
+ * handler for the current namespace
+ * (see TIP 181). */
int code = TCL_OK;
int traceCode = TCL_OK;
int checkTraces = 1;
@@ -3236,10 +3240,10 @@
/*
* Find the procedure to execute this command. If there isn't one,
- * then see if there is a command "unknown". If so, create a new
- * word array with "unknown" as the first word and the original
- * command words as arguments. Then call ourselves recursively to
- * execute it.
+ * then see if there is an unknown command handler registered for this
+ * namespace. If so, create a new word array with the handler as the
+ * first words and the original command words as arguments. Then call
+ * ourselves recursively to execute it.
*
* If caller requests, or if we're resolving the target end of an
* interpeter alias (TCL_EVAL_INVOKE), be sure to do command name
@@ -3255,15 +3259,52 @@
iPtr->varFramePtr = NULL;
}
cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[0]);
+ /*
+ * Grab current namespace before restoring var frame, for unknown
+ * handler check below.
+ */
+ if (iPtr->varFramePtr != NULL && iPtr->varFramePtr->nsPtr != NULL) {
+ currNsPtr = iPtr->varFramePtr->nsPtr;
+ } else {
+ /* Note: Assumes globalNsPtr can never be NULL. */
+ currNsPtr = iPtr->globalNsPtr;
+ }
iPtr->varFramePtr = savedVarFramePtr;
if (cmdPtr == NULL) {
+ int newObjc, handlerObjc;
+ Tcl_Obj **handlerObjv;
+ /*
+ * Check if there is an unknown handler registered for this
+ * namespace. Otherwise, use the global namespace unknown handler.
+ */
+ if (currNsPtr->unknownHandlerPtr == NULL) {
+ currNsPtr = iPtr->globalNsPtr;
+ }
+ if (currNsPtr == iPtr->globalNsPtr &&
+ currNsPtr->unknownHandlerPtr == NULL) {
+ /* Global namespace has lost unknown handler, reset. */
+ currNsPtr->unknownHandlerPtr =
+ Tcl_NewStringObj("::unknown", -1);
+ Tcl_IncrRefCount(currNsPtr->unknownHandlerPtr);
+ }
+
+ if (Tcl_ListObjGetElements(interp,
+ currNsPtr->unknownHandlerPtr, &handlerObjc, &handlerObjv)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ newObjc = objc + handlerObjc;
newObjv = (Tcl_Obj **) ckalloc((unsigned)
- ((objc + 1) * sizeof(Tcl_Obj *)));
- for (i = objc-1; i >= 0; i--) {
- newObjv[i+1] = objv[i];
+ (newObjc * sizeof (Tcl_Obj *)));
+ /* Copy command prefix from unknown handler. */
+ for (i = 0; i < handlerObjc; ++i) {
+ newObjv[i] = handlerObjv[i];
+ }
+ /* Add in command name and arguments. */
+ for (i = objc-1; i >= 0; --i) {
+ newObjv[i+handlerObjc] = objv[i];
}
- newObjv[0] = Tcl_NewStringObj("::unknown", -1);
Tcl_IncrRefCount(newObjv[0]);
cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, newObjv[0]);
if (cmdPtr == NULL) {
@@ -3272,8 +3313,8 @@
code = TCL_ERROR;
} else {
iPtr->numLevels++;
- code = TclEvalObjvInternal(interp, objc+1, newObjv,
- command, length, 0);
+ code = TclEvalObjvInternal(interp, newObjc, newObjv, command,
+ length, 0);
iPtr->numLevels--;
}
Tcl_DecrRefCount(newObjv[0]);
Index: generic/tclDecls.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclDecls.h,v
retrieving revision 1.114
diff -u -r1.114 tclDecls.h
--- generic/tclDecls.h 7 Jun 2005 02:07:24 -0000 1.114
+++ generic/tclDecls.h 13 Jun 2005 22:05:07 -0000
@@ -3496,6 +3496,19 @@
EXTERN Tcl_DriverTruncateProc * Tcl_ChannelTruncateProc _ANSI_ARGS_((
Tcl_ChannelType * chanTypePtr));
#endif
+#ifndef Tcl_GetNamespaceUnknownHandler_TCL_DECLARED
+#define Tcl_GetNamespaceUnknownHandler_TCL_DECLARED
+/* 561 */
+EXTERN Tcl_Obj * Tcl_GetNamespaceUnknownHandler _ANSI_ARGS_((
+ Tcl_Interp * interp, Tcl_Namespace * nsPtr));
+#endif
+#ifndef Tcl_SetNamespaceUnknownHandler_TCL_DECLARED
+#define Tcl_SetNamespaceUnknownHandler_TCL_DECLARED
+/* 562 */
+EXTERN int Tcl_SetNamespaceUnknownHandler _ANSI_ARGS_((
+ Tcl_Interp * interp, Tcl_Namespace * nsPtr,
+ Tcl_Obj * handlerPtr));
+#endif
typedef struct TclStubHooks {
struct TclPlatStubs *tclPlatStubs;
@@ -4098,6 +4111,8 @@
int (*tcl_GetBignumFromObj) _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* obj, mp_int* value)); /* 558 */
int (*tcl_TruncateChannel) _ANSI_ARGS_((Tcl_Channel chan, Tcl_WideInt length)); /* 559 */
Tcl_DriverTruncateProc * (*tcl_ChannelTruncateProc) _ANSI_ARGS_((Tcl_ChannelType * chanTypePtr)); /* 560 */
+ Tcl_Obj * (*tcl_GetNamespaceUnknownHandler) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Namespace * nsPtr)); /* 561 */
+ int (*tcl_SetNamespaceUnknownHandler) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Namespace * nsPtr, Tcl_Obj * handlerPtr)); /* 562 */
} TclStubs;
#ifdef __cplusplus
@@ -6382,6 +6397,14 @@
#define Tcl_ChannelTruncateProc \
(tclStubsPtr->tcl_ChannelTruncateProc) /* 560 */
#endif
+#ifndef Tcl_GetNamespaceUnknownHandler
+#define Tcl_GetNamespaceUnknownHandler \
+ (tclStubsPtr->tcl_GetNamespaceUnknownHandler) /* 561 */
+#endif
+#ifndef Tcl_SetNamespaceUnknownHandler
+#define Tcl_SetNamespaceUnknownHandler \
+ (tclStubsPtr->tcl_SetNamespaceUnknownHandler) /* 562 */
+#endif
#endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.235
diff -u -r1.235 tclInt.h
--- generic/tclInt.h 7 Jun 2005 21:46:08 -0000 1.235
+++ generic/tclInt.h 13 Jun 2005 22:05:12 -0000
@@ -234,6 +234,9 @@
Tcl_Ensemble *ensembles; /* List of structures that contain the details
* of the ensembles that are implemented on
* top of this namespace. */
+ Tcl_Obj *unknownHandlerPtr; /* A script fragment to be used when command
+ * resolution in this namespace fails. TIP
+ * 181. */
int commandPathLength; /* The length of the explicit path. */
NamespacePathEntry *commandPathArray;
/* The explicit path of the namespace as an
Index: generic/tclNamesp.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclNamesp.c,v
retrieving revision 1.77
diff -u -r1.77 tclNamesp.c
--- generic/tclNamesp.c 7 Jun 2005 21:46:18 -0000 1.77
+++ generic/tclNamesp.c 13 Jun 2005 22:05:25 -0000
@@ -12,6 +12,7 @@
* Copyright (c) 1997 Sun Microsystems, Inc.
* Copyright (c) 1998-1999 by Scriptics Corporation.
* Copyright (c) 2002-2005 Donal K. Fellows.
+ * Copyright (c) 2005 Neil Madden.
*
* Originally implemented by
* Michael J. McLennan
@@ -251,6 +252,9 @@
static int NamespaceTailCmd _ANSI_ARGS_((
ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]));
+static int NamespaceUnknownCmd _ANSI_ARGS_((
+ ClientData dummy, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[]));
static int NamespaceWhichCmd _ANSI_ARGS_((
ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]));
@@ -850,6 +854,7 @@
nsPtr->compiledVarResProc = NULL;
nsPtr->exportLookupEpoch = 0;
nsPtr->ensembles = NULL;
+ nsPtr->unknownHandlerPtr = NULL;
nsPtr->commandPathLength = 0;
nsPtr->commandPathArray = NULL;
nsPtr->commandPathSourceList = NULL;
@@ -950,6 +955,14 @@
}
/*
+ * If the namespace has a registered unknown handler (TIP 181), then free
+ * it here.
+ */
+ if (nsPtr->unknownHandlerPtr != NULL) {
+ Tcl_DecrRefCount(nsPtr->unknownHandlerPtr);
+ }
+
+ /*
* 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
@@ -2912,13 +2925,13 @@
"children", "code", "current", "delete", "ensemble",
"eval", "exists", "export", "forget", "import",
"inscope", "origin", "parent", "path", "qualifiers",
- "tail", "which", (char *) NULL
+ "tail", "unknown", "which", (char *) NULL
};
enum NSSubCmdIdx {
NSChildrenIdx, NSCodeIdx, NSCurrentIdx, NSDeleteIdx, NSEnsembleIdx,
NSEvalIdx, NSExistsIdx, NSExportIdx, NSForgetIdx, NSImportIdx,
NSInscopeIdx, NSOriginIdx, NSParentIdx, NSPathIdx, NSQualifiersIdx,
- NSTailIdx, NSWhichIdx
+ NSTailIdx, NSUnknownIdx, NSWhichIdx
};
int index, result;
@@ -2986,6 +2999,9 @@
case NSTailIdx:
result = NamespaceTailCmd(clientData, interp, objc, objv);
break;
+ case NSUnknownIdx:
+ result = NamespaceUnknownCmd(clientData, interp, objc, objv);
+ break;
case NSWhichIdx:
result = NamespaceWhichCmd(clientData, interp, objc, objv);
break;
@@ -4295,6 +4311,167 @@
/*
*----------------------------------------------------------------------
*
+ * 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(dummy, interp, objc, objv)
+ 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 > 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "?script?");
+ return TCL_ERROR;
+ }
+
+ currNsPtr = Tcl_GetCurrentNamespace(interp);
+
+ if (objc == 2) {
+ /*
+ * Introspection - return the current namespace handler.
+ */
+ resultPtr = Tcl_GetNamespaceUnknownHandler(interp, currNsPtr);
+ if (resultPtr == NULL) {
+ resultPtr = Tcl_NewObj();
+ }
+ Tcl_SetObjResult(interp, resultPtr);
+ } else {
+ rc = Tcl_SetNamespaceUnknownHandler(interp, currNsPtr, objv[2]);
+ if (rc == TCL_OK) {
+ Tcl_SetObjResult(interp, objv[2]);
+ }
+ 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(interp, nsPtr)
+ 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).
+ */
+ currNsPtr->unknownHandlerPtr =
+ Tcl_NewStringObj("::unknown", -1);
+ 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(interp, nsPtr, handlerPtr)
+ 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;
+ Namespace *currNsPtr = (Namespace *)nsPtr;
+
+ if (currNsPtr->unknownHandlerPtr != NULL) {
+ /* Remove old handler first. */
+ Tcl_DecrRefCount(currNsPtr->unknownHandlerPtr);
+ }
+ /*
+ * If NULL or an empty list is passed, then reset to the default
+ * handler.
+ */
+ if (handlerPtr == NULL) {
+ currNsPtr->unknownHandlerPtr = NULL;
+ } else {
+ if (Tcl_ListObjLength(interp, handlerPtr, &lstlen) != TCL_OK) {
+ /* Not a list */
+ return TCL_ERROR;
+ } else if (lstlen == 0) {
+ /* Empty list - reset to default. */
+ currNsPtr->unknownHandlerPtr = NULL;
+ } else {
+ /*
+ * Increment ref count and store. The reference count is
+ * decremented either in the code above, or when the namespace
+ * is deleted.
+ */
+ Tcl_IncrRefCount(handlerPtr);
+ currNsPtr->unknownHandlerPtr = handlerPtr;
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* NamespaceTailCmd --
*
* Invoked to implement the "namespace tail" command that returns the
Index: generic/tclStubInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclStubInit.c,v
retrieving revision 1.118
diff -u -r1.118 tclStubInit.c
--- generic/tclStubInit.c 7 Jun 2005 02:07:27 -0000 1.118
+++ generic/tclStubInit.c 13 Jun 2005 22:05:27 -0000
@@ -983,6 +983,8 @@
Tcl_GetBignumFromObj, /* 558 */
Tcl_TruncateChannel, /* 559 */
Tcl_ChannelTruncateProc, /* 560 */
+ Tcl_GetNamespaceUnknownHandler, /* 561 */
+ Tcl_SetNamespaceUnknownHandler, /* 562 */
};
/* !END!: Do not edit above this line. */
Index: tests/namespace.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/namespace.test,v
retrieving revision 1.44
diff -u -r1.44 namespace.test
--- tests/namespace.test 30 May 2005 00:04:49 -0000 1.44
+++ tests/namespace.test 13 Jun 2005 22:05:33 -0000
@@ -838,7 +838,7 @@
} {1 {wrong # args: should be "namespace subcommand ?arg ...?"}}
test namespace-20.2 {Tcl_NamespaceObjCmd, bad subcommand} {
list [catch {namespace wombat {}} msg] $msg
-} {1 {bad option "wombat": must be children, code, current, delete, ensemble, eval, exists, export, forget, import, inscope, origin, parent, path, qualifiers, tail, or which}}
+} {1 {bad option "wombat": must be children, code, current, delete, ensemble, eval, exists, export, forget, import, inscope, origin, parent, path, qualifiers, tail, unknown, or which}}
test namespace-20.3 {Tcl_NamespaceObjCmd, abbreviations are okay} {
namespace ch :: test_ns_*
} {}
@@ -945,7 +945,7 @@
} {1 {wrong # args: should be "namespace eval name arg ?arg...?"}}
test namespace-25.2 {NamespaceEvalCmd, bad args} {
list [catch {namespace test_ns_1} msg] $msg
-} {1 {bad option "test_ns_1": must be children, code, current, delete, ensemble, eval, exists, export, forget, import, inscope, origin, parent, path, qualifiers, tail, or which}}
+} {1 {bad option "test_ns_1": must be children, code, current, delete, ensemble, eval, exists, export, forget, import, inscope, origin, parent, path, qualifiers, tail, unknown, or which}}
catch {unset v}
test namespace-25.3 {NamespaceEvalCmd, new namespace} {
set v 123
@@ -1842,6 +1842,87 @@
while parsing result of ensemble unknown subcommand handler
invoked from within
"foo bar"}}
+# TIP 181 - namespace unknown tests
+test namespace-48.1 {unknown: default handler ::unknown} {
+ set result [list [namespace eval foobar { namespace unknown }]]
+ lappend result [namespace eval :: { namespace unknown }]
+ namespace delete foobar
+ set result
+} {{} ::unknown}
+test namespace-48.2 {unknown: default resolution global} {
+ proc ::foo {} { return "GLOBAL" }
+ namespace eval ::bar { proc foo {} { return "NAMESPACE" } }
+ namespace eval ::bar::jim { proc test {} { foo } }
+ set result [::bar::jim::test]
+ namespace delete ::bar
+ rename ::foo {}
+ set result
+} {GLOBAL}
+test namespace-48.3 {unknown: default resolution local} {
+ proc ::foo {} { return "GLOBAL" }
+ namespace eval ::bar {
+ proc foo {} { return "NAMESPACE" }
+ proc test {} { foo }
+ }
+ set result [::bar::test]
+ namespace delete ::bar
+ rename ::foo {}
+ set result
+} {NAMESPACE}
+test namespace-48.4 {unknown: set handler} {
+ namespace eval foo {
+ namespace unknown [list dispatch]
+ proc dispatch {args} { return $args }
+ proc test {} {
+ UnknownCmd a b c
+ }
+ }
+ set result [foo::test]
+ namespace delete foo
+ set result
+} {UnknownCmd a b c}
+test namespace-48.5 {unknown: search path before unknown is unaltered} {
+ proc ::test2 {args} { return "TEST2: $args" }
+ namespace eval foo {
+ namespace unknown [list dispatch]
+ proc dispatch {args} { return "UNKNOWN: $args" }
+ proc test1 {args} { return "TEST1: $args" }
+ proc test {} {
+ set result [list [test1 a b c]]
+ lappend result [test2 a b c]
+ lappend result [test3 a b c]
+ return $result
+ }
+ }
+ set result [foo::test]
+ namespace delete foo
+ rename ::test2 {}
+ set result
+} {{TEST1: a b c} {TEST2: a b c} {UNKNOWN: test3 a b c}}
+test namespace-48.6 {unknown: deleting handler restores default} {
+ rename ::unknown ::_unknown_orig
+ proc ::unknown {args} { return "DEFAULT: $args" }
+ namespace eval foo {
+ namespace unknown dummy
+ namespace unknown {}
+ }
+ set result [namespace eval foo { dummy a b c }]
+ rename ::unknown {}
+ rename ::_unknown_orig ::unknown
+ namespace delete foo
+ set result
+} {DEFAULT: dummy a b c}
+test namespace-48.7 {unknown: setting global unknown handler} {
+ proc ::myunknown {args} { return "MYUNKNOWN: $args" }
+ namespace eval :: { namespace unknown ::myunknown }
+ set result [namespace eval foo { dummy a b c }]
+ namespace eval :: { namespace unknown {} }
+ rename ::myunknown {}
+ namespace delete foo
+ set result
+} {MYUNKNOWN: dummy a b c}
+
+
test namespace-48.1 {ensembles and namespace import: unknown handler} {
namespace eval foo {