2

これは、コマンド プロンプトを使用して対話型 TCL セッションを実装するだけのコードですMyShell >

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

このコードMyShell >は端末でプロンプトを表示し、Enter ボタンが押されるのを待ちます。ヒットしていない間、コードは何もしません。これが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

Tcl は「nohang」のような機能をチャネル全体に適用します。これは、チャネルをノンブロッキングに設定することによって行われます。その後、 anyreadはそこにあるデータgetsのみを返し、待機せずに利用可能な完全な行のみを返し、puts(書き込み可能なチャネルで) その出力が OS に非同期的に送信されるように手配します。これは、操作中のイベント ループに依存します。

登録済みのファイル イベント ハンドラーでノンブロッキング チャネルを使用することをお勧めします。それをノンブロッキングと組み合わせて、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]
}

vwaitTclはバックグラウンドで物事を魔法のように処理しないため、イベントを処理するためにまたはのいずれかを呼び出す必要があることを除いてupdate(Tkも使用していない限り、Tkは特別です)、それは問題なく機能します。魔法のようなバックグラウンド処理は、必要以上にトラブルを引き起こします…</p>


非同期イベント処理に深くからまっている場合は、Tcl 8.6 のコルーチンを使用してコードを再構築することを検討してください。特に、 Coronetのようなコードは大いに役立ちます。ただし、以前の Tcl 実装はコルーチンをまったくサポートできないため、これは Tcl 8.6 に大きく依存しています。これらの機能を有効にするには、単純な C 呼び出しから継続への低レベルの実装を書き直す必要がありました。

于 2012-01-04T12:29:41.040 に答える
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 を stdin の読み取り可能なファイル イベント ハンドラーとして登録するため、読み取り可能なデータがある場合は常に呼び出されます。

于 2012-01-04T09:00:04.977 に答える