본문으로 바로가기

try/catch/finally 커맨드

category Tcl & Tk/팁 (Tip) 2025. 3. 26. 10:35

출처: http://people.man.ac.uk/~zzcgudf/tcl/try.tcl

 

아래의 코드로 Tcl에서도 try/catch/finally 구문을 사용할 수 있습니다. 이 스크립트를 사용하면 예외 처리를 쉽게 할 수 있어 스크립트의 오류를 최소한의 코드로 구조화된 방식으로 처리할 수 있습니다. Tcl 8.0 이상에서 사용 가능합니다.

namespace eval ::try {
    namespace export try
    variable bodyMatch {    \("uplevel" body line}
    proc helper {script part {eiv ei} {ecv ec} {codev code} {msgv msg}} {
        global errorInfo errorCode
        variable bodyMatch
        upvar 1 $eiv ei $ecv ec $codev code $msgv msg
        set code [catch [list uplevel 2 $script] msg]
        set ec $errorCode
        set lines [split $errorInfo "\n"]
        if {$code == 1} {
            while {![regexp $bodyMatch [lindex $lines end]]} {
                set lines [lrange $lines 0 [expr {[llength $lines]-2}]]
            }
            regsub {"uplevel" body} [lindex $lines end] $part fixed
            set lines [lrange $lines 0 [expr {[llength $lines]-2}]]
            lappend lines $fixed
        }
        set ei [join $lines "\n"]
    }
    proc try {body args} {
        # First, parse apart the args
        set hasFinally 0
        set catches {}
        for {set i 0} {$i<[llength $args]} {incr i} {
            set word [lindex $args $i]
            if {![string compare $word catch]} {
                if {$i+1 >= [llength $args]} {
                    return -code error "missing matcher to catch"
                } elseif {$i+2 >= [llength $args]} {
                    return -code error "missing body to catch"
                }
                lappend catches [lindex $args [incr i]]
                lappend catches [lindex $args [incr i]]
            } elseif {![string compare $word finally]} {
                if {$i+1 >= [llength $args]} {
                    return -code error "missing body to finally"
                }
                set finally [lindex $args [incr i]]
                set hasFinally 1
            } else {
                return -code error "unknown keyword \"$word\" to try:\
                        should be \"try body ?catch matcher body ...?\
                        ?finally body?\""
            }
        }

        # Now evaluate the body
        helper $body "try body"

        # Handle errors
        if {$code == 1} {
            foreach {matcher handler} $catches {
                if {[string match $matcher $ec]} {
                    helper $handler "catch \"$matcher\" body"
                    break
                }
            }
        }

        # Do the finally clause
        if {$hasFinally} {
            helper $finally "finally clause" a b c d
            if {$c} {
                set ei $a
                set ec $b
                set code $c
                set msg $d
            }
        }

        # Now we can return.  Phew!
        return -code $code -errorinfo $ei -errorcode $ec $msg
    }
}
namespace import ::try::try

## EXAMPLE ##
# try {
#     set f [open /non/existant/file]
# } catch {POSIX ENOENT *} {
#     puts "That file doesn't exist!"
# } catch {POSIX EACCES *} {
#     puts "You may not open that file!"
# } finally {
#     puts "Wibble..."
# }

try.tcl
0.00MB

'Tcl & Tk > 팁 (Tip)' 카테고리의 다른 글

popen 구현 하기  (0) 2025.03.26
C로 만드는 base64 디코드 커맨드  (0) 2025.03.26
특정 주기로 실행하는 every 커맨드  (0) 2025.03.26
Windows의 트레이 영역에 Notification 팝업 띄우기  (0) 2025.03.26
Round Frame  (0) 2025.03.26