PYK 2015-12-27: Replaced Larry Smith's Code with a rewrite that avoids proliferation of global variables by using stacks and indexes in namespace dictionaries instead.
variable stacks
variable procs
proc pushproc {name arguments {code {}}} {
variable procs
variable stacks
set oldname [uplevel [list namespace which $name]]
if {$oldname ne {}} {
while 1 {
set uniq [info cmdcount]
set newname [namespace qualifiers $oldname]::[
namespace tail $oldname]-$uniq
if {[namespace which $newname] eq {}} break
}
rename $oldname $newname
dict lappend stacks $oldname $newname
dict set procs $newname [list $oldname [expr {[llength [
dict get $stacks $oldname]] - 1}]]
}
if {$code eq {}} {
rename [uplevel [list namespace which $argumemts]] $name
} else {
uplevel [list proc $name $arguments $code]
}
}
proc pullproc {name {newname {}}} {
variable procs
variable stacks
set name [uplevel [list namespace which $name]]
if {[dict get exists $stacks $name]} {
set stack [dict get $stacks $name]
uplevel [list rename $name $newname]
uplevel [list rename [lindex $stack end] $name]
dict unset procs [lindex $stack end]
set stack [lreplace $stack[set stack {}] end end]
if {![llength $stack]} {
dict unset stacks $name
}
}
}
proc getprev args {
variable procs
variable stacks
if {[llength $args]} {
set name [lindex $args 0]
} else {
set name [lindex [info level -1] 0]
}
set name [uplevel [list namespace which $name]]
if {[dict exists $stacks $name]} {
return [lindex [dict get $stacks $name] end]
} elseif {[dict exists $procs $name]} {
lassign [dict get $procs $name] key index
return [lindex [dict get $stacks $key] [expr {$index-1}]]
}
}
proc callprev args {
set name [uplevel [list [namespace current]::getprev]]
if {$name ne {}} {
tailcall $name {*}$args
}
}Example:
pushproc test x {
puts "first $x ([lindex [ info level 0 ] 0])"
}
pushproc test x {
puts "second $x ([lindex [info level 0] 0])"
callprev $x
}
pushproc test x {
puts "third $x ([lindex [info level 0] 0])"
callprev $x
}
test a
pullproc test
test b
pullproc test
test c
# another example
pushproc file {op args} {
switch $op {
getacl {return getacl}
putacl {return putacl}
default {eval callprev $op $args}
}
}
puts [file exists foo]
puts [file getacl foo]steveb 2011-08-01: Jim has built-in support for stacking via local and upcall. A procedure declared as local stacks over any existing definition and when that proc is deleted, the original is restored. Very handy for overriding unknown.
proc a msg {
puts "orig: $msg"
}
proc b {} {
# Invokes the original a
a b1
local proc a msg {
puts "new: $msg"
# Invoke the original a
upcall a $msg
}
# Invokes the local a
a b2
# When b returns, the local a is deleted, restoring the original a
}
b
# Now the original a is restored
a globalGives:
orig: b1 new: b2 orig: b2 orig: global