跳转到内容

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
 }
华夏公益教科书