为什么这段代码应该从stdin读取为空?

mer*_*ito 2 c io macos terminal

代码来自Kilo项目:

/*
 * Use write() and terminal escape (ESC) sequence
 * to query cursor position.
 */

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

#define ESC 27

int main(int argc, char const *argv[]) {
    char buf[32];
    unsigned int i = 0;
    int rows, cols;

    write(STDOUT_FILENO, "\033[6n", 4);

    while (i < sizeof(buf)-1) {
        if (read(STDIN_FILENO,buf+i,1) != 1) break;
        if (buf[i] == 'R') break;
        i++;
    }
    buf[i] = '\0';

    /* Parse it. */
    if (buf[0] != ESC || buf[1] != '[') return -1;
    if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
    printf("%d %d\n", rows, cols);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

OS X terminal.app的结果是:

?  /Users/name/Desktop/demo ./write
^[[44;1R
44 1
?  /Users/name/Desktop/demo 
?  /Users/name/Desktop/demo 
Run Code Online (Sandbox Code Playgroud)

结果有5行,但我无法理解这些行为:

  1. 为什么在第2行输出这些字符?因为write()函数已经写了一些字符STDOUT?如果是,我该如何抑制此输出?

  2. 为什么read()函数可以从中读取内容STDIN?我认为STDIN现在应该是空的,因为我没有按任何键.

  3. 在第2行之后,它将阻止.我为什么要按ENTER

  4. 为什么第4行是空的?因为ENTER我刚刚按下了吗?

在OS X 10.11.6 Terminal.app中运行

chq*_*lie 5

转义序列\e[6n用于向终端查询光标位置.终端通过输入字符来回答,好像它们是由用户键入的一样.答案格式是\e[y;xR其中y的行数和x列数,两者1为主.这里\e[44;1R是终端在线模式下回显的,就像任何其他用户输入一样.请注意,转义字节的回显为^[.您可以使用退格键编辑此输出.尝试通过更改列号来修改列号,^[[44;11R并在按ENTER时查看效果.

程序尝试读取此输入但由于终端处于线路模式,您需要输入ENTER键以输入整行输入以供系统使用.

请注意,程序通过单个read()系统调用逐字节地从系统读取此输入.它在获取时停止读取R,因此换行保留在系统缓冲区中.

程序sscanf()解析\e[44;1,打印44 1(第44行,第1列)并退出.

shell回显命令提示符,读取待处理的换行符并回显另一个命令提示符.

我不知道如何抑制line2输出.我怀疑重定向stdout会有所作为.

使用stty()系统调用将终端设置为原始模式之前write()应该阻止此输出以及需要输入ENTER键.如果您更改终端模式,即线路规则,请记住保存当前设置并在退出程序之前恢复它们.