diff options
author | dgp <dgp@users.sourceforge.net> | 2006-02-01 18:27:42 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2006-02-01 18:27:42 (GMT) |
commit | bf2e20ec8703a3c6e725e464bb4e7fca8af0834c (patch) | |
tree | c00a6c3b557759767b41407974391d1117ad0c25 /generic/tclBasic.c | |
parent | 2e9bf45bc4d2510a07a538c48f8103957ede3aaf (diff) | |
download | tcl-bf2e20ec8703a3c6e725e464bb4e7fca8af0834c.zip tcl-bf2e20ec8703a3c6e725e464bb4e7fca8af0834c.tar.gz tcl-bf2e20ec8703a3c6e725e464bb4e7fca8af0834c.tar.bz2 |
TIP#181 IMPLEMENTATION
* doc/Namespace.3: New command [namespace unknown]. New public
* doc/namespace.n: C routines Tcl_(Get|Set)NamespaceUnknownHandler. * doc/unknown.n: [Patch 958222].
* generic/tcl.decls:
* generic/tclBasic.c:
* generic/tclInt.h:
* generic/tclNamesp.c:
* tests/namespace.test:
* generic/tclDecls.h: make genstubs
* generic/tclStubInit.c:
Diffstat (limited to 'generic/tclBasic.c')
-rw-r--r-- | generic/tclBasic.c | 69 |
1 files changed, 57 insertions, 12 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 735874b..cfd7e90 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclBasic.c,v 1.187 2006/01/11 17:34:53 dgp Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.188 2006/02/01 18:27:43 dgp Exp $ */ #include "tclInt.h" @@ -3246,6 +3246,10 @@ TclEvalObjvInternal( 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 command + * handler for the current namespace + * (see TIP 181). */ int code = TCL_OK; int traceCode = TCL_OK; int checkTraces = 1; @@ -3260,9 +3264,10 @@ TclEvalObjvInternal( /* * Find the function 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. + * 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 @@ -3278,25 +3283,65 @@ TclEvalObjvInternal( 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; + if (currNsPtr == NULL) { + Tcl_Panic("TclEvalObjvInternal: NULL global namespace pointer"); + } + } iPtr->varFramePtr = savedVarFramePtr; if (cmdPtr == NULL) { - newObjv = (Tcl_Obj **) - ckalloc((unsigned) ((objc + 1) * sizeof(Tcl_Obj *))); - for (i = objc-1; i >= 0; i--) { - newObjv[i+1] = objv[i]; - } - newObjv[0] = Tcl_NewStringObj("::unknown", -1); + 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) + (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]; + } Tcl_IncrRefCount(newObjv[0]); cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, newObjv[0]); + if (cmdPtr == NULL) { Tcl_AppendResult(interp, "invalid command name \"", TclGetString(objv[0]), "\"", NULL); 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]); |