2
votes

In my main tcl script, I am calling a tcl proc wrapped in a catch command. This proc in-turn calls 10 more procs.

When there is an error in execution in any of those 10 procs, TCL still continues execution of my main script as expected and I am just able to view the error message which I captured. This error message may/may-not be conclusive enough to determine which of the 10 procs errored out during execution.

Is there a way to still keep capturing all the stdout until the point of error? I know it can be done by writing all messages (puts statements) in those 10 procs to another log file. But I'm interested in knowing if there is any other way.

2

2 Answers

1
votes

The catch command doesn't intercept I/O at all. To intercept output, the simplest and most method is to put a channel transform on that channel with chan push.

oo::class create Capture {
    variable contents encoding
    # Implement the channel interception protocol
    method initialize {handle mode} {
        set contents {}
        return {initialize finalize write}
    }   
    method finalize handle {
        # We do nothing here
    }
    method write {handle buffer} {
        append contents $buffer
        return $buffer
    }

    # Methods for ordinary people!
    method capture {channel body} {
        set encoding [chan configure $channel -encoding]
        chan push $channel [self]
        try {
            uplevel 1 $body
        } finally {
            chan pop $channel
        }
    }
    method contents {} {
        # Careful; need the encoding as channels work with binary data
        return [encoding convertfrom $encoding $contents]
    }
}

How to use this class:

set capt [Capture new]
$capt capture stdout {
    puts "Hello world!"
}
puts "Captured [string length [$capt contents]] characters"
puts [lmap c [split [$capt contents] ""] {scan $c "%c"}]

Output (I assume you recognise ASCII codes; the 13 10 at the end is a carriage-return/new-line sequence):

Hello world!
Captured 14 characters
72 101 108 108 111 32 119 111 114 108 100 33 13 10
0
votes

catch won't capture the stdout of a Tcl procedure, it will capture the return value.

A demo in an interactive tclsh:

% proc p {} {puts "some stdout"; return "return value"}
% catch p result
some stdout
0
% set result
return value