这是该工具的前端dc
;这个想法是键入一个中缀表达式 (2 + 3),将其映射到相应的后缀符号 (2 3 +) 并将其发送到dc
. 它是做什么的bc
。
我正在使用管道执行此操作,但前端挂起等待输出。
这是代码;我将在下面继续评论它。我的“h”命令dc
未实现,因此我正在寻找作为dc
.
TL; DR:该过程挂起,因为stdout
indc
没有刷新或者这就是我认为已经找到的。无论如何,我如何阅读它或在每次写入后强制刷新?
我发现的内容在下面评论。
#define DC_EOF_RCV "dc: 'h' (0150) unimplemented"
#define DC_EOF_SND "h\n"
static FILE *sndfp, *rcvfp;
int dcinvoke() {
int pfdout[2], pfdin[2];
pid_t pid;
pipe(pfdout);
pipe(pfdin);
switch (pid = fork()) {
case -1: exit(1);
case 0:
dup2(pfdout[0], STDIN_FILENO);
dup2(pfdin[1], STDOUT_FILENO);
close(pfdout[0]);
close(pfdout[1]);
close(pfdin[0]);
close(pfdin[1]);
execlp("dc", "dc", "-", NULL);
}
close(pfdout[0]);
close(pfdin[1]);
sndfp = fdopen(pfdout[1], "w");
rcvfp = fdopen(pfdin[0], "r");
return 1;
}
void dcsnd(const char *s) {
fputs(s, sndfp);
fflush(sndfp);
}
void dcrcv(char *buf, size_t max) {
fgets(buf, max, rcvfp); // <<<<< HANGS HERE
}
int turnaround() {
dcsnd(DC_EOF_SND); fflush(sndfp);
}
int rcvall() {
char buf[256];
turnaround();
for (;;) {
dcrcv(buf, sizeof(buf));
if (! strcmp(buf, DC_EOF_RCV)) {
break;
}
printf("%s", buf);
}
return 1;
}
int prompt(const char *msg, char *res, size_t resmax, int *eofp) {
char *p;
printf("\n%s ", msg);
if (!fgets(res, resmax, stdin)) {
*eofp = 1;
} else {
if (p = strrchr(res, '\n')) {
*p = 0;
}
*eofp = 0;
}
return 1;
}
int main() {
char buf[128], line[128];
int eof;
dcinvoke();
dcsnd("2 3 +\n");
dcsnd(DC_EOF_SND);
rcvall();
for (;;) {
prompt("Expression", buf, sizeof(buf), &eof);
if (eof) {
break;
}
snprintf(line, sizeof(line), "%s\n", buf);
dcsnd(line);
rcvall();
}
dcsnd("q\n");
return 0;
}
为了简单起见,我删除了错误检查。
前端挂在行:
fgets(buf, max, rcvfp);
因为我真的不知道如何找到问题,所以我写了自己的dc
,它什么都不做,只是正确响应“h”命令并将它得到的所有内容输出到文件中(所以我可以调试它;我不知道其他方法)。如果有用,我可以在这里添加。
我发现对fflush(stdout)
in (my)的调用会dc
恢复前端,因为对fgets
finally 的调用会返回。
我无法改变dc
自己。怎么能不挂fgets
?
我的一些想法:
使用另一个线程刷新
rcvfp
(stdout
ofdc
)使用伪终端编写它
我正在寻找建议或一种简单的方法来避免它们。
我尝试过了: