等效的Tcl "chan push"可以用C代码实现吗?



我有一个嵌入式Tcl解释器,希望将其stderr和stdout重定向到应用程序中的控制台小部件。

对stderr使用chan-push命令似乎有效(还没有进行太多测试(,如下所述:

TCL:将proc的输出重定向到文件

我可以有一个具有所需tcl命名空间定义等的文件,并在使用tcl_CreateInterp创建interp后执行tcl_Eval来获取该脚本。

我可以使用Tcl C库调用而不是通过Tcl_Eval运行Tcl命令来做同样的事情吗?

要在C中实现通道转换,首先必须定义一个Tcl_ChannelType结构。这样的结构指定了转换的名称,以及指向可以在通道上进行的不同操作的函数的指针。接下来,您将实现执行这些操作的函数。其中最重要的是inputProcoutputProc。您还必须实现watchProc。如果不需要的话,其他操作的指针可以设置为NULL

例如,它可能看起来像:

static const Tcl_ChannelType colorChannelType = {
"color",
TCL_CHANNEL_VERSION_5,
NULL,
ColorTransformInput,
ColorTransformOutput,
NULL,                       /* seekProc */
NULL,                       /* setOptionProc */
NULL,                       /* getOptionProc */
ColorTransformWatch,
NULL,                       /* getHandleProc */
NULL,                       /* close2Proc */
NULL,                       /* blockModeProc */
NULL,                       /* flushProc */
NULL,                       /* handlerProc */
NULL,                       /* wideSeekProc */
NULL,
NULL
};

然后,当你想把转换推到一个通道上时:

chan = Tcl_StackChannel(interp, &colorChannelType, clientData,
Tcl_GetChannelMode(channel), channel);

有关Tcl源代码的完整示例,请参阅tclZlib.c

这并不是我的问题的答案,但也许它会帮助人们通过使用Tcl_Eval来显示执行重定向的Tcl代码来了解什么是有效的。

proc redir_stdout {whichChan args} {
switch -- [lindex $args 0] {
initialize {
return {initialize write finalize}
}
write {
::HT_puts $whichChan [lindex $args 2]
}
finalize {
}
}
}
chan push stderr [list redir_stdout 1]
chan push stdout [list redir_stdout 2]

两个chan-push命令使用相同的proc,但传递不同的标识符(1或2(来指示stdout还是stderr是输出的发起者。

HT_puts是由C代码提供的扩展:

Tcl_CreateObjCommand(interp,"HT_puts",putsCmd,(ClientData) NULL,NULL);

int TclInterp::putsCmd(ClientData ,Tcl_Interp *,int objcnt,Tcl_Obj * CONST *objv)
{
if (objcnt != 3)
return TCL_ERROR;
int length;
int whichChan;
Tcl_GetIntFromObj(interp,objv[1],&whichChan);
//qDebug() << "Channel is $whichChan";
QString out =Tcl_GetStringFromObj(objv[2],&length);
QColor textColor;
if (whichChan==1)
textColor = QColor(Qt::red);
else
textColor = QColor(Qt::white);
console->putData(out.toUtf8(),textColor);
//qDebug() << out;
return TCL_OK;
}

从stderr转发的文本变为红色,而从stdout转发的文本则变为白色。

而且,正如我上面提到的,通过Tcl_Eval执行的每个后续命令都需要对Tcl_Eval返回值进行如下处理:

if (rtn != TCL_OK)
{
QString output = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
console->putData(output.toUtf8(),QColor(Qt::red));
//qDebug("Failed Tcl_Eval: %d n%sn", rtn,
}

将TCL_ERROR上的tclsh通常打印到stderr的内容输入控制台(而不是应用程序的stderr(。

我计划在C中做类似的操作,以消除在重定向的解释器中运行Tcl代码的需要。但是,真的没有必要。

执行重定向的Tcl_Eval是在执行Tcl_CreateInterp之后立即执行的。任何使用该interp的后续Tcl_Eval都会将stdout和stderr重定向到我的应用程序控制台。

此外,我很难理解如何使用Tcl_StackChannel,也找不到可以效仿的例子。

老实说,我不能说我完全理解Tcl的实现。我对传递给";chan-push";命令。

看起来proc是用chan-push命令中指定的列表和args列表调用的。args列表的第一个元素是类似于";写";或";初始化";。第三个元素看起来像要打印的字符串。

仍在努力寻找传递内容的定义,而不必深入研究命名空间集成之类的东西。

因此,这个Tcl代码可能不是最好的实现,但到目前为止它是有效的(测试有限(。

最新更新