简体   繁体   English

c程序中的非规范终端模式缓冲区标准输出

[英]Non canonical terminal mode buffer stdout in c program

I am working a school project (building a very basic shell).我正在做一个学校项目(构建一个非常基本的外壳)。

The idea is to be able to do line edition like in bash.这个想法是能够像在 bash 中那样进行行编辑。 For this, I change the terminal mode to non canonical and I stop echo.为此,我将终端模式更改为非规范并停止回声。

I made a very simple code to expose my issue (please note, I do check for functions returns etc... I just made it as short as possible for this 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);
}

So basically it's a loop on read to catch user entries.所以基本上它是一个循环读取来捕获用户条目。 It clears the screen for 'c', output char for 'b', break and restore the original terminal mode for 'q'.它为“c”清除屏幕,为“b”输出字符,为“q”中断并恢复原始终端模式。

Issue is :问题是:

Whenever I type anything, it seems to be buffered because nothing happens until I break the loop with 'q'.每当我输入任何东西时,它似乎都被缓冲了,因为在我用 'q' 中断循环之前什么都不会发生。 At this moment, the output show on screen, if I typed 5 times b, I'll get the 5 b's and if I types 'c', the screen will be cleared.此时,输出显示在屏幕上,如果我输入 5 次 b,我将得到 5 个 b,如果我输入“c”,屏幕将被清除。 BUT, only after typing 'q'.但是,只有在输入“q”之后。 The behaviour is the same while restoring or not the original terminal mode.恢复或不恢复原始终端模式时的行为是相同的。 (the last line before return ) return前的最后一行)

What I suspect :我怀疑的是:

After making the code very short and checking all returns, I tend to think there could only be an issue with the way I change the terminal mode ?在使代码非常短并检查所有返回之后,我倾向于认为只有我更改终端模式的方式有问题? I tries with the flags TCSAFLUSH and TCSADRAIN for the tcsetattr function with same result.我为tcsetattr函数尝试使用标志TCSAFLUSHTCSADRAIN ,结果相同。

Thanks !谢谢 ! :) :)

✅ SOLVED : ✅ 解决了:

Ok so for anyone who encounter this situation, it's quite interesting because it made me learn many stuffs (well it's a school project so...).好吧,对于遇到这种情况的人来说,这很有趣,因为它让我学到了很多东西(嗯,这是一个学校项目,所以......)。

Using putchar in the tputs parameters was the issue, because putchar is buffered, juste like printf.tputs参数中使用putchar是问题所在,因为 putchar 是缓冲的,就像 printf 一样。 I ended up trying two things that led me to the realisation: fflush() after the tputs function call would work so obviously the issue was buffer related.我最终尝试了两件让我意识到的事情:在tputs函数调用之后的fflush()会起作用,所以显然问题与缓冲区有关。 Then tried to output to STDERR_FILENO and it kinda solved it too, and in fact the stderr is the only one _IONBF , so not buffered.然后尝试输出到 STDERR_FILENO 并且它也解决了它,实际上 stderr 是唯一的_IONBF ,因此没有缓冲。

So I ended up creating a putchar function with only write in it, and that was it.所以我最终创建了一个只有write的 putchar 函数,就是这样。

Here are more info about the three buffer modes:以下是有关三种缓冲模式的更多信息:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM