2
votes

I need to redirect output of a proc to a file. The "redirect" command isn't working for the Tcl interpreter that my tool uses. So I'm trying "exec echo [proc_name]" instead, which was suggested in one of the threads on this site. But this doesn't work, the file ${dump_dir}/signal_list.txt comes out empty,

proc dump_signals {{dump_dir "."}} {
  upvar build build
  puts "Dumping signals.."
  set my_file [open ${dump_dir}/signal_list.txt w]
  exec echo [get_signals] > $my_file
}

'get_signals' is a proc, which calls another proc,

proc puts_name_and_value {name} {
  set value [value %h $name]
  puts "$name $value"
}

proc get_signals {} {

  # Get list of signals
  set signal_list {test.myreg test.myreg2}
  foreach signal $signal_list {
    puts_name_and_value $signal
  }
}

My workaround for now is this, writing to the file in the bottom level proc by upvar'ing the file variable. This works but isn't the most clean way of doing this. Please let me know how to cleanly redirect the output of a proc to a file.

proc puts_name_and_value {name} {
  upvar my_file my_file

  set value [value %h $name]
  puts $my_file "$name $value"
  #puts "$name $value"
}

proc get_signals {} {
  upvar my_file my_file

  # Get list of signals
  set signal_list {test.myreg test.myreg2}
  foreach signal $signal_list {
    puts_name_and_value $signal
  }
}

proc dump_signals {{dump_dir "."}} {
  upvar build build
  puts "Dumping signals.."
  set my_file [open ${dump_dir}/signal_list.txt w]
  get_signals
}
1

1 Answers

0
votes

Your dump_signals proc writes to standard output, and doesn't return anything. So of course trying to use a shell to redirect its output to a file isn't going to result in anything in the file.

One solution is to use tcl's transchan API with chan push and chan pop to temporarily override what stdout goes to. Example:

#!/usr/bin/env tclsh

proc redirector {fd args} {
    switch -- [lindex $args 0] {
        initialize {
            # Sanity check
            if {[lindex $args 2] ne "write"} {
                error "Can only redirect an output channel"
            }
            return {initialize write finalize}
        }
        write {
            puts -nonewline $fd [lindex $args 2]
        }
        finalize {
            close $fd
        }
    }
}

proc writer_demo {} {
    puts "line one"
    puts "line two"
}

proc main {} {
    chan push stdout [list redirector [open output.txt w]]
    writer_demo
    chan pop stdout
}
main

Running this script will produce a file output.txt with the contents of writer_demo's puts calls instead of having them go to standard output like normal.


You could also just pass the file handle to write to as an argument to your functions (Instead of using upvar everywhere):

proc puts_name_and_value {out name} {
  set value [value %h $name]
  puts $out "$name $value"
}

proc get_signals {{out stdout}} {
  # Get list of signals
  set signal_list {test.myreg test.myreg2}
  foreach signal $signal_list {
    puts_name_and_value $out $signal
  }
}

proc dump_signals {{dump_dir "."}} {
  upvar build build
  puts "Dumping signals.."
  set my_file [open ${dump_dir}/signal_list.txt w]
  get_signals $my_file
}