Arjen Markus I read a question the other day on c.l.t. about tracing a script and I replied to a reply from Larry Virden, but while I misunderstood the question and his answer, I kept thinking "what does ksh -x actually do?" Then the light went on and I realised what I should have done, come up with a small script like the one below.
While it is far from perfect (I have one script that seems to get stuck with it), it is a beginning. For the moment: here it is "as is". Maybe I will be able to perfect it later:
# trace_script.tcl --
# Trace a script that is being executed
# Usage:
# tclsh trace_script.tcl script-to-run args
#
# namespace Trace --
# Private namespace
#
namespace eval ::Trace {
variable traceOut stdout
}
# prepareLine --
# Prepare the line of code for output
#
# Arguments:
# line Line of code
# Result:
# Line of code with [ and ] escaped
#
proc ::Trace::prepareLine {line} {
string map {[ \\\[ ] \\\] \" \\\" \{ \\\{ \} \\\} } $line
}
# source --
# Redefine the source command to manipulate the source
# of the script
#
# Arguments:
# filename Name of the file to be sourced
# Result:
# Whatever the source file does
# Side effects:
# The manipulated source file is loaded
#
if {[info commands ::tcl::source] == {}} then {
rename source ::tcl::source
}
proc source {filename} {
set infile [open $filename "r"]
set outfile [open TMP_$filename "w"]
while { [gets $infile line] >=0 } {
puts $outfile "puts \$::Trace::traceOut \"[::Trace::prepareLine $line]\""
puts $outfile $line
}
close $infile
close $outfile
::tcl::source TMP_$filename
file delete -force TMP_$filename
}
# main --
# Prepare argv and source the code
#
namespace import
catch {
console show
}
set filename [lindex $argv 0]
set argv [lrange $argv 1 end]
source $filenameMSW says, nice :) I've taken the freedom to change the target of the rename to ::tcl::source and remove the temporary file later.
RS: Writing a temporary file isn't necessary - just collect the "instrumented" code in a string variable and eval that. But I see a bigger danger: not every line contains a single command - sometimes it's less, or more. Consider
example with a long line that we want to continue \
on the next line
set data {
red
green
blue
}The putses will be inserted both inside the 'example' command, and in the 'data' block, probably both leading to unexpected behavior. Better use trace execution, it's built in - see Steppin' out