I am working with a procedure in tcl over which I have no control. It puts out a lot of verbose on the output window like:
Response:<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><soapenv:Fault><faultcode>soapenv:Server</faultcode><faultstring>Item not valid: The specified Standard SIP1 Profile was not found</faultstring><detail><axlError><axlcode>5007</axlcode><axlmessage>Item not valid: The specified Standard SIP1 Profile was not found</axlmessage><request>updatePhone</request></axlError></detail></soapenv:Fault></soapenv:Body></soapenv:Envelope>
Is there any way i can redirect this stdout to a variable? I am new to tcl and am not aware how i can do this.
If you are using Tcl 8.6, you can trap all the output to stdout by adding a suitable transform via chan push:
# Use a class to simplify the capture code
oo::class create CapturingTransform {
variable var
constructor {varName} {
# Make an alias from the instance variable to the global variable
my eval [list upvar \#0 $varName var]
}
method initialize {handle mode} {
if {$mode ne "write"} {error "can't handle reading"}
return {finalize initialize write}
}
method finalize {handle} {
# Do nothing, but mandatory that it exists
}
method write {handle bytes} {
append var $bytes
# Return the empty string, as we are swallowing the bytes
return ""
}
}
# Attach an instance of the capturing transform
set myBuffer ""
chan push stdout [CapturingTransform new myBuffer]
# ... call the problem code as normal ...
# Detach to return things to normal
chan pop stdout
Things to note: this captures all output on the channel, however produced (it even works across threads or where the output is generated at the C level), and this puts bytes into myBuffer as the capturing is applied after the conversion to the channel's configured encoding. And it requires 8.6; the API concerned wasn't exposed to scripts in earlier versions (though it's C-equivalent was used by some extensions for things such as SSL support).
Always the same question..
You have a few options:
Write a Tcl Extension in C that exposes Tcl_SetStdChannel to script level. Probably one of the better solutions, but not that easy.
Rename and replace puts. For most output that comes from libs that write to stdout without being asked for this should be good enough. But there are a lot of other ways how someone could write something to stdout, e.g. chan puts, fcopy, exec echo foo >@stdout.
I think that it is hard to rewrite all possible places where a channel can be used.
Remove stdout from the interp. Downside is that you don't get the output. You can get stdout back after the procedure has run. For example:
set tint [interp create]
interp transfer {} stdout $tint
... call your stuff here...
interp share $tint stdout {}
interp delete $int
Note that you should probably not create the interp each time you need that. Create one once, and reuse it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With