c程序中的非规范终端模式缓冲区stdout

Non canonical terminal mode buffer stdout in c program

我正在做一个学校项目(构建一个非常基础的 shell)。

我们的想法是能够像 bash 那样进行行版。为此,我将终端模式更改为非规范模式并停止回显。

我编写了一个非常简单的代码来暴露我的问题(请注意,我会检查函数 returns 等等......我只是为了这个 post 让它尽可能短)

#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
    int     ret;
    char    buff;
    char    *term_name;
    char    *termcap;
    struct termios  termios_new;
    struct termios  termios_backup;

    /*
    ** Init termcap library
    */
    term_name = getenv("TERM");
    tgetent(NULL, term_name);

    /*
    ** Get the terminal mode to non canonical and shut down echo
    */
    bzero(&termios_new, sizeof(struct termios));
    tcgetattr(STDIN_FILENO, &termios_backup);
    termios_new = termios_backup;

    termios_new.c_lflag &= ~(ICANON);
    termios_new.c_lflag &= ~(ECHO);
    termios_new.c_cc[VMIN] = 1;
    termios_new.c_cc[VTIME] = 0;

    /*
    **  Set the change
    */
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios_new);

    /*
    ** Get the termcap for clearing screen on the particular terminal
    */
    termcap = tgetstr("cl", NULL);

    /*
    ** Loop read to get user entries and clear screen for 'c', output char for 'b', break for 'q'
    */
    while((ret = read(STDIN_FILENO, &buff, 1)) > 0)
    {
        if (buff == 'c')
            tputs(termcap, 1, putchar);
        else if (buff == 'b')
            putchar(buff);
        else if (buff == 'q')
            break ;
        buff = 0;
    }

    /*
    ** Put back the terminal mode as found before
    */
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios_backup);
    return (0);
}

所以基本上它是一个读取循环以捕获用户条目。它清除 'c' 的屏幕,'b' 的输出字符,中断并恢复 'q'.

的原始终端模式

问题是:

每当我键入任何内容时,它似乎都被缓冲了,因为在我用 'q' 打破循环之前什么都没有发生。 此时,输出显示在屏幕上,如果我键入 5 次 b,我将得到 5 个 b,如果我键入 'c',屏幕将被清除。 但是,只有在输入 'q' 之后。 无论是否恢复原始终端模式,行为都是相同的。 (return之前的最后一行)

我怀疑的是:

在使代码非常短并检查所有 returns 之后,我倾向于认为只能是我更改终端模式的方式有问题? 我尝试为 tcsetattr 函数使用标志 TCSAFLUSHTCSADRAIN,结果相同。

谢谢! :)

✅ 已解决:

好吧,对于遇到这种情况的任何人来说,这很有趣,因为它让我学到了很多东西(好吧,这是一个学校项目,所以...)。

tputs 参数中使用 putchar 是问题所在,因为 putchar 是缓冲的,就像 printf 一样。 我最终尝试了两件事,让我意识到:fflush()tputs 函数调用起作用之后,显然问题与缓冲区相关。 然后尝试输出到 STDERR_FILENO,它也有点解决了,事实上 stderr 是唯一的 _IONBF,所以没有缓冲。

所以我最终创建了一个只有 write 的 putchar 函数,仅此而已。

以下是有关三种缓冲模式的更多信息: