**Communicating with other programs - fileevent, after** !!!!!! '''[Tcl Tutorial Lesson 42%|%Previous lesson%|%]''' | '''[Tcl Tutorial Index%|%Index%|%]''' | '''[Tcl Tutorial Lesson 41%|%Next lesson%|%]''' !!!!!! You can use the `fileevent` (or `chan event` in Tcl 8.5) to continuously communicate with another program. If that program takes input from the prompt (standard input), you can send it data or commands. Output to the screen (standard output) can be caught and handled. Here is a simple example. The program we are going to run is this: ====== # calc.tcl -- # Demo program # for {set i 0} {$i < 10} {incr i} { after 1000 puts $i flush stdout } ====== We use the `after` command to have it wait a little (1000 milliseconds, actually) before printing the next line. To ensure that the short line that is written is actually sent to the standard output rightaway, we use the `flush` statement. It may or may not be necessary - using it is safest. The counter part is the following program: ====== proc getline {chan} { global done gets $chan line if { ! [eof $chan] } { puts ">> $line" } else { close $chan set done 1 } } set program [open "|tclsh calc.tcl" r] fileevent $program readable [list getline $program] fconfigure $program -buffering line vwait done ====== Central in this program is the procedure `getline`. It takes a single argument, the channel to read from. When it is invoked, it reads a single line and echos it to the screen (standard output). If an end-of-file condition occurs, it closes the channel - the connection to the external process. Now the external process is started using the `open` command, instead of `exec`, so that we can communicate with it (here: only catch the output to standard output). The channel, in the variable `program`, is prepared for the type of communication we want via the `fconfigure` command, but it is not entirely necessary. When the end-of-file condition occurs - the other program stopped or closed its standard output channel, the channel in the controlling program is closed, but also the global variable `done` is set. This signals the `vwait` command to complete: until the variable `done` is set, it will wait and process any events. ***Interrupting the other program*** Suppose the other program takes a much longer time to run than you find acceptable. You can schedule code to run after a certain period so that the other program is killed. Unfortunately killing another program is a system-dependent action, using a command like `kill` on Linux, but we can close the channel to the program: ====== # Close the channel after 100 seconds ... after 100000 { catch { close $program } set done 1 } ====== The `catch` is necessary to make sure that the error reported by the other program on standard error does not interfer with our steering program (data written to standard error causes this). And out of laziness we have not used a proper procedure, but normally you would put code that is to be run via the `after` command in procedures to avoid quoting and scope problems. Such code runs in the ''global'' namespace. Besides killing another program or severing the connection, you can also use the `after` command as a way to send events to your program, enabling an event-driven programming style. !!!!!! '''[Tcl Tutorial Lesson 42%|%Previous lesson%|%]''' | '''[Tcl Tutorial Index%|%Index%|%]''' | '''[Tcl Tutorial Lesson 41%|%Next lesson%|%]''' !!!!!!