深圳市华为技术有限公司
文档编号
产品版本
密级
研究管理部文档中心
产品名称:测试平台
共76页
TCL培训教程(全)
(仅供内部使用)
拟制:
审核:
审核:
批准:
陈旭盛
日期:
日期:
日期:
日期:
深圳市华为技术有限公司
版权所有 侵权必究
2000/12/08
yyyy/mm/dd
yyyy/mm/dd
yyyy/mm/dd
TCL培训教程
程(全)
2010-11-02
绝密
请输入文档
档编号
版权所
所有,侵权必究
究
第2页,共
共76页
TCL培训教程(全)
程
绝密
请输入文档
档编号
修订记录
日期
修订
订版本
2000/12/08 2.00
2010-11--02
描述
初稿完成
作者
陈旭盛
盛
版权所
所有,侵权必究
究
第3页,共
共76页
TCL培训教程
程(全)
2010-11-02
绝密
请输入文档
档编号
版权所
所有,侵权必究
究
第4页,共76页
TCL培训教程
程(全)
2010-11-02
绝密
请输入文档
档编号
版权所
所有,侵权必究
究
第5页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
目
录
1引言
言
2语法
法
2.11脚本、命令
令和单词符号
号
2.22置换(substittution)
2.2.1变量置
置换(variable subtitution)
2.2.2命令置
置换(commannd substitutionn)
2.2.3反斜杠
杠置换(backsslash substitution)
2.2.4双引号
号和花括号
2.33注释
3变量
量
3.11简单变量
3.22数组
3.33相关命令
3.3.1set
3.3.2unset
3.3.3append
d和incr
4表达
达式
4.11操作数
4.22运算符和优
优先级
4.33数学函数
5List
5.11list命令
5.22concat命令:
5.33lindex命令
5.44llength命令
5.55linsert命令
5.66lreplace命令
令:
5.77lrange 命令:
5.88lappend命令
令:
5.99lsearch 命令
令:
5.110lsort命令:
5.111split命令:
5.112join命令
6控制
制流
6.11if命令
6.22循环命令:while 、for、 foreach
6.2.1while命令
命
6.2.2for命令
令
2010-11--02
版权所
所有,侵权必究
究
6
7
7
7
8
8
8
9
9
10
10
11
11
11
11
12
12
12
12
13
14
14
14
15
15
15
15
15
15
16
16
16
17
17
17
17
17
18
第6页,共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
6.2.3foreach
h命令
6.2.4break和continue命令
令
6.2.5switch 命令
6.11eval命令
6.22source命令
7过程
程(procedure)
7.11过程定义和
和返回值
7.22局部变量和
和全局变量
7.33缺省参数和
和可变个数参
参数
7.44引用:upvaar
8字符
符串操作
8.11format命令
8.22scan命令
8.33regexp命令
8.44regsub命令
8.55string命令
c
?-noccase? ?-lengthh int? string1 string2
s
8.5.1string compare
8.5.2string equal ?-nocasse? ?-length int? string1 sttring2
8.5.3string first string1 sttring2 ?startinndex?
c
8.5.4string index string charIndex
8.5.5string last string1 string2 ?starrtindex?
8.5.6string length strinng
m
?-nocasse? pattern striing
8.5.7string match
8.5.8string range stringg first last
8.5.9string repeat stringg count
g replace string
s
first last
l ?newstrinng?
8.5.10string
8.5.11string
g tolower strring ?first? ?last?
?
8.5.12string
g toupper striing ?first? ?last?
8.5.13 string
g trim strinng ?chars?
8.5.14string
g trimleft strinng ?chars?
8.5.15string
g trimright string
s
?charss?
9文件
件访问
9.11文件名
9.22基本文件输
输入输出命令
令
9.33随机文件访
访问
9.44 当前工作目
目录
9.55文件操作和
和获取文件信
信息
10错误
误和异常
100.1错误
100.2从TCL脚本
本中产生错误
误
100.3使用catch捕获错误
捕
100.4其他异常
2010-11--02
版权所
所有,侵权必究
究
18
19
19
19
19
20
20
20
21
21
22
22
23
23
25
25
25
25
26
26
26
26
26
27
27
27
27
27
27
27
27
28
28
28
29
30
30
33
33
34
35
35
第7页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
11深入
入TCL
11.1查询数组中的元素
11.2 info命令
11.2.1变量
量信息
11.2.2过程
程信息
11.2.3命令
令信息
11.2.4 TCL
L的版本和库
库
11.2.5 命令
令的执行时间
间
11.2.6 跟踪
踪变量
11.2.7 命令
令的重命名和
和删除
11.2.8 unkn
nown命令
11.2.9自动
动加载
史记录
12历史
13TCL
L和C\C++
13.1生成自己的TCLSH
13.2扩展自己的命令:方
方法(一)
13.2.1编写扩展命令对
对应的C/C++过程
过
13.2.2注册
册命令
13.2.3命令
令返回值和命
命令对应的过
过程的返回值
值
13.3扩展自己的命令:方
方法(二)
13.3.1Tcl_O
Obj结构
13.3.2编写扩展命令对
对应的C/C++过程
过
13.3.3注册
册命令
13.4利用clientD
Data参数和deleteProc
d
参数
数
应
嵌入TCL
13.5在C/C++应用程序中嵌
结
14总结
2010-11--02
版权所
所有,侵权必究
究
37
37
38
38
39
40
41
41
41
43
44
44
45
47
48
48
48
49
50
52
52
54
54
55
58
59
第8页,共
共76页
TCL培训教程
程(全)
2010-11-02
绝密
请输入文档
档编号
版权所
所有,侵权必究
究
第9页,共76页
TCL培训教程(全)
程
绝密
请输入文档
档编号
TCL培训教程(全)
关键词:TCL
要:本文是TCL
L教材的第三
三稿,前两稿
稿分别是《
《TCL的使用》和《TCL培训教程》
培
。这
摘
一稿加入了
了不少内容,是北研TCL
L兴趣小组共
共同努力的结果。本文
文详细介绍了
了TCL
的各个方面
面,特别对利
利用C\C++语言扩展
语
TCL
L命令作了详
详细论述。本
本文附有大
大量实
例。
缩略语清单: TCL
一种脚本语
语言
Tool Coommand Lannguage
参考资料清单: 请在表
在表格中罗列本
本文档所引用
用的有关参考文
文献名称、作
作者、标题、编
编号、发布日
日期和
出版单位等基
基本信息。
参考
考资料清单
名称
作者
编号
发布
布日期
查阅
阅地点或 出版
版单位(若不
不
渠
渠道
为本
为本公司发布的
的
文献,请填写此
文献
此
列)
Tcl and
a Tk
ToolK
Kit
Jo
ohn
981-2355-
K.Ousterhout
K
t 951-6
1999
TCL的使用 陈旭盛
陈
TCL培
培训教程 陈旭盛
陈
自己
己的图
书
Addison
Weesley
Pubblishing
Com
mmpany
自写
写文档
自写
写文档
1 引言
TCL((Tool Commaand Language))是一种解释执
执行的脚本语
语言(Scripting Language)。 它提供了通用的
通
编程能力
力:支持变量
量、过程和控
控制结构;同时TCL还拥
拥有一个功能
能强大的固有的核心命令集
集。
由于TCL的解释器
器是用一个C\C
C++语言的过
过程库实现的,
,因此在某种
种意义上我们又可以把TCL
L看作
有丰富的用于扩
扩展TCL命令
令的C\C++过程
程和函数,可
可以很容易就在C\C++应用
用程序
一个C库,这个库中有
CL,而且每个
个应用程序都
都可以根据自己的需要对T
TCL语言进行
行扩展。我们可
可以针对某一
一特定
中嵌入TC
应用领域对TCL语言的
的核心命令集
集进行扩展,加
加入适合于自
自己的应用领
领域的扩展命令
令,如果需要
要,甚
结构,TCL解
解释器将把扩展
展命令和扩展
展控制结构与
与固有命令和固
固有控制结构
构同等
至可以加入新的控制结
扩展后的TCL语
语言将可以继
继承TCL 核心
心部分的所有
有功能,包括核
核心命令、控
控制结构、数
数据类
看待。扩
2010-11--02
版权所
所有,侵权必究
究
第10页,共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
型、对过程的支持等。
。根据需要,我们甚至可以屏蔽掉TCL
L的某些固有
有命令和固有控
控制结构。通
通过对
展、继承或屏
屏蔽,用户用
用不着象平时定
定义一种计算
算机语言那样
样对词法、语法
法、语义、语
语用等
TCL的扩展
各方面加以定义,就可
可以方便的为
为自己的应用领
领域提供一种
种功能完备的脚
脚本语言。
展性使得它能
能很好地适应产
产品测试的需
需要,测试任
任务常常会由于
于设计和需求
求的改
TCL良好的可扩展
让测试人员疲
疲于应付。利用
用TCL的可扩
扩展性,测试
试人员就可以迅
迅速继承多种
种新技
变而迅速改变,往往让
点迅速推出扩
扩展TCL命令集
集,以用于产
产品的测试中,可以较容易
易跟上设计需
需求的
术,并针对产品新特点
变化。
是一种比C\C+
++ 语言有着更
更高抽象层次
次的语言,使
使用TCL可以在
在一种更高的
的层次
另外,因为TCL是
掉了编写C\C+
++程序时必须
须涉及到的一
一些较为烦琐的细节,可以
以大大地提高
高开发
上编写程序,它屏蔽掉
语言写的测试
试例脚本,即使
使作了修改,也用不着重新
新编译就可以
以调用
测试例的速度。而且, 使用TCL语
器直接执行。可以省却不少时间。
TCL解释器
TCL 目前已成为自
自动测试中事
事实上的标准。
。
2 语法
简单的讲,TCL语
语言的语法实际上是一些T
TCL解释器怎样对TCL命令
令进行分析的规则的集合。
2.1 脚本、命
命令和单词符
符号
一个TCL脚本可以
以包含一个或
或多个命令。命
命令之间必须
须用换行符或
或分号隔开,下
下面的两个脚
脚本都
是合法的:
set a 1
set b 2
或
set a 1;set b 2
令包含一个或
或几个单词,第
第一个单词代
代表命令名,另外的单词则
则是这个命令
令的参
TCL的每一个命令
空格或TAB键
键隔开。
数,单词之间必须用空
解释器对一个
个命令的求值
值过程分为两部
部分:分析和
和执行。在分析
析阶段,TCL
L 解释器运用
用规则
TCL解
把命令分成一个个独立
立的单词,同
同时进行必要的置换(substiitution); 在执
执行阶段,T
TCL 解释器会
会把第
个命令是否有定义,如果有
有定义就激活
活这个命令对应的C/C++过
过程,
一个单词当作命令名,并查看这个
参数传递给该
该命令过程,让
让命令过程进
进行处理。
并把所有的单词作为参
2.2 置换(substitution))
2010-11--02
版权所
所有,侵权必究
究
第11页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
注:在下面的所有
有章节的例子
子中,'%'为TC
CL的命令提示
示符,输入命
命令回车后,T
TCL会在接着
着的一
说明,不是例
例子的一部分。
。
行输出命令执行结果。'//'后面是我自己加上的说
解释器在分析
析命令时,把所有的命令参
参数都当作字
字符串看待,例
例如:
TCL解
%set x 10
///定义变量x,并
并把x的值赋为
为10
10
y的值是x+100,而不是我
我们期望的1100
%set y x+100 //y
x+1000
上例 的第二个命令
令中,x被看 作字符串x+1100的一部分 ,如果我们想
想使用x的值''10' ,就必须
须告诉
器:我们在这
这里期望的是
是变量x的值,而非字符'x'。
。怎么告诉TCL解释器呢,这就要用到
到TCL
TCL解释器
语言中提供的置换功能
能。
提供三种形式
式的置换:变
变量置换、命令
令置换和反斜
斜杠置换。每
每种置换都会导
导致一个或多
多个单
TCL提
词本身被其他的值所代
代替。置换可
可以发生在包括
括命令名在内
内的每一个单词
词中,而且置
置换可以嵌套。
。
2.22.1 变量置换(variable subtitution)
$符号标记,变量置换会导
导致变量的值
值插入一个单词
词中。例如:
变量置换由一个$
/
100,这里x被
被置换成它的
的值10
%set y $x+100 //y的值是10+
10+100
不是我们想要的
的值110,而是
是10+100,因
因为TCL解释
释器把10+100看
看成是一个字
字符串
这时,y的值还不
令置换,使得
得TCL会把10+
+100看成一个
个表达式并求值
值。
而不是表达式,y要想得到值110,还必须用命令
2.22.2 命令置换(command sub
bstitution)
括起来的TCL命
命令及其参数
数,命令置换
换会导致某一个命令的所有
有或部分单词
词被另
命令置换是由[]括
替。例如:
一个命令的结果所代替
%set y [expr $x+100]
110
值是110,这里
里当TCL解释器遇到字符'[['时,它就会把
把随后的exprr作为一个命令
令名,从而激
激活与
y的值
expr对应的
的C/C++过程
程,并把'expr'和
和变量置换后
后得到的'10+110'传递给该命
命令过程进行
行处理。
如果在上例中我们
们去掉[],那么
么TCL会报错
错。因为在正常
常情况下,TCL解释器只把
把命令行中的
的第一
字符串处理,看作是命令的
的参数。
个单词作为看作命令,其他的单词都作为普通字
意,[]中必须是
是一个合法的
的TCL脚本,长
长度不限。[]]中脚本的值 为最后一个命
命令的返回值
值,例
注意
如:
+100;set b 3000] //y的值为3300,因为set b 300的返回
回值为300
%set y [expr $x+
2010-11--02
版权所
所有,侵权必究
究
第12页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
300
有了命令置换,实
实际上就表示
示命令之间是可
可以嵌套的,即一个命令
令的结果可以作
作为别的命令
令的参
数。
2.22.3 反斜杠置换(backslash substitution)
语言中的反斜
斜杠置换类似
似于C语言中 反斜杠的用法
法,主要用于
于在单词符号
号中插入诸如
如换行
TCL语
符、空格、[、$等被TCL解释器当作
作特殊符号对
对待的字符。例
例如:
m
multiple\\ space //msg的值为multipple space。
set msg
如果没有'\'的话,TCL会报错,因为解释器
器会把这里最后
后两个单词之
之间的空格认为
为是分隔符,于是
命令有多于两个
个参数,从而
而报错。加入了'\'后,空格
格不被当作分隔
隔符,'multipple space'被认
认为是
发现set命
一个单词(word)。又例
例如:
%set msg money\ \$3333\ \nArrray\ a\[2]
个命令的执行
行结果为:mooney $3333
//这个
Array a[2]
符。
这里的$不再被当作变量置换符
支持以下的反
反斜杠置换:
TCL支
Backkslash Sequencce
Reeplaced By
\aa
Audible alertt (0x7)
\bb
Backspace (00x8)
\ff
Form feed (0xxc)
\nn
Newline (0xaa)
\rr
Carriage retuurn (0xd)
\t
Tab (0x9)
\vv
(
Vertical tab (0xb)
\dddd
Octal value given
g
by ddd
(one, two, or three d's)
\xxhh
Hex value givven by hh
(any number of h's)
n
spacee
\ newline
A single spacce character.
例如
如:
%seet a \x48
//对应 \xhhh
H
//十六进制
制的48正好是
是72,对应H
2010-11--02
版权所
所有,侵权必究
究
第13页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
% set
s a \110
//对应
H
的110正好是
是72,对应H
//八进制的
%sett a [expr \
// 对应\newline space,一个命令可
可以用\newline转到下一行继续
\ddd
2+33]
5
2.22.4 双引号和花括号
外,TCL提供
供另外两种方法
法来使得解释
释器把分隔符
符和置换符等特
特殊字符当作
作普通
除了使用反斜杠外
理,这就要使
使用双引号和花
花括号({})。
字符,而不作特殊处理
解释器对双引
引号中的各种
种分隔符将不
不作处理,但 是对换行符 及$和[]两种
种置换符会照
照常处
TCL解
理。例如:
%set x 100
100
%set y "$x ddd"
100 ddd
所有特殊字符
符都将成为普通
通字符,失去
去其特殊意义
义,TCL解释器
器不会对其作
作特殊
而在花括号中,所
处理。
xpr 10+100]}
%set y {/n$x [ex
/n$x [expr 10+100]
2..3 注释
是'#','#'和直
直到所在行结
结尾的所有字符
符都被TCL看
看作注释,TC
CL解释器对注
注释将
TCL中的注释符是
是,'#'必须出
出现在TCL解释
释器期望命令
令的第一个字符
符出现的地方
方,才
不作任何处理。不过,要注意的是
被当作注释。
例如:
This is a comm
ment
%#T
%set a
100 # Not
N a commeent
uld be "set varN
rName ?newV
Value?"
wronng # args: shou
%set b 101 ; # thiis is a commennt
101
第二行中'#'就不被当作注释符
符,因为它出
出现在命令的中
中间,TCL解
解释器把它和后
后面的字符当
当作命
令的参数处理,从而导
导致错误。而
而第四行的'#''就被作为注释
释,因为前一
一个命令已经用
用一个分号结
结束,
器期望下一个
个命令接着出现。现在在这
这个位置出现
现'#',随后的字
字符就被当作注释了。
TCL解释器
2010-11--02
版权所
所有,侵权必究
究
第14页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
3 变量
TCL支持两种类
支
类型的变量:简单变量和
和数组。
3.1 简单变量
量
一个
个TCL的简单
单变量包含两
两个部分:名字和值。名字和值都
都可以是任意
意字符串。例如
一 个 名 为 “1323 7&
&*: hdgg" 的 变 量 在 TC
CL 中 都 是 合 法 的 。 不 过 为 了 更 好 的 使 用 置 换
(substitution),变量名
名最好按C\C++语言中标
标识符的命名
名规则命名。
。 TCL解释器
器在分析一
一个变
量置换时
时,只把从$
$符号往后直
直到第一个
个不是字母、数字或下划
划线的字符之
之间的单词
词符号
作为要被
被置换的变量
量的名字。例
例如:
% set a
2
2
set a.1 4
4
% set
b $a.1
2.1
行,我们希望
望把变量a.1的
的值付给b,但
但是TCL解释器
器在分析时只
只把$符号之后
后直到
在最后一个命令行
字或下划线的
的字符(这里是
是'.')之间的单词符号(这
这里是'a')当作
作要被置换的
的变量
第一个不是字母、数字
成2,然后把字符
符串“2.1”付给
给变量b。这显
显然与我们的
的初衷不同。
的名字,所以TCL解释器把a置换成
当然
然,如果变量
量名中有不是
是字母、数字或下划线
线的字符,又
又要用置换,
,可以用花
花括号
把变量名
名括起来。例
例如:
%set b ${a.1}
4
令能生成一个
个变量、也能
能读取或改变
变一个变量的值。例如
如:
TCL中的set命令
% seet a {kdfj kjdff}
kdfj kjdf
k
如果
果变量a还没有定义,这
这个命令将生
生成 变量a,并将其值置
置为kdfj kjddf,若a已定
定义,
就简单的
的把a的值置
置为kdfj kjdf。
%sett a
kdfj kjdf
k
2010-11--02
版权所
所有,侵权必究
究
第15页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
这个
个只有一个参
参数的set命令
令读取a的当
当前值kdfj kjdf。
3.2 数组
数组
组是一些元素的
的集合。TCL的数组和普通
通计算机语言
言中的数组有很
很大的区别。在TCL中,不
不能单
独声明一个数组,数组
组只能和数组
组元素一起声明。数组中,数组元素的
的名字包含两部
部分:数组名
名和数
组中元素的名字,TCL中数组元素的
的名字(下标
标〕可以为任何
何字符串。例如:
例
seet day(monday)
1
seet
2
day(tuesdaay)
第
第一个命令生
生成一个名 为 day 的数组
组,同时在 数组中生成
成一个名为 monday
m
的数 组元
素,并把
把值置为1,第二个命令
令生成一个名
名为tuesday的数组元素,
的
,并把值置为2。
简单
单变量的置换已经在前
前一节讨论过
过,这里讲
讲一下数组元
元素的置换。
。除了有括
括号之
外,数组
组元素的置换
换和简单变量
量类似。例
例:
seet a monday
seet
day(mond
day) 1
seet b $day(mo
onday) //b的值
值为1,即daay(monday)的值。
的
seet c $day($a))
//c的值为
为1,即day((monday)的值
值。
TCL不
不能支持复杂
杂的数据类型,这是一个很大
大的缺憾,也
也是TCL受指责
责很多的方面
面。但是TCL的
的一个
扩展ITCL填补了这个缺
缺憾。
3.3 相关命令
令
3.33.1 set
这
这个命令在3.
1已有详细介绍。
3.33.2 unset
这个
个命令从解释
释器中删除变量
量,它后面可
可以有任意多个参数,每个
个参数是一个
个变量名,可以
以是简
单变量,也可以是数组
组或数组元素
素。例如:
y(monday)
% unset a b day
除了变量a、bb和数组元素dday(monday),但是数组dday并没有删除
除,其他元素
素还存
上面的语句中删除
数组的名字。例
例如:
在,要删除整个数组,只需给出数
day)
%puts $day(mond
y(monday)": no such eleement in arrray
can't read "day
% puts $day(tuesday)
2010-11--02
版权所
所有,侵权必究
究
第16页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
2
%unset day
% puts $day(tuesday)
y(tuesday)": no such vaariable
can't read "day
3.33.3 append和
和incr
这两个命令提供了
了改变变量的
的值的简单手段
段。
本加到一个变
变量的后面,例
例如:
append命令把文本
% set txt hello
hello
% append txt "! How are yoou"
hello! How are you
变量值加上一
一个整数。inccr要求变量原
原来的值和新加
加的值都必须
须是整数。
incr命令把一个变
%set b a
a
% incr b
"
expected integer but got "a"
%set b 2
2
%incr b 3
5
4 表达式
TCL中
中的表达式类似于ANSI C的
的表达式。表
表达式由操作数
数和操作符构
构成,下面分别
别介绍。
4..1 操作数
表达式的操作
作数通常是整 数或实数。整
整数一般是十
十进制的,
TCL表
但如果整数
数的第一个字
字符是
0(zero), 那么TCL将把
把这个整数看
看作八进制的
的,如果前两 个字符是0x则
则这个整数被
被看作是十六
六进制
的实数的写法与ANSI C中完
完全一样。如
如:
的。TCL的
2..1
7..9e+12
6ee4
2010-11--02
版权所
所有,侵权必究
究
第17页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
3..
4..2 运算符和
和优先级
下面的表格中列出
出了TCL中用到
到的运算符,它们的语法形
形式和用法跟
跟ANSI C中很相
相似。这里就
就不一
算符是按优先
先级从高到低往
往下排列的。同一格中的运
运算符优先级
级相同。
一介绍。下表中的运算
式
语法形式
-a
!a
~a
a*b
a/b
a%b
a+b
a-b
a<<b
a>>b
a<b
a>b
a<=b
a>=b
a= =b
a!=b
a&b
a^b
a|b
a&&b
a||b
a?b:c
结果
负a
非a
操作数类型
操
i
int,float
i
int,float
i
int
i
int,float
i
int,float
i
int
i
int,float
i
int,float
i
int
i
int
i
int,float,st
tring
i
int,float,st
tring
i
int,float,st
tring
i
int,float,st
tring
i
int,float,st
tring
i
int,float,st
tring
i
int
i
int
i
int
i
int,float
i
int,float
a
a:int,float
乘
除
取模
加
减
左移位
右移位
小于
大于
小于等于
大于等于
等于
不等于
位操作与
位操作异或
位操作或
逻辑与
逻辑或
选择运算
1..1 数学函数
数
TCL支
支持常用的数
数学函数,表达
达式中数学函
函数的写法类似于C\C++语
语言的写法,数
数学函数的参
参数可
以是任意表达式,多个
个参数之间用逗号隔开。例
例如:
%set x 2
2
% expr 2* sin($x<3)
1.68294196962
其中
中expr是TCL的一个命令
的
,语法为: expr arg ?aarg ...?
2010-11--02
版权所
所有,侵权必究
究
第18页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
两个
个 ?之间的参数表示可
可省,后面介
介绍命令时对于可省参
参数都使用这
这种表示形
形式。
expr可以有一个或多
多个参数,它
它把所有的参
参数组合到一起,作为
为一个表达式
式,然后求值
值:
%exppr 1+2*3
7
%exppr 1 +2 *3
7
需要
要注意的一点
点是,数学函
函数并不是命
命令,只在
在表达式中出
出现才有意义
义。
TCL中支持的数
数学函数如下
下
abs( x)
x
Absolute vaalue of x.
acos(( x)
Arc cosine of
o x, in the rannge 0 to p.
asin( x)
Arc sine of x, in the rangee -p/2 to p/2.
atan( x)
Arc tangentt of x, in the raange -p/2 to p//2.
ngent of x/ y, in the range -pp/2 to p/2.
atan22( x, y) Arc tan
ceil( x)
t
x.
Smallest intteger not less than
x
cos( x)
Cosine of x ( x in radians).
cosh(( x)
Hyperbolic cosine of x.
double( i)
e
to integeer i.
Real value equal
exp( x)
e raised to the power x.
floor(( x)
Largest inteeger not greateer than x.
fmodd( x, y)
Floating-point remainder of x divided by
b y.
hypot( x, y)
Square roott of ( x 2 + y 2 ).
x
int( x)
Integer valuue produced byy truncating x.
log( x)
x
Natural logaarithm of x.
log100( x)
Base 10 loggarithm of x.
pow(( x, y)
x raised to the
t power y.
roundd( x)
Integer valuue produced byy rounding x.
sin( x)
x
Sine of x ( x in radians).
sinh( x)
Hyperbolic sine of x.
sqrt( x)
Square roott of x.
x
tan( x)
Tangent of x ( x in radianns).
tanh(( x)
Hyperbolic tangent of x.
2010-11--02
所有,侵权必究
究
版权所
第19页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
TCL中有很多命
命令都以表达
达式作为参数
数。最典型
型的是expr命令,另外if、while、forr等循
环控制命
命令的循环控
控制中也都使
使用表达式
式作为参数。
2 List
list这
这个概念在TC
CL中是用来表
表示集合的。T
TCL中list是由
由一堆元素组
组成的有序集合
合,list可以嵌
嵌套定
义,list每
每个元素可以是
是任意字符串
串,也可以是llist。下面都是
是TCL中的合
合法的list:
{}
/
//空list
{a b c d}
{a {bb c} d} //list可
可以嵌套
list是
是TCL中比较重
重要的一种数
数据结构,对于编写复杂的
的脚本有很大
大的帮助,TC
CL提供了很多
多基本
命令对listt进行操作,下
下面一一介绍
绍:
2..1 list命令
语法: list ? valuee value...?
个list,list的元
元素就是所有
有的value。例:
:
这个命令生成一个
% list 1 2 {3 4}
1 2 {3 4}
2..2 concat命
命令:
语法:concat list ?liist...?
变成新list的一
一个元素。
这个命令把多个liist合成一个lisst,每个list变
2..3 lindex命令
令
语法:lindex list index
i
元素。例:
返回list的第index个(0-based)元
3 4}} 2
% liindex {1 2 {3
34
2..4 llength命
命令
语法:llength listt
数。例
返回list的元素个数
% lleength {1 2 {3 4}}
3
2..5 linsert命令
2010-11--02
版权所
所有,侵权必究
究
第20页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
语法:linsert list index
i
value ?vvalue...?
新串是把所有
有的value参数值
值插入list的第
第index个(0-based)元素之前
前得到。例:
返回一个新串,新
4 1 7 8 {99 10}
% linnsert {1 2 {3 4}}
1 7 8 {9 10} 2 {3 4}
4
2..6 lreplace命
命令:
语法:lreplace listt first last ?vallue value ...?
新串是把list的
的第firs (0-based)t到第last 个(0-based)元
个
元素用所有的vvalue参数替换
换得到
返回一个新串,新
数,就表示删
删除第first到第
第last个元素。例:
的。如果没有value参数
{ 10} 2 {3 4}}} 3 3
% lreeplace {1 7 8 {9
1 7 8 2 {3 4}
% lreeplace {1 7 8 2 {3 4}} 4 4 4 5 6
1782456
2..7 lrange 命令:
命
语法:lrange list first last
(
第last (0-based)元素组成的串,如果last的
的值是end。就
就是从第first个
个直到
返回list的第first (0-based)到第
串的最后。
例:
% lraange {1 7 8 2 4 5 6} 3 end
2456
2..8 lappend命
命令:
语法:lappend varrname value ?value...?
?
素附加到变量
量varname后面
面,并返回变
变量的新值, 如果varnamee不存
把每 个value的值 作为一个元素
在,就生成这个变量。例:
% lapppend a 1 2 3
123
% sett a
123
2..9 lsearch 命令:
命
语法:lsearch ?-ex
xact? ?-glob? ?-regexp? list pattern
个匹配模式paattern的元素的
的索引,如果
果找不到匹配
配就返回-1。 -exact、-globb、 返回 list中第一个
三种模式匹配
配的技术。-exxact表示精确匹
匹配;-glob的
的匹配方式和
和string match命
命令的匹配方
方式相
regexp是三
2010-11--02
版权所
所有,侵权必究
究
第21页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
同,将在后面第八节介
介绍string命令
令时介绍;-reegexp表示正规
规表达式匹配
配,将在第八
八节介绍regexpp命令
glob匹配。例
例:
时介绍。缺省时使用-g
% sett a { how aree you }
how are you
% lseearch $a y*
2
% lseearch $a y?
-1
2..10 lsort命令
令:
语法:lsort ?optio
ons? list
串。options可以
以是如下值:
这个命令返回把liist排序后的串
-asciii
按ASCII字
字符的顺序排序
序比较.这是缺
缺省情况。
-dictiionary 按字典
典排序,与-asccii不同的地方
方是:
(1)不考虑
虑大小写
(2)如果元
元素中有数字的
的话,数字被当
当作整数来排
排序.
因此:biigBoy排在biggbang和bigboyy之间, x10y 排在x9y和x11
排
1y之间.
元素转换成整
整数,按整数排序.
-integger 把list的元
-real
把list的元
元素转换成浮点
点数,按浮点数
数排序.
符比较)
-increeasing 升序(按ASCII字符
-decrreasing 降序
序(按ASCII字符
符比较)
-com
mmand comm
mand TCL自动
动利用commannd 命令把每两
两个元素一一
一比较,然后给出
出排序结果。
2..11 split命令:
语法:split string ?splitChars?
分隔符splitChhars分成一个个单词,返回
回由这些单词
词组成的串。如
如果splitCharss
把字符串string按分
字符分开。如果
果splitChars没
没有给出,以空
空格为分隔符。
。例:
是一个空字符{},string被按字
ou" .
% split "how.are.yo
how are you
ou"
% split "how are yo
how are you
ou" {}
% split "how are yo
how{}are{}you
2010-11--02
版权所
所有,侵权必究
究
第22页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
2..12 join命令
nString?
语法:join list ?join
命令是命令的
的逆。这个命令
令把list的所有
有元素合并到
到一个字符串中,中间以joinString分开
开。缺
join命
省的joinS
String是空格。例:
% joiin {h o w { } a r e { } y o u}} {}
how are you
y
.
% joiin {how are you}
how.are.you
3 控制流
TCL中的控制流和
和C语言类似,包括if、whhile、for、fooreach、switchh、break、coontinue等命令
令。下
面分别介绍。
3..1 if命令
b
?elseiff test2 body22 elseif.... ? ?else bodyn??
语法: if test1 body1
先把test1当作
作一个表达式
式求值,如果值
值非0,则把bbody1当作一个脚本执行并
并返回所得值
值,否
TCL先
则把test2当
当作一个表达
达式求值,如果值非0,则把body2当作
作一个脚本执行
行并返回所得
得值……。例如
如:
if { $x>0 } {
.....
}eelseif{ $x==
=1 } {
.....
}eelseif { $x==
=2 } {
....
}eelse{
.....
}
一定要写在上
上一行,因为如
如果不这样,TCL 解释器
器会认为if命令
令在换行符处
处已结
注意,上例中'{'一
一行会被当成新
新的命令,从
从而导致错误
误的结果。在
在下面的循环命
命令的书写中
中也要注意这
这个问
束,下一
题。书写中还要注意的
的一个问题是
是if 和{之间应
应该有一个空
空格,否则TCL解释器会把
把'if{'作为一个
个整体
而导致错误。
当作一个命令名,从而
3..2 循环命令:while 、fo
or、 foreach
h
3.22.1 while命令
令
2010-11--02
版权所
所有,侵权必究
究
第23页,共
共76页
TCL培训教程
程(全)
语法为:
绝密
请输入文档
档编号
while test body
是一个脚本,如果表达式的
的值非0,就运
运行脚本,直
直到表达式为00才停
参数test是一个表达式,body是
令中断并返回
回一个空字符串
串。
止循环,此时while命令
例如:
假
假设变量
a 是一
一个链表,下
下面的脚本把a 的值复制到
到b:
set b " "
set i [eexpr [llength $a] -1]
while { $i>=0}{
nd b [lindex $aa $i]
lappen
incr i -1
}
3.22.2 for命令
语法为: for init teest reinit bodyy
第二个参数teest是一个表达
达式,用来决定循环什么时
时候中断,第
第三个
参数init是一个初始化脚本,第
初始化的脚本
本,第四个参数
数body也是脚
脚本,代表循环
环体。下例与
与上例作用相同:
参数reinitt是一个重新初
set b " "
for {seet i [expr [llenggth $a] -1]} {$$i>=0} {incr i -1} {
lappend b [llindex $a $i] }
3.22.3 foreach命令
语法形式
这个命令有两种语
1。
foreach varN
Name list bodyy
变量,第二个 参数list 是一
一个表(有序集
集合),第三个
个参数body是
是循环
第一 个参数varNaame是一个变
一个元素,都
都会执行循环体
体一次。 下例
例与上例作用相同:
体。每次取得链表的一
set b " "
foreach
h i $a{
set b [linsert $b 0 $i]
}
f
varlistt1 list1 ?varlistt2 list2 ...? Boody
2。 foreach
这种 形式包含了第
第一种形式。 第一个参数
数varlist1是一 个循环变量列
列表,第二个
个参数是一个
个列表
量会分别取listt1中的值。boody参数是循环
环体。 ?varlisst2 list2 ...?表示
示可以有多个
个变量
list1,varlist1中的变量
例如:
列表和列表对出现。例
2010-11--02
版权所
所有,侵权必究
究
第24页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
set x {}
foreaach {i j} {a b c d e f} {
lapppend x $j $i
}
这时总共有三次循
循环,x的值为
为"b a d c f e"。
set x {}
foreaach i {a b c} j {d e f g} {
lapppend x $i $j
}
这时
时总共有四次
次循环,x的值为"a d b e c f {} g"。
set x {}
foreaach i {a b c} {jj k} {d e f g} {
lapppend x $i $j $k
$
}
这时总共有三次循
循环,x的值为
为"a d e b f g c {} {}"。
3.22.4 break和coontinue命令
在循
循环体中,可以用break和ccontinue命令中
中断循环。其
其中break命令
令结束整个循环
环过程,并从
从循环
中跳出,continue只是结束本次循环
环。
3.22.5 switch 命令
令
和C语
语言中switch语句一样,T
TCL中的switcch命令也可以
以由if命令实现
现。只是书写
写起来较为烦
烦琐。
switch命令
令的语法为: switch ? optioons? string { pattern
p
body ? pattern body ...?}
第一
一个是可选参数options,表
表示进行匹配
配的方式。TC
CL支持三种匹
匹配方式:-exxact方式,-gglob方
式,-regeexp方式,缺省情
情况表示-gloob方式。-exacct方式表示的
的是精确匹配,
,-glob方式的
的匹配方式和
和string
match 命令
令的匹配方式
式相同(第八节
节介绍),-regeexp方式是正规
规表达式的匹
匹配方式(第八
八节介绍)。第
第二个
参数stringg 是要被用来
来作测试的值,第三个参数
数是括起来的一
一个或多个元
元素对,例:
switcch $x {
a b {inccr t1}
c {inccr
t2}
defaultt {incr t3}
2010-11--02
版权所
所有,侵权必究
究
第25页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
}
其中a的后面跟一个'-'表示使用和下一个模
模式相同的脚
脚本。default表
表示匹配任意
意值。一旦swiitch命
令 找到一
一个模式匹配,
,就执行相应
应的脚本,并返
返回脚本的值
值,作为switcch命令的返回
回值。
3..3 eval命令
命令是一个用
用来构造和执行
行TCL脚本的
的命令,其语法
法为:
eval命
eval arg
a ?arg ...?
它可以接收一个或
或多个参数,然后把所有的参数以空格
格隔开组合到
到一起成为一个
个脚本,然后
后对这
如:
个脚本进行求值。例如
%evval set a 2 ;seet b 4
4
3..4 source命
命令
sourcce命令读一个
个文件并把这个
个文件的内容
容作为一个脚本
本进行求值。例如:
sourcce e:/tcl&c/helllo.tcl
注意路径的描述应
应该和UNIX相
相同,使用'/'而
而不是'\'。
cedure)
4 过程(proc
TCL支持过程的
支
的定义和调用
用,在TCL中,过程可以看
看作是用TC
CL脚本实现的
的命令,效
效果与
TCL的固
固有命令相似
似。我们可以
以在任何时候
候使用proc命令定义自
命
己的过程,TCL中的过
过程类
似于C中的函数。
4.1 过程定义
义和返回值
TCL中过程是由
由proc命令产生
生的:
例如
如:
% prooc add {x y } {expr $x+$y}}
proc命令的第一
命
一个参数是你
你要定义的过
过程的名字
字,第二个参
参数是过程的
的参数列表
表,参
数之间用
用空格隔开,
,第三个参
参数是一个TC
CL脚本,代
代表过程体。 proc生成一
一个新的命
命令,
可以象固
固有命令一样
样调用:
% addd 1 2
3
2010-11--02
版权所
所有,侵权必究
究
第26页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
在定
定义过程时,
,你可以利用return命令
令在任何地方
方返回你想要的值。 return
r
命令迅
迅速中
断过程,并把它的参
参数作为过程
程的结果。例如:
% prooc abs {x} {
if {$xx >= 0} { retu
urn $x }
returnn [expr -$x]
}
过程
程的返回值是
是过程体中最
最后执行的那
那条命令的
的返回值。
4.2 局部变量
量和全局变量
量
对于
于在过程中定
定义的变量,因为它们
们只能在过程
程中被访问,并且当过程
程退出时会
会被自
动删除,所以称为局
局部变量;在所有过程
程之外定义的
的变量我们称
称之为全局
局变量。TCL
L中,
局部变量
量和全局变量
量可以同名,两者的作
作用域的交集
集为空:局部
部变量的作用
用域是它所
所在的
过程的内
内部;全局变
变量的作用域
域则不包括
括所有过程的
的内部。这一
一点和C语言
言有很大的不
不同.
如果
果我们想在过
过程内部引用
用一个全局
局变量的值,可以使用global
g
命令。例如:
% sett a 4
4
% prooc sample { x } {
gllobal a
inncr a
reeturn [expr $a+
+$x]
}
mple 3
% sam
8
%set a
5
全局
局变量a在过
过程中被访问
问。在过程中
中对a的改变
变会直接反映
映到全局上。
。如果去掉
掉语句
global a,
TCL会出错,因
会
因为它不认识
识变量a.
4.3 缺省参数
数和可变个数
数参数
TCL还提供三种
还
种特殊的参数
数形式:
首先
先,你可以定
定义一个没有
有参数的过程
程,例如:
2010-11--02
版权所
所有,侵权必究
究
第27页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
proc add {} { exprr 2+3}
其次
次,可以定义
义具有缺省参
参数值的过程,我们可
可以为过程的
的部分或全部
部参数提供
供缺省
值,如果
果调用过程时
时未提供那些
些参数的值
值,那么过程
程会自动使用
用缺省值赋给
给相应的参
参数。
和C\C++中具有缺省
省参数值的函
函数一样,有
有缺省值的
的参数只能位
位于参数列表
表的后部,即在
第一个具
具有缺省值的
的参数后面的所有参数
数,都只能是
是具有缺省值
值的参数。
例如
如:
proc add {val1 {vaal2 2} {val3 3}}{
3
expr $vaal1+$val2+$vaal3
}
则:
add 1
//值为6
2
add 2 20 //值为25
add 4 5 6 //值为15
1
另外
外,TCL的过
过程定义还支
支持可变个数
数的参数,如果过程的
的最后一个参
参数是args, 那么
就表示这
这个过程支持
持可变个数的参数调用
用。调用时,位于
位 args以前
前的参数象普
普通参数一
一样处
理,但任
任何附加的参
参数都需要
要在过程体中
中作特殊处理
理,过程的局部变量arrgs将会被设
设置为
一个列表
表,其元素就
就是所有附
附加的变量。如果没有附
附加的变量,args就设置
置成一个空
空串,
下面是一
一个例子:
prroc add { vall1 args } {
set sum
s
$val1
foreach i $args {
incr
sum $i
}
n $sum
return
}
则:
addd 2 //值为2
addd 2 3 4 5 6 ///值为20
4.4 引用:u
upvar
2010-11--02
版权所
所有,侵权必究
究
第28页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
命令
令语法:upvar ?level?
?
otherV
Var myVar ?ottherVar myVaar ...?
upvarr命令使得用
用户可以在过
过程中对全局
局变量或其
其他过程中的
的局部变量进
进行访问。 upvar
命令的第
第一个参数otherVar
o
是我
我们希望以引
引用方式访问
问的参数的名
名字,第二
二个参数myV
Var 是
这个过程
程中的局部变
变量的名字,一旦使用
用了upvar 命令
令把otherVarr 和myVar 绑定
绑 ,那么在
在过程
中对局部
部变量myVarr 的读写就相
相当于对这个
个过程的调用者中otherrVar 所代表的局部变量
量的读
写。下面
面是一个例子
子:
% prooc temp { arg
g}{
uppvar $arg b
seet b [expr $b
b+2]
}
% prooc myexp { var } {
seet a 4
teemp a
reeturn [expr $v
var+$a]
}
则:
% myyexp 7
13
这个
个例子中,upvar
u
把$arg((实际上是过
过程 myexp中的变量
中
a)和过程
和
temp 中的变量
中
b 绑定,
绑
对b的读写
写就相当于
于对a的读写。
。
upvarr 命令语法中
中的 level 参数
数表示:调
调用 upvar 命令
令的过程相
相对于我们希
希望引用的 变量
myVar在调
调用栈中相
相对位置。例
例如:
upvarr 2 other x
这个
个命令使得当
当前过程的 调用者的调
调用者中的变
变量 other,可
可以在当前
前过程中利用
用x访
问。缺省
省情况下,level
l
的值为1,即当前过
过程(上例中
中的temp)的调
调用者(上例
例中的myexp))中的
变量(上例
例中myexp的a)可以在当
当前过程中利
利用局部变量
量(上例中tem
mp的b)访问。
如果
果要访问全局
局变量可以这
这样写:
upvarr #0 other x
2010-11--02
所有,侵权必究
究
版权所
第29页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
那么
么,不管当前
前过程处于调
调用栈中的
的什么位置,都可以在当前过程中
中利用x访问全局
变量otherr。
5 字符串操
操作
因为
为TCL把所有
有的输入都当
当作字符串 看待,所以
以TCL提供了
了较强的字符
符串操作功能,
TCL中与
与字符串操作
作有关的命令
令有:string、format、reegexp、regsubb、scan等。
5.1 format命
命令
语法
法:format forrmatstring ?vvlue value...?
formaat 命令类似 于 ANSIC 中 的 sprintf 函数
数和 MFC 中 CString
C
类提供
供的 Format 成员函数。
成
它按
formatstrinng提供的格
格式,把各个
个value的值组
组合到formattstring中形成
成一个新字符
符串,并返
返回。
例如:
%set name john
John
%set age 20
20
y
old" $naame $age]
%set msg [formaat "%s is %d years
d
john is 20 years old
5.2 scan命令
令
语法
法:scan strinng format varrName ?varN
Name ...?
scan 命令可以认
命
认为是 format 命令的逆,
命
其功能类似
似于 ANSI C 中的 sscanf函数。它按
函
f
format
提供的格
格式分析 striing 字符串, 然后把结 果存到变量
量 varName 中 , 注意除了空
空格和 TAB 键之
外,strinng 和format中的字符和
中
'%
%'必须匹配。例如:
% scaan "some
26
34" "some %d %d"
% ab
2
% sett a
26
% sett b
34
% scaan "12.34.56.78" "%d.%d..%d.%d" c d e f
2010-11--02
版权所
所有,侵权必究
究
第30页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
4
he value of c is %d,d is %d,e is %d ,f is %d" $c $d $ee $f]
% puuts [format "th
the value
v
of c is 12,d
1 is 34,e is 56 ,f is 78
scan命
命令的返回值
值是匹配的变量
量个数。而且
且,我们发现
现,如果变量vvarName不存在
在的话,TCL
L会自
动声明该变量。
5..3 regexp命
命令
语法:regexp ?sw
witchs? ?--? expp string ?matchVar?\ ?subM
MatchVar subMatchVar...?
判断正规表达式
式exp是否全部
部或部分匹配
配字符串stringg,匹配返回11,否则0。
regexxp命令用于判
在正规表达式中,一些字符具
具有特殊的含义
义,下表一一
一列出,并给予
予了解释。
字符
符
意义
匹配任意
意单个字符
表示从头
头进行匹配
表示从末
末尾进行匹配
配
匹配字符
符x,这可以抑制字符x的
的含义
匹配字符
符集合chars中
中给出的任意
意字
符,如果cchars中的第
第一个字符是
是^,表
示匹配任意
意不在charss中的字符,chars
的表示方法
法支持a-z之
之类的表示。
把regexp作
作为一个单项
项进行匹配
对*前面的
的项0进行次或多次匹配
配
对+前面的
的项进行1次
次或多次匹配
配
对?前面的
的项进行0次
次或1次匹配
配
匹配regexpp1或regexp22中的一项
.
^
$
\x
[chars]]
(regexp)
*
+
?
regexp1|regexp2
是从《Tcl andd Tk ToolKit》中摘下来的,下面进行说
说明:
下面的一个例子是
^((0
0x)?[0-9a-fA-F]+|[0
0-9]+)$
这个正规表达式匹
匹配任何十六
六进制或十进制
制的整数。
以|分开(0x)?[0-9a-fA
A-F]+和[0-9
9]+,表示可
可以匹配其中的
的任何一个,事实
两个正规表达式以
上前者匹配十六进制,后者匹配的十进制。
示必须从头进行匹配,从而
而上述正规表
表达式不匹配jkk12之类不是以0x或数字开
开头的串。
^表示
2010-11--02
版权所
所有,侵权必究
究
第31页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
$表示必须从末尾
尾开始匹配,从而上述正规
规表达式不匹
匹配12jk之类不
不是数字或a-ffA-F结尾的串
串。
0-9a-fA-F]+ 进行说明,
,(0x)表示0xx一起作为一项
项,?表示前一
一项(0x)可以出现0
下面以(0x)?[0
A-F]表示可以是任意0到9之间的单个
个数字或a到f或
或A到F之间的
的单个字母,+表
次或多次,[0-9a-fA
数字或字母可
可以重复出现一
一次或多次。
示象前面那样的单个数
% reggexp {^((0x)?[0-9a-fA-F]+|[0-9]+)$} ab
1
% reggexp {^((0x)?[0-9a-fA-F]+|[0-9]+)$} 0xxabcd
1
% reggexp {^((0x)?[0-9a-fA-F]+|[0-9]+)$} 123345
1
% reggexp {^((0x)?[0-9a-fA-F]+|[0-9]+)$} 1223j
0
后面有参数maatchVar和subM
MatchVar,则
则所有的参数
数被当作变量名
名,如果变量
量不存
如果regexp命令后
gexp把匹配整
整个正规表达式的子字符串
串赋给第一个
个变量,匹配正
正规表达式的
的最左
在,就会被生成。 reg
符串赋给第二
二个变量,依次
次类推,例如
如:
边的子表达式的子字符
+) *([a-z]+)} " there is 1000 apples" totaal num wordd
% reggexp { ([0-9]+
1
% puuts " $total ,$nu
um,$word"
100 apples ,100,aapples
regexxp可以设置一
一些开关(swiitchs〕,来控
控制匹配结果:
-nocaase 匹配时不
不考虑大小写
-indicces 改变各个
个变量的值,这是各个变量
量的值变成了
了对应的匹配
配子串在整个字
字符串中所处
处位置
的索引。例如:
% reegexp -indicess { ([0-9]+) *(([a-z]+)} " theere is 100 apples" total nuum word
1
% puuts " $total ,$nu
um,$word"
9 20 ,10 12,15 20
正好子串“ 100 ap
pples”的序号是
是9-20,"100"的
的序号是10-112,"apples"的序
序号是15-20
-- 表示这后面再没
表
没有开关 (sswitchs〕了,即使后面有以'-'开头的参
参数也被当作正
正规表达式的
的一部
分。
1..1 regsub命
命令
语法:regsub ?sw
witchs? exp striing subSpec varname
v
2010-11--02
版权所
所有,侵权必究
究
第32页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
regsuub的第一个参
参数是一个整个
个表达式,第
第二个参数是一个输入字符
符串,这一点
点和regexp命令
令完全
一样,也是当匹配时返
返回1,否则返
返回0。不过rregsub用第三
三个参数的值来
来替换字符串
串string中和正
正规表
四个参数被认
认为是一个变量
量,替换后的
的字符串存入这
这个变量中。例如:
达式匹配的部分,第四
They live theree lives " their x
% reggsub there "T
1
% puuts $x
Theyy live their livees
这里there被用theiir替换了。
几个开关(switcchs):
regsuub命令也有几
-nocaase 意义同reg
gexp命令中。
-all 没有这个开关
关时,regsub只替换第一个
个匹配,有了这个开关,reegsub将把所有
有匹配的地方
方全部
替换。
意
命令中。
-- 意义同regexp命
1.2 string命
命令
string命令的语法
法:string
o
option
arg ?aarg...?
string命令具有强
强大的操作字 符串的功能,
,其中的optiion选项多达220个。下面介
介绍其中常用
用的部
分。
1.22.1 string com
mpare ?-noca
ase? ?-length int? string1 sttring2
把字
字符串string1和
和string2进行
行比较,返回值为-1、0或1,分
分别对应strinng1小于、等于或大于strinng2。
如果有 -llength 参数, 那么只比较
较前 int 个字符
符,如果 int 为负数,那么
么这个参数被
被忽略。 如果
果有 nocase参数
数,那么比较
较时不区分大小
小写。
1.22.2 string equal ?-nocase?? ?-length innt? string1 striing2
把字
字符串string1和
和string2进行
行比较,如果 两者相同,返
返回值为1, 否则返回0。 其他参数与
与8.5.1
同。
1.22.3 string firrst string1 strin
ng2 ?startindeex?
在strring2 中从头查找与string11匹配的字符序列,如果找
找到,那么就
就返回匹配的第
第一个字母所
所在的
位置(0-baased)。如果没
没有找到,那
那么返回-1。如
如果给出了sttartindex变量
量,那么将从sstartindex处开
开始查
找。例如:
% strring first ab defabc
3
2010-11--02
版权所
所有,侵权必究
究
第33页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
% strring first ab defabc 4
-1
1.22.4 string in
ndex string cha
arIndex
返回
回string 中第ch
harIndex个字符
符(0-based)。charIndex可以
以是下面的值
值:
整数
数n: 字符串中第
第n个字符(0--based)
end : 最后一个字符
-整数n:倒数
数第n个字符。
。string indexx "abcd" end-11 返回字符'c'
end-
如果
果charIndex小于
于0,或者大于
于字符串strinng的长度,那
那么返回空。
例如:
% strring index abcdef 2
c
% strring index abcdef end-2
d
1.22.5 string
laast string1 strring2 ?startinndex?
参照8.5.3.唯一的区
区别是从后往
往前查找
1.22.6 string
leength
string
g
返回字符串string的
的长度.
1.22.7 string maatch ?-nocase?? pattern stringg
如果
果pattern 匹配sstring,那么返回1,否则返回
回0.如果有-noccase参数,那么
么就不区分大小
小写.
在patttern 中可以使
使用通配符:
*
匹配string中
中的任意长的任
任意字符串,包
包括空字符串
串.
?
匹配string中
中任意单个字符
符
集合chars中给
给出的任意字符,其中可以使
使用 A-Z这种
种形式
[charrs] 匹配字符集
\x
匹配单个字
字符x,使用'\'是为了让x可以为字符*,-,[,]..
例子:
a
% string match * abcdef
1
% strring match a* abcdef
1
def abcdef
stringg match a?cd
2010-11--02
版权所
所有,侵权必究
究
第34页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
1
% strring match {a[[b-f]cdef} abccdef //注意一
一定药用'{',否则
则TCL解释器
器会把b-f当作命
命令名
//从而导
导致错误
1
% strring match {a[[b-f]cdef} acccdef
1
1.22.8 string raange
string first
f
last
返回
回字符串string
g中从第first个
个到第last个字
字符的子字符
符串(0-based)。
。如果first<00,那么first被
被看作
0,如果laast大于或等于
于字符串的长度
度,那么last被
被看作end,如
如果first比lasst大,那么返回空。
1.22.9 string reepeat string count
返回
回值为:重复了
了string字符串
串count次的字
字符串。例如:
% strring repeat "ab
bc" 2
abcabbc
1.22.10string
reeplace
strin
ng first
lastt ?newstring?
返 回 值 为 : 从 字 符 串 stringg 中 删 除 了 第 first 到 第 lasst 个 字 符 (0-bbased) 的 字 符 串 , 如 果 给 出 了
newstring变
变量,那么就
就用newstringg替换从第firsst到第last个字
字符。如果firrst<0,那么fiirst被看作0,如果
last大于或
或等于字符串的长度,那么
么last被看作eend,如果first比last大或者
者大于字符串
串string的长度
度或者
last小于0,
,那么原封不
不动的返回striing 。
1.22.11string toolower string
g ?first? ?last?
返回
回值为:把字
字符串string转
转换成小写后的字符串,如
如果给出了first和last变量
量,就只转换ffirst和
last之间的
的字符。
1.22.12string tooupper string
g ?first?
?last?
同88.5.11。转换成
成大写。
1.22.13 string trrim
string ?chars?
返回
回值为:从striing字符串的 首尾删除掉 了字符集合cchars中的字符
符后的字符串
串。如果没有
有给出
chars,那
那么将删除掉spaces、tabs、newlines、caarriage returnss这些字符。例
例如:
% strring trim "abcd
de" {a d e}
bc
% strring trim "
def
>"
def
2010-11--02
版权所
所有,侵权必究
究
第35页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
1.22.14string triimleft string ?chars?
?
同8.5.13。不过只
只删除左边的
的字符。
1.22.15string trimright
striing ?chars?
同8.5.13。不过只
只删除右边的
的字符。
2 文件访问
问
TCL提供了丰富
提
富的文件操作
作的命令。通
通过这些命令你可以对
对文件名进行
行操作(查找
找匹配
某一模式
式的文件)、以顺序或随
随机方式读写
写文件、检
检索系统保留
留的文件信息
息(如最后
后访问
时间)。
2.1 文件名
TCL中文件名和
和我们熟悉的
的windows表示
示文件的方
方法有一些区
区别:在表示
示文件的目录结
构时它使
使用 '/' ,而不
不是 '\' ,这和
和 TCL 最初是
是在 UNIX 下实现有关。
下
。比如 C 盘 tcl 目录下的 文件
sample.tcll在TCL中这样
样表示:C://tcl/sample.tcll。
件输入输出命
命令
2.2 基本文件
这个
个名为tgrep的过程,可以
的
以说明TCL文件
文 I/O的基本
本特点:
proc tgrep { patterrn filename} {
set f [open $filenaame r]
whilee { [gets $f liine ] } {
if {[regexp $paattern $line]} {
puts stdo
out $line
}
}
closee $f
}
以上
上过程非常象
象UNIX的greep命令, 你可以用两个
你
个参数调用它
它,一个是模
模式,另一
一个是
文件名,tgrep将打印
印出文件中所
所有匹配该模式的行。
下面
面介绍上述过
过程中用到的
的几个基本的文件输入
入输出命令。
open
n name ?accesss?
2010-11--02
版权所
所有,侵权必究
究
第36页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
open
n命令 以acceess方式打开文件name。返回供其他
他命令(gets,cllose等)使用的
的文件标识
识。如
果name的第一个字符
的
符是“|”,管道
道命令被触
触发,而不是
是打开文件。
文件
件的打开方式
式和我们熟悉
悉的C语言类
类似,有以下
下方式:
r
只
只读方式打开
开。文件必须
须已经存在
在。这是默认
认方式。
r+ 读写方式打开
读
开,文件必须
须已经存在
在。
w 只写方式打开
只
开文件,如果
果文件存在
在则清空文件
件内容,否则
则创建一新的空文件。
w+ 读写方式打开
读
开文件,如文
文件存在则
则清空文件内
内容,否则创
创建新的空文
文件。
a 只写方式打开
只
开文件,文件
件必须存在
在,并把指针
针指向文件尾
尾。
a+ 读写方式打开
读
开文件,并把
把指针指向
向文件尾。如
如文件不存在
在,创建新的空文件。
open
n命令返回一个字符串用于表识打开的文件。当调用别的命令(如:
gets,puts,cclose,〕对打
打开的文件
件进行操作时
时,就可以使
使用这个文件
件标识符。TCL有三个
个特定
的文件标
标识: stdin,stdout和stderrr ,分别对应标准输入
入、标准输出
出和错误通道
道,任何时
时候你
都可以使
使用这三个文
文件标识。
读ffileId标识的文
文件的下一行
行,忽略换行符
符。如果命令
令中有varName就把
Name?
gets fileId ?varN
该行的字符数
数(文件尾返回
回-1),如果
果没有varNamee参数,返回文
文件的下一行
行作为
该行赋给它,并返回该
文件尾,就返
返回空字符串)
)。
命令结果(如果到了文
和geets类似的命令
令是read,不
不过read不是
是以行为单位
位的,它有两
两种形式:
读
读并返回
fileIdd标识的文件中所有剩下
中
如果没有noneewline
的字节。如
read ?-nonewline?? fileId
开关,则
则在换行符处
处停止。
read fileId numB
Bytes
在fileIId标识的文件
件中读并返回
回下一个num
mbytes字节。
puts ?-nonewlinee? ?fileId? strring
puts命令把
命
string写到
写 fileId中,如果没有
有nonewline开关的
开
话,添加
加换行符。fiileId默认是stdout。命令返回值为一
一空字符串。
puts命令使用
命
C的标准
的
I/O库的缓冲区方
库
方案,这就意
意味着使用puts产生的信
信息不会立
立即出
现在目标
标文件中。如
如果你想使数
数据立即出
出现在文件中
中,那你就调
调用flush命令
令:
2010-11--02
所有,侵权必究
究
版权所
第37页,共
共76页
TCL培训教程
程(全)
flush
h
fileId
绝密
请输入文档
档编号
把缓冲区内
把
容写到fileIdd标识的文件
件中,命令返
返回值为空字
字符串。
flush命令迫使缓
缓冲区数据写
写到文件中。flush直到数据被写完
完才返回。当
当文件关闭 时缓
冲区数据
据会自动flush。
closee ?fileId?
关闭标识为
关
f
fileId
的文件,命令返回
回值为一空字
字符串。
这里
里特别说明的
的一点是,TCL
T 中对串口
口、管道、socket等的操
操作和对文件
件的操作类
类似,
以上对文
文件的操作命
命令同样适用
用于它们。
2.3 随机文件
件访问
默认
认文件输入输
输出方式是 连续的:即
即每个 gets或爎
或 ead 命令返
返回的是上
上次 gets或爎 ead
e 访
问位置后
后面的字节
节,每个 putss 命令写数据
据是接着上
上次 puts 写的
的位置接着写
写。 TCL 提 供了
seek,tell和eof等命令使
使用户可以非连续访问
问文件。
每个
个打开的打开
开文件都有访
访问点,即下次读写开
开始的位置。文件打开时
时,访问点
点总是
被设置为
为文件的开头
头或结尾,这
这取决于打
打开文件时使
使用的访问模
模式。每次读
读写后访问位置
按访问的
的字节数后移
移相应的位数
数。
可以
以使用seek命令来改变文
文件的访问点
点:
seek fileId offset
?origin?
把fileIdd标识的文件
件的访问点设
设置为相对于
于origin偏移
移量为
位置。origin可以是
可
start,current,ennd,默认是start。命令的
的返回值是一
一空字符串。
offset的位
例如
如:seek fileIId 2000
改 fieleId标识的文件访
改变
标
访问点,以便
便下次读写开
开始于文件
件的第
2000个字
字节。
seek 的第三个参
参数说明偏移
移量从哪开
开始计算。第
第三个参数必
必为 start,currrent 或 end 中 的一
个。 startt是默认值:即偏移量是
是相对文件
件开始处计算
算。 current 是偏移量从当
是
当前访问位
位置计
算。end是偏移量从
是
文件尾开始
始计算。
tell fileId
f
返回
回fileId标识的
的文件的当前
前访问位置。
。
eof fileId
f
如果到达fileId标识的文件的
标
的末尾返回1,否则返回
回0 。
2.4 当前工作
作目录
2010-11--02
版权所
所有,侵权必究
究
第38页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
TCL提供两个命
提
命令来管理当
当前工作目录
录:pwd和Cdd。
pwd和UNIX下的
的pwd命令完全
全一样, 没有参数,返
没
返回当前目录
录的完整路
路径。
cd 命令也和
命
UN
NIX命令也一
一样,使用一
一个参数,可以把工作
作目录改变为
为参数提供
供的目
录。如果
果 cd 没使用参数, UNIX
X 下,会把 工作目录变
变为启动 TCL
L 脚本的用户
户的工作目 录,
WINDOW
WS 下会把工
工作目录变为
为windows操作系统的安
安装目录所在
在的盘的根
根目录(如:C:/)
C 。
值得注意
意的是,提供
供给cd的参数
数中路径中的应该用'/'而不是
而
'\'。如
如 cd C:/TCL/lib。这是UNIX
U
的风格。
2.5 文件操作
作和获取文件
件信息
TCL提供了两个
提
个命令进行文
文件名操作:glob和file,用来操作文
文件或获取文件信息。
glob命令采用一
命
一种或多种模
模式作为参数
数,并返回
回匹配这个(些)模式的
的所有文件
件的列
表,其语
语法为:
glob ?switches? paattern ?patternn ...?
其中
中switches可以
以取下面的值
值:
-nocoomplain :允
允许返回一个
个空串,没有
有-nocomplainn时,如果结
结果是空的,就返回错误
误。
-- :表示switchees结束,即后
后面以'-'开头
头的参数将不
不作为switchhes。
glob命令的模式
命
式采用string match
m
命令(见8.5.7节)的匹
匹配规则。例
例如:
%gloob *.c *.h
main.c hash.c hassh.h
返回
回当前目录中
中所有.c或.hh的文件名。 glob 还允许
许模式中包
包含' 括在花括
括号中间以
以逗号
分开的多
多种选择',例
例如 :
%gloob {{src,backu
up}/*.[ch]}
src/m
main.c src/hash
h.c src/hash.hh backup/hashh.c
下面
面的命令和上
上面的命令等
等价:
glob {src/*.[ch]} {backup/*.[ch]]}
注意
意:这些例子
子中模式周围的花括号
号是必须的,可以防止命
命令置换。在调用globb命令
对应的C过程前这些
些括号会被TCL
T 解释器去
去掉。
如果
果glob的模式
式以一斜线结
结束,那将只
只匹配目录名
名。例如:
2010-11--02
版权所
所有,侵权必究
究
第39页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
glob */
只返
返回当前目录
录的所有子目
目录。
如果
果glob返回的
的文件名列表
表为空,通常
常会产生一个
个错误。但是glob的在样
样式参数之
之前的
第一个参
参数是"-nocoomplain"的话
话,这时即使
使结果为空,glob也不会
会产生错误。
对文
文件名操作的
的第二个命令是file。fiile是有许多选项的常用
用命令,可以
以用来进行 文件
操作也可
可以检索文件
件信息。这
这节讨论与名
名字相关的选
选项,下一
一节描述其他
他选项。使用
用file
命令时,我们会发现
现其中有很明显的UNIX
X痕迹。
file atime
nam
me
返回一个十进制
制的字符串,表示文件name
n
最后被访
访问的时间
间。时
间是以秒
秒为单位从1970
1 年1月1日12:00AM开始计算。如果文件naame 不存在或
或查询不到
到访问
时间就返
返回错误。例
例:
% file atime license.txt
975945600
file
copy
?-force?
?--?
source
file
copy
?-force?
?--?
source ?souurce ...?
tarrget
targgetDir
这个
个命令把 sourrce 中指明的
的文件或目录
录递归的拷
拷贝到目的地
地址 targetDirr ,只有当存
存在 force选项
项时,已经存
存在的文件才
才会被覆盖
盖。试图覆盖
盖一个非空的
的目录或以一
一个文件覆
覆盖一
个目录或
或以一个目录
录覆盖一个文
文件都会导
导致错误。--的含义和前
前面所说的一
一样。
file
delete
?--force?
?--??
pathname
命令删除pathnname指定的
的文件
?pathnamee ... ? 这个命
或目录,当指定了-force
时,非
非空的目录也
也会被删除。即使没有
有指定-force,只读文件
,
件也会
不存在的文件
件不会引发
发错误。
被删除。删除一个不
file
dirname
name
返回nam
me中最后一个
个“/”前的所
所有字符;如
如果 name 不包含
不
“/”,返回
回“.”;如果name
n
中最后
后一个“/”是第
第name的第一
一个字符,返回“/”。
file
executable name
2010-11--02
如果
果name对当前
前用户是可以执行的,就返回1,否
否则返回0。
所有,侵权必究
究
版权所
第40页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
nam
me
如果name
n
存在于当
当前用户拥有搜索权限
限的目录下返
返回1,否则
则返回
file extension na
ame
返回name
n
中最后的“.”以后(
(包括这个小
小数点)的所
所有字符。如果
file
exists
0。
name中没
没有“.”或最后
后斜线后没有
有“.”返回空
空字符。
file isdirectory name
n
如果
果name是目录
录返回1,否
否则返回0。
如果naame是文件返
返回1,否则返回0。
file isfile name
file lstat name arrayName
a
除了利用lsstat内核调用
用代理stat内核
核调用之外
外,和file statt命令
一样,这
这意味着如果
果name是一个
个符号连接
接,那么这个
个命令返回的
的是这个符号
号连接的信
信息而
不是这个
个符号连接指
指向的文件
件的信息。对
对于不支持符号连接的
的操作系统,
,这个命令
令和和
file stat命令一样。
命
file mkdir dir
?dir ...?
这
这个命令和
U
UNIX
的mkdiir命令类似,创建dir中指
指明的目录
录。如
果dir已经
经存在,这个
个命令不作任
任何事情,也不返回错
错误。不过如
如果试图用一
一个目录覆
覆盖已
经存在的
的一个文件会
会导致错误。这个命令
令顺序处理各
各个参数,如
如果发生错误
误的话,马
马上退
出。
file mtime
m
name
返回十进制的字
字符串,表示
示文件name最后被修改的
最
的时间。时
时间是
以秒为单
单位从1970年1月1日12:00AM开始计
计算。
file owned namee
如果naame被当前用
用户拥有,返
返回1,否则
则返回0。
file readable nam
me
如果当
当前用户可
可对name进行
行读操作,返
返回1,否则返回0。
2010-11--02
所有,侵权必究
究
版权所
第41页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
file readlink na
ame
返回name代表的符号连接
接所指向的文
文件。如果name
n
不是符
符号连
接或者找
找不到符号
号连接,返回
回错误。在
在不支持符号
号连接的操
操作系统 ( 如 windows) 中 选项
readlink没有定义。
没
file rename ? -fforce? ?--? source
s
targeet
file rename ?-fforce?
?--? source
?souurce ...? targgetDir
这个
个命令同时具
具有重命名和
和移动文件
件(夹)的功能。把source指定的文件或
指
或目录改名或移
动到targeetDir下。 只有当存在
只
-fforce选项时,
,已经存在
在的文件才会
会被覆盖。 试图覆盖一
试
一个非
空的目录
录或以一个文
文件覆盖一个
个目录或以
以一个目录覆
覆盖一个文件
件都会导致错
错误。
file rootname name
返回name中最
最后“.”以前(
(不包括这个
个小数点)的所有字符
符。如
果name中没有“
中
.”返回
回Name。
file size name
返回十进制字符串
串,以字节表
表示name的大
大小。如果文
文件不存在
在或得
不到name的大小,返
返回错误。
file stat
name arrayName
调用statt内核来访问
问name,并设
设置arrayNam
me参数来保存
存stat
的返回信
信息。 arrayN
Name被当作
作一个数组,它将有以下
下元素:atiime、ctime、dev、gid、ino、
mode、mtime
m
、nlink、size、type和uid。除了
了type以外,其
其他元素都
都是十进制的
的字符串,tyype元
素和file type
t 命令的返
返回值一样。
。其它各个
个元素的含义
义如下:
2010-11--02
atime
最后
后访问时间
间.
ctime
状态
态最后改变
变时间.
dev
包含
含文件的设
设备标识.
gid
文件
件组标识.
ino
设备
备中文件的
的序列号.
mode
文件
件的mode比特位
比
.
mtime
最后
后修改时间
间.
nlink
到文
文件的连接
接的数目.
size
按字
字节表示的
的文件尺寸.
所有,侵权必究
究
版权所
第42页,共
共76页
TCL培训教程(全)
程
绝密
请输入文档
档编号
文件
件所有者的
的标识.
uid
这里
里的atime、mtime
m
、size元素与前面讨
元
讨论的file的选项有相同
的
同的值。要了
了解其他元
元素更
多的信息
息,就查阅stat
s 系统调用
用的文件;每
每个元都直接
接从相应statt返回的结构
构域中得到。
。文
件操作的
的stat选项提
提供了简单的
的方法使一次
次能获得一
一个文件的多
多条信息。这
这要比分多次调
用file来获
获得相同的信
信息量要显
显著的快。
file tail name
file type name
返回namee中最后一个
个斜线后的所
所有字符,如
如果没有斜
斜线返回namee。
返回文
文件类型的 字符串,返
返回值可能
能是下列中的
的一个: file
f 、
directory、characterspeecial、blockS
Special、fifo、link或sockeet。
w
nam
me
file writable
如果当前
前用户对nam
me可进行写
写操作,返回
回1,否则返回0。
3 错误和异
异常
错误
误和异常处理
理机制是创建
建大而健壮的应用程序
序的必备条件
件之一,很多
多计算机语
语言都
提供了错
错误和异常处
处理机制,TCL
T 也不例外
外。
错误
误 (Errors) 可以
以看作是异常
常 (Exceptionns) 的特例。 TCL 中,异
异常是导致脚
脚本被终止 的事
件,除了
了错误还包括
括break、conntinue 和returrn等命令。TCL
T 允许程序
序俘获异常,
,这样仅有
有程序
的一部分
分工作被撤销
销。程序脚本
本俘获异常
常事件以后,可以忽略它
它,或者从异
异常中恢复
复。如
果脚本无
无法恢复此异
异常,可以把
把它重新发
发布出去。下
下面是与异常
常有关的TCL命令:
catch
h command ?vvarName?
这个命令
令把command作为
作 TCL脚本
本求值,返回一个整型
型值表
明commaand结束的状
状态。如果提
提供varName参数,
参
TCL将生成变量
将
v
varName
,用
用于保存com
mmand
产生的错
错误消息。
errorr message ?inffo? ?code?
这个命
命令产生一个
个错误,并把
把message作为
为错误信息
息。如
果提供innfo参数,则
则被用于初始
始化全局变量errorInfo。如果提供code
c 参数,将
将被存储到
到全局
变量errorrCode中。
2010-11-02
版权所
所有,侵权必究
究
第43页,共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
returrn -code co
ode ?-errorin
nfo info? ?-errrorcode erroorCode? ?strinng?
这个命
命令使特定
定过程
返回一个
个异常。codde指明异常的
的类型,必
必须是ok,errorr,return,break,,continue或者
者是一个整数
数。errorinfo选项用于指定
选
定全局变量
量errorInfo 的初
初始值,-errrorcode用于指定全局变
变量errorCodee的初
始值。 string
s
给出retuurn的返回值
值或者是相关
关的错误信息
息,其默认值
值为空。
3.1 错误
当发
发生一个TCL
L错误时,当
当前命令被终
终止。如果
果这个命令是
是一大段脚本
本的一部分
分,那
么整个脚
脚本被终止。
。如果一个
个TCL过程在运行中发生
生错误,那么
么过程被终止
止,同时调
调用它
的过程,以至整个调
调用栈上的活
活动过程都
都被终止,并
并返回一个错
错误标识和一
一段错误描
描述信
息。
举个
个例子,考虑
虑下面脚本,它希望计算
算出列表元
元素的总和:
set lisst {44 16 123 98 57}
set suum 0
foreaach el $list {
seet sum [expr $sum+$elemen
$
nt]
}
ment": no suchh variable
=> caan't read "elem
这个
个脚本是错误
误的,因为没
没有element这个变量。
这
TCL分析expr命令时,会试图用element
变量的值
值进行替换,
,但是找不
不到名字为ellement的变量
量,所以会报
报告一个错
错误。由于fooreach
命令利用
用TCL解释器
器解释循环体
体,所以错误
误标识被返
返回给foreach。foreach收到
到这个错误
误,会
终止循环
环的执行,然
然后把同样的错误标识
识作为它自己
己的返回值返
返回给调用者
者。按这样
样的顺
序,将致
致使整个脚本
本终止。错误信息can't read "elemennt": no such variable
v
会被一
一路返回,并且
很可能被
被显示给用户
户。
很多
多情况下,错
错误信息提
提供了足够的
的信息为你指
指出哪里以
以及为什么发
发生了错误 。然
而,如果
果错误发生在
在一组深层嵌
嵌套的过程
程调用中,仅
仅仅给出错误
误信息还不能
能为指出哪
哪里发
生了错误
误提供足够 信息。为了
了帮助我们指
指出错误的
的位置,当 TCL
T 撤销程序
序中运行的 命令
时,创建
建了一个跟踪
踪栈,并且
且把这个跟踪
踪栈存储到全
全局变量errrorInfo中。跟
跟踪栈中描
描述了
每一层嵌
嵌套调用。例
例如发生上面
面的那个错
错误后,errorrInfo有如下的
的值:
2010-11--02
版权所
所有,侵权必究
究
第44页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
can't read "elementt": no such varriable
whhile executing
"exprr $sum+$elem
ment"
("fforeach" body line 2)
invvoked from wiithin
"foreach el $list {
m [expr $sum+
+$element]
set sum
}""
在全
全局变量errorrCode中,TC
CL还提供了
了一点额外的
的信息。erroorCode变量是
是包含了一
一个或
若干元素
素的列表。第
第一个元素
素标示了错误
误类别,其他元素提供
供更详细的相
相关的信息。不
过,errorrCode变量是
是TCL中相对
对较新的变量
量,只有一部分处理文
文件访问和子
子过程的命
命令会
设置这个
个变量。如果
果一个命令产
产生的错误
误没有设置errrorCode变量
量,TCL会填
填一个NONE值。
值
当用
用户希望得到
到某一个错误
误的详细的信
信息,除了
了 命令返回值
值中的错误信
信息外,可
可以查
看全局变
变量errorInfo和errorCode的值。
的
3.2 从TCL脚
脚本中产生错
错误
大多
多数TCL错误
误是由实现TCL
T 解释器的
的C代码和内
内建命令的C代码产生的
的。然而,通过
执行TCL
L命令error产生错误也是
是可以的,见
见下面的例子
子:
if {($$x<0)||($x>100
0)} {
errror "x is out off range ($x)"
}
error命令产生了
命
了一个错误,并把它的参
参数作为错误
误消息。
作为
为一种编程的
的风格,你应
应该只在迫
迫不得已终止
止程序时下才
才使用error命令。如果
命
果你认
为错误很
很容易被恢复
复而不必终
终止整个脚本
本,那么使用通常的retturn机制声明
明成功或失
失败会
更好(例
例如,命令成
成功返回某
某个值,失败
败返回另一个值,或者
者设置变量来
来表明成功
功或失
败)。尽
尽管从错误
误中恢复是可
可能的,但
但恢复机制比
比通常的 retuurn 返回值机
机制要复杂 。因
此,最好
好是在你不想
想恢复的情况
况下才使用
用error命令。
ch捕获错误
误
3.3 使用catc
2010-11--02
版权所
所有,侵权必究
究
第45页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
错误
误通常导致所
所有活动的TCL
T 命令被终
终止,但是
是有些情况下
下,在错误发
发生后继续
续执行
脚本是有
有用的。例如
如,你用unset取消变量
量x的定义,但
但执行unsett时,x可能不
不存在。如
如果你
用unset取消不存在的
取
的变量,会产
产生一个错误:
% unnset x
can'tt unset "x": no
o such variablee
此时
时,你可以用
用catch命令忽
忽略这个错误
误:
% cattch {unset x}
1
CL脚本。如
如果脚本正常
常完成,cattch返回0。如
如果脚本中发
发生错误,catch
catchh的参数是TC
会俘获错
错误(这样保
保证catch本身不被终止
止掉)然后返
返回1表示发
发生了错误。
。上面的例子忽
略unset的任何错误,
的
这样如果x存在则被取
取消,即使x以前不存在
在也对脚本没
没有任何影响
响。
catchh命令可以有
有第二个参数
数。如果提供这个参数
数,它应该是
是一个变量名,catch把脚本
把
的返回值
值或者是出错
错信息存入这
这个变量。
%catch {unset x} msg
m
1
%set msg
can't unset "x": no such variable
在这
这种情况下,unset命令产
产生错误,所以msg被设
设置成包含了出错信息
息。如果变量
量x存
在,那么
么unset会成功
功返回,这样catch的返
返回值为0,msg
m 存放unseet命令的返回
回值,这里
里是个
空串。如
如果在命令正
正常返回时,你想访问
问脚本的返回
回值,这种形
形式很有用;如果你想
想在出
错时利用
用错误信息做
做些什么,如
如产生log文件,这种形
文
形式也很有用
用。
3.4 其他异常
常
错误
误不是导致运
运行中程序被
被终止的唯一形式。错
错误仅是被称
称为异常的一
一组事件的
的一个
特例。除
除了 error , TCL
T 中还有三
三种形式的
的异常,他们
们是由 breakk 、 continue 和 return 命令 产生
的。所有
有的异常以相
相同的方式
式导致正在执
执行的活动脚本被终止
止,但有两点
点不同:首
首先,
errorInfo和errorCode只在错误异常
只
常中被设置;其次,除
除了错误之外
外的异常几乎
乎总是被一
一个命
令俘获,不会波及其
其他,而错误通常撤销
销整个程序中
中所有工作。
。例如,breeak和continuee通常
是被引入
入到一个如foreach
f
的循环
环命令中;foreach将俘
俘获break和coontinue异常,
,然后终止
止循环
2010-11--02
版权所
所有,侵权必究
究
第46页,共
共76页
TCL培训教程(全)
程
绝密
请输入文档
档编号
或者跳到
到下一次重复
复。类似地
地,return通常
常只被包含在
在过程或者
者被source引入
入的文件中。过
程实现和
和source命令将俘获returnn异常。
所有
有的异常伴随
随一个字符串
串值。在错误情况,这
这个串是错误
误信息,在return
r
方式,串是
过程或脚
脚本的返回值
值,在break和continue方式,串是空
方
空的。
catchh命令其实可
可以俘获所有
有的异常,不仅是错误
误。catch命令
令的返回值表
表明是那种
种情况
的异常,catch命令的
的第二个参数
数用来保存与异常相关
关的串。例如
如:
%catch {return "all done"} stringg
2
%set string
all done
下表
表是对命令: catch com
mmand ?varN
Name? 的说明
明。
catcch返回值
0
1
2
3
4
其他值
描述
正常返回
回,varNam
me给出返
回值
错误。 varName给出错误信
息
执行了rreturn命令,varName
包含过程
程返回值或者返回给
source的
的结果
执行了break命令,varName
为空
执行了continue命令
令,
varName为空
用户或应
应用自定义
俘获
获者
无异常
常
catch
catch,sourrce,过程
调用
catch,for,fforeach,w
hile,过程
catch,for,fforeach,w
hile,过程
catch
与caatch命令提供
供俘获所有异
异常的机制相
相对应,retuurn可以提供
供产生所有类
类型异常。
这里
里有一个do命令的实现,
命
使用了catcch和return来正确处理异
异常:
prroc do {varNaame first last body}
b
{
global errorIn
nfo errorCodee
upvar $varName v
for {set v $fiirst} {$v <= $llast} {incr v} {
switch [catch {uplevvel $body} striing] {
1 {reeturn -code errror -errorInfo $errorInfo \
2010-11--02
版权所
所有,侵权必究
究
第47页,共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
-errorcodde $errorCode $string}
2 {rreturn -code reeturn $string}
3 reeturn
}
}
}
这个
个新的实现在
在catch命令中
中求循环体的值,然后
后检查循环体
体是如何结束
束的。如果
果没有
发 生 异 常 (0) , 或 者 异 常 是 continue(4) , 那 么 do 继 续 下 一 个 循 环 。 如 果 发 生 error(1) 或 者
return(2),那么do使用
用return把异常传递到调
调用者。如果
果发生了breaak(3)异常,那么do正常
常返回
到调用者
者,循环结束
束。
当doo反射一个errror到上层时
时,它使用了
了return的-errrorInfo选项,保证错误发
发生后能够
够得到
一个正确
确的调用跟
跟踪栈。 -errrorCode 选项 用于类似的
的目的以传
传递由 catch 命令得到的
命
初始
errorCode ,作为 do 命令的
命
errorC
Code 返回。如
如果没有 -eerrorCode 选项
项, errorCodde 变量总是 得到
NONE值。
1 深入TCL
L
本章
章描述了一个
个允许您查询
询和操纵TC
CL解释器内
内部状态的命
命令集。例如
如,您可以通过
这些命令
令看一个变量
量是否存在,可以查看
看数组有哪些
些入口(entry)), 监控所有对
对变量的访
访问操
作,可以
以重命名和删
删除一个命令
令或处理那
那些未定义命
命令的参考信
信息。
1.1 查询数组
组中的元素
利用
用array命令可
可以查询一个
个数组变量
量中已经定义
义了的元素的
的信息。array命令的形
形式如
下:
arrayy option arrrayName ?aarg arg ...?
由于
于option的不同
同,array命令有多种形
形式。
如果
果我们打算开
开始对一个数
数组的元素
素进行查询,我们可以先
先启动一个搜索(search)),这
可以由下
下面的命令做
做到:
2010-11--02
版权所
所有,侵权必究
究
第48页,共
共76页
TCL培训教程
程(全)
arrayy startseracch
绝密
请输入文档
档编号
这个
个命令初始化
化一个对 naame 数组的所
所有元素的 搜索
arrayNam
me
(search),返回一个搜
搜索标识(seaarch identifierr),这个搜索
索标识将被用
用于命令arrray nextelemeent、
array anyymore和array
y donesearch
h。
arrayy
nextelemeent
arrayNaame searchId
这个命
命令返回arraayName的下一
一个元素,如果
arrayName 的所有元素
素在这一次
次搜索中都已
已经返回, 那么返回一
一个空字符
符串。 搜索 标识
必
array startserach
h 的返回值。 注意:如 果对 arrayNaame 的元素进
进行了添加 或删
searchId 必须是
除,那么
么所有的搜 索都会自动
动结束,就象
象调用了命
命令 array donesearch 一样
样,这样会 导致
array nexxtelement操作
作失败。
arrayy anymore arrayName
a
seearchId
如
如果在一个搜
搜索中还有元
元素就返回1,否则返回
回0 。
searchId 同 上 。 这 个 命 令 对 具 有 名 字 为 空 的 元 素 的 数 组 尤 其 有 用 , 因 为 这 时 从 array
nextelemeent中不能确
确定一个搜索
索是否完成。
。
arrayy donesearch
h arrayName searchId
s
这
这个命令中止
止一个搜索,并销毁和这
这个搜索有
有关的
所有状态
态。searchId同上。命令
令返回值为一
一个空字符串。当一个
个搜索完成时
时一定要注 意调
用这个命
命令。
arrayy命令的其他
他option如下:
arrayy exists arrrayName
如
如果存在一个
个名为arrayN
Name的数组
组,返回1,否
否则返回0。
arrayy get arrayN
Name ?pattern?
这个命
命令的返回值
值是一个元素
素个数为偶数
数的的list。我们
可以从前
前到后把相邻
邻的两个元
元素分成一个
个个数据对,那么,每
每个数据对的
的第一个元
元素是
arrayNamee 中元素的名
名字,数据
据对的第二个
个元素是该数
数据元素的
的值。数据对
对的顺序没 有规
律。如果
果没有patternn参数,那么
么数组的所有
有元素都包含
含在结果中
中,如果有paattern参数,那么
只有名字
字和pattern匹配
匹 (用string match的匹配
配规则)的元
元素包含在结
结果中。如果
果arrayNamee不是
一个数组
组变量的名字
字或者数组中没有元素
素,那么返回
回一个空list。例:
。
% sett b(first) 1
1
% sett b(second) 2
2
% arrray get b
2010-11--02
所有,侵权必究
究
版权所
第49页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
seconnd 2 first 1
arrayy
set
arra
ayName list
设置数组
组arrayName的元素的值
的
。 list 的 形式
式和array get的
返回值的
的list形式一样
样。如果arrrayName不存
存在,那么生
生成arrayNam
me。例:
% arrray set a {firrst 1 second 2}
2
% puuts $a(first)
1
% arrray get a
seconnd 2 first 1
arrayy names
arrayName
a
?
?pattern?
这
这个命令返
回数组arrayyName中和模
模式pattern匹配的
匹
元素的名
名字组成的一
一个list。如
如果没有patteern参数,那
那么返回所有
有元素。如果
果数组中没
没有匹
配的元素
素或者arrayN
Name不是一个
个数组的名
名字,返回一
一个空字符串
串。
arrayy
size
arrrayName
返回代
代表数组元素
素个数的一
一个十进制的
的字符串, 如果
arrayNamee 不是一个数
数组的名字,那么返回
回0 。
下面
面这个例子通
通过使用arraay names 和foreach
f
命令,枚举了数
数组所有的元
元素:
foreaach i [array names a] {
p
puts
"a($i)=$
$a($i)"
}
当然
然,我们也可
可以利用 staartsearch 、 anymore
a
、 neextelement 、 和 donesearcch 选项来遍 历一
个数组. 这种方法 比上面所给
给出的 foreachh 方法的效率
率更高,不
不过要麻烦得
得多,因此 不常
用。
1.2 info命令
令
info命令提供了
命
查看TCL解释
释器信息的
的手段,它有
有超过一打的
的选项,详细
细说明请参
参考下
面几节。
1.22.1 变量信息
息
info命令的几个选
命
选项提供了
了查看变量信
信息的手段。
2010-11--02
版权所
所有,侵权必究
究
第50页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
info exists varN
Name
如
如果名为
varN
Name的变量在
在当前上下文(作为全局
局或局部变量
量)存
在,返回
回1,否则返
返回0。
如果没有pattern
p
参数,那么返回包
包含所有全局
局变量名字
字的一
info globals ?pa
attern?
个list。如
如果有patternn参数,就只
只返回那些和
和pattern匹配
配的全局变量
量(匹配的方
方式和string match
m
相同)。
info locals ?pattern?
如
如果没有
patteern参数,那
那么返回包含
含所有局部变
变量(包括当
当前过
程的参数
数)名字的一个list,globaal和upvar命令
令定义的变量将不返回
回。如果有paattern参数,就只
返回那些
些和pattern匹配的局部变
匹
变量(匹配的方
方式和stringg match相同
同)。
info
vars ?patteern?
如果
果没有patternn参数,那么
么返回包括局
局部变量和可
可见的全局
局变量
的名字的
的一个list。如
如果有patterrn参数,就只
只返回和模式pattern匹配
配的局部变量
量和可见全
全局变
量。模式
式中可以用namespace
n
来限
限定范围,如:foo::option*,就只返
返回namespacee中和option**匹配
的局部和
和全局变量。
。 (注:tcl800以后引入了
了namespace概念,不过
概
我们一般编
编写较小的TCL程
序,可以
以对namespacce不予理睬,
,用兴趣的话可以查找
找相关资料。)
下面
面针对上述命
命令举例,假
假设存在全局
局变量globaal1和global2,并且有下列
列的过程存
存在:
proc test {arg1 arg2} {
global global1
set local1 1
set local2 2
...
}
然后
后在过程中执
执行下列命令
令:
% innfo vars
global1 arg1 arg2 local2 local1
不
//global2不可见
% innfo globals
global2 global1
% innfo locals
arg1 arg2 local2 lo
ocal1
% innfo vars *al*
global1 local2 local1
2010-11--02
所有,侵权必究
究
版权所
第51页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
1.11.1 过程信息
息
info 命令的另外
外的一些选项
项可以查看过
过程信息。
info procs ?patterrn?
如果没
没有pattern参数,命令返
参
返回当前nam
mespace中定义
义的所有过
过程的
名字。如
如果有 patterrn 参数,就 只返回那些
些和 pattern 匹配的过程的
匹
的名字 ( 匹配
配的方式和 string
s
match相同
同)。
info body procna
ame
a
procnam
me
info args
返回
回过程procnam
me的过程体
体。 procnamee必须是一个
个TCL过程。
返回包
包含过程proccname的所有
有参数的名字
字的一个listt。 procnamee必须
是一个TCL过程。
v
info default procname arg varname
procname必须
须是一个TCL
L过程, arg必须是这个
必
个过程
的一个变
变量。如果arg
a 没有缺省
省值,命令返
返回0;否则
则返回1,并
并且把arg的缺
缺省值赋给
给变量
varname。
info level ?numb
ber?
如果
果没有numberr参数,这个
个命令返回当
当前过程在调
调用栈的位
位置。
如果有nuumber参数,那么返回的
的是包含 在调用栈的位
在
位置为numbeer的过程的过
过程名及其
其参数
的一个list。
下面
面针对上述命
命令举例:
procc maybeprint {a b {c 24}} {
if {$a<$b} {
p stdout "c is $c"
puts
}
}
% inffo body maybeeprint
if {$a<$b} {
p stdout "c is $c"
puts
}
% inffo args maybeeprint
abc
ybeprint a x
% inffo default may
0
ybeprint a c
% innfo default may
2010-11--02
版权所
所有,侵权必究
究
第52页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
1
%seet x
24
下面
面的过程打印
印出了当前的调用栈,并显示了每
每一个活动过
过程名字和参
参数:
proc printStack{}{{
s level [info level]
set
f {set i 1} {$
for
$i<$level} {inncr i} {
puts "Levell $i:[info levell $i]"
}
}
1.11.2 命令信息
息
info 命令的另外
命
外选项可以查
查看命令信息
息。
info commands ?p
pattern?
如果没有参
参数pattern,这个命令返
返回包含当前
前namspace中所有
固有、扩
扩展命令以及
及以proc命令
令定义的过
过程在内的所
所有命令的名
名字的一个
个list。patternn参数
的含义和
和info procs一样。
一
info cmdcount
返回了一
一个十进制字
字符串,表明
明多少个命令曾在解释
释器中执行过
过。
info complete command
如
如果命令是
c
command
完整
整的,那么返
返回1,否则
则返回0。这
这里判
断命令是
是否完整仅判
判断引号,括
括号和花括
括号是否配套
套。
info
script
如果当前有
有脚本文件正在Tcl解释
释器中执行,则返回最内层处于激
激活状
态的脚本
本文件名;否
否则将返回一
一个空的字
字符串。
1.11.3 TCL的版
版本和库
info
tclversion
info
library
返回为Tccl解释器返回
回的版本号,
,形式为maajor.minor,例
例如8.3。
返回Tcl库目录的完
完全路径。这个目录用
用于保存Tcl所使用的标
所
标准脚
本,TCL
L在初始化时
时会执行这个
个目录下的脚
脚本。
1.11.4 命令的执行时间
TCL提供
提 time命令
令来衡量TC
CL脚本的性能
能:
2010-11--02
版权所
所有,侵权必究
究
第53页,共
共76页
TCL培训教程
程(全)
time script ?coun
nt?
绝密
请输入文档
档编号
这个命
命令重复执
执行script脚本
本count次。 再把花费的
再
总时间的用
用count
除,返回
回一次的平均
均执行时间,单位为微
微秒。如果没
没有count参数
数,就取执行
行一次的时间。
1.11.5 跟踪变量
TCL提供了
提
tracee命令来跟踪
踪一个或多个
个变量。如
如果已经建立
立对一个变量
量的跟踪,则不
论什么时
时候对该变量
量进行了读
读、写、或删
删除操作,就
就会激活一
一个对应的Tcl
T 命令,跟
跟踪可
以有很多
多的用途:
1.监视
视变量的用
用法(例如打
打印每一个读
读或写的操作
作)。
2.把变
变量的变化
化传递给系统
统的其他部分
分(例如一
一个TK程序中
中,在一个小
小图标上始
始终显
示某个变
变量的当前值
值)。
3.限制
制对变量的
的某些操作(例如对任何
何试图用非
非十进制数的
的参数来改变
变变量的值
值的行
为产生一
一个错误。)
)或重载某些
些操作(例
例如每次删除
除某个变量时
时,又重新创
创建它)。
tracee命令的语法
法为:
tracee option ?arg arg ...?
其中
中option有以下
下几种形式:
tracee variable
name ops command
这个命令设
设置对变量name
n
的一个跟
跟踪:每次
次当对
变量name作ops操作时,就会执
执行command命令。
命
namee可以是一个
个简单变量,
,也可以是
是一个
数组的元
元素或者整个
个数组。
ops可以是以下几
可
几种操作的一
一个或几个
个的组合:
r 当变量被读时
当
时激活commaand命令。
w 当变量被写时
当
时激活comm
mand命令。
u 当变量被删除
当
除时激活com
mmand命令。通过用unseet命令可以显
显式的删除一
一个变量,一个
过程调用
用结束则会隐
隐式的删除所
所有局部变
变量。当删除
除解释器时也
也会删除变量
量,不过这
这时跟
踪已经不
不起作用了。
。
当对
对一个变量的
的跟踪被触
触发时, TCL
L 解释器会自
自动把三个参数添加到
到命令 commaand 的
参数列表
表中。这样command
c
实际
际上变成了
comm
mand name1 name2
n
op
2010-11--02
版权所
所有,侵权必究
究
第54页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
其中
中op指明对变
变量作的什么
么操作。nam
me1和name2用于指明被
用
被操作的变量
量: 如果变
变量是
一个标量
量,那么nam
me1给出了变
变量的名字,而name2是一个空字符
是
符串;如果变
变量是一个
个数组
的一个元
元素,那么 name1 给出数
数组的名字
字,而 name2 给出元素的
给
的名字;如果
果变量是整 个数
组,那么
么 name1 给出
出数组的名字
字而 name2 是一个空字符
是
符串。为了
了让你很好的
的理解上面 的叙
述,下面
面举一个例子
子:
trace variable collor
w pvar
p
trace variable a(length) w pvar
proc pvar {name ellement op} {
i {$element !=
if
=""} {
set name ${name}($elem
ment)
}
u
upvar
$name x
p "Variablee $name set to $x"
puts
}
上面
面的例子中,对标量变量
量color和数
数组元素a(lenngth)的写操作
作都会激活
活跟踪操作pvvar。
我们看到
到过程pvar有三个参数,
有
,这三个参
参数TCL解释
释器会在跟踪
踪操作被触发
发时自动传
传递给
pvar。比如如果我们
们对color的值
值作了改变,那么激活的
的就是pvar color
c
"" w。我
我们敲入:
% sett color green
Variaable color set to
t green
greenn
comm
mand 将在和触发跟踪操
操作的代码同
同样的上下文中执行:如果对被跟
跟踪变量的访问
是在一个
个过程中,那
那么commandd就可以访问
问这个过程的
的局部变量
量。比如:
proc Hello { } {
set a 2
trace variable b w { puts $a ;list }
set b 3
}
% Heello
2
3
2010-11--02
所有,侵权必究
究
版权所
第55页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
对于
于被跟踪变量
量的读写操作,commannd是在变量被读之后,而返回变量
量的值之前
前被执
行的。因
因此,我们可
可以在comm
mand对变量的
的值进行改
改变,把新值
值作为读写的
的返回值。而且
因为在执
执行commandd时,跟踪机
机制会临时失
失效,所以在
在command中对变量进行
中
行读写不会
会导致
command被递归激活
被
活。例如:
% traace variable b r tmp
% prooc tmp {var1 var2
v
var3 } {
upvarr $var1 t
incr t 1
}
% sett b 2
2
% puuts $b
3
% puuts $b
4
如果
果对读写操作
作的跟踪失败,即comm
mand 失败, 那么被跟踪
踪的读写操作
作也会失败
败,并
且返回和
和command同样的失败信
同
信息。利用这
这个机制可
可以实现只读
读变量。下面
面这个例子
子实现
了一个值
值只能为正整
整数的变量:
trace variable size w forceInt
me element opp} {
proc forceInt {nam
upvvar $name x
if ![regexp {^[0-9
9]*$} $x] {
e
error
"value must
m b a postivee integer"
}
}
如果
果一个变量有
有多个跟踪信
信息,那么各个跟踪被
被触发的先后
后原则是:最
最近添加的
的跟踪
最先被触
触发,如果有
有一个跟踪发
发生错误,后面的跟踪
踪就不会被触
触发。
tracee vdelete name
n
ops coommand
删除对变量naame的ops操作
作的跟踪。返
返回值为一
一个空
字符串。
2010-11--02
所有,侵权必究
究
版权所
第56页,共
共76页
TCL培训教程
程(全)
tracee
vinfo
nam
me
绝密
请输入文档
档编号
这个命
命令返回对变量的跟踪
踪信息。返回
回值是一个list,list的每
每个元
素是一个
个子串,每个
个子串包括两个元素:跟踪的操作
作和与操作关
关联的命令。如果变量
量name
不存在或
或没有跟踪信
信息,返回一
一个空字符
符串。
1.11.6 命令的重
重命名和删除
renam
me 命令可以
以用来重命名
名或删除一个
个命令。
renam
me oldNamee newName
把命令oldN
Name改名为
为newName,如果newNam
me为空,那
那么就
从解释器
器中删除命令
令oldName。
下面
面的脚本删除
除了文件I/O命令:
命
foreeach cmd {open close read gets puts} {
rename $cmd {}
}
任何
何一个Tcl命令
令都可以被重
重命名或者
者删除,包括
括内建命令以
以及应用中定
定义的过程
程和命
令。重命
命名一个内建
建命令可能
能会很有用,例如,exitt命令在Tcl中被定义为立
中
立即退出过
过程。
如果某个
个应用希望在
在退出前获得
得清除它内
内部状态的机
机会,那么可
可以这样作:
renaame exit exit.o
old
procc exit status {
appplication-speccific cleanup
...
exxit.old $status
}
在这
这个例子中,exit命令被
被重命名为 exit.old
e
,并且
且定义了新 的 exit 命令, 这个新命
命令作
了应用必
必需的清除工
工作而后调
调用了改了名
名字的exit命令来结束进
命
进程。这样在
在已存在的
的描述
程序中调
调用exit时就会有机会做
做清理应用状
状态的工作。
。
1.11.7 unknownn命令
unkn
nown命令的语法为:
unkn
nown
cmdNa
Name ?arg arg ...?
当
当一个脚本试
试图执行一个不存在的
的命令时,TCL解
释器会激
激活 unknow
wn 命令,并 把那个不存
存在的命令
令的名字和参
参数传递给
给 unknown 命 令。
2010-11--02
版权所
所有,侵权必究
究
第57页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
unknown命令不是TC
CL的核心的
的一部分,它
它是由TCL脚本实现的,
脚
,可以在TC
CL安装目录
录的lib
子目录下
下的init.tcl文件中找到其
其定义。
unkn
nown命令具有以下功能
能:
1。如
如果命令是一个在TCL的某个库文
文件(这里的库
库文件指的是TCL目录的lib子目录
录下的
TCL脚本
本文件)中定义
义的过程,则加载该库
库并重新执行
行命令,这
这叫做“auto-loading”(自动加
载),关
关于它将在下
下一节描述。
2。如
如果存在一个
个程序的名
名字与未知命
命令一致,则
则调用exec命令来调用该
命
该程序,这
这项特
性叫做“auto-exec”(自动执行) 。例如你输
输入“dir”作为一个命令
令,unknown会执行“execc dir”
当前目录的内
内容,如果这
这里的命令
令没有特别指
指明需要输入
入输出重定向,则自动
动执行
来列出当
功能会使
使用当前Tcll应用所拥有
有的标准输入
入输出流,以及标准错
错误流,这不
不同于直接
接调用
exec命令
令,但是提供
供了在Tcl应用
用中直接执行
行其他应用
用程序的方法
法。
3。如
如果命令是一组特殊字
字符,将会产
产生一个新
新的调用,这
这个调用的内
内容是历史
史上已
经执行过
过的命令。例
例如,如果
果命令时“!!”则
则上一条刚
刚执行过的命
命令会再执行
行一遍。下
下一章
将详细讲
讲述该功能。
。
4。若
若命令是已知命令的唯
唯一缩写,则
则调用对应的
的全名称的正确命令。在TCL中允
允许你
使用命令
令名的缩写,只要缩写唯一即可。
如果
果你不喜欢unknown
u
的缺
缺省的行为,你也可以自己写一个
个新版本的unnknown或者
者对库
中已有unnknown的命
命令进行扩展
展以增加某项
项功能。如果你不想对
对未知命令做
做任何处理
理,也
可以删除
除unknown,这样当调用
用到未知命令
令的时候就会
会产生错误。
1.11.8 自动加载
载
在 unnknown过程中
中一项非常
常有用的功能
能就是自动 加载,自动
动加载功能允
允许你编写一组
Tcl过程放
放到一个脚本文件中,然后把该文
文件放到库目录之下,当程序调用
用这些过程
程的时
候,第一
一次调用时由
由于命令还
还不存在就会
会进入unknow
wn命令,而
而unknown则会
会找到在哪
哪个库
文件中包
包含了这个过
过程的定义,接着会加
加载它,再去
去重新执行命
命令,而到下
下次使用刚
刚才调
用过的命
命令的时候,由于它已经
经存在了,从而会正常
常的执行命令
令,自动加载
载机制也就
就不会
被再次启
启动。
2010-11--02
版权所
所有,侵权必究
究
第58页,共
共76页
TCL培训教程(全)
程
绝密
请输入文档
档编号
自动
动加载提供了
了两个好处,
,首先,你可以把有用
用的过程建立
立为过程库,
,而你无需
需精确
知道过程
程的定义到底
底在哪个源文
文件中,自
自动加载机制
制会自动替你
你寻找,第二
二个好处在
在于自
动加载是
是非常有效率
率的,如果没有自动加
加载机制你将
将不得不在TCL
T 应用的开
开头使用souurce命
令来加载
载所有可能用
用到的库文
文件,而应用
用自动加载机制,应用
用启动时无需
需加载任何
何库文
件,而且
且有些用不到
到的库文件永
永远都不会
会被加载,既
既缩短了启动
动时间又节省
省了内存。
使用
用自动加载只
只需简单的按
按下面三步来
来做:
第一
一,在一个目
目录下创建一
一组脚本文
文件作为库,一般这些文
文件都以".tccl"结尾。每
每个文
件可以包
包含任意数量
量的过程定义
义。建议尽
尽量减少各脚
脚本文件之间
间的关联,让
让相互关联
联的过
程位于同
同一个文件中
中。为了能
能够让自动加
加载功能正确
确运行,prooc命令定义一
一定要顶到
到最左
边,并且
且与函数名用
用空格分开,过程名保
保持与proc在同一行上。
第二
二步,为自 动加载建立
立索引。启
启动 Tcl 应用 比如 tclsh , 调用命令 auto_mkindeex dir
pattern , 第一个参数
第
数是目录名,第二个参数
数是一个模
模式。auto_m
mkindex在目录
录dir中扫描
描文件
名和模式
式pattern匹配
配的文件,并
并建立索引以指出哪些
些过程定义在
在哪些文件中
中,并把索
索引保
存到目录
录 dir 下一个 叫 tclindex 的文件中。如
的
如果修改了文
文件或者增
增减过程,需
需要重新生
生成索
引。
第三
三步是在应用
用中设置变量auto_path,把存放了希望使用到
到的库所在的
的目录赋给
给它。
auto_path变量包含了
变
了一个目录的
的列表,当自
自动加载被启
启动的时候
候,会搜索auuto_path中所
所指的
目录,检
检查各目录下
下的tclindex文件来确认
文
认过程被定义
义在哪个文件
件中。如果一
一个函数被
被定义
在几个库
库中,则自动
动加载使用在
在auto_path中靠前的那个
中
个库。
例如
如,若一个应
应用使用目录
录/usr/local/tccl/lib/shapes下的库,则在
下
在启动描述中
中应增加:
set auto_path
[linsert
[
$auto__path 0 /usr/loocal/tcl/lib/shappes]
这将
将把/usr/local//tcl/lib/shapes作为起始搜
作
搜索库的路径
径,同时保 持所有的Tccl/Tk库不变
变,但
是在 /usr//local/tcl/lib/shhapes中定义
义的过程具有
有更高的优 先级,一旦
旦一个含有索
索引的目录
录加到
了auto_paath中,里面
面所有的过程
程都可以通过
过自动加载使
使用了。
2 历史记录
录
2010-11--02
版权所
所有,侵权必究
究
第59页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
这部
部分内容主要
要描述TCL的历史机制
的
,涉及到对
对以前执行过
过的命令的应
应用。历史
史机制
在一个列
列表中保留了
了最近执行过
过的命令,使你不必重
重新敲入命令
令,还可以对
对以前的命
命令进
行修改以
以创建新的命
命令而不必重
重新输入新
新的命令,特
特别是在命令
令较长时更加
加方便。
historry命令的格式
式为:
histoory ?option? ?arg arg ...?
其中
中option 可为add, change, clear, event, info, keep, neextid, 或者reedo。老版本
本中有substituute 和
words,现
现在的版本(8.0以后)中被删掉了
了,增添了clear
c 。下面一
一一介绍:
histoory 和historry info相同,显示以前
前执行过的命
命令和序号,如果执行过
过的命名个
个数超
过了历史
史记录列表允
允许的最大的数量,则
则只能按最大
大数量显示最
最近执行过的命令。
注意
意: history 命令本身在
命
历史记录列
列表中也占 了一条,如
如:原来只有
有一条命令
令 set a
123,现在
在输入historry,则:
%hisstory
1 set a 123
2 history
显示
示出两条历史
史记录。
histoory add com
mmand ?exeec?
在历史
史记录列表中
中加一条命令,如果有
有exec选项,则执
行该命令
令,并返回结
结果 ;如果
果没指定execc选项,则返
返回空字符串
串作为结果。
。其中添加
加的新
命令要用
用双引号或花
花括号括上。如:
%history add "set b 100" exec
100
%history
1 hiistory add "sett b 100" exec
2 sett b 100
3 hisstory
histoory change neewValue ?evennt?
用newValue
n
替代
代序号为evennt的命令,同时历史记
记录中
的命令被
被改写。如没
没指定event则替换当前
则
前命令。如:
%history
2010-11--02
所有,侵权必究
究
版权所
第60页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
1 set a 123
2 set b 23
3 history
%history change "sset a 100" 1
%history
//set a 123被set a 100替换了。
替
s a 100
1 set
2 set
s b 23
3 history
4 history "set a 100" 1
5 history
%history change "sset c 1"
%history
1 set a 100
2 set b 23
3 history
4 history "set a 100" 1
5 history
6 set c 1
//这里historry change "sett c 1"被set c 1替换了
7 history
histoory clear
清除历史记录
清
录列表的内
内容,但记录
录列表允许的
的最大记录数
数这一属性
性仍然
保留。例
例如:如果用
用history keepp 50把最大记
记录数改变
变为50,historry clear后记录
录内容空了,但
最大记录
录数仍为50。
histoory event ?eevent?
其 event为历
其中
历史事件的序
序号,返回该
该序号的命令
令行,如果
果没指
定event则返回上一条
则
条命令行。如
如:
% hisstory
1 seet a 123
2 seet b 23
3 history
%history event 1
set a 123
2010-11--02
所有,侵权必究
究
版权所
第61页,共
共76页
TCL培训教程(全)
程
绝密
请输入文档
档编号
%history event
histtory event 1
histoory info ?co
ount?
没有
有count参数时
时和history命令一样,有
命
有count参数 时返回最近
时
近执行
的count个命令。
个
histoory keep ?cou
unt?
把历史记录列表
表允许的最大
大数量设置为
为count。系统
统最初的最
最大记
录为20。
histoory nextid
返回下一条
条将要添加到
到历史记录
录列表中的命
命令的序号。例:
%history
seet a 123
2 set b 23
3 history
%history nextid
5
//因为history nextidd的序号为4。
histoory redo ?even
nt?
重新执
执行记录列表
表中序号为
为event的命令
令。event缺省
省为-1。
快捷
捷键操作
!!
同命令 hisstory redo相同
同。
!event
同命令 hiistory redo eveent相同。
这两
两个快捷键操
操作对应上一
一节unknownn命令的第3个功能。
个
3 TCL和C
C\C++
在阅
阅读以下章节
节之前,假定你已经安
安装了TCL8.11或更高版本
本,同时有一
一个C或C++的
集成开发
发环境。注意
意安装TCL时一定要选择
时
择定制安装
装,把头文件
件和库文件都
都安装上。
TCL解释器是由
解
由一个C库实
实现的,在某
某种意义上TCL
T 语言可以
以看作是一
一个C库。我
我们可
以调用 TCL
T 提供的库
库函数来生 成 TCL 解释
释器、求一个
个 TCL 脚本的
的值或扩展 TCL 固有命 令。
2010-11--02
版权所
所有,侵权必究
究
第62页,共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
TCL提供
供了一组有用
用的库函数来
来供用户访问
问TCL的变量
量、分析命令参数、操
操作TCL列表
表、求
TCL表达
达式的值等。
3.1 生成自己
己的TCLSH
我们
们可以轻易的
的利用TCL库函数生成和
库
和Tclsh完全一
一样的程序:
#incluude "tcl.h"
#incluude "stdio.h"
#incluude "stdlib.h"
int Tcl_AppInit(T
T
cl_Interp *interp);
main(int argc, charr *argv[])
{
Tcl_Main(argc, argv,Tcl_ApppInit);
exxit(0);
}
int Tcl_AppInit(T
T
cl_Interp *interp)
{
Tcl_init(interp));
reeturn TCL_OK
K;
}
在工程中加入TCL
L对应的库文
文件,编译执行
行。在其中交
交互敲入命令,会发现和T
Tclsh完全一样
样。给
出这个例子只是为了说
说明利用TCL
L提供的库函数
数是可以多么
么方便的生成
成自己的应用。
。但这个例子
子目前
还没有加入我们自己的
的东西,下面
面一步我们就将
将加入我们自
自己扩展的命令
令。
3.2 扩展自己
己的命令:方
方法(一)
TCL提
提供了一整套
套供用户扩展
展自己的命令
令的函数(请
请参考 文档 《 TCL 库函数
数介绍 ( 一 ) 》和
《TCL库函数介绍
库
(二)》〕。下面
面介绍怎样扩
扩展自己的TCL命令。
TCL允
允许用户扩展
展命令,TCL解
解释器将把扩
扩展命令和固有命令同等对
对待。TCL的
的扩展命令要求
求用C
或C++实
实现。扩展一
一个TCL命令大
大致可以分为
为两步:编写扩
扩展命令对应
应的C/C++过程
程,注册命令
令。
3.22.1 编写扩展
展命令对应的
的C/C++过程
程
TCL要
要求所有的T
TCL扩展命令
令对应的C/C+
++过程具有同
同样的形式。 在tcl.h文件
件中对TCL命令
令过程
Tcl_CmdProc的定义是这样的:
2010-11--02
版权所
所有,侵权必究
究
第63页,共
共76页
TCL培训教程
程(全)
typedef
int
绝密
请输入文档
档编号
Tcl_CmdProc
T
(ClientData
clientdata,Tcl_Interrp*
interp,int
argc,cchar*
argv[]);
个参数clientdaata暂时可以不
不予理会,在
在13.2.2将会介
介绍。
这个函数中第一个
一个TCL解释器
器,TCL解释
释器是一个复
复杂的结构,不
不过让用户可
可见的部分比
比较简
interpp参数指向一
单,TCL中
中的定义如下
下:
Typeedef struct Tcl_
_Interp {
char * result;
Tcl_ffreeProc * freeeProc;
int errorLine;
}Tcl__Interp;
argc和
和argv与我们
们编写C语言程
程序时main函数的两个参数
数的含义基本
本一样,argc代
代表命令的参
参数个
数(包括命令名自身〕,argv是一个
个字符串数组
组,记录各个参数的字符形
形式。
值为整型,将
将在13.2.3节单
单独讲解。
命令过程的返回值
单的扩展例子
子。假如我们想
想扩展一个命
命令 add ,形式
式为add int1 int2,实现两
两个整
下面给出一个简单
以这样给出其
其实现:
数相加。那么我们可以
A
ntData clientdaata,Tcl_Interp** interp,int arggc,char * argvv[])
int AddCmd(Clien
{
iff(argc!=3)
{
interp-->result="Useaage Error! shoould be : add int1
i
int2";
return TCL_ERROR
R;
}
innt i,j;
iff(TCL_OK!=T
Tcl_GetInt(inteerp,argv[1],&i))
{
sprintff(interp->resullt,"Expect inteeger but got %s",argv[1]);
%
return TCL_ERROR
R;
}
Tcl_GetInt(inteerp,argv[2],&jj))
iff(TCL_OK!=T
{
sprintff(interp->resullt,"Expect inteeger but got %s",argv[2]);
%
return TCL_ERROR
R;
}
2010-11--02
所有,侵权必究
究
版权所
第64页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
i=
=i+j;
spprintf(interp->
>result,"%d",i));
reeturn TCL_OK
K;
}
其中
中, Tcl_GetInnt 等函数可
可以参考文档
档《 TCL 库 函数介绍 ( 一 ) 》和《 TCL
T 库函数 介绍
(二)》。
3.22.2 注册命令
令
TCL提供了一个
提
个库函数Tcl__CreateComm
mand 负责把每
每一个使用C/C++语言编
编写的上述
述形式
的TCL命令过程向
命
TC
CL解释器注
注册,它的原型
型为:
Tccl_CreateComm
mand
(Tcl_IInterp* interrp, char*
ClienntData
clienttdata,
c
cmdName,
Tcl_CmdProcc*
cmdProc,,
Tcl_CmdDeleteP
Proc* deletePrroc)
第一
一个参数是一
一个解释器指
指针。
第二
二个参数是你
你想给自己的
的TCL命令取
取的名字。
第三
三个参数是一
一个函数指针
针,指向我们
们自己用C/C+++语言编写的TCL命令过
过程。
一旦
旦注册成功,T
TCL解释器将
将把命令过程cmdProc和命令名
和
cmddName严格对
对应起来,一旦你
一
在TCL中激活了命令
中
令名cmdNam
me,TCL解释器
器就会自动调
调用命令过
过程cmdProc.例如
例 :TCL解释器
解
遇到命令
令add,就会调
调用AddCmd命令过程
命
.
第四
四个参数是用
用来传递用户
户自己定义
义的数据对象
象的,TCL记录这个参数
记
数指向的对象
象,并
把它传递
递给命令过程
程cmdProc的第一个参数
的
数。利用这个参数我们
们可以方便的
的实现在多 个命
令过程中
中对同一个数
数据对象进行
行操作。
ClienntData类型在
在TCL的定义
义为 typedef vooid *ClientDaata; 它可以指
指向任何类型
型。
最后
后一个参数是
是一个函数指针,它指
指向一个回调
调函数,当我
我们从解释器
器 interp中删 除命
令 cmdNaame 时 , 函 数 deleteProoc 就 会 被 激 活 , deletteProc 必 须 有 同 一 的 形 式 , 在 TC
CL 中
Tcl_CmdD
DeleteProc的定
定义为:
typeddef void (Tcl_CmdDeleteProc) (ClientDaata clientData);
我们
们可以利用这
这个回调函 数中释放 cllientData 占用
用的内存。在
在较为复杂 的 TCL 扩展 中,
我们将不
不可避免的要
要用到Tcl_C
CreateCommannd的最后两个
个参数。
对于
于我们上面编
编写的AddCm
md过程我们
们可以这样注
注册:
2010-11--02
版权所
所有,侵权必究
究
第65页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
Tcl_C
CreateCommaand(interp,"add",AddCmd,N
NULL,NULL));
把这
这个语句加 到 13.1 节所 举例子的 Tcl_AppInit
T
函
函数的
Returnn TCL_OK 语句之前,
语
再把
AddCmd函数的原型和
函
和实现加入
入那个例子,编译执行。就可以交互
互执行了:
%addd 2 3
5
%addd a 2
Expeect integer but got 'a'
这样
样,就在TCL
L中扩展了一
一个命令add,TCL解释器
器遇到add命令时,就会
命
会把add命令
令及其
后面的参
参数传递给对
对应的命令过
过程AddCmdd处理。
3.22.3 命令返回
回值和命令对
对应的过程的返回值
TCL命
命令的返回值
值总是一个字
字符串,一个命
命令的返回值
值是由它对应的C/C++过程
程决定的。从13.2.2
节所举的
的例子我们也可
可以看出来, TCL命令的
的返回值是由 对应的C/C++
+过程中interrp->result的值
值决定
的。在AdddCmd的例子
子中,如果我们
们把
Sprinntf(interp->ressult,"%d",i);
修改为
o %s and %s
% is :%d",aargv[1],argv[2]],i);
Sprinntf(interp->ressult,"the sum of
重新编译执行,那
那么
%Addd 2 3
the suum of 2 and 3 is :5
需要注意的一点是
是,interp->reesult的预分配
配空间只有2000个字节,如果
果命令的结果
果的长度超过2200个
数Tcl_SetResuult或Tcl_AppeendResult来管
管理命令结果。
字节,那么请使用函数
们已经看到,一
一个命令对应
应的C/C++过程
程的返回值是
是一个整型值。TCL中命令
令对应
在13.2.1节中我们
过程允许的返
返回值是 TCL
L_ERROR 、 TCL_OK
K 、 TCL_B
BREAK 、TC
CL_CONTIN
NUE和
的C/C++过
TCL_RET
TURN,这些返
返回值是TCL
L为了方便实现控制流和对
对脚本文件的
的求值进行控制
制而引入的。通过
设置命令
令过程的返回值
值,我们可以
以控制TCL脚
脚本的执行过
过程,也可以实
实现自己的控
控制流。TCL
L中的
while命令
令就是这样实现
现的。
int WhileCmd(Clie
W
entData clientD
Data, Tcl_Inteerp *interp,
innt argc, char *aargv[])
{
innt bool;
2010-11--02
版权所
所有,侵权必究
究
第66页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
innt code;
iff (argc != 3)
{
interp-->result = "wroong # args";
return TCL_ERROR
R;
}
w
while
(1)
{
ult(interp);
Tcl_ResetResu
oolean(interp, argv[1], &boool)!= TCL_OK
K)
iff (Tcl_ExprBo
{
return TCL__ERROR;
}
iff (bool == 0)
{
return TCL_OK;
}
coode = Tcl_Evaal(interp, argvv[2]);
iff (code == TCL
L_CONTINU
UE)
{
continu
ue;
}
= TCL_BREA
AK)
ellse if (code ==
{
return TCL_OK;
}
ellse if (code != TCL_OK)
{
return code;
}
}
TCL扩展命令
令时,也应该注
注意设置TCL
L命令过程的
的返回值以控制
制TCL命令的
的执行
我们在自己设计T
当某一个命令
令有错时,整个
个脚本还能继
继续往下执行
行,那么我们可
可以把那个命
命令过
过程。如果我们希望当
L_OK。例如,在扩展了addd命令之后,我们可以编写如下脚本:
程的返回值总设为TCL
2010-11--02
所有,侵权必究
究
版权所
第67页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
%evaal set a 2; ad
dd a 3 ;set b 4
Expeect integer but got a
%set b
Can'tt read "b":no such
s
varible
这说明,由于在执
执行“add a 3”时出错,导致“set b 4””根本没有被执
执行。现在,我们在AddC
Cmd过
全部改为TCL__OK,再编译执
执行:
程中,所有的返回值全
dd a 3 ;set b 4
%evaal set a 2; ad
4
%set b
4
执行了。
这说明set b 4被执
TCL 解 释 器 在 执 行 脚 本 时 , 如 果 遇 到 脚 本 中 某 一 个 命 令 对 应 的 命 令 过 程 的 返 回 值 为
ROR,那么解
解释器马上退出,不再对后
后面的脚本求
求值。由此可见,利用命令
令对应的过程
程的返
TCL_ERR
回值,我
我们可以控制
制脚本的执行
行过程。根据
据实践,一般
般的原则是, 如果有语法
法错误,应该
该返回
TCL_ERR
ROR,别的情
情况下可以根据
据需要决定。
3.3 扩展自己
己的命令:方
方法(二)
从上面的介绍来看
看,TCL从外
外部应用到内部
部实现都是基
基于字符串的
的,这样在涉及
及到类型转换
换时,
及其字符串表
表示之间来回转
转换,效率比
比较低,加上
上TCL是解释执
执行的,导致
致在利
需要在各种数据类型及
用TCL作较
较为大型的应
应用程序时执
执行速度不够理
理想,所以在
在TCL8.0以后
后的版本中,T
TCL在内部实
实现中
引入了一
一个新的数据
据结构Tcl_O
Obj,代替了原来单纯的
的字符串表示
示。利用这个
个结构,可
可以一
方面保持
持TCL库函数
数的前向兼容
容,另一方面
面可以提高
高TCL解释执行的速度。
由于
于这一结构的
的引入,TCL
L也提供了另
另外一套扩
扩展TCL命令的函数,与
与13.2介绍的
的方法
稍有不同
同。
下面
面先对Tcl_Obbj结构作一介
介绍。
结构
3.33.1 Tcl_Obj结
在TC
CL中,Tcl_O
Obj结构定义
义如下:
typeddef struct Tcl_
_Obj {
int refC
Count;
char *b
bytes;
int leng
gth;
2010-11--02
版权所
所有,侵权必究
究
第68页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
Tcl_Ob
bjType *typeP
Ptr;
union {
long longVaalue;
double doubbleValue;
VOID *otheerValuePtr;
struct {
OID *ptr1;
VO
VO
OID *ptr2;
} tw
woPtrValue;
} internalReep;
} Tcll_Obj;
在TC
CL的新的实现
现中,所有的对象(变量的值
值,命令参数
数,命令结果等等)都以Tcll_Obj对象保存
存:
1.分量
量bytes和leng
gth实际代表了
了对象的字符
符串表示,byytes必须以nulll结尾。如果bytes为null,表示
对象的字符串表示无效
效。
向一个Tcl_ObbjType,其中
中记录了对象的
的内部类型的
的名称、释放对
对象的内部表
表示的
2.typePtr 分量指向
果这个分量为
为null,那么表
表示internalRepp分量无效。
函数的指针等等。如果
当typePtr 分量
量不为空时,iinternalRep用
用来保存对象的
的内部表示,这可以是一个
个整数,也可
可以是
3。当
一个双精度浮点数,或
或者一个指针
针,或者两个指
指针。
分量refCount记
记录对象被引
引用的次数, 由此决定什
什么时候可以安
安全的释放这
这个对象占用
用的空
4。分
间。对扩展TCL命令的
的用户来说,怎样维护refC
Count是很关键
键的。
表示,TCL可
可以当需要字符
符串形式时,就输出Tcl_O
Obj的字符串形
形式,需要对
对象的
采用了这种内部表
际类型的值。下面以一系列
列命令调用来
来说明TCL是怎
怎么利用Tcl__Obj结构的:
实际类型时就输出实际
set x 123
这个命令赋予变量
量x一个无类型
型的Tcl_Obj对
对象,其bytess分量包含"1223",而lengthh分量的值为33。这
有效,而typeP
Ptr分量为空,因而内部表
表示internalRepp无效。
时对象的字符串表示有
puts $x
有效的,所以
以直接取得x的
的字符串表示。
。
这时,因为x的字符串表示是有
incr x
命令对应的过
过程调用 Tcl_G
GetIntFromObbj函数从x对应
应的对象表示
示中取得一个整
整数。这个函
函数首
incr命
先检查x的
的对应的Tcl_
_Obj对象是否
否已经是一个整
整数对象。因
因为现在typeP
Ptr为空,所以
以并非一个整
整数对
象,因此
此它需要转换这
这个对象:从
从字符串表示
示中可以得到
到internalRep. longValue的 值为123,同
同时把
typePtr指向一个整数的
的Tcl_ObjTyppe结构。这时
时,两种表示方
方法都成为有
有效的了。接
接着incr命令把
把对象
2010-11--02
所有,侵权必究
究
版权所
第69页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
的internallRep. longVallue值加1,同
同时调用Tcl_InnvalidateStrinngRep来使得xx的字符串表示
示无效。因为
为此时
字符串表示还是123,而实际应该为
为124。
puts $x
这时又需要x的字
字符串表示,而
而这时字符串
串表示已经无
无效,所以需要
要转换internaalRep. longVaalue来
获取x的字
字符串表示。这个命令调用
用后,两种表
表示又都成为有
有效的了。
从上面可以看出,TCL之所以采用Tcl_Obj来表示对象,就是为了尽
尽量减少类型的
的转换次数。但这
一定的额外工
工作量。所以如果不是对速
速度有特殊的
的要求的话。我
我们扩展TCL
L命令
也给用户扩展带来了一
绍的方法,而不
不必使用下面
面介绍的方法。
完全可以使用13.2介绍
3.33.2 编写扩展
展命令对应的
的C/C++过程
程
第二种TCL扩展命
命令对应的C//C++过程的形
形式和13.2介绍的稍有不同
同。在tcl.h文
文件中的定义
义是这
样的:
typedef
int Tcll_ObjCmdProoc( ClientData clientData, Tcl_Interp
*
*interp,
i
int
objc, Tcl_Obj* const objv[]
o
);
2中介绍的完全
全一样。
前两个参数和13.2
代表Tcl_Obj对
对象的个数,因为命令的每
每个参数(包含
含命令名本身
身)都用一个对
对象表示,所以
以objc
objc代
事实上相当于Argc。
个对象数组,指向各个参数
数的对象表示
示。
第四个参数是一个
值和13.2完全一
一样。
命令过程的返回值
中给出的扩展例
例子用第二种
种形式改写一下:
下面我们把13.2中
A
ntData clientdaata,Tcl_Interp** interp,int obbjc,Tcl_Obj * const
c
objv[])
int AddCmd(Clien
{
iff(objc!=3)
{
interp-->result="Useaage Error!";
return TCL_ERROR
R;
}
innt i,j,l1,l2;
iff(TCL_OK!=T
Tcl_GetIntFrom
mObj(interp,oobjv[1],&i))
{
sprintff(interp->resullt,"Expect inteeger but got %s",Tcl_GetStr
%
ringFromObj(oobjv[1],&l1));;
return TCL_ERROR
R;
}
2010-11--02
版权所
所有,侵权必究
究
第70页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
iff(TCL_OK!=T
Tcl_GetIntFrom
mObj(interp,oobjv[2],&j))
{
sprintff(interp->resullt,"Expect inteeger but got %s",Tcl_GetStr
%
ringFromObj(oobjv[2],&l2));;
return TCL_ERROR
R;
}
=i+j;
i=
spprintf(interp->
>result,"%d",i));
reeturn TCL_OK
K;
}
除了Tcl_GetInnt换成了Tcl__GetIntFromO
Obj之外,基本
本没有多大的
的不同。
我们可以看到,除
3.33.3 注册命令
令
相应
应的,第二种
种扩展方法也
也提供了自己命令注册
册函数,它的原
原型为:
void Tcl_CreateObjCommandd ( Tcl_Interpp * interp,
Tcl_ObjCm
mdProc *
chhar * cmdNam
me,
cm
mdProc,
ClientData clientData, Tcl_CmdDelleteProc * deleeteProc)
事实
实上这和13.22中介绍的Tcll_CreateComm
mand 命令差 不多,唯一
一的区别在于
于第三个参
参数,
即命令过
过程必须是第
第二种形式的命令过程
程。
如果
果我们使用了
了第二种方法
法扩展了命令过程,那
那么必须使用
用第二种方法
法注册命令
令,否
则会导致
致错误。
除了
了13.3.2和13.33.3中讲到的
的不同外,两
两种扩展方 法没有太大
大的不同。不
不过如果我
我们在
扩展过程
程中自己构造
造了 Tcl_Objj对象的话, 一定要注 意维护其被
被引用的次数
数。另外也 要注
意,象133.3.1中的例子讲到的inccr命令过程那
那样,如果
果需要的话,必须让对象
象的内部表
表示的
一种失效
效。
3.4 利用clie
entData参数
数和deletePrroc参数
在使
使用C ++扩
扩展 TCL命令
令时,我们不
不可避免的 要用到类和
和自定义类型
型,这时有
有这种
需求:几
几个或一组命
命令需要对同一个对象
象进行操作。这时我们除
除了利用全局
局变量外,还有
其他办法
法吗?有!那
那就是利用clientData
c
参数
数。
前面的例子中,我
我们已经看到
到,每一个命令
令函数的第一
一个参数是CliientData类型,
,而用来注册
册自定
个ClientData类
类型的参数。 这个
义命令的库函数Tcl_CreateCommannd 和Tcl_CreaateObjCommaand,也有一个
2010-11--02
版权所
所有,侵权必究
究
第71页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
ClientDataa 类型参数指
指向的就是自定
定义命令所要
要处理的对象
象,而且ClienttData 被定义
义为void *类型
型,可
以指向任何类型的对象
象。如果用户想在命令中使
使用自己定义
义的数据对象,
,就可以利用
用ClientData。
Tcl_C
CreateCommaand和Tcl_CreeateObjComm
mand函数还有
有一个参数是
是(Tcl_CmdD
DeleteProc * 〕 类
型,这个参数指向一个
个回叫(callbaack)函数,当删
删除某一个命
命令或程序退
退出时,TCL会
会调用对应的
的回叫
的数据对象进
进行善后处理。Tcl_CmdDeeleteProc 的定
定义如下:
函数来对该命令处理的
ARGS_((ClienttData clientDaata))
typeddef void (Tcl_CmdDeleteProc) _ANSI_A
可以看出,Tcl_C
CmdDeleteProc * 类型是指
指向一个带有
有一个ClientDaata类型参数,无返回值的
的函数
计一个这样的
的回调函数来释
释放自定义命
命令所处理的
的数据类型的对
对象申请的存
存储空
的指针,我们可以设计
间。
下面
面将以一个简
简单的类(claass)来说明在
在扩展TCL命令时怎么使
命
使用自己定义
义的数据类型
型。
#incluude "Tcl.h"
class Sample
{
privaate:
innt x;
publiic:
Saample(){ x=0;;}
Saample(Samplee& sa){ x=sa.xx;}
vooid Set(int _x));
innt Get();
};
int Saample::Get()
{
reeturn x;
}
void Sample::Set(int _x)
{
=_x;
x=
}
int Tccl_InitApp(Tccl_Interp* inteerp);
int MyGetCmd(Cli
M
ientData clienntdata,Tcl_Inteerp* interp,int argc,char * argv[]);
a
int MySetCmd(Cli
M
entData clienttdata,Tcl_Interp* interp,int argc,char * arrgv[]);
void DeleteProc(ClientData clienntdata);
2010-11--02
所有,侵权必究
究
版权所
第72页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
void main(int argc,,char* argv[])
{
Tcl_Main(argc,argv,Tcl_InitApp);
reeturn;
}
int Tccl_InitApp(Tccl_Interp* inteerp)
{
Tcl_IInit(interp);
Sampple* pSam=neew Sample;
Tcl_C
CreateCommaand(interp, "m
myget", MyG
GetCmd,
(C
ClientData)pS
Sam,
(T
Tcl_CmdDeleeteProc*) DeleteProc);
CreateCommaand(interp,
Tcl_C
"
"myset",
M
MySetCmd,
(ClientDataa)pSam,
(T
Tcl_CmdDeletteProc* )DeletteProc);
K;
reeturn TCL_OK
}
M
ientData clienntdata,Tcl_Inteerp* interp,int argc,char * argv[])
a
int MyGetCmd(Cli
{
iff(argc!=1)
{
interp-->result="Usagge error!";
return TCL_ERROR
R;
}
=(Sample* )cllientdata;
Saample* pSam=
iff(!pSam)
{
return TCL_ERROR
R;
}
>result,"%d",ppSam->Get());
spprintf(interp->
reeturn TCL_OK
K;
}
int MySetCmd(Cli
M
entData clienttdata,Tcl_Interp* interp,int argc,char * arrgv[])
{
iff(argc!=2)
{
2010-11--02
所有,侵权必究
究
版权所
第73页,共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
interp-->result="Usagge error!";
return TCL_ERROR
R;
}
=(Sample* )cllientdata;
Saample* pSam=
iff(!pSam)
{
return TCL_ERROR
R;
}
innt i;
iff(TCL_OK!=T
Tcl_GetInt(inteerp,argv[1],&i))
{
sprintff(interp->resullt,"Expect inteeger but got %s",argv[1]);
%
return TCL_ERROR
R;
}
Sam->Set(i);
pS
spprintf(interp->
>result,"%d",i));
reeturn TCL_OK
K;
}
void DeleteProc(ClientData clienntdata)
{
innt static i=0;
iff(i!=0)
return;
deelete (char*)cllientdata;
i=
=1;
}
编译
译运行这个例
例子,交替 敲入命令 myget
m
和 myset 可以反映出
出对数据对象
象 pSam的操
操作导
致的变化
化。 函数DeeleteProc当我
我们删除mygget或myset命令时会被激
命
激活,这时与
与这两个命
命令相
关的对象
象*pSam的空
空间被释放.调试运行这个
调
个程序,在
在控制台中敲
敲入
renam
me myget {}
这个
个命令从解释
释器中删除myget
m
命令,我们会发现
现DeleteProc函数会被自动
函
动调用。敲入
入
renam
me myset {}
DeletteProc函数也
也会被自动调
调用。
2010-11--02
所有,侵权必究
究
版权所
第74页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
事实
实上这个简单
单的利用类进
进行扩展的例子揭示了
了更多的含义
义:首先,说
说明我们可
可以在
以前利用
用C++编写的
的代码的基础
础上进行TC
CL扩展,提
提高代码的可
可重用性,我
我们编写的
的代理
的TCL扩展这样作的
扩
的;另外,我
我们不但可以利用TCL对C函数作单
单元测试,也可以利用
用TCL
对类的成
成员函数作单
单元测试。
3.5 在C/C++
+应用程序中
中嵌入TCL
在 133.1 中,我们
们扩展 TCL 的方法是利用
的
用 Tcl_Main 函数直接生成
函
成一个独立
立的 TCL 交互
互式程
序。其实
实,我们还有
有更好的使用
用TCL的方法
法:在应用程序中嵌入
入TCL。
前面
面已经说过,TCL在某种
种意义上可以
以被认为是一
一个C函数/过程库。这
这决定了TCL
L可以
和C/C++应用程序无
应
无缝集成-----我们可以轻
我
轻易的把TCL嵌入到我们
们的一个C/C+++应用程序
序中,
这也是TCL
T 被广泛应
应用的一个重
重要原因。TCL的可嵌
嵌入性使得我
我们可以为每
每一个应用程序
提供一个
个支持变量、
、过程、控制
制流等编程
程要素并包括
括扩展命令和
和固有命令在
在内的功能
能完备
的TCL扩展语言。
扩
下面
面介绍在一个
个C/C++程序
序中嵌入TCL的方法.
假设
设我们已经用
用VC6生成了
了一个应用程
程序,并且加
加入一个菜单
单项TCL,OnT
Tcl是菜单项
项TCL
的消息响
响应函数:
void CMyExView:::OnTcl()
{
Tcl_Interp* interp=Tcl_CreaateInterp();
iff(Tcl_InitApp((interp))
{
AfxMeessageBox("TCL initialize Error!");
E
return;
}
C
CFileDialog
dlg
g(TRUE,NUL
LL,NULL,OFN
N_HIDEREADONLY|OFN
N_FILEMUST
TEXIST,
"Tcl Files(**.tcl)|*.tcl|All Files(*.*)|*.*|
F
|");
DoModal())
iff(IDOK!=dlg.D
{
return;
}
C
CString
strFileP
Path=dlg.GetP
PathName();
2010-11--02
版权所
所有,侵权必究
究
第75页,共
共76页
TCL培训教程
程(全)
绝密
请输入文档
档编号
//eevaluate the TCL
T
descriptioon file
iff(TCL_OK!=T
Tcl_EvalFile(interp,(char*)((const char*)sttrFilePath))
{
AfxMeessageBox("There are errorss in your Tcl File");
F
Tcl_DeeleteInterp(intterp);
return;
}
Tcl_DeleteInterrp(interp);
}
我们
们可以把前面
面的扩展命令 add 的实现
现部分集成到这个程序
序中,那么我
我们可以编 写一
个这样的
的脚本:
seet a 2
seet b 3
addd $a $b
存成
成一个文件。点击菜单 项TCL,就可以打开这
这个个编辑好
好的TCL文件
件并执行。遗憾
的是我们
们不能看到执
执行结果。不过我们可
可以通过单步
步调试来跟
跟踪命令的执
执行过程.在实际
在
应用中,如果想看到
到命令执行结果,可以
以在我们的扩
扩展命令过程
程中加入对命
命令执行结
结果输
出到某一
一个窗口的语
语句。
4 总结
这篇文章是《TCL
L的使用》和《TCL培训教
教程》的补充和修订,并加
加入了很多新
新内容。其中第
第9、
10、11、12章是新加
加的内容,新加
加的各个章节
节是北研测试部
部TCL兴趣小
小组各个成员共
共同努力的结
结果:
章
完成,第10章杜祥宇完成,
章
,第11章由邓
邓沈鸿完成,最后由我对各
各个章节进行
行了整
第9、12章由付剑仲完
理和修改,统一组稿。
了TCL的各个
个方面,特别对
对使用C\C++
+语言扩展TC
CL命令作了详
详尽的描述, 这是
本文基本上介绍了
找到的内容。参照本文的例子,用户完
完全可以写出
出自己的TCL扩展命令。希
扩
希望这
所有的参考书上难以找
试部使用TCL起一些推动作
起
作用。
篇文章能对推广在测试
本上来说还是
是要上机实习
习,希望测试
试部所有员工
工大家都能安
安装上
学习 一门计算机 语言,从根本
TCL,加以
以实习,在应
应用的基础上
上才能进一步提
提高。如果需
需要一些本文
文中没有的内容
容,可以查阅
阅TCL
自带的帮助。
2010-11--02
版权所
所有,侵权必究
究
第76页,共
共76页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
目 录
1初始化函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2解释器的生成和删除及TCL脚本的求值函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
3命令生成和删除函数及结果处理函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4分析函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
5总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
6访问TCL变量的函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
7Hash表操作函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
8字符串操作函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
9TCL库函数的最新情况 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
第 1 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
TCL库函数介绍(一)
关键词:TCL
摘
要:本文旨在推广TCL的使用,通过分类介绍TCL的库函数的用法,让用户了解怎样利用这些
库函数去编写TCL扩展命令。
为了让用户能方便地扩展TCL命令,TCL为用户提供了大量的库函数供用户使用,满足用户各
方面的需要。用户可以在用C\C++语言编写扩展的TCL命令过程或函数时,调用这些库函数。要真
正理解这些库函数的用法,最佳途径是参照一些例子,并实际使用。在我的一篇文档《TCL的使用
》中有一些这些函数的使用的例子。下面分类对TCL的库函数进行介绍。
1 初始化函数
这组函数用于用户初始化应用。
1.Tcl_Init函数
原型: int Tcl_Init (Tcl_Interp *interp)
参数interp是一个指向TCL解释器的指针。Tcl_Init函数只作一些简单的初始化工作,没多大的
用处。不过,用户一般需要提供自己的初始化函数,原型与Tcl_Init一样,在这个函数中,要作应
用的初始化工作,如注册自己的TCL扩展命令,生成自己需要的数据对象等。这个函数必须在生成
TCL解释器后才能调用。生成TCL解释器可以调用Tcl_CreateInterp函数,另外Tcl_Main函数中也会
自动生成TCL解释器。
2.Tcl_Main函数
原型:void Tcl_Main (int argc, char **argv,Tcl_AppInitProc *appInitProc)
如果用到这个函数的话,应该在你的C\C++程序的main函数中调用,它的前两个参数和main函
数的两个参数一样,第三个参数是一个函数指针,指向一个初始化函数,其原型和Tcl_Init一样。
如果程序没有任何命令行参数,Tcl_Main调用appInitProc初始化函数,并启动一个TCL的命令解释
循环,建立一个交互环境,等待你输入TCL命令和脚本并解释执行。如果程序有命令行参数,那它
先调用appInitProc函数作一些初始化工作,然后把第一个命令行参数作为TCL脚本文件名,并求值
返回,其余参数不予理会。
2 解释器的生成和删除及TCL脚本的求值函数
这组函数提供生成和删除TCL解释器及对TCL脚本进行求值的功能。每一个TCL应用,都必须
拥有至少一个TCL解释器,事实上几乎所有的TCL库函数都有一个指向TCL解释器的指针的参数。
每一个扩展的TCL命令都和特定的TCL解释器相关联,只有在对该命令进行了注册的TCL解释器
中,这个命令才是有效的,才能被解释执行。
1.Tcl_CreateInterp函数
原型:Tcl_Interp *Tcl_CreateInterp(void)
第 2 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
这个函数生成一个新的TCL解释器,并返回指向这个解释器的指针。
2.Tcl_DeleteInterp函数
原型:void Tcl_DeleteInterp(Tcl_Interp *interp)
这个函数删除一个TCL解释器,并会触发用户定义的回调函数,作一些善后工作。
3. Tcl_Eval函数
原型: int Tcl_Eval(Tcl_Interp *interp char *script)
这 个 函 数 在 解 释 器 interp 中 求 脚 本 script 的 值 并 返 回 执 行 情 况 。 结 果 和 错 误 信 息 保 存 在
interp->result中。函数返回值表示执行情况,为以下五个值之一:
TCL_OK :表示执行成功
TCL_ERROR:表示执行过程中遇到了不可克服的错误
TCL_BREAK:表示break命令被激活
TCL_CONTINUE :表示conitinue命令被激活
TCL_RETURN: 表示return 命令被激活
事实上所有int型的TCL库函数都以上述值为返回值,TCL_OK和TCL_ERROR最常用,后面三
个只是当用户需要实现自己的控制流才会用到。下面介绍的库函数就不再介绍返回值。
4. Tcl_EvalFile 函数
原型:int Tcl_EvalFile(Tcl_Interp *interp, char *fileName)
这个函数在解释器interp中求脚本文件fileName的值并返回执行情况。结果和错误信息保存在
interp->result中。
5. Tcl_GlobalEval函数
原型:int Tcl_GlobalEval(Tcl_Interp *interp, char *script)
这个函数在解释器interp中在全局层次上求脚本script的值并返回执行情况。结果和错误信息保
存在interp->result中。
6. Tcl_VarEval函数
原型:int Tcl_VarEval(Tcl_Interp *interp, char *string, char *string,... (char *) NULL)
这个函数具有可变个数参数,必须以NULL作为最后一个参数,标记参数结束,它把所有的字
符串参 数合并成一 个,在解释 器interp中 求它 的值 并返回 执行情 况。结 果和错误信 息保存在
interp->result中。
3 命令生成和删除函数及结果处理函数
这组函数用于生成和注册用户自己定义的TCL扩展命令及管理TCL命令的结果。用户只有自己
用C\C++语言编写了定义TCL命令的函数或过程,并注册,才能被解释器所识别和使用。这里还应
该区分两个概念:TCL命令结果和定义命令的C\C++函数或过程的返回值。命令结果是执行TCL命
令后,TCL解释器返回的命令执行结果,形式为字符串;而定义命令的C\C++函数或过程的返回值
第 3 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
指的是我们编写的用来定义TCL命令的C\C++函数或过程的返回值,这些返回值已经在Tcl_Eval函
数的说明中介绍了。TCL命令的结果需要我们在定义TCL命令的C\C++函数或过程中给出,如果我
们希望TCL命令执行后返回某个值,只要把这个值以字符串形式存入interp->result中,TCL解释器
就会在执行这个命令后返回这个字符串形式的值。
1. Tcl_CreateCommand函数
原型:void Tcl_CreateCommand(Tcl_Interp * interp, char * cmdName,Tcl_CmdProc *
cmdProc,
ClientData clientData,Tcl_CmdDeleteProc * deleteProc)
这个函数在解释器interp中生成一个命令,并把它注册到这个解释器。这样这个命令在这个解
释器中就可以和TCL固有命令一样使用。函数的第一个参数指向TCL解释器,第二个参数是一个字
符串,代表命令名,第三个参数是一个函数指针,指向你用C\C++写的定义该命令的函数或过程,
第四个参数指向你希望传给你的函数或过程的数据对象,第四个参数也是一个函数指针,指向一
个回调函数,当你删除这个命令时,解释器会自动激活这个过程。tcl.h中对Tcl_CmdProc的定义如
下:
typedef int Tcl_CmdProc(ClientData clientData,
Tcl_Interp *interp, int argc,char *argv[]);
其中:typedef
void * ClientData;
每一个用C\C++写的定义命令的函数或过程必须为上面的形式:第一个参数实际上是一个
void指针,可以指向任何数据类型,这里指向用户需要传给那些函数或过程的数据对象,第二个参
数指向解释器,第三个参数代表这个命令的参数个数(包括命令名本身),第四个参数是一个字符串
数组,其中保存各个参数的字符串形式的值。返回值为整数,只能为 TCL_OK、TCL_ERROR 、
TCL_BREAK、TCL_CONTINUE 、TCL_RETURN其中之一,这在上面已经介绍过。
2. Tcl_DeleteCommand函数
原型: int Tcl_DeleteCommand(Tcl_Interp *interp, char *cmdName)
这个函数从解释器中删除一个命令,同时激活该命令对应的回调函数。
我们在利用C\C++编写TCL扩展命令过程时,一般可以通过把interp->result指向一个字符串或
使用 sprintf 函数来设置命令的执行结果。但是interp->result的缺省大小只有200字节,如果命令结
果太长就会出错。因此TCL提供了以下库函数来供用户管理命令结果:
3. Tcl_SetResult 函数
原型:Tcl_SetResult(Tcl_Interp *interp, char *string,Tcl_FreeProc* freeProc)
这个函数的第一个参数是一个TCL解释器,第二个参数是一个将作为命令结果的字符串,第三
个参数是一个函数指针,定义如下:
typedef void (Tcl_FreeProc)(char *blockPtr)
第三个参数的值可以为:
TCL_STATIC :这表示string是静态的,Tcl_SetResult只简单的把它的指针存入interp->result
TCL_VOLATITLE:表示string会改变,Tcl_SetResult会把它复制到interp->result,如果
string太长,会重新分配内存。
第 4 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
TCL_DYNAMIC:表示string是用malloc分配的内存,并成为TCL的一个属性:Tcl_SetResult
将把interp->freeproc设置 free 以释放内存。
一个Tcl_FreeProc类型的函数:表示string是动态分配的, TCL最终会调用这个函数来释
放内存。
4. Tcl_AppendResult 函数
原型:Tcl_AppendResult(Tcl_Interp *interp, char *string,char *string, ... (char *) NULL)
这个函数是具有可变个数参数的函数,必须以NULL作为最后一个参数,标记参数结束,它把
所有的string参数按顺序添加到interp->result中。
5. Tcl_AppendElement 函数
原型:Tcl_AppendElement(Tcl_Interp *interp, char *string)
使 用 这 个 函 数 时 , 命 令 结 果 应 是 一 个 链 表 , 它 把 string 参 数 作 为 链 表 的 一 个 元 素 添 加 到
interp->result中。这个函数当需要生成一个链表时很有用。
6. Tcl_ResetResult 函数
原型:Tcl_ResetResult(Tcl_Interp *interp)
这个函数把interp->result清空。
4 分析函数
这组函数用于对命令的参数进行分析,是最常用到的库函数。前面已经介绍过,每一个定义
TCL命令的C\C++函数或过程都有参数argc和argv,TCL解释器在解释执行TCL命令时,会把命令的
参数个数和参数的字符串形式传给定义这个命令的C\C++函数的argc和argv参数,并执行这些函数
或过程。因为所有参数以字符串形式传递,所以我们需要对它们进行分析,从而会用到以下函
数:
1.Tcl_GetInt函数
原型:int Tcl_GetInt(Tcl_Interp *interp, char *string, int *intPtr)
这个函数把string作为一个整数分析,值存在*intPtr中。成功返回TCL_OK ,失败返回
TCL_ERROR,并把错误信息存在interp->result中。
2. Tcl_GetDouble函数
原型:int Tcl_GetDouble(Tcl_Interp *interp, char *string, double *doublePtr)
这个函数把string作为一个浮点数分析,值存在*doublePtr中。成功返回TCL_OK ,失败返回
TCL_ERROR,并把错误信息存在interp->result中。
3. Tcl_GetBoolean函数
原型:int Tcl_GetBoolean(Tcl_Interp *interp, char *string, int *intPtr)
第 5 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
这个函数把string作为一个BOOL值分析,并把0\1存在*intPtr中。成功返回TCL_OK ,失败返
回TCL_ERROR,并把错误信息存在interp->result中。
4. Tcl_ExprString函数
原型:int Tcl_ExprString(Tcl_Interp *interp, char *string)
这 个 函 数 把 string 作 为 一 个 表 达 式 求 值 , 成 功 返 回 TCL_OK 并 把 值 作 为 一 个 字 符 串 存 入
interp->result,失败返回TCL_ERROR,并把错误信息存在interp->result中
5. Tcl_ExprLong函数
原型:int Tcl_ExprLong(Tcl_Interp *interp, char *string, long *longPtr)
这个函数同Tcl_ExprString,只是把结果作为一个长整型存入*longPtr,当值不能转换成一个整
数时,发生错误。
6. Tcl_ExprDouble函数
原型:int Tcl_ExprDouble(Tcl_Interp *interp, char *string,double *doublePtr)
这个函数同Tcl_ExprString,只是把结果作为一个浮点数存入*doublePtr,当值不能转换成一个
浮点数 时,发生错误。
7. Tcl_ExprBoolean函数
原型:int Tcl_ExprBoolean(Tcl_Interp *interp, char *string, int * intPtr)
这个函数同Tcl_ExprString,只是把结果作为0\1存入*intPtr,当值不能转换成一个BOOL值 时
, 发生错误。
8. Tcl_SplitList函数
原型:int Tcl_SplitList(Tcl_Interp *interp, char *list, int *argcPtr,char ***argvPtr)
这个函数把list作为一个链表进行分析,并生成一个字符串数组,数组的元素是链表的元素。
成 功 返 回 TCL_OK , 链 表 元 素 的 个 数 存 入 *argcPtr , 并 把 argvPtr 指 向 生 成 的 数 组 。 失 败 返 回
TCL_ERROR,并把错误信息存在interp->result中。字符串数组的空间是动态分配的,必须由调用
者释放。
9. Tcl_Merge函数
原型:char *Tcl_Merge(int argc, char **argv)
这个函数是Tcl_SplitList的逆过程,返回指向生成的TCL链表的指针。链表的储存空间是动态
分配的,调用者需要释放为链表分配的空间。
5 总结
第 6 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
这篇文章介绍了TCL库中的常用到的几类函数,并结合自己的实际使用经验作了较为详细的
说明,相信会给用户使用C\C++编写自己的TCL扩展命令带来一定的帮助。以后将陆续介绍所有的
TCL库函数,以推动TCL的应用。
TCL库函数介绍(二)
关键词:TCL
摘
要: 本文承接TCL库函数介绍(一) ,旨在推广TCL的使用,通过分类介绍TCL的库函数的用
法,让用户了解怎样利用这些库函数去编写TCL扩展命令。
6 访问TCL变量的函数
这组函数提供了在C代码中生成、修改、读取和删除TCL变量的手段。而且还提供了监视和限
制变量访问的机制。这组函数是使用很频繁的一组函数。
1. Tcl_SetVar函数
原型:char *Tcl_SetVar (Tcl_Interp *interp, char *varName, char *newValue, int flags)
这个函数把名为变量varName的变量的值设置为newValue,如果这个变量还不存在就声明这个
变量。这个函数对变量操作的运行时刻上下文是这样的:如果这个操作发生在一个过程的运行
中,那么这个操作针对的是这个过程的局部变量;否则这个操作针对的是一个全局变量。如果这
个操作成功完成,函数返回指向这个变量的新值的指针。如果发生了错误,那么返回NULL。
函数最后一个参数flags的取值可以为以下几个值中的一个或几个,中间以位操作符|连接:
TCL_GLOBAL_ONLY:表示这个操作总是针对全局变量varName的。
TCL_LEAVE_ERR_MSG:表示如果操作失败,错误信息保存在interp->result中。
TCL_APPEND_VALUE:表示把newValue的值附加到以前的值后面,不覆盖原来的值。
TCL_LIST_ELEMENT:表示在设置或附加newValue的值之前,把它转换为链表的元素。
注意:如果varName是带括号的形式,如:a(b),那么这个函数将设置或生成一个数组元素,括
号前的a将作为一个数组名,而括号中的b将作为数组元素的索引值。
2. Tcl_SetVar2函数
原型:char *Tcl_SetVar2(Tcl_Interp *interp, char *name1,char *name2 , char *newValue, int flags)
这个函数功能与Tcl_SetVar函数类似。如果name2为NULL,那么它和Tcl_SetVar函数的功能完
全一样。如果name2不为空,那么name1不能是带括号的形式(如: a(b)〕,这时name1作为数组
名,而name2作为数组元素的索引。其余情况完全同Tcl_SetVar函数,事实上Tcl_SetVar函数的实现
中只是简单的调用了Tcl_SetVar2函数。
3. Tcl_GetVar函数
原型: char *Tcl_GetVar(Tcl_Interp *interp, char *varName,int flags)
这个函数用来获取变量varName的值,用法可以完全参考Tcl_SetVar,不过flags只支持
TCL_GLOBAL_ONLY和TCL_LEAVE_ERR_MSG,这应该是很自然的事情。
4. Tcl_GetVar2 函数
原型: char *Tcl_GetVar2(Tcl_Interp *interp , char *name1 , char *name2 , int flags)
第 7 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
这个函数的用法与Tcl_GetVar的区别同Tcl_SetVar和Tcl_SetVar2的区别。
5. Tcl_UnsetVar函数
原型:int Tcl_UnsetVar (Tcl_Interp *interp , char *varName , int flags)
这个函数从TCL解释器interp中删除变量varName,如果操作成功,返回TCL_OK,如果因为变
量varName不存在或其他原因不能删除,那么返回TCL_ERROR。如果varName是一个数组名,没
有 给 出 索 引 , 那 么 整 个 数 组 都 被 删 除 。 flags 只 支 持 TCL_GLOBAL_ONLY 和
TCL_LEAVE_ERR_MSG。
6. Tcl_UnsetVar2函数
原型:int Tcl_UnsetVar2 (Tcl_Interp *interp , char *name1 , char* name2, int flags)
这个函数的用法与Tcl_UnsetVar的区别同Tcl_SetVar和Tcl_SetVar2的区别。
7. Tcl_TraceVar函数
原型: int Tcl_TraceVar(Tcl_Interp *interp, char *varName, int flags,
Tcl_VarTraceProc *proc, ClientData clientData)
这个函数用于对变量进行跟踪,当读、写或删除一个变量时就会自动激活一个C过程。跟踪可
以用于很多目的:如debug、生成只读变量等。 varName是要跟踪的变量名,flags可以是以下几个
值 中 的 一 个 或 几 个 , 中 间 用 位 操 作 符 | 连 接 : TCL_TRACE_READS 、 TCL_TRACE_WRITES 、
TCL_TRACE_UNSETS和TCL_GLOBAL_ONLY,其含义一目了然。 clientData是回调函数proc中会用
到的数据对象。
proc是当用户对varName作flags中指定的操作时,被激活的回调函数,其原型必须和以下定义
匹配:
typedef char *Tcl_VarTraceProc(ClientData clientData , Tcl_Interp *interp , char *name1 ,
char *name2 , int flags);
其中clientData、interp两个参数就指向Tcl_TraceVar中对应的参数,name1和name2两个参数给
出要被跟踪的变量名,其含义同Tcl_SetVar2中的name1和name2。
对于读操作,回调函数在Tcl_GetVar和Tcl_GetVar2 返回之前被激活,如果在回调函数中改变
了变量的值,那么这个被修改了的值将被返回。对于写操作,回调函数当变量的值被修改后被激
活,回调函数可以修改变量的值,并且这个值将作为Tcl_SetVar和Tcl_SetVar2 的结果。对于删除
操作,回调函数在变量被删除之后被激活,所以在回调函数中不能访问这个变量。
在变量跟踪的回调函数中可以调用Tcl_GetVar2 和Tcl_SetVar2 函数来读写被跟踪的变量,在回
调函数中所有对变量的跟踪都被临时关掉了,所以对Tcl_GetVar2 和Tcl_SetVar2的调用不会激活回
调函。回调函数成功返回NULL,失败返回包含错误信息的串。
8. Tcl_TraceVar2 函数
原型: int Tcl_TraceVar2 (Tcl_Interp *interp, char * name1,char* name2, int flags,
Tcl_VarTraceProc *proc, ClientData clientData)
这个函数的用法与Tcl_TraceVar的区别同Tcl_SetVar和Tcl_SetVar2 的区别。
9. Tcl_UntraceVar函数
原型:Tcl_UntraceVar (Tcl_Interp *interp, char *varName,int flags,
Tcl_VarTraceProc *proc, ClientData clientData)
第 8 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
这个函数把对一个变量的跟踪取消。各个参数的含义同Tcl_TraceVar。
10. Tcl_UntraceVar2 函数
原型:Tcl_UntraceVar2 (Tcl_Interp *interp, char *name1,char *name2,int flags,
Tcl_VarTraceProc *proc, ClientData clientData)
这个函数的用法与Tcl_UntraceVar的区别同Tcl_SetVar和Tcl_SetVar2 的区别。
11. Tcl_VarTraceInfo 函数
原型: ClientData Tcl_VarTraceInfo (Tcl_Interp *interp, char *varName,
int flags, Tcl_VarTraceProc *proc, ClientData prevClientData)
这个函数用于获取变量varName的跟踪信息。注意,flags的值只有TCL_GLOBAL_ONLY有
效。如果prevClientData是NULL,那么函数返回最近一次变量的跟踪消息,没有跟踪消息就返回
NULL 。 如 果 prevClientData 非 空 , 那 么 必 须 是 上 一 次 Tcl_VarTraceInfo 的 返 回 值 , 利 用
Tcl_VarTraceInfo,我们可以递归得到变量的所有跟踪信息。
12. Tcl_VarTraceInfo2 函数
原型: ClientData Tcl_VarTraceInfo2 (Tcl_Interp *interp, char *name1,char* name2,
int flags, Tcl_VarTraceProc *proc, ClientData prevClientData)
这个函数的用法类似于Tcl_VarTraceInfo,区别同Tcl_SetVar和Tcl_SetVar2 的区别。
7 Hash表操作函数
Hash表是由一个个入口(entry)组成的,每个入口包含一个关键码(key)和一个值值(value),在一
个Hash表中关键码是唯一的,任意两个入口都必须有不同的关键码。通过关键码,Hash表可以快
速找到它对应的入口和与之关联的值。Hash表对需要维护大量的数据并希望快速定位数据的应用
程序是必不可少的。TCL通过一些库函数为用户提供了操作Hash表的能力。
1. Tcl_InitHashTable函数
原型:void Tcl_InitHashTable(Tcl_HashTable *tablePtr, int keyType)
这个函数生成一个新的Hash表,并且把表的信息存储在*tablePtr中,keyType表示关键码
的类型,其取值可以为以下几个:
TCL_STRING_KEYS:表示关键码是字符串。
TCL_ONE_WORD_KEYS:表示关键码是一个single-world大小的值,如整数。
其他:关键码的最后一种形式是整数数组,这时keyType指明整数数组中整数的个数,注意
这时数组的大小必须一样。
2. Tcl_DeleteHashTable函数
原型:void Tcl_DeleteHashTable(Tcl_HashTable *tablePtr)
这个函数删除Hash表上的所有入口(entry),并释放相关的内存空间。
3. Tcl_CreateHashEntry函数
原型:void Tcl_HashEntry *Tcl_CreateHashEntry(Tcl_HashTable *tablePtr,
char *key,int *newPtr)
这个函数生成Hash 表tablePtr的 一个关键码为 key 的新入口,如果新入口成功生成,那么
newPtr被设置为1,否则设置为0。
第 9 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
4. Tcl_FindHashEntry函数
原型:Tcl_HashEntry * Tcl_FindHashEntry(Tcl_HashTable *tablePtr, char *key)
这个函数在Hash表tablePtr中寻找关键码为key的入口,找到返回指向入口的指针,否则返回
NULL。
5. Tcl_DeleteHashEntry函数
原型:Tcl_DeleteHashEntry(Tcl_HashEntry *entryPtr)
这个函数把入口entryPtr从它所在的Hash表中删除。
6. Tcl_GetHashValue函数
原型:ClientData Tcl_GetHashValue(Tcl_HashEntry *entryPtr)
这个函数从入口entryPtr中得到对应的值。
7. Tcl_SetHashValue函数
原型:voidTcl_SetHashValue (Tcl_HashEntry *entryPtr, ClientData value)
这个函数把value中的值设置到入口entryPtr中。
8. Tcl_GetHashKey函数
原型:char *Tcl_GetHashKey(Tcl_HashEntry *entryPtr)
这个函数从入口entryPtr中获取关键码,返回关键码的字符串形式。
9. Tcl_FirstHashEntry函数
原型:Tcl_HashEntry *Tcl_FirstHashEntry(Tcl_HashTable *tablePtr,Tcl_HashSearch *searchPtr)
这个函数开始搜索整个tablePtr指向的Hash表的元素,把搜索信息存放在searchPtr中,并返回
Hash表的第一个入口,如果Hash表为空返回NULL。
10. Tcl_NextHashEntry函数
原型:Tcl_HashEntry *Tcl_NextHashEntry(Tcl_HashSearch *searchPtr)
这个函数返回searchPtr中的下一个入口,如果所有入口都已返回就返回NULL。这个函数和
Tcl_FirstHashEntry函数配合可以遍历整个Hash表的入口。
11. Tcl_HashStats函数
原型: char *Tcl_HashStats(Tcl_HashTable *tablePtr)
这个函数用于获取Hash表tablePtr中入口的分布情况,分布情况以字符串形式返回。
8 字符串操作函数
TCL提供的这组字符串操作函数,可以实现动态字符串,字符串匹配和判断一个命令是否完
整。
1. void Tcl_DStringInit函数
原型:Tcl_DStringInit(Tcl_DString *dsPtr)
这个函数把dsPtr清空。 Tcl_DString是TCL定义的一个结构,用来表示一个动态字符串。
2. void Tcl_DStringAppend函数
原型:char *Tcl_DStringAppend(Tcl_DString *dsPtr, char *string, int length)
这个函数把字符串string中的length个字符附加到dsPtr之后,并返回dsPtr的新值。如果length小
于0,那么把string(包含NULL〕全附加到dsPtr之后。
第 10 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
3. void Tcl_DStringAppendElement函数
原型: char *Tcl_DStringAppendElement(Tcl_DString *dsPtr, char *string)
这个函数把string转换成一个list成员并附加到dsPtr中(如果需要会加上一个分隔符〕。返回值
为dsPtr的新值。
4. voidTcl_DStringFree函数
原型:Tcl_DStringFree(Tcl_DString *dsPtr)
这个函数释放dsPtr中分配的所有内存,并把dsPtr置为空。
5. void Tcl_DStringResult函数
原型: Tcl_DStringResult(Tcl_Interp *interp, Tcl_DString *dsPtr)
这个函数把dsPtr的值传给interp->result,并重新初始化dsPtr,把它置为空。
6. Tcl_CommandComplete函数
原型:int Tcl_CommandComplete(char *cmd)
这个函数用于检查命令cmd是否完整,它会自动检查命令的参数个数及括号配对的情况,命令
完整返回1,否则返回0。
7。 int Tcl_StringMatch(char *string, char *pattern)
如果字符串string匹配模式pattern,返回1,否则返回0。
9 TCL库函数的最新情况
以上介绍的都是TCL7.6版本的库函数。在这些函数的内部实现中,所有的变量及其值都是以
字符串形式来访问的,而使用字符串形式必然会涉及到频繁的字符串的比较和转换,降低TCL的解
释执行速度。在TCL8.1以上版本,对函数的内部实现作了一些改进,以一个新的结构Tcl_Obj来代
替了单纯的字符串表示。利用这个结构,可以一方面保持TCL库函数的前向兼容,另一方面可以提
高TCL解释执行的速度。下面对Tcl_Obj结构作一介绍。
在TCL中,Tcl_Obj结构定义如下:
typedef struct Tcl_Obj {
int refCount;
char *bytes;
int length;
Tcl_ObjType *typePtr;
union {
long longValue;
double doubleValue;
VOID *otherValuePtr;
struct {
VOID *ptr1;
VOID *ptr2;
} twoPtrValue;
} internalRep;
第 11 页,共 12 页
TCL库函数介绍
----------------------------------------------------------------------------------------------------------------------------------------------------
} Tcl_Obj;
仔细研究这个结构,你会发现实际上这个结构中对一个对象用了两种表示方法:
1.字符串形式的表示:这由bytes和length两个分量来表示。字符串形式也是对象的外在表示形
式,因为在TCL语言级,一切都看作字符串。但bytes为空是表示字符串表示形式无效。
2.对象的实际的类型: typePtr 结构表示对象的实际类型,联合类型internalRep用来存储对象的
值。当typePtr为空时,表示这种表示方法无效。
采用了这种内部表示,TCL可以当需要字符串形式时,就输出Tcl_Obj的字符串形式,需要对
象的实际类型时就输出实际类型的值。其实现原理是:两种表示方法互相关联,每次修改了两种
表示中的一种,并不立即修改另一种表示,而是把另外一种表示标记为无效。只有当需要另一种
表示,才从改变了的那种表示转换得到所需要的表示。TCL试图利用这种方法来减少在运行时的转
换工作,提高执行效率。但是这也给用户在使用上带来了不便,用户需要自己控制两种方式的有
效无效状态,当然这只是对扩展TCL命令的语言的用户而言。
虽 然 TCL 的 8.1 以 上 版 本 作 了 扩 展 , 但 使 用 以 前 的 函 数 并 不 受 任 何 影 响 。 对 于 如 何 使 用
Tcl_Obj结构及与之相关的库函数来扩展TCL命令,将在参考了相关资料及充分实践的基础上作详
细的介绍。
第 12 页,共 12 页
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )