user9900698
user9900698

Reputation:

Capture stdout within a TCL catch command

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.

Upvotes: 2

Views: 1713

Answers (2)

Donal Fellows
Donal Fellows

Reputation: 137757

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

Upvotes: 2

glenn jackman
glenn jackman

Reputation: 247122

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

Upvotes: 0

Related Questions