创建一个TCL解释器,它只支持我提供的命令

时间:2012-05-08 15:25:15

标签: tcl interpreter sandbox

说我已经定义了proc f1 proc f2和proc f3。现在我想创建一个TCL解释器,将proc f1 proc f2和proc f3的代码输入到该解释器中,并限制除f1,f2和f3之外的所有命令都在该解释器中。我怎么能这样做?

编辑:

如果在解释器中调用了f1,f2和f3以外的命令,我已经创建了一个错误消息并且应该在解释器中执行代码(假设这个另一个代码来自同一个解释器,在使用f1,f2和f3 procs)获取代码之后应该停止。

2 个答案:

答案 0 :(得分:9)

你不能完全这样做,但你可以做一些与大多数目的相似的事情。

你应该做的是通常在解释器中创建命令f1,f2和f3,然后创建一个根本没有Tcl命令的子解释器,并为你想要在该子解释器中公开的命令添加别名到父母的命令。

# First define f1-f3 in whatever way you want

# Now make the context; we'll use a safe interpreter for good measure...
set slave [interp create -safe]

# Scrub namespaces, then global vars, then commands
foreach ns [$slave eval namespace children ::] {
    $slave eval namespace delete $ns
}
foreach v [$slave eval info vars] {
    $slave eval unset $v
}
foreach cmd [$slave eval info commands] {
    # Note: we're hiding, not completely removing
    $slave hide $cmd
}

# Make the aliases for the things we want
foreach cmd {f1 f2 f3} {
    $slave alias $cmd $cmd
}

# And evaluate the untrusted script in it
catch {$slave invokehidden source $theScript}

# Finally, kill the untrusted interpreter
interp delete $slave

答案 1 :(得分:2)

这是一个简单的解决方案:逐行读取输入。如果第一个标记是f1,f2或f3,则执行命令,按 Control + C 或键入exit退出循环:

proc f1 {args} { puts "f1:$args" }
proc f2 {args} { puts "f2:$args" }
proc f3 {args} { puts "f3:$args" }

while 1 {
    puts -nonewline ">"
    flush stdout
    gets stdin line
    set firstToken [lindex $line 0]
    if {[lsearch {f1 f2 f3 exit} $firstToken] != -1} {
        eval $line
    }
}

此解决方案存在一些问题:

  1. Eval被认为是危险的
  2. 编辑功能不多,您可能想要使用tclreadline包
  3. 尽管存在这些缺点,但解决方案实施起来非常简单。