跳轉到內容

Tcl 程式設計/函式

來自華夏公益教科書,開放的書籍,開放的世界

命令基本上分為 C 定義的命令、過程和別名(以及從 Tcl 8.5 開始的組合)。您可以使用

rename oldname newname

要刪除命令(使其不再可訪問),請使用空字串作為新名稱

rename oldname {}

內省:使用

info commands

C 定義的命令

[編輯 | 編輯原始碼]

這些命令在 C 中實現,並註冊為在 Tcl 直譯器中可用。它們可以來自 Tcl 核心,也可以來自已載入的共享庫(DLL)- 例如 Tk。

要獲取內建命令的列表,請從 info commands 的結果中減去 info procs 的結果

set builtins {}
set procs [info procs]
foreach cmd [info commands] {
   if {[lsearch -exact $procs $cmd] == -1} {lappend builtins $cmd}
}

以下 C 定義的命令在新的 tclsh 中可用。有關詳細文件,請參閱相應的聯機幫助頁,例如,在 http://www.tcl.tk/man/tcl8.5/TclCmd/ - 我將只對每個命令進行簡要描述

after
用於定時事件的命令組
after msec ?script?
等待或在一段時間後執行指令碼
append varName arg..
將引數追加到字串變數
array
用於陣列的命令組
binary
用於二進位制掃描和格式化的命令組
break
終止當前迴圈
case
已棄用,使用 switch
catch script ?varName?
捕獲 script 中的可能的錯誤
cd path
更改工作目錄
clock
處理日期和時間的命令組
close handle
關閉通道(檔案、套接字等)
concat list..
將引數合併成一個空格分隔的列表
continue
開始當前迴圈的下一個迭代
encoding
處理字元集編碼的命令組
eof handle
如果通道位於檔案末尾,則為 1,否則為 0
error message ?info? ?code?
使用給定訊息引發錯誤
eval arg..
將引數作為指令碼進行評估
exec file arg..
執行一個獨立的程序
exit ?int?
終止此程序,返回狀態 0..127
expr arg..
算術和邏輯引擎,使用類似於 C 的語法和函式(變數引用使用 $name)。此外,從 Tcl 8.4 開始,有 eqne 運算子用於字串相等或不相等;從 8.5 開始,還有 inni 運算子用於列表包含或不包含
expr {"foo" in {foo bar grill}} == 1

expr 的引數在大多數情況下應該是 {花括號括起來的}。這可以防止 Tcl 解析器預先替換變數,而 expr 本身必須從字串中解析值。在花括號括起來的表示式中,expr 可以自行解析變數引用,並在可能的情況下直接獲取其數值。通常更快。唯一的例外是,當您想要從變數中替換運算子時,不應使用花括號

foreach op {+ - * /} {puts [expr 1 $op 2]}
fblocked handle
如果上次輸入操作用盡了所有可用輸入,則返回 1,否則返回 0
fconfigure handle -option value...
配置通道,例如其編碼或換行符轉換
fcopy handle1 handle2
將資料從 handle1 複製到 handle2
file
處理檔案的命令組
fileevent
處理通道(可讀、可寫)事件(但不是檔案)的命令組
flush handle
確保通道的緩衝區已寫入。在 puts -nonewline 之後很有用
for initbody condition stepbody body
迴圈,與 C 的 for 有些類似
foreach varlist list ?varlist list...? body
遍歷一個或多個列表。varlist 可以是單個或多個 varName。例如
% foreach {x y} {1 0  1 2  0 2  0 0} {puts "x:$x, y:$y"}
x:1, y:0
x:1, y:2
x:0, y:2
x:0, y:0
format fstring arg..
將引數 %-格式化為 fstring,類似於 C 的 sprintf()
gets handle ?varName?
從 handle 讀取一行。如果給出變數,則將行分配給它並返回讀取的字元數;否則返回行。保證防範緩衝區溢位
glob ?-options? pattern..
匹配 glob 模式(可以包含 * 和 ? 萬用字元)的檔案列表
global varName..
宣告給定的變數為全域性變數
history
列出最近的互動式命令
if condition ?then? body1 ?elseif condition body2...? ??else? bodyN?
條件語句
incr varName ?amount?
將整數變數增加給定的數量(預設為 1)。使用負數來減少
info
用於內省的命令組
interp
用於直譯器的命令組
join list ?separator?
將列表轉換為字串,在元素之間使用分隔符(預設為 " ")
lappend varName arg..
將引數追加到列表變數。也可以用於確保變數存在
lappend x ;# corresponds to: if {![info exists x]} {set x ""}
lindex list int..
透過整數索引(es)檢索列表中的元素
linsert list int arg..
在列表的 int 位置插入引數
list ?arg..?
從引數建立列表
llength list
列表的長度
load filename ?name?
載入共享庫(DLL)
lrange list from to
返回整數索引 from-to 處的子列表
lreplace list from to arg..
用引數替換列表中的子列表
lsearch ?-options? list element
在列表中搜索元素,返回其整數索引,如果未找到,則返回 -1。可用於從列表中選擇元素子集(使用 -all 選項)
lset varName int.. value
將命名列表變數中的現有元素設定為給定值,該元素由整數(es)索引
lsort ?-options? list
對列表進行排序
namespace
處理名稱空間的命令組
open name ?mode ?permissions??
開啟檔案或管道,返回控制代碼
package
處理包的命令組
pid ?handle?
返回當前程序的 ID。也可以返回給定管道通道的管道的 pid 列表
proc name arglist body
定義過程
puts ?-nonewline? ?channel? string
將一行輸出到給定的通道(預設情況下為 stdout)。要防止從已關閉的管道(如 morehead)中出現錯誤,請使用
proc puts! str {if [catch {puts $str}] exit}
pwd
返回當前工作目錄
read handle ?int?
從 handle 讀取 int 個位元組(如果沒有給出 int,則讀取所有位元組)
regexp ?-options? re string ?varName...?
在字串中匹配 re 的正則表示式,可能將帶括號的子匹配分配給給定的變數
regsub ?-options? re value substring ?varName?
用子字串替換 value 中正則表示式 re 的出現次數。如果給出 varName,則將新值分配給它,並返回替換次數;否則返回新值
rename cmdName1 cmdName2
將命令從 cmdName1 重新命名為 cmdName2,如果 cmdName2 為 {},則刪除 cmdName1
return ?value?
退出當前過程或已原始碼化的指令碼
scan string format ?varName...?
根據字串中的 %-格式提取值到給定的變數。類似於 C 的 sscanf()
seek channelId offset ?origin?
將檔案中的指標移動到給定位置
set varName ?value?
如果給出,則將變數設定為值,並返回變數的值
socket ?-myaddr addr? ?-myport myport? ?-async? host port
開啟 TCP 連線的客戶端作為通道
socket -server command ?-myaddr addr? port
開啟 TCP 連線的伺服器端,為客戶端請求註冊一個處理程式回撥命令
source filename
評估給定檔案的內容
split list ?charset?
將字串拆分為列表,使用 charset 字串中的任何字元作為分隔符(預設為 " ")
string
處理字串的命令組
subst ?-options? string
在字串中執行命令、變數或反斜槓替換
switch ?-options? ?--? value alternatives
如果值匹配,則執行一個備選方案
tell handle
返回檔案內部的位元組位置
time body ?int?
執行 body int 次(預設 1),返回每次迭代使用了多少微秒
trace
用於將操作繫結到變數或命令的命令組
unset varName..
刪除給定的變數
update ?idletasks?
服務事件
uplevel ?level? body
在呼叫堆疊中向上評估 body
upvar ?level? varName localVarName...
將給定的變數繫結到呼叫堆疊中的給定區域性變數。用於按引用呼叫,例如用於陣列
variable varName ?value ?varName value...??
宣告變數在名稱空間中是非區域性的
vwait varName
掛起執行,直到給定變數發生變化。如果事件迴圈尚未啟用,則啟動它
while condition body
只要條件不為 0,就執行 body

Tcl 中的過程對應於其他語言中的過程、子程式或函式。它們始終返回一個結果(即使是空字串 ""),因此稱它們為函式可能最合適。但出於歷史原因,用於建立函式的 Tcl 命令稱為 **proc**,因此人們通常稱它們為過程。

proc name argumentlist body

示例

proc sum {a b} {return [expr {$a+$b}]}

return 是多餘的,因為 proc 在到達其末尾並返回其最後一個結果時會自動返回。

proc sum {a b} {expr {$a+$b}}

以下變體更加靈活,因為它接受任意數量的引數(特殊引數名 args 將所有剩餘引數收集到一個列表中,該列表是引數 args 的值)。

proc sum args {
    set res 0
    foreach arg $args {set res [expr {$res + $arg}]}
    return $res
}

一個優雅但效率較低的替代方法是透過 join 使用加號連線 args 來構建字串,並將該字串提供給 expr

proc sum args {expr [join $args +]}

如果 proc 定義中的引數是一個包含兩個元素的列表,則如果在呼叫中未給出第二個元素,則將其作為預設值(在本例中為 "Sir")。

proc greet {time {person Sir}} {return "good $time, $person"}
% greet morning John
good morning, John
% greet evening
good evening, Sir

**內省:** 使用以下命令獲取所有已定義過程的名稱。

info procs

還有一些 **info** 子命令可以獲取過程的引數列表、可能的預設引數和主體。以下示例將它們結合起來,根據名稱重新建立過程的文字形式(corpproc 的反向)。

proc corp name {
   set argl {}
   foreach arg [info args $name] {
      if [info default $name $arg def] {lappend arg $def}
      lappend argl $arg
   }
   list proc $name $argl [info body $name]
}

使用 **rename**,您可以過載任何命令,包括 C 編碼的命令。首先將原始命令重新命名為其他名稱,然後使用相同的簽名重新實現它,最終呼叫原始命令。例如,以下是一個過載的 proc,它報告是否多次使用相同的名稱定義了過程。

rename proc _proc
_proc proc {name argl body} {
   if {[info procs $name] eq $name} {
       puts "proc $name redefined in [info script]"
   }
   _proc $name $argl $body
}

**命名引數:** 命令的引數主要透過位置傳遞。但是,很容易新增 Python 或 Ada 中已知的行為,即引數可以在函式呼叫中命名,這可以更好地記錄程式碼,並允許以任意順序傳遞引數。

這個想法(正如在 Welch 的書中發現的那樣)是使用一個數組(這裡稱為 "" - "匿名陣列"),該陣列以引數名為鍵。最初,您可以設定一些預設值,並可能使用 proc 的引數覆蓋它們(該引數必須成對,即包含偶數個元素)。

proc named {args defaults} {
   upvar 1 "" ""
   array set "" $defaults
   foreach {key value} $args {
     if {![info exists ($key)]} {
        set names [lsort [array names ""]]
        error "bad option '$key', should be one of: $names"
     }
     set ($key) $value
   }
}

用法示例

proc replace {s args} {
  named $args {-from 0 -to end -with ""}
  string replace $s $(-from) $(-to) $(-with)
}

測試

% replace suchenwirth -from 4 -to 6 -with xx
suchxxirth
% replace suchenwirth -from 4 -to 6 -witha xx
bad option '-witha', should be one of: -from -to -with

按名稱或值傳遞引數

[編輯 | 編輯原始碼]

通常,命令的引數按值傳遞(作為常量,或在變數名前面加上 $)。這可以安全地防止副作用,因為命令只會獲得值的副本,而無法更改變數。

但是,有時就是需要這樣。想象一下,您想要一個自定義命令將變數設定為零。在這種情況下,在呼叫時指定變數的名稱(不帶 $),並在 proc 中使用 **upvar** 將名稱(在範圍 "1 up" 中,即呼叫者的範圍)連結到本地變數。我通常在作為變數名的引數前面加上一個 _(例如 _var),並將 upvar 連結到沒有 _ 的相同名稱(例如 var)。

% proc zero _var {upvar 1 $_var var; set var 0}
% set try 42
42
% zero try
0
% set try
0

如果您經常使用按引用呼叫,您可以使用特殊模式(例如 &arg)來指示此類引數,並使用以下程式碼生成必要的 **upvar**。

proc use_refs { {char &}} {
   foreach v [uplevel 1 {info locals}] {
       if [string match $char* $v] {
           uplevel 1 "upvar 1 \${$v} [string range $v 1 end]"
       }
   }
}

就是這樣。最好先在 proc 內部呼叫此命令,並對以特定字元開頭的所有引數進行 upvar 操作,預設字元為 "&" - 它執行類似於以下程式碼的程式碼

upvar 1 ${&foo} foo

在呼叫者的範圍內。測試

proc test_refs {a &b} {
   use_refs
   puts a=$a,b=$b
   set b new_value
}
% set bar 42
42
% test_refs foo bar
a=foo,b=42

因此,a(按值傳遞)和 b(按引用傳遞)的值是可讀的;並且在呼叫者中更改 b 的副作用也發生了。

% set bar
new_value

變數範圍

[編輯 | 編輯原始碼]

在過程內部,變數預設情況下是本地的。它們只存在於 proc 中,並在 return 時被清除。但是,您可以將本地變數繫結到呼叫堆疊中更高的變數(例如,在呼叫者中),直到最頂層的全域性範圍。

proc demo arg {
   global g
   set    g 0            ;# will effect a lasting change in g
   set local 1           ;# will disappear soon
   set ::anotherGlobal 2 ;# another way to address a global variable
   upvar 1 $arg myArg    ;# make myArg point at a variable 1-up
   set          myArg 3  ;# changes that variable in the calling scope
}

還可以將命令定義為一個或多個單詞序列的別名,這些單詞將在執行之前替換它。(有趣的是 {} 引數是源和目標直譯器的名稱,它們通常是當前直譯器,由空字串 {} 或 "" 命名)。示例

interp alias {} strlen {} string length
interp alias {} cp     {} file copy -force

內省:使用以下命令獲取所有已定義別名的名稱。

interp aliases

高階概念

[編輯 | 編輯原始碼]

直譯器

[編輯 | 編輯原始碼]

Tcl 是一種解釋型(加上即時位元組編譯)語言,因此直譯器當然是一種核心型別的物件。每次執行 Tcl 時,至少會執行一個直譯器,它接收指令碼並對其進行評估。

還可以建立額外的 "從屬" 直譯器來封裝資料和程序,這些直譯器又可以有它們自己的 "子從屬" 直譯器,依此類推,最終形成一個樹形層次結構。示例

% interp create helper
helper
% helper eval {expr 7*6}
42
% interp delete helper
% helper eval {expr 1+2}
invalid command name "helper"

透過刪除直譯器,所有全域性變數(以及名稱空間變數)也會被釋放,因此,如果需要,您可以使用它來進行模組化和封裝。

特別是,**安全直譯器** 故意限制了功能(例如,訪問檔案系統或 Web),因此來自 Web 的可能惡意程式碼無法造成重大破壞。

內省:以下命令列出當前直譯器的子直譯器("從屬")。

% interp slaves

整合(從 Tcl 8.5 開始),是指根據標準模式由子命令組成的命令。例如,Tcl 的內建 **chan** 和 **clock** 命令。子命令的排程以及對不存在子命令的提示性錯誤訊息都是內建的。子命令位於名為 "-map" 的 dict 結構中,包含交替的名稱和操作。非常簡單的示例

namespace ensemble create -command foo -map \
      {bar {puts Hello} grill {puts World}}

建立了一個名為 foo 的命令,它可以像下面這樣呼叫。

% foo bar
Hello
% foo grill
World
% foo help
unknown or ambiguous subcommand "help": must be foo, or bar

顯然,整合也是實現面向物件程式設計的一個很好的基礎,其中命令是物件的名稱,對映包含其方法。

**內省:** 使用以下命令序列化整合的對映。

namespace ensemble configure $name -map

名稱空間

[編輯 | 編輯原始碼]

名稱空間是用於存放過程、非區域性變數和其他名稱空間的容器。它們形成一個樹形結構,根位於名為 "::" 的全域性名稱空間。它們的名稱也使用 :: 作為分隔符,因此 ::foo::bar::foo 的子節點,::foo:: 的子節點(類似於 Unix 上的路徑名,其中 / 既是分隔符又是根)。

簡而言之,名稱空間是一個單獨的區域,或者說是 範圍,過程和變數在該範圍內可見,並且對該範圍私有。

要建立名稱空間,只需在其中 eval 某些指令碼(可以為空)。

namespace eval ::foo {}

現在您可以使用它來定義過程或變數。

proc ::foo::test {} {puts Hello!}
set  ::foo::var 42

要刪除名稱空間(並清理其所有變數、過程和子名稱空間),可以使用以下命令。

namespace delete ::foo

內省

namespace children ::
info var namespace::*
info commands namespace::*

以下程式碼給出了 Tcl 名稱空間(其中 ::,即全域性名稱空間,特別有趣 - 所有(孫)子節點也被新增)的變數和子節點所佔用的位元組大小的近似值。如果您多次呼叫此 proc,則可以觀察資料是否正在累積。

proc namespace'size ns {
  set sum [expr wide(0)]
  foreach var [info vars ${ns}::*] {
      if {[info exists $var]} {
          upvar #0 $var v
          if {[array exists v]} {
              incr sum [string bytelength [array get v]]
          } else {
              incr sum [string bytelength $v]
          }
      }
  }
  foreach child [namespace children $ns] {
      incr sum [namespace'size $child]
  }
  set sum
}

用法示例

% puts [namespace'size ::]
179914

執行緒

[編輯 | 編輯原始碼]

Tcl 使用者傳統上對執行緒(輕量級併發子程序)持懷疑態度 - 事件迴圈模型已被證明非常強大,並且更容易除錯。最初來自 Tk,事件迴圈已經遷移到 Tcl,並用於

  • 檔案事件(比實際檔案更關注通道)
  • 計時事件
  • UI 事件(使用者進行的滑鼠或鍵盤操作)

但是,在 Tcl 構建中啟用執行緒的趨勢正在增長。底層模型是每個執行緒都在它自己的直譯器中執行,因此它基本上與外部世界隔離。執行緒之間的通訊必須使用顯式方法進行。

包和擴充套件

[編輯 | 編輯原始碼]

包是 Tcl 推薦的模組化軟體,尤其是支援庫。使用者最常使用的命令是

package require name ?version?

您可以使用純 Tcl 或作為擴充套件的包裝器來編寫包,擴充套件包括一個或多個已編譯的共享庫(以及可選的一個或多個 Tcl 指令碼)。流行的擴充套件包括

  • BWidget(將有用的部件新增到 Tk - 更多內容見下文)
  • Expect(支援透過網路進行遠端執行)
  • Img(將對 Tk 新增對其他影像檔案格式的支援)
  • snack(聲音輸入/輸出)
  • Snit(OO 擴充套件,支援 Tk 中的 "超級部件")
  • sqlite(一個微小但功能強大的 SQL 資料庫)
  • tcllib(一個純 Tcl 包的集合 - 更多內容見下文)
  • TclOO(從 8.5 開始的規範面向物件擴充套件)
  • tcltcc(一個內建的 C 編譯器 - 更多內容見下文)
  • TclX(系統相關擴充套件的集合,例如訊號處理)
  • tdom(XML 解析器,SAX 或 DOM,帶有 XPath 查詢支援)
  • Tk(跨平臺 GUI 工具包,更多內容見下文)
  • tkcon(一個擴充套件了的功能豐富的控制檯)
  • XOTcl(高階動態 OO 擴充套件)

一個小例子包

[編輯 | 編輯原始碼]

以下指令碼建立了一個簡單的但有教育意義的包 futil,它在同名的名稱空間中實現了兩個用於讀取和寫入完整文字檔案的 proc,以及一個小的內省輔助函式 futil::?。註冊包(package provide)的命令僅在一切順利後才執行 - 這樣,有錯誤的原始碼,在包要求期間引發錯誤,將不會被註冊。(其他錯誤你必須自己發現並修復...)

常見的 Tcl 分發實踐有一個很好的習慣,即進行深入的測試,通常是在一個單獨的測試目錄中。另一方面,在同一個檔案中將自測試包含在程式碼中使編輯更容易,因此在 package provide 之後,只會在將此檔案作為頂層指令碼原始碼時執行的部分,它會練習在 futil 中定義的命令。是否應該將讀取的字串與寫入的字串相等是可爭議的 - 當前實現如果字串不以 \n 結尾,就會將 \n 附加到字串中,因為有些工具會抱怨或行為異常,如果它們沒有看到最後的換行符。

如果測試也沒有遇到任何錯誤,即使是包索引的必要構造也會被觸發 - 假設目錄中只包含一個包。否則,你最好刪除這些行,並自己處理索引建立。

使用此包的指令碼只需要包含這兩行

lappend ::auto_path <directory of this file>
package require futil

如果你安裝(複製)包含原始碼和 pkgIndex.tcl 的目錄到 ${tcl_install_directory}/lib 下,你甚至可以省略第一行。

namespace eval futil {
    set version 0.1
}

但現在回到組成包的單個指令碼(將其儲存為 futil.tcl 會更有意義)。我們在 futil 名稱空間中提供了一個 read 和一個 write 函式,外加一個小的內省函式 ?,它返回可用函式的名稱

proc futil::read {filename} {
   set fp [open $filename]
   set string [::read $fp] ;# prevent name conflict with itself
   close $fp
   return $string
}
proc futil::write {filename string} {
   set fp [open $filename w]
   if {[string index $string end]!="\n"} {append string \n}
   puts -nonewline $fp $string
   close $fp
}
proc futil::? {} {lsort [info procs ::futil::*]}
# If execution comes this far, we have succeeded ;-)
package provide futil $futil::version
#--------------------------- Self-test code
if {[info ex argv0] && [file tail [info script]] == [file tail $argv0]} {
   puts "package futil contains [futil::?]"
   set teststring {
       This is a teststring
       in several lines...}
   puts teststring:'$teststring'
   futil::write test.tmp $teststring
   set string2 [futil::read test.tmp]
   puts string2:'$string2'
   puts "strings are [expr {$teststring==$string2? {}:{not}}] equal"
   file delete test.tmp ;# don't leave traces of testing
   # Simple index generator, if the directory contains only this package
   pkg_mkIndex -verbose [file dirn [info scr]] [file tail [info scr]]
}

Tcllib

[edit | edit source]

Tcllib 是一個純 Tcl 包的集合。它可以從 sourceForge 獲取,但也是 ActiveTcl 的一部分。以下包含的包列表可能不完整,因為 Tcllib 正在不斷增長...

  • aes - 高階加密標準。
  • asn - asn.1 BER 編碼器/解碼器
  • http/autoproxy - 用於自動使用 HTTP 代理伺服器的程式碼
  • base64 - 字串和檔案的 Base64 編碼和解碼。
  • bee - BitTorrent 序列化編碼器/解碼器。
  • bibtex - Neil Madden 的 bibtex 檔案解析器。尚未完全完成,因此未設定為安裝。
  • calendar - 日曆操作(參見 tcllib 日曆模組)。
  • cmdline - 各種形式的命令列和選項處理。
  • comm - 基於套接字的程序間通訊。模擬 Tk 的 send 命令的形式。
  • control - 用於 tcl 流程結構的程式,如 assert、do/until、do/while、no-op
  • counter - 用於計數器和直方圖的程式
  • crc - 計算字串和檔案的各種 CRC 校驗和。
  • csv - 操作逗號分隔值資料
  • des - 資料加密標準。 ::DES::des (尚未安裝)
  • dns - 與域名系統互動。 dns::address、dns::cleanup、dns::cname、dns::configure、dns::name、dns::reset、dns::resolve、dns::status、dns::wait,
  • doctools - 用於以簡單但強大的格式編寫手冊頁/文件的系統。
  • exif - exif::analyze exif::fieldnames
  • fileutil - 用於操作檔案的實用程式,模擬各種 unix 命令列應用程式(cat、find、file(type)、touch、...)。
  • ftp - FTP(檔案傳輸協議)的客戶端實現。迫切需要重寫。
  • ftpd - FTP 的伺服器端實現
  • grammar_fa - 對有限自動機進行操作。
  • html - 從 Tcl 指令碼生成 HTML。 html::author、html::author、html::bodyTag、html::cell、html::checkbox、html::checkSet、html::checkValue、html::closeTag、html::default、html::description、html::description、html::end、html::eval、html::extractParam、html::font、html::for、html::foreach、html::formValue、html::getFormInfo、html::getTitle、html::h、html::h1、html::h2、html::h3、html::h4、html::h5、html::h6、html::hdrRow、html::head、html::head、html::headTag、html::if、html::init、html::init、html::keywords、html::keywords、html::mailto、html::meta、html::meta、html::minorList、html::minorMenu、html::openTag、html::paramRow、html::passwordInput、html::passwordInputRow、html::radioSet、html::radioValue、html::refresh、html::refresh、html::row、html::select、html::selectPlain、html::set、html::submit、html::tableFromArray、html::tableFromList、html::tagParam、html::textarea、html::textInput、html::textInputRow、html::title、html::title、html::urlParent、html::varEmpty、html::while,
  • htmldoc - 這不是一個真正的模組,而是 tcllib 1.3 安裝 tcllib 文件的 HTML 格式的地方。
  • htmlparse - 用於允許對包含 HTML 的字串進行有限操作的程式。 ::htmlparse::parse、 ::htmlparse::debugCallback、 ::htmlparse::mapEscapes、 ::htmlparse::2tree、 ::htmlparse::removeVisualFluff、 ::htmlparse::removeFormDefs,
  • ident - RFC 1413 ident 客戶端協議實現
  • imap4 - 當前用於與 IMAP 伺服器互動的未記錄程式碼
  • inifile - 用於操作初始化檔案的程式碼。 ::ini::open、 ::ini::close、 ::ini::commit、 ::ini::sections、 ::ini::keys、 ::ini::value
  • dns/ip - IP 地址的操作。 ::ip::version、 ::ip::is、 ::ip::normalize、 ::ip::equal、 ::ip::prefix
  • irc - 網際網路中繼聊天程式。 irc::config、irc::connection,
  • javascript - 生成 Javascript 以包含在 HTML 頁面中。 javascript::BeginJS、javascript::EndJS、javascript::MakeMultiSel、javascript::MakeClickProc、javascript::makeSelectorWidget、javascript::makeSubmitButton、javascript::makeProtectedSubmitButton、javascript::makeMasterButton、javascript::makeParentCheckbox、javascript::makeChildCheckbox
  • jpeg - 編輯註釋塊,獲取 JPG 格式影像的尺寸和資訊,讀取影像的 exif 資料
  • ldap - LDAP(輕量級目錄訪問協議)的客戶端實現。
  • log - 用於將日誌條目新增到檔案的通用程式。 ::log::levels、 ::log::logMsg、 ::log::lv2longform、 ::log::lv2color,::log::lv2priority,
  • logger - ::logger::walk、 ::logger::services、 ::logger::enable、 ::logger::disable (日誌模組的一部分)
  • math - 通用數學程式。 ::math::calculus、 ::math::combinatorics、 ::math::cov、 ::math::fibonacci、 ::math::integrate、 ::math::interpolate、 ::math::max、 ::math::mean、 ::math::min、 ::math::optimize、 ::math::product、 ::math::random、 ::math::sigma、 ::math::statistics、 ::math::stats、 ::math::sum
  • md4 -  ::md4::md4、 ::md4::hmac、 ::md4::MD4Init、 ::md4::MD4Update、 ::md4::MD4Final
  • md5 - [填寫此模組的描述]  ::md5::md5、 ::md5::hmac、 ::md5::test、 ::md5::time、 ::md5::<<<
  • md5crypt -  ::md5crypt::md5crypt、 ::md5crypt::aprcrypt
  • mime - ::mime::initialize、 ::mime::parsepart、 ::mime::finalize、 ::smtp::sendmessage
  • multiplexer - [填寫外部介面]
  • ncgi - 用於 CGI 應用程式的程式。 ::ncgi::reset、 ::ncgi::urlStub、 ::ncgi::urlStub
  • nntp - 用於與 Usenet 新聞伺服器互動的例程。 ::nntp::nntp、 ::nntp::NntpProc、 ::nntp::NntpProc、 ::nntp::okprint、 ::nntp::message,
  • ntp - 網路時間協議程式 ::ntp::time
  • png - 編輯註釋塊,獲取可移植網路圖形格式的影像尺寸和資訊。
  • pop3 - 用於從 pop3 伺服器讀取郵件的郵局協議函式。 ::pop3::open、 ::pop3::close、 ::pop3::status,
  • pop3d - 郵局協議伺服器。 pop3d::new
  • profiler -  ::profiler::tZero、 ::profiler::tMark、 ::profiler::stats、 ::profiler::Handler、 ::profiler::profProc、 ::profiler::init
  • rc4 - 流加密。 ::rc4::rc4
  • report - 以各種報告樣式格式化文字。 ::report::report , ::report::defstyle、 ::report::rmstyle,
  • sha1 -  ::sha1::sha1、 ::sha1::hmac
  • smtpd - ::smtpd::start、 ::smtpd::stop、 ::smtpd::configure、 ::smtpd::cget
  • snit - Snit's Not Incr Tcl - OO 包。基於委託。 ::snit::type、 ::snit::widget、 ::snit::widgetadaptor
  • soundex::knuth - 基於字母理論發音的字串匹配
  • stooop - OO 包。 stooop::class、stooop::virtual、stooop::new、stooop::delete、stooop::classof
  • struct1 - struct 的版本 1(見下文),為向後相容性提供。
struct::list、 ::struct::graph、 ::struct::matrix、 ::struct::queue、 ::struct::stack、 ::struct::Tree、 ::struct::record、 ::struct::skiplist、 ::struct::prioqueue,新建: ::struct::sets
  • tar - 解壓縮、列出和統計 tar 包中的檔案,以及建立新的 tar 包
  • textutil - 用於處理大量文字的實用程式。 textutil::expand - expand 宏處理器的核心。
  • tie - Tcl 陣列的永續性。
  • treeql - 樹查詢語言,靈感來自 COST。
  • uri - 處理 uri/url(拆分、合併、...)
  • uuid - 建立唯一識別符號。

TclOO

[edit | edit source]

TclOO 是一個可載入的包,用於提供面向物件程式設計的基礎,旨在使 Itcl、Snit 或 XOTcl 等特定 OO 風格能夠構建在它之上。但它本身也是一個可用的 OO 系統,提供類、多重繼承、mixin 和過濾器。以下是一些示例程式碼,讓你瞭解一下

#!/usr/bin/env tclsh85
package require TclOO
namespace import oo::*
class create Account {
   constructor { {ownerName undisclosed}} {
       my variable total overdrawLimit owner
       set total 0
       set overdrawLimit 10
       set owner $ownerName
   }
   method deposit amount {
       my variable total
       set total [expr {$total + $amount}]
   }
   method withdraw amount {
       my variable {*}[info object vars [self]] ;# "auto-import" all variables
       if {($amount - $total) > $overdrawLimit} {
           error "Can't overdraw - total: $total, limit: $overdrawLimit"
       }
       set total [expr {$total - $amount}]
   }
   method transfer {amount targetAccount} {
       my variable total
       my withdraw $amount
       $targetAccount deposit $amount
       set total
   }
   destructor {
       my variable total
       if {$total} {puts "remaining $total will be given to charity"}
   }
}

tcltcc

[edit | edit source]

Tcltcc 是一個可載入的包,它包裝了 Tiny C 編譯器 (tcc) 以供 Tcl 使用。它可以用於

  • 將 C 程式碼直接編譯到記憶體中
  • 生成動態載入庫 (DLL) 或可執行檔案。

便利函式生成包裝程式碼,因此使用者只需編寫真正重要的 C 程式碼。

示例

將 C 函式“動態地”包裝到 Tcl 命令中(此處在互動式會話中顯示)

% package require tcc
0.2
% namespace import tcc::*
% cproc sigmsg {int i} char* {return Tcl_SignalMsg(i);} 
% sigmsg 4
illegal instruction

生成一個帶有快速實現的斐波那契數的 DLL

% set d [tcc::dll]
% $d ccode {
     static int fib(int n) {return n <= 2? 1 : fib(n-1) + fib(n-2);}
  }
% $d cproc fiboy {int n} int {return fib(n);}
% $d write -name fiboy
% load fiboy[info sharedlibextension]
% fiboy 20
6765

生成一個帶有額外的 square 命令的 tclsh

% set code [tcc::wrapCmd square {double x} double x_square {return x*x;}]
% append code {
    int AppInit(Tcl_Interp *interp) {
       int rc;
       rc = Tcl_CreateObjCommand(interp,"square",x_square,NULL,NULL);
           return Tcl_Init(interp);
    }
    int main(int argc, char *argv[]) {
        Tcl_Main(argc, argv, AppInit);
        return 0;
    }
}
% tcc $::tcc::dir exe t
% t add_file    $::tcc::dir/c/crt1.c
% t add_library tcl8.5
% t compile     $code
% t output_file mytclsh.exe
% exec mytclsh.exe {<<puts [square 5]}
25.0

Tcltcc 是開源的,LGPL 許可的,可從 http://code.google.com/p/tcltcc/ 獲取。在當前早期階段(2007 年 10 月),完整的功能僅在 Windows 95/XP 平臺上可用,但記憶體中編譯在 Linux 上也可以工作。

tDOM 是一個用於 XML/HTML 處理的流行擴充套件,它允許 SAX 風格的“即時”解析和 DOM 方法,在記憶體中表示整個 XML 元素。

這是一個 SAX 風格應用程式的例子。隨 tDOM 附帶的 expat 解析器使用回撥來處理元素開始、字元資料和處理指令。元素、屬性、字元和處理指令都進行了計數,此外還對每種元素型別進行了計數。

 #!/usr/bin/env tclsh
 package require tdom
 #--- Callbacks for certain parser events
 proc el {name attlist} {
     global g
     incr ::nEl
     incr ::nAtt [llength $attlist]
     inc g($name)
 }
 proc ch data {
    incr ::nChar [string length $data]
 }
 proc pi {target data} {
    incr ::nPi
 }
 proc inc {varName {increment 1}} {
    upvar 1 $varName var
    if {![info exists var]} {set var 0}
    incr var $increment
 }
 #--- "main" loop
 if ![llength $argv] {puts "usage: $argv0 file..."}
 foreach file $argv {
     foreach i {nEl nAtt nChar nPi} {set $i 0} ;# reset counters
     array unset g
     set p [expat -elementstartcommand el \
            -characterdatacommand          ch \
            -processinginstructioncommand  pi ]
     if [catch {$p parsefile $file} res] {
                puts "error:$res"
     } else {
        puts "$file:\n$nEl elements, $nAtt attributes, $nChar characters,\
            $nPi processing instructions"
        foreach name [lsort [array names g]] {
            puts [format %-20s%7d $name $g($name)]
        }
    }
    $p free
 }
華夏公益教科書