[英]Can the equivalent of Tcl "chan push" be implemented in C code?
我有一个嵌入式 Tcl 解释器,并希望将其 stderr 和 stdout 重定向到应用程序中的控制台小部件。
对 stderr 使用 chan push 命令似乎有效(尚未进行太多测试),如下所述:
我可以有一个包含所需 tcl 命名空间定义等的文件,并在使用 Tcl_CreateInterp 创建一个 interp 之后执行一个 Tcl_Eval 来获取该脚本。
我可以使用 Tcl C 库调用而不是通过 Tcl_Eval 运行 Tcl 命令来做同样的事情吗?
不是我的问题的真正答案,但也许它会帮助某人通过使用 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 是 output 的发起者。
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%s\n", rtn,
}
将 TCL_ERROR 上的 tclsh 通常打印到标准错误的内容放入控制台(而不是应用程序的标准错误)。
我计划在 C 中执行等效操作,以消除在解释器中运行 Tcl 代码以进行重定向的需要。 但是,真的没有这个必要。
执行重定向的 Tcl_Eval 在执行 Tcl_CreateInterp 之后立即执行。 使用该 interp 的任何后续 Tcl_Evals 都会将 stdout 和 stderr 重定向到我的应用程序的控制台。
此外,我无法理解如何使用 Tcl_StackChannel 并且找不到可以遵循的示例。
老实说,不能说我完全理解 Tcl 的实现。 我根据引用的线程对传递给“chan push”命令中使用的 proc 的内容做了一些假设。
看起来 proc 是使用 chan push 命令中指定的列表和一个 args 列表调用的。 args 列表的第一个元素是一个名称,如“write”或“initialize”。 第三个元素看起来像要打印的字符串。
仍在尝试找到所传递内容的定义,而不必深入研究命名空间集合之类的东西。
因此,这个 Tcl 代码很可能不是最好的实现,但它目前正在工作(测试有限)。
要在 C 中实现通道转换,首先必须定义一个Tcl_ChannelType
结构。 这样的结构指定了转换的名称和指向可以在通道上完成的不同操作的函数的指针。 接下来,您实现执行这些操作的函数。 最重要的是inputProc
和outputProc
。 您还必须实现一个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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.