2

这是一个代码,它只是实现了一个带有命令提示符的交互式 TCL 会话MyShell >

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

此代码MyShell >在终端提示并等待按下回车键;虽然它没有被击中,但代码什么也不做。这就是gets命令的作用。

我需要的是gets命令的替代方法,比如coolget. 该coolget命令不应该等待输入按钮,而是注册一些当它被击中时要调用的插槽,然后继续执行。所需的代码应如下所示:

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

这是我需要的:

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 }
4

2 回答 2

4

我认为您需要查看 fileevent、fconfigure 和 vwait 命令。使用这些,您可以执行以下操作:

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

此代码将 GetData 注册为标准输入的可读文件事件处理程序,因此只要有可读取的数据,就会调用它。

于 2012-01-04T09:00:04.977 回答
4

Tcl 将类似“nohang”的功能应用于整个通道,它是通过将通道配置为非阻塞来完成的。之后, anyread将只返回那里的数据,gets只返回无需等待即可获得的完整行,并且puts(在可写通道上)将安排其输出异步发送到操作系统。这取决于正在运行的事件循环。

建议您将非阻塞通道与已注册的文件事件处理程序一起使用。您可以将其与非阻塞相结合来实现您的coolget想法:

proc coolget {channel callback} {
    fileevent $channel readable [list apply {{ch cb} {
        if {[gets $ch line] >= 0} {
            uplevel [lappend cb $line]
        } elseif {[eof $ch]} {
            # Remove handler at EOF: important!
            fileevent $ch readable {}
        }
    }} $channel $callback]
}

这样就可以正常工作了,除非您必须调用其中一个vwaitupdate处理事件(除非您也使用了 Tk;Tk 是特殊的),因为 Tcl 不会在后台神奇地处理事情;神奇的后台处理带来的麻烦多于其价值……</p>


如果您在异步事件处理中纠缠不清,请考虑使用 Tcl 8.6 的协程来重构代码。特别是,像Coronet这样的代码可以提供很大帮助。然而,这非常依赖于 Tcl 8.6,因为早期的 Tcl 实现根本不支持协程;必须将低级实现从简单的 C 调用重写为延续以启用这些功能,并且通过合理的努力这是无法向后移植的。

于 2012-01-04T12:29:41.040 回答