diff options
| -rw-r--r-- | generic/tclBasic.c | 14 | ||||
| -rw-r--r-- | generic/tclInt.h | 3 | ||||
| -rw-r--r-- | generic/tclNamesp.c | 20 | ||||
| -rw-r--r-- | tests/namespace.test | 16 |
4 files changed, 43 insertions, 10 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index ffd69c4..78685f0 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -4741,13 +4741,23 @@ TEOV_NotFound( Namespace *dummyNsPtr; const char *simpleName; + tryParentNS: (void) TclGetNamespaceForQualName(interp, qualName, currNsPtr, - TCL_NAMESPACE_ONLY, &currNsPtr, &dummyNsPtr, &dummyNsPtr, - &simpleName); + TCL_NAMESPACE_ONLY | TCL_FIND_IF_NOT_SIMPLE, &currNsPtr, + &dummyNsPtr, &dummyNsPtr, &simpleName); if ((currNsPtr == NULL) || (simpleName == NULL) || currNsPtr->unknownHandlerPtr == NULL || (currNsPtr->flags & (NS_DYING | NS_DEAD)) ) { + /* traverse to alive parent namespace containing handler */ + if (currNsPtr) { + qualName = currNsPtr->fullName; + qualLen = strlen(qualName); + if (qualLen > 2 && memchr(qualName, ':', qualLen)) { + currNsPtr = iPtr->globalNsPtr; + goto tryParentNS; + } + } /* fallback to the global unknown */ currNsPtr = iPtr->globalNsPtr; if (currNsPtr == NULL) { diff --git a/generic/tclInt.h b/generic/tclInt.h index 68c07f2..de92a7d 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -400,10 +400,13 @@ struct NamespacePathEntry { * TCL_NAMESPACE_ONLY - (see tcl.h) Look only in the context ns. * TCL_CREATE_NS_IF_UNKNOWN - Create unknown namespaces. * TCL_FIND_ONLY_NS - The name sought is a namespace name. + * TCL_FIND_IF_NOT_SIMPLE - Retrieve last namespace even if the rest of + * name is not simple name (contains ::). */ #define TCL_CREATE_NS_IF_UNKNOWN 0x800 #define TCL_FIND_ONLY_NS 0x1000 +#define TCL_FIND_IF_NOT_SIMPLE 0x2000 /* * The client data for an ensemble command. This consists of the table of diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 290dcea..37092fe 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -2280,11 +2280,8 @@ TclGetNamespaceForQualName( if (flags & TCL_FIND_ONLY_NS) { nsName = start; } else { - *nsPtrPtr = nsPtr; - *altNsPtrPtr = altNsPtr; *simpleNamePtr = start; - Tcl_DStringFree(&buffer); - return TCL_OK; + goto done; } } else { /* @@ -2334,6 +2331,15 @@ TclGetNamespaceForQualName( } } else { /* Namespace not found and was not * created. */ + if (flags & TCL_FIND_IF_NOT_SIMPLE) { + /* + * return last found NS and not simple name relative it, + * e. g. ::A::B::C::D -> ::A::B and C::D, if + * namespace C cannot be found in ::A::B + */ + *simpleNamePtr = start; + goto done; + } nsPtr = NULL; } } @@ -2364,11 +2370,8 @@ TclGetNamespaceForQualName( */ if ((nsPtr == NULL) && (altNsPtr == NULL)) { - *nsPtrPtr = NULL; - *altNsPtrPtr = NULL; *simpleNamePtr = NULL; - Tcl_DStringFree(&buffer); - return TCL_OK; + goto done; } start = end; @@ -2398,6 +2401,7 @@ TclGetNamespaceForQualName( nsPtr = NULL; } +done: *nsPtrPtr = nsPtr; *altNsPtrPtr = altNsPtr; Tcl_DStringFree(&buffer); diff --git a/tests/namespace.test b/tests/namespace.test index c8c1992..5a8f6f4 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -3056,6 +3056,22 @@ test namespace-52.13 {unknown: invocation outside of NS doesn't evade namespace } -cleanup { namespace delete ::foo } -result {{::foo:bar:_unknown ::foo::bar xxx} {::foo:bar:_unknown ::foo bar::xxx} {::foo:bar:_unknown :: ::foo::bar::xxx} {::foo:bar:_unknown :: foo::bar::xxx}} +test namespace-52.14 {unknown: invocation outside of NS doesn't evade namespace unknown for command with sub-NS, bug 910d67a229fe7f65} -body { + namespace eval ::foo::bar { + proc _unknown args {list ::foo:bar:_unknown [uplevel {namespace current}] $args} + namespace unknown [namespace current]::_unknown + } + set res {} + lappend res [namespace inscope ::foo::bar {xxx::yyy}] [namespace inscope ::foo {bar::xxx::yyy}] [::foo::bar::xxx::yyy] [namespace inscope :: {foo::bar::xxx::yyy}] + # now with existsing ::foo::bar::xxx, but without unknown handler inside (only parent ::foo::bar has a handler): + namespace eval ::foo::bar::xxx {} + lappend res [namespace inscope ::foo::bar {xxx::yyy}] [namespace inscope ::foo {bar::xxx::yyy}] [::foo::bar::xxx::yyy] [namespace inscope :: {foo::bar::xxx::yyy}] +} -cleanup { + namespace delete ::foo + unset -nocomplain res +} -result [lrepeat 2 \ + {::foo:bar:_unknown ::foo::bar xxx::yyy} {::foo:bar:_unknown ::foo bar::xxx::yyy} {::foo:bar:_unknown :: ::foo::bar::xxx::yyy} {::foo:bar:_unknown :: foo::bar::xxx::yyy} +] # TIP 314 - ensembles with parameters test namespace-53.1 {ensembles: parameters} { |
