0
votes

Running our software will start a Tcl shell in Terminal, then we can execute a series of tcl commands in this Tcl shell by souce a tcl script file. But the tcl commands inside the tcl script file will not be printed on the Tcl shell, so, we cannot see what commands have been executed by source the tcl script.

So my question is, is there any configuration of Tcl can print out the commands in the script when the script been source.

Following is an sample tcl script

# sample.tcl, composed of 3 tcl commands:
read designfile
analyze
write output

If we interactively execute the 3 tcl commands in the Tcl shell, the result will be look as:

Tcl> read designfile
Info: reading designfile
Info: size: 128k
...
...
Tcl> analyze
Info: analyzing designfile
Info: 108 modules need to be analyzed
...
...
Tcl> write output
Info: analyzed data been written into file "output"

If we source this tcl sript in Tcl shell, the result will be:

Tcl> source sample.tcl
Info: reading designfile
Info: size: 128k
...
...
Info: analyzing designfile
Info: 108 modules need to be analyzed
...
...
Info: analyzed data been written into file "output"

We expect the the result will be as below when we source the script.

Tcl> source sample.tcl
> read designfile
Info: reading designfile
Info: size: 128k
...
...
> analyze
Info: analyzing designfile
Info: 108 modules need to be analyzed
...
...
> write output
Info: analyzed data been written into file "output"
2

2 Answers

1
votes

That's a job for an execution trace. These can be applied to all sorts of Tcl commands, not just procedures.

trace add execution source enterstep {apply {{cmd op} {
    # Trim multiline commands down a bit; I find this helps me at least!
    regsub {\n.*} $cmd ... cmd
    # Print what's being run
    puts "EXECUTE: $cmd"
}}}
source thefile.tcl

Note that this may print a lot more than you expect! Here's a more sophisticated version that prints only the outermost level of execution.

# Called before [source] starts running
trace add execution source enter {apply {args {
    global SOURCE_LEVEL
    if {![info exists SOURCE_LEVEL]} {
        set SOURCE_LEVEL [info level]
    }
}}}
# Called after [source] finishes running
trace add execution source leave {apply {args {
    global SOURCE_LEVEL
    if {$SOURCE_LEVEL == [info level]} {
        unset SOURCE_LEVEL
    }
}}}
# Called for every command called while [source] is running
trace add execution source enterstep {apply {{cmd op} {
    global SOURCE_LEVEL
    if {$SOURCE_LEVEL == [info level]} {
        regsub {\n.*} $cmd "..." cmd
        puts "EXECUTE: $cmd"
    }
}}}
1
votes

Thanks Donal very much! Based on his suggestion, finally I got the trace command as below to satisfy my requirment.

proc print {args} {
    set cmd [lindex $args 0]
    puts stdout "$> $cmd"
}

trace add execution source enterstep print