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 {
