Version 2 of puts workaround

Updated 2003-02-28 19:41:07

if 0 {Richard Suchenwirth 2003-02-28 - In a wish on the iPAQ, a plain puts raises the error

 cannot find channel named "stdout"

But as puts is a frequent and useful command, we want to have it working. So here�s a substitute that redirects the output to a specified text widget, if the (implicit or explicit) channel name is stdout or stderr, but else calls the original puts, which was renamed into the ::tcl namespace: }

 proc redef_puts w {
    set ::putsw $w
    if ![llength [info command ::tcl::puts]] {
       rename puts ::tcl::puts
       proc puts args {
          set la [llength $args]
          if {$la<1 || $la>3} {
             error "usage: puts ?-nonewline? ?channel? string"
          }
          set nl \n
          if {[lindex $args 0]=="-nonewline"} {
             set nl ""
             set args [lrange $args 1 end]
          }
          if {[llength $args]==1} {
             set args [list stdout $args]
          }
          foreach {channel s} $args break
          if {$channel=="stdout" || $channel=="stderr"} {
             $::putsw insert end $s$nl
          } else {
             set cmd ::tcl::puts
             if {$nl==""} {lappend cmd -nonewline}
             lappend cmd $channel $s
             eval $cmd
          }
       }
    }
 }

Lars H: The (roughly) Tcl 7.4 interpreter embedded in the (recently retired) Alpha7 [L1 ] text editor suffered from a similar problem. In that case the bug was much nastier: a simple [puts stdout "whatever"] would crash the entire application, since there was a bug in its code for emulating a console window.

I wrote a package I called terminal ([L2 ], also distributed with the Alpha text editor as of v7.6) to work around this problem. Besides a redefinition of puts similar to the above, it also features a set of commands that make it convenient to print messages smaller than a line. The commands

  for {set n 1} {$n<=10} {incr n} {
      terminal::print_word space "\[$n" none
      if {$n % 7 == 0} then {
          terminal::print_word newline "And that's divisible by 7." none
      }
      terminal::print_word none "\]" space
      if {$n % 5 == 0} then {
          terminal::print_word newline "Interruption!" newline
      }
  }

would print the following to "the terminal":

  [1] [2] [3] [4] [5]
  Interruption!
  [6] [7
  And that's divisible by 7.] [8] [9] [10]
  Interruption!

The first and third arguments of [terminal::print_word] request that the string in the second argument is separated from surrounding text by a certain degree of whitespace. Note that there are no stray spaces at the beginning or end of lines.

Oh, yes. I should also point out that the package is written so that it works also on a standard tclsh (or whatever) shell. The main point is to provide the terminal::print_word etc. commands -- the puts workaround was a minor point.


Arts and Crafts of Tcl-Tk Programming