我试图为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;
}
知道为什么它声称空字符串是无效命令吗?
答案 0 :(得分:3)
问题是你确定字符串长度的表达式是错误的。 strlen(init)
会生成比LEN(init)
返回的值少一个的值,因为后者在计数中包含 终止NUL字符 。这意味着您将NUL写在管道上(它不属于它),并且Tcl将其解释为一个奇怪的(但合法!)命令名称。当然没有这样的命令(除非你做proc \u0000 {} {puts BOOM}
)但它仍然会检查它在脚本自动加载机制中是否有任何知识可以提供该命令。 (将这个小程序添加到您发送的脚本中 - 记住将\
翻倍 - 将此消息写出来:
i read 'BOOM '
QED。
如果您将write
更改为实际发送正确的字节数,则一切都按预期工作。