|
TclX (Extended Tcl) TclX(Extended Tcl)はNetSoftの Karl LehenbauerさんとMark Diekhansさんによって開発された、 Tcl言語の最も有名な拡張ライブラリのひとつです。 現在はTcl 8.4以降に対応した版が公開されており、 TclX自身のバージョンもまた8.4です。 TclXはTcl言語のみの拡張で、Tkに関する拡張はありません。 次のような機能が追加されています。
●インストールしよう % sh configure % make % su root # make install TclXの拡張が入ったtclshは「tcl」、wishは「wishx」という名前です。 どちらもTclXのコマンドが追加された他は普通のtclshやwishとして使えます。 ただ、私がインストールしようとしたときには、 make installの途中で「/pub/tcl が見つかりません」 という不可解なエラーで異常終了してしまいました。 一応、それでも使えていますけど…
●再帰グロブ recursive_globは、
recursive_glob startdir_list glob_list
このように使います。例えば、現在のディレクトリから下を検索し、
*.tclという名前のファイルを全部リストにして得るには、
set files [recursive_glob . *.tcl]
とします。
for_recursive_globはその制御構造版です。 例えば、現在のディレクトリから下を検索し、*.tclという名前のファイルを全部調べ、 その中の 'require' という文字列が含まれる行を行番号つきで全部出力するには、 このようにします。これは便利ライオン。
for_recursive_glob a {.} {*.tcl} {
set fp [open $a r]
for {set n 1} {! [eof $fp]} {incr n} {
set buf [gets $fp]
if {[regexp {require} $buf]} {
puts "$a\[$n\]:$buf"
}
}
close $fp
}
●コマンドのトレースとプロファイリング cmdtrace on [open cmd.log w] profile -commands -eval on source "freecell.tcl"; # 何か好きなファイルを cmdtrace off profile off ProfResult profrep ProfResult calls prof.logcmdtraceがコマンドのトレースをするコマンドで、 'on' を指定してから 'off' で中止するまでが記録されます。 'on' を指定するときに、Tcl標準のopenコマンドでファイルを開いたときのid を一緒につけると、結果はそのファイル(上ではcmd.log)に書き出されます。 省略するとstdoutに書き出されます。 profileはプロファイリングをするコマンドで、 使い方はほぼ同様です。'on' のときに -commands や-evalをつけるとチェックが細かくなります。 結果は'off'のときに引数で指定した名前の変数にハッシュ配列の形で格納されます。 こちらは、結果を整形してファイルに出力するのに profrepという専用のコマンドがあります。 2番目の引数は整形の際のソート基準で、「cpu」「calls」「real」 から選べます。最後の引数が出力ファイル名です。 コマンドのトレース結果はcmd.logにこのように書き出されます。
1: profile -commands -eval on
1: lindex freecellunix.tcl 0
1: source freecellunix.tcl
2: namespace eval FreeCell {\n\nset ImageData(spade) { R0lGODdhEwATAPc...}
3: set ImageData(spade) { R0lGODdhEwATAPcAAAAAAAAAVQAAqgAA/wAkAAA...}
3: set CANVASWIDTH 380
3: set CANVASHEIGHT 380
3: clock seconds
3: expr srand(930965642)
3: proc ProgramInit {} {\nvariable Score\nset Score(win) 0; set ...}
一番左はプロシージャの階層の番号です。
「expr srand([clock seconds])」のような入れ子のコマンドが、
「clock seconds」と「expr srand(930965642)」
という、2段階で記録されているのがわかります。
プロファイリングの結果はprof.logにこのように書き出されます。
-----------------------------------------------------------------------------
Procedure Call Stack Calls Real Time CPU Time
-----------------------------------------------------------------------------
FreeCell::random 380 158 157
FreeCell::Init
source
return 380 0 0
FreeCell::random
FreeCell::Init
source
llength 175 10 11
FreeCell::Init
source
list 156 0 0
FreeCell::DrawCardAtCanvasLocationOf
FreeCell::DrawAll
FreeCell::Init
source
...
...
つまり呼ばれた回数が一番多かったのが FreeCell::random
というプロシージャで、それと同じ回数だけ、そのプロシージャから戻る時の
returnコマンドが使われるので、この2つがトップに並んでいるわけです。
以下、ここでは呼ばれた回数順にソートされて結果が報告されています。
文字列を空または空白だけからなる文字列と比較するとき、
llengthの値が零かどうかで比べるという、私のクセがよく出ています。
●ランタイムヘルプ tcl>help lappendなどとTclコマンド、またはTclXコマンドの名前を入力すると、 ヘルプが表示されます。TclXコマンドの使い方がわからないときに非常に役立ちます。
●UNIXシステムプログラミング
# シグナルの番号は「SIGINT」「INT」「2」のどの形式でもOK
signal trap SIGINT trapINT
signal trap 15 trapTERM
proc trapINT {args} {
tk_messageBox -message "SIGINT Trapped."
}
proc trapTERM {args} {
tk_messageBox -message "SIGTERM Trapped."
}
label .laba -text Hello
button .cmda -text {Send Any Signal} -command exit
pack .laba -side top
pack .cmda -side top
●ハローミスターパイプマン
#! /usr/local/bin/perl
chomp($s = <STDIN>);
if(/^\d/){
($a) = gethostbyaddr(pack("C*", split(/\./, $s)), 2);
} else {
($a) = join(".", unpack("C*", gethostbyname($s)));
}
print "[$a]\n";
# end.
…えーとこれは本題ではないわけで、 今度は親プロセスたるTclスクリプトのほうですが、
#! /usr/local/bin/tclsh
package require Tclx
pipe fdin1 fdout1
pipe fdin2 fdout2
if {[fork] == 0} {
dup $fdin1 stdin
dup $fdout2 stdout
set cmd "perl ./gethost.pl"
eval execl $cmd
} else {
set alt_stdout [dup stdout]
dup $fdin2 stdin
dup $fdout1 stdout
fcntl stdout NONBLOCK 1
fcntl stdout NOBUF 1
puts "www.kantei.go.jp" ; # 話題の首相官邸をセレクト(ホントは適当)
set buf [gets stdin]
puts $alt_stdout "*** $buf ***"
puts $alt_stdout "salvaged: [wait]"
}
# end.
このスクリプトはpipe、dup、fork、execl、fcntl の5つのシステムコールを使って、子プロセスを起動してその標準入力、 標準出力をそれぞれ親プロセスの標準出力、標準入力と接続しています。 この方法でなぜ標準入出力が接続できるのかは割愛しますが、 これらのシステムコールと同名のTclコマンドのおかげで、PerlやPythonと同様、 低レベルなシステムプログラミングもこのように可能というわけですね。
●DNSによる名前解決(円満に)
#! /usr/local/bin/tclsh
package require Tclx
while 1 {
puts -nonewline ">"; flush stdout
set a [gets stdin]
if {[eof stdin]} break
if {[regexp {^[[:digit:]]} $a]} {
puts [host_info official_name $a]
} else {
puts [host_info addresses $a]
}
}
# end.
これはnslookupコマンドの簡易版みたいな対話型のコマンドラインツールで、 入力されたホスト名とIPアドレスを相互に変換して表示してくれます。 IPアドレスからそれが指すサーバ機の正規のホスト名を知るには、 host_info official_name コマンドを使います。また、そのマシンが持っている別名のリストを知るには、 host_info aliasesコマンドを使います。 逆にホスト名からIPアドレスを求めるには、 host_info addressesコマンドを使います。
|