Index: library/lib/nx-shell.tcl =================================================================== diff -u -r2c896da7b1d39e489eb56aa35c9421951c652ee3 -r0956bd063e7aaa155b4dccad0997b381ddd5ec15 --- library/lib/nx-shell.tcl (.../nx-shell.tcl) (revision 2c896da7b1d39e489eb56aa35c9421951c652ee3) +++ library/lib/nx-shell.tcl (.../nx-shell.tcl) (revision 0956bd063e7aaa155b4dccad0997b381ddd5ec15) @@ -1,6 +1,6 @@ package require nx -package provide nx::shell 1.0 +package provide nx::shell 1.1 nx::Object create ::nx::shell2 { @@ -25,15 +25,23 @@ } :protected object method evalScript {-exit:switch script} { - set script [list catch [string trim $script] [current]::result [current]::opts] + set script [list interp invokehidden {} catch [string trim $script] [current]::result [current]::opts] set r [uplevel #0 $script] if {$r == 1} { puts stderr [dict get ${:opts} -errorinfo] if {$exit} { - exit 1 + :onExit -shell 1 } else { unset :opts; } + } elseif {$r == 2 && [info exists :statusCode]} { + set sc ${:statusCode} + unset :statusCode + if {$exit} { + :onExit -shell $sc + } else { + set :forever $sc + } } else { if {${:result} ne ""} { puts stdout ${:result} @@ -48,23 +56,21 @@ } :public object method run {argc argv} { - if {[catch { - if {$argc == 0} { + :exitOn + if {$argc == 0} { # interactive mode :prompt stdout fconfigure stdin -blocking 0 -buffering line fileevent stdin readable [list [current] onRead] vwait :forever fileevent stdin readable {} - exit + :onExit -shell ${:forever} } else { # non-interactive modes :nonInteract {*}$argv } - } msg]} { - puts stderr "[current] failed unexpectedly with '$msg'" - exit 2 - } + :exitOff + return 0 } :protected object method nonInteract {-c:switch args} { @@ -92,6 +98,66 @@ } } } + + :public object method onExit {-shell:switch {statusCode 0}} { + if {$shell} { + :exitOff + # outer (shell) exit + return -code ok -level [info level] $statusCode + } else { + # inner (script) exit + set :statusCode $statusCode + return -code return -level [info level] + } + } + + :public object method onCatch {-shell:switch args} { + set r [uplevel 1 [list interp invokehidden {} catch {*}$args]] + if {$r == 2 && [info exists :statusCode]} { + return -code return + } + return $r + } + + # :public object method exitOn {} { + # if {[interp alias {} ::exit] eq ""} { + # interp hide {} exit {}; + # interp alias {} ::exit {} [current] onExit + # interp hide {} catch; + # interp alias {} ::catch {} [current] onCatch + # } + # } + + # :public object method exitOff {} { + # if {[interp alias {} ::exit] ne ""} { + # interp alias {} ::exit {} + # interp expose {} exit; + # interp alias {} ::catch {} + # interp expose {} catch; + # } + # } + + :public object method exitOn {} { + if {[info commands ::_exit] eq ""} { + # + # exit is already aliased/hidden by nx::test + # + rename ::exit ::_exit + proc ::exit {{exitCode 0}} "[current] onExit \$exitCode" + interp hide {} catch; + interp alias {} ::catch {} [current] onCatch + } + } + + :public object method exitOff {} { + if {[info commands ::_exit] ne ""} { + rename ::exit "" + rename ::_exit ::exit + interp alias {} ::catch {} + interp expose {} catch; + } + } + } nx::Object create ::nx::shell { @@ -129,7 +195,7 @@ } } -package provide nx::shell 1.0 +package provide nx::shell 1.1 # Local variables: # mode: tcl Index: library/xotcl/xotclsh.in =================================================================== diff -u -r3ee0ac91f0a8034ec4739bc2af1016cdf30fbe57 -r0956bd063e7aaa155b4dccad0997b381ddd5ec15 --- library/xotcl/xotclsh.in (.../xotclsh.in) (revision 3ee0ac91f0a8034ec4739bc2af1016cdf30fbe57) +++ library/xotcl/xotclsh.in (.../xotclsh.in) (revision 0956bd063e7aaa155b4dccad0997b381ddd5ec15) @@ -17,8 +17,9 @@ # package require XOTcl 2 -package require nx::shell +package require nx::shell 1.1 namespace import -force ::xotcl::* -nx::shell2 run $argc $argv +set exitCode [nx::shell2 run $argc $argv] +exit $exitCode Index: library/xotcl/xowish.in =================================================================== diff -u -r3ee0ac91f0a8034ec4739bc2af1016cdf30fbe57 -r0956bd063e7aaa155b4dccad0997b381ddd5ec15 --- library/xotcl/xowish.in (.../xowish.in) (revision 3ee0ac91f0a8034ec4739bc2af1016cdf30fbe57) +++ library/xotcl/xowish.in (.../xowish.in) (revision 0956bd063e7aaa155b4dccad0997b381ddd5ec15) @@ -18,8 +18,9 @@ # package require Tk package require XOTcl 2 -package require nx::shell +package require nx::shell 1.1 namespace import -force ::xotcl::* -nx::shell2 run $argc $argv +set exitCode [nx::shell2 run $argc $argv] +exit $exitCode Index: nxsh.in =================================================================== diff -u -r3ee0ac91f0a8034ec4739bc2af1016cdf30fbe57 -r0956bd063e7aaa155b4dccad0997b381ddd5ec15 --- nxsh.in (.../nxsh.in) (revision 3ee0ac91f0a8034ec4739bc2af1016cdf30fbe57) +++ nxsh.in (.../nxsh.in) (revision 0956bd063e7aaa155b4dccad0997b381ddd5ec15) @@ -14,8 +14,10 @@ # markup in the first line of a script. It is designed to work with # multiple installed Tcl shells during development. # -package require nx::shell +package require nx::shell 1.1 namespace import -force ::nx::* -nx::shell2 run $argc $argv +set exitCode [nx::shell2 run $argc $argv] +exit $exitCode + Index: nxwish.in =================================================================== diff -u -r3ee0ac91f0a8034ec4739bc2af1016cdf30fbe57 -r0956bd063e7aaa155b4dccad0997b381ddd5ec15 --- nxwish.in (.../nxwish.in) (revision 3ee0ac91f0a8034ec4739bc2af1016cdf30fbe57) +++ nxwish.in (.../nxwish.in) (revision 0956bd063e7aaa155b4dccad0997b381ddd5ec15) @@ -17,8 +17,9 @@ # package require Tk -package require nx::shell +package require nx::shell 1.1 namespace import -force ::nx::* -nx::shell2 run $argc $argv +set exitCode [nx::shell2 run $argc $argv] +exit $exitCode Index: tests/shells.test =================================================================== diff -u -r56f9658ad54dd6756c9ec588e978b7db066791b7 -r0956bd063e7aaa155b4dccad0997b381ddd5ec15 --- tests/shells.test (.../shells.test) (revision 56f9658ad54dd6756c9ec588e978b7db066791b7) +++ tests/shells.test (.../shells.test) (revision 0956bd063e7aaa155b4dccad0997b381ddd5ec15) @@ -46,6 +46,18 @@ file delete -force $tmpfile + # exit and exit codes + ? [list exec $nxsh -c "exit 0"] "" + ? [list exec $nxsh -c "exit 1"] "child process exited abnormally" + ? [list exec $nxsh -c "exit 2"] "child process exited abnormally" + ? [list exec $nxsh -c "exit 5"] "child process exited abnormally" + ? [list catch [list exec $nxsh -c "exit 5"] ::res ::opts] "1" + ? {set ::res} "child process exited abnormally" + ? {lindex [dict get $::opts -errorcode] end} "5" + unset ::res; unset ::opts + ? [list exec $nxsh -c << "exit 0"] "" + ? [list exec $nxsh -c << "exit 1"] "child process exited abnormally" + ## avoid pollution of global namespace ## set tclsh [info nameofexecutable] ## set gvars1 [exec $tclsh << {puts [info vars]}]