diff options
| author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2024-03-07 22:55:11 (GMT) |
|---|---|---|
| committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2024-03-07 22:55:11 (GMT) |
| commit | 8186166c8c63b8b4bd2c89c8a277afda50316c3b (patch) | |
| tree | f861218c75424c64ae3ae15f4169cfb803665604 | |
| parent | 4058bf7e375b06ed9a7dd6b08faf27e1f7d01c42 (diff) | |
| parent | 4fbee3712ec9b889a1f6f5a5e1bd1386a661edc7 (diff) | |
| download | tcl-8186166c8c63b8b4bd2c89c8a277afda50316c3b.zip tcl-8186166c8c63b8b4bd2c89c8a277afda50316c3b.tar.gz tcl-8186166c8c63b8b4bd2c89c8a277afda50316c3b.tar.bz2 | |
Rebase to 9.0
| -rw-r--r-- | generic/tclBasic.c | 36 | ||||
| -rw-r--r-- | tests/namespace.test | 25 |
2 files changed, 57 insertions, 4 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index e8ff3d9..d87fea6 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -4804,12 +4804,40 @@ TEOV_NotFound( * unknown command handler for the current * namespace (TIP 181). */ Namespace *savedNsPtr = NULL; + + int qualLen; + const char *qualName = TclGetStringFromObj(objv[0], &qualLen); currNsPtr = varFramePtr->nsPtr; - if ((currNsPtr == NULL) || (currNsPtr->unknownHandlerPtr == NULL)) { - currNsPtr = iPtr->globalNsPtr; - if (currNsPtr == NULL) { - Tcl_Panic("Tcl_EvalObjv: NULL global namespace pointer"); + if ((currNsPtr == NULL) || (currNsPtr->unknownHandlerPtr == NULL) || + (qualLen > 2 && memchr(qualName, ':', qualLen)) /* fast check for NS:: */ + ) { + /* + * first try to find namespace unknown handler of the namespace + * of executed command if available: + */ + Namespace *dummyNsPtr; + const char *simpleName; + + (void) TclGetNamespaceForQualName(interp, qualName, currNsPtr, + TCL_NAMESPACE_ONLY | TCL_FIND_IF_NOT_SIMPLE, &currNsPtr, + &dummyNsPtr, &dummyNsPtr, &simpleName); + if ((currNsPtr == NULL) || (simpleName == NULL)) { + goto globNS; + } + while (currNsPtr->unknownHandlerPtr == NULL || + (currNsPtr->flags & (NS_DYING | NS_DEAD)) + ) { + /* traverse to alive parent namespace containing handler */ + if (!(currNsPtr = currNsPtr->parentPtr)) { + globNS: + /* fallback to the global unknown */ + currNsPtr = iPtr->globalNsPtr; + if (currNsPtr == NULL) { + Tcl_Panic("TEOV_NotFound: NULL global namespace pointer"); + } + break; + } } } diff --git a/tests/namespace.test b/tests/namespace.test index ae233cb..9976cf3 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -3124,6 +3124,31 @@ test namespace-52.12 {unknown: error case must not reset handler} -body { } -cleanup { namespace delete foo } -result ok +test namespace-52.13 {unknown: invocation outside of NS doesn't evade namespace unknown, bug 910d67a229fe7f65} -body { + namespace eval ::foo::bar { + proc _unknown args {list ::foo:bar:_unknown [uplevel {namespace current}] $args} + namespace unknown [namespace current]::_unknown + } + list [namespace inscope ::foo::bar {xxx}] [namespace inscope ::foo {bar::xxx}] [::foo::bar::xxx] [namespace inscope :: {foo::bar::xxx}] +} -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} { |
