【问题标题】:tcl/Tk 'invalid command name ""' when being controlled via a pipetcl/Tk 'invalid command name ""' 当通过管道控制时
【发布时间】:2015-01-02 01:47:00
【问题描述】:

我试图为 C 程序模拟一个简单的 GUI,方法是分叉 C 程序并在子程序中执行 wish,然后将一堆 tcl/tk 命令从父程序传递到它。创建表单后,我会让 C 程序继续读取 tcl 程序的输出并响应它。

我大部分时间都在工作,但在这个例子中,我不断收到来自 tcl 的消息:

invalid command name ""

它没有破坏任何东西,但我真的不明白是什么原因造成的。

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define DIE do { perror(__FUNCTION__); exit(EXIT_FAILURE); } while (0)
#define LEN(a) (sizeof(a) / sizeof(*a))

int child(int p2c[2], int c2p[2]) {
    if (close(p2c[1])) DIE;
    if (close(c2p[0])) DIE;

    if (dup2(p2c[0], fileno(stdin)) < 0) DIE;
    if (dup2(c2p[1], fileno(stdout)) < 0) DIE;

    char * cmds[] = { "wish", NULL };
    execvp(cmds[0], cmds);
    DIE;
}

int parent(int p2c[2], int c2p[2]) {
    if (close(p2c[0])) DIE;
    if (close(c2p[1])) DIE;

    char init[] = "button .b -text {Print} -command {puts hi}\n"
                  "button .x -text {Exit} -command {exit}\n"
                  "grid .b -column 0 -row 0\n"
                  "grid .x -column 0 -row 1\n";
    if (write(p2c[1], init, LEN(init)) < LEN(init)) DIE;
    if (close(p2c[1])) DIE;

    char buf[1<<10];
    ssize_t s;

    while ((s = read(c2p[0], buf, LEN(buf))) > 0) {
        buf[s-1] = '\0';

        printf("i read '%s'\n", buf);
    }

    return 0;
}

int main(int argc, char ** argv) {
    int p2c[2]; // parent to child pipe
    int c2p[2];

    if (pipe(p2c)) DIE;
    if (pipe(c2p)) DIE;

    switch (fork()) {
        case -1: DIE;              break;
        case  0: child(p2c, c2p);  break;
        default: parent(p2c, c2p); break;
    }

    return EXIT_SUCCESS;
}

知道为什么它声称空字符串是无效命令吗?

【问题讨论】:

    标签: c tcl tk


    【解决方案1】:

    问题是您确定字符串长度的表达式是错误的。 strlen(init) 将产生一个比 LEN(init) 返回的值小一的值,因为后者在计数中包含 终止 NUL 字符。这意味着你将 NUL 写在管道上(它不属于它的地方),Tcl 将它解释为一个奇怪的(但合法的!)命令名。当然,没有这样的命令(除非你使用proc \u0000 {} {puts BOOM}),但它仍然会检查它在脚本自动加载机制中知道的任何内容是否可以提供该命令。 (将这个小程序添加到您发送过来的脚本中——记住将\ 加倍——会改为写出这条消息:

    我读到'BOOM '

    QED。

    如果您更改 write 以实际发送正确的字节数,那么一切都会按您的预期进行。

    【讨论】:

    • 啊!是的,我故意用 '\0' 替换 TCL 发回的换行符,但我完全忘记在我发送的内容中删除空字节。多么愚蠢的错误。谢谢!
    • @scott_fakename 我们在 Tcl 的实现中使用类似的宏来有效地处理字符串文字,但我们还有一个额外的-1。出于显而易见的原因…… ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多