'''AtExit''' handlers. A common problem I had was that during an application I was setting up things like pipes (in the filesystem), add tons of temporary data, etc. I was then faced with the junk the program left after ending, so I was thinking of how to solve this, and was reminded of the atexit - C function. So I wrote the following (it's quite short, that's why I include it here) # put this in a file and write the pkgIndex "magic" # package require AtExit # oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo # When you call exit, calls any proc named after the scheme # AtExit_*. It may have arbitrary arguments as long as they # are default arguments (or no args at all of course). They are # called in no special order, except if the first argument's default # value is an integer: It is taken to be a priority then. The higher, # the earlier the proc is called # ==> Should the prio arg be forced to be named 'prio*' instead ? -Martin #rename exit to something else, install an exit # fcn which is capable of calling some cleanup # routines for, well, cleaning up. rename exit __shock namespace eval ::AtExit { variable outchann namespace export outchan print proc outchan { {chan stderr} } { variable outchann if {[info exists outchann]&& ($outchann != "stderr" && $outchann != "stdout")} { close $outchann } set outchann $chan } proc noOutput { } { variable outchann if {[info exists outchann]&& ($outchann != "stderr" && $outchann != "stdout")} { flush $outchann close $outchann } catch { unset outchann } } # if you wonder what this one is for - I like, in the development # stage of a program, to print stuff of the exit handlers into the # exit-logfile (I just set ::debugging 1) - so I use # ::AtExit::print "text" in the cleanup routines for dbg msgs proc print { string } { variable outchann if {[info exists outchann]} { puts $outchann $string } } } proc exit {{status 0}} { if {[info exists ::debugging] && $::debugging} { ::AtExit::outchan [open exit.log {WRONLY CREAT TRUNC}] } foreach proc [info procs AtExit_*] { if ![llength [info args $proc]] { lappend procs1 $proc } else { set bad 0 foreach arg [set args [info args $proc]] { if ![info default $proc $arg junk] { set bad 1; break } } if {!$bad} { info default $proc [lindex $args 0] prio if [string is integer $prio] { lappend procs_prio [list $prio $proc] } } else { ::AtExit::print "Cannot call finalizer <$proc> - it needs arguments!" } } } foreach proc [lsort -integer -decreasing -index 0 $procs_prio] { ::AtExit::print "AtExit is calling finalizer <$proc>" uplevel #0 $proc } foreach proc $procs1 { ::AtExit::print "AtExit is calling finalizer " uplevel #0 $proc } # This is no AtExit handler because it needs to # be called as absolutely last thing. if {[info exists ::AtExit::outchann] && ($::AtExit::outchann != "stderr" && $::AtExit::outchann != "stdout")} { puts $::AtExit::outchann "Done handling exit handlers, closing stream and exitting." close $::AtExit::outchann } # bye bye __shock $status } package provide AtExit 0.1 This way you write some AtExit_* functions which expect no arguments, and which are called once you call exit. If you want to exit without calling those handlers, you can always '''shock''' (__shock) your program. Another thing which comes handy, is to install a handler for your window if you use tk: wm protocol . WM_DELETE_WINDOW exit This way even if you kill your application with the help of the windowmanager, exit will be called, and thus your exit-handlers will be called, too. I suppose this can be easily enhanced so the exit handlers have a priority; one possibility which comes to my mind is declaring the procs so that they have a default argument 'priority'; the list of procs to call would then be sorted by the values of those default parameters.. Oh, yes, it's quite easy. Suppose once I'm home and have time again I'll do just that :) ''Okay, did just that. Hope you enjoy it. -Martin [mailto:Ephaeton@gmx.net]''