Index: openacs-4/packages/acs-tcl/tcl/exception-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/exception-procs.tcl,v diff -u -N -r1.6 -r1.7 --- openacs-4/packages/acs-tcl/tcl/exception-procs.tcl 6 Dec 2017 10:09:20 -0000 1.6 +++ openacs-4/packages/acs-tcl/tcl/exception-procs.tcl 10 Dec 2017 15:15:45 -0000 1.7 @@ -42,44 +42,115 @@ return "" } -ad_proc -private ad_try {code args} { +if {$::tcl_version eq "8.6"} { - @author rhs@mit.edu - @creation-date 2000-09-09 + # + # Tcl 8.6 variant of ad_try + # + + ad_proc ad_try { + {-auto_abort:boolean true} + body + args + } { + + Generic code for OpenACS to handle exceptions and traps based on + Tcl's primitives. This implementation is a slight generalization + of the Tcl 8.6 builtin ::try, which handles ad_script_aborts + automatically. - Executes $code, catches any exceptions thrown by ad_raise and runs - any matching exception handlers. + The command "ad_try" should replace the various exception handling + constructs such as "catch", which tend to swallow often error + conditions, making debugging unnecessarily hard. It will make + "with_finally" and "with_catch" obsolete, which should be marked + as deprecated in the not-to-far future. - If you use this I will kill you. + @see with_finally + @see with_catch + + } { + # + # Per default, ad_script_abort exceptions are automatically passed + # through the higher handlers, aborting all execution levels. Only + # the top-level processor should handle these cases (probably + # silently). + # + set extraTraps {} + if {$auto_abort_p} { + # + # The "subst" below is just used for resolving $body in + # the debug message. + # + lappend extraTraps \ + trap {AD EXCEPTION ad_script_abort} {result} [subst { + puts stderr "ad_script_abort of <$body> return value <\$result>" + ::throw {AD EXCEPTION ad_script_abort} \$result + }] + } + # + # Call the Tcl 8.6 builtin/compliant ::try in the scope of the caller + # + #puts stderr EXEC=[list ::try $body {*}$extraTraps {*}$args] + + tailcall ::try $body {*}$extraTraps {*}$args + } + +} else { + # version for Tcl 8.5 - @see with_finally - @see with_catch -} { + ad_proc ad_try { + {-auto_abort:boolean true} + body + args + } { + + Generic code for OpenACS to handle exceptions and traps based on + Tcl's primitives. This implementation is a slight generalization + of the Tcl 8.6 builtin ::try, which handles ad_script_aborts + automatically. - if {[set errno [catch {uplevel $code} result]]} { - if {$errno == 1 - && [lindex $::errorCode 0] eq "AD" - && [lindex $::errorCode 1] eq "EXCEPTION" - } { - set exception [lindex $::errorCode 2] + The command "ad_try" should replace the various exception handling + constructs such as "catch", which tend to swallow often error + conditions, making debugging unnecessarily hard. It will make + "with_finally" and "with_catch" obsolete, which should be marked + as deprecated in the not-to-far future. - set matched 0 - for {set i 0} {$i < [llength $args]} {incr i 3} { - if {[string match [lindex $args $i] $exception]} { - set matched 1 - break - } - } - - if {$matched} { - upvar [lindex $args $i+1] var - set var $result - set errno [catch {uplevel [lindex $args $i+2]} result] - } + @see with_finally + @see with_catch + + } { + # + # Per default, ad_script_abort exceptions are automatically passed + # through the higher handlers, aborting all execution levels. Only + # the top-level processor should handle these cases (probably + # silently). + # + set extraTraps {} + if {$auto_abort_p} { + # + # The "subst" below is just used for resolving $body in + # the debug message. + # + lappend extraTraps \ + trap {AD EXCEPTION ad_script_abort} {result} [subst { + puts stderr "ad_script_abort of <$body> return value <\$result>" + ::throw {AD EXCEPTION ad_script_abort} \$result + }] } + # + # Call the Tcl 8.6 builtin/compliant ::try in the scope of the caller + # + #puts stderr EXEC=[list ::try $body {*}$extraTraps {*}$args] + + #uplevel [list ::try $body {*}$extraTraps {*}$args] - return -code $errno -errorcode $::errorCode -errorinfo $::errorInfo $result - } + if {[catch {uplevel [list ::try $body {*}$extraTraps {*}$args]} msg opts]} { + dict incr opts -level + return {*}$opts $msg + } else { + return $msg + } + } } # Local variables: