Search code examples
tclstdininteractivegets

TCL gets command with kind of -nohang option?


Here is a code which just implements an interactive TCL session with command prompt MyShell >.

puts -nonewline stdout "MyShell > "
flush stdout
catch { eval [gets stdin] } got
if { $got ne "" } {
    puts stderr $got
}

This code prompts MyShell > at the terminal and waits for the enter button to be hit; while it is not hit the code does nothing. This is what the gets command does.

What I need, is some alternative to the gets command, say coolget. The coolget command should not wait for the enter button, but register some slot to be called when it is hit, and just continue the execution. The desired code should look like this:

proc evaluate { string } \
{
    catch { eval $string } got
    if { $got ne "" } {
        puts stderr $got
    }
}

puts -nonewline stdout "MyShell > "
flush stdout
coolgets stdin evaluate; # this command should not wait for the enter button
# here goes some code which is to be executed before the enter button is hit

Here is what I needed:

proc prompt { } \
{
   puts -nonewline stdout "MyShell > "
   flush stdout
}


proc process { } \
{
   catch { uplevel #0 [gets stdin] } got
   if { $got ne "" } {
       puts stderr $got
       flush stderr
   }
   prompt
}

fileevent stdin readable process

prompt
while { true } { update; after 100 }

Solution

  • I think you need to look at the fileevent, fconfigure and vwait commands. Using these you can do something like the following:

    proc GetData {chan} {
        if {[gets $chan line] >= 0} {
           puts -nonewline "Read data: "
           puts $line
        }
    }
    
    fconfigure stdin -blocking 0 -buffering line -translation crlf
    fileevent stdin readable [list GetData stdin]
    
    vwait x
    

    This code registers GetData as the readable file event handler for stdin, so whenever there is data available to be read it gets called.