'''errx''' The idea of errx came to me as I was enerved by debugging puts. It resembles a bit of the BSD ''errx/warnx'' pair, although it combines both functionalities into one function. Furthermore it offers something like a debuggers '''bt''' , i.e. backtrace. It is not yet finished, but I use it daily already, although the more fancy things (like the bt) are not yet fully finished or even nonexistant. ''Martin Weber'' [mailto:Ephaeton@gmx.net] ---- Make it simple, paste it here - code on a wiki page, with the ensuing discussions, is more attractive and pedagogical than a URL to download a tar.gz bundle... ([RS] ;-) ---- In fact I had exactly that in mind - errx itself is lean, but I am using it in a bundle with some other stuff - bgerror, and some other utility stuff which I've packed into ::Error ... gonna present errx here and offer the rest for download :) ----- And here we go. This is the factored out errx which I already use. I have cut out about anything which is not yet finished. ----- # When this is sourced, set errchann and debugging if not set # to sane values. if {![info exists ::errchann]} { set ::errchann stderr } if {![info exists ::debugging]} { set ::debugging 0 } proc errx { txt {flags {info debug}} } { global argv0 debugging errchann errorInfo lastargs if {![string length $errchann]} { return } if {![info exists debugging]} { set debugging 0 } # if !debugging immediate return when flags contain debug if {([set dbgpos [lsearch $flags debug]] != -1) && !$debugging} { return } else { set flags [lreplace $flags $dbgpos $dbgpos] } upvar _DEBUG _debug if {![info exists _debug]} { set _debug 0 } if {([set dbgpos [lsearch $flags DEBUG]] != -1) && !$_debug} { return } else { set flags [lreplace $flags $dbgpos $dbgpos] } if {[info level]==1} { ;# caller is global! set caller "*global*" set verbose "" } else { set caller [lindex [info level -1] 0] set verbose "$argv0:\[<$caller>\] Called as: [info level -1]" } if {[set flp [lsearch $flags time]]!= -1} { set intro "$argv0@([clock format [clock seconds]]):\[<$caller>\]" set flags [lreplace $flags $flp $flp] } else { set intro "$argv0:\[<$caller>\]" } switch -- $flags { sparse { puts $errchann "$txt" } "" - debug { ;# this shouldn't happen, but can if two debug flags are given. puts $errchann "$intro: $txt" } info { puts $errchann "$intro: $txt" } warning { puts $errchann "$intro: $txt"} error { puts $errchann "$intro: $txt\n$verbose" ; exit 1 } critical { puts $errchann "$intro: ** CRITICAL ERROR ! **" if {[info exists errorInfo]} { puts $errchann " -- $errorInfo" } if {[info exists errorCode]} { puts $errchann " -- $errorCode" } for {set lv [expr [info level] -1 ]} { $lv } { incr lv -1 } { puts $errchann "================================================================================" puts $errchann " Level $lv, [info level $lv]." puts $errchann " Local variables:" uplevel #$lv { foreach v [info locals] { upvar #[info level] $v _v; puts $::errchann "$v=$_v\t" } } puts $errchann "\n" } exit 1 } default { errx "Invalid flags given to errx ($flags)!" error } } return } ----- Its strong points are mainly that you can switch messages on and off, and even use for non debugging, but warning or informational purposes. If the variable ''_DEBUG'' is set in the calling environment, and set to 1 (or true), then the '''DEBUG''' token works. If the global variable ''debugging'' is set, then the '''debug''' token works. (works in the sense like "the debug '''modifier''' works", see the first and third example) In general you'd use it like follows: # if {$_DEBUG} in calling environment, output msg errx "local-var-I-want-to-know is $bla" {info DEBUG} # output a unconditionally errx "I just deleted my harddisk!" warning # if {$::debugging}, output a msg errx "Hmm, environment doesn't seem sane..." debug # Output a error along with stack backtrace, inspection # of local variables up the stack and a timestamp, # exit the application. errx "YIKES! THE ALIENS ARE COMING!" {critical time} # Kill the application with your error message errx "hmm, something went wildly wrong." error What I like about it is that it displays the caller and the script for which it works, normally with 'puts' you do all the same all the time: puts stderr "this-proc, that-var is $bla @ [clock format [clock seconds]" Furthermore, when you switch your code to use a global routine like that, can easily say something like: set ::debugging 1 set ::errchann [open debug.log {WRONLY CREAT TRUNC}] and collect all information from it at a central place... ----- Once I finished errx to the like I want it, I'll put up the tar.gz I mentioned earlier. Included in this Error module is a facility for bgerror handling (installing/reinstalling of handlers etc.), setting of debug - levels (offers control of verbosity on a global level, too), Switching of errchann with reinstalling the old one, a predefined bgerror for use with event-driven '''tcl''' applications, and concise documentation. Things errx is going to learn still: * norecord, record Record error messages in an internal stack for use if errchann is unset * replay Get the messages from the stack * rdr "redirect", Report grandparent-caller, not parent-environment (For use with ''replay'') * ml or multiline Better handling for multiline messages [probably automatic] * stack Just display a stack trace * vars Display callers environment (info locals) - these are to be combined, too ... if you have further suggestions, well, this is a wiki :) Go ahead. ----- ''More to come, -Martin''