5

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

编辑:

如果在解释器中调用了除 f1、f2 和 f3 之外的命令,我创建了一条错误消息,并执行源自解释器的代码(假设在获得带有 f1、f2 和 f3 procs 的代码)应该停止。

4

2 回答 2

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
于 2012-05-08T16:59:44.207 回答
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 包

尽管存在这些缺点,但该解决方案实施起来非常简单。

于 2012-05-08T20:09:24.000 回答