Skip to content
Advertisement

Closing then opening standard input in C under Linux

I have a C console application under Linux (Raspbian – Raspberry Pi). The program has some character animation – it prints out messages character by character. For example, the text

Please give me your name!

is printed out completely after 5 seconds (char by char).

Afterwards, the user is asked to type in their name, which works just fine if the user waits for the message to be printed out. However, if the user is impatient and hits the keys on the keyboard randomly, the input request later is compromised.

Imagine the user types in

abcnefghn

while the above text is being echoed (‘n’ means new line – enter). If that happens, the user will not be asked to properly type in his/her name, but the array of characters ‘abc’ will be accepted as input and gets validated.

My question is how to disable input (buffering) temorarily (on Linux). I have tried several methods and read numerous posts about doing so, but none of them worked for my purpose.

The function that is responsible for asking for input is as follows:

int getLine(char *s, int length)
{
    int i;
    char c;

    for (i = 0; i < length && (c = getchar()) != EOF && c != 'n'; i++)
    {
        if (c == '')
        {
            i--;
        }
        else
        {
            s[i] = c;
        }
    }

    s[i] = '';

    while (c != EOF && c != 'n')
    {
        c = getchar();
    }

    return i;
}

Empty lines are eliminated with the help of a while loop in the function calling the one above so enter inputs are considered invalid.

I tried closing stdin, but could not reopen it:

fclose(stdin);

and emptying buffer before the getLine:

char buf[BUFSIZ];
while (c = fgets(buf, BUFSIZ, stdin) != NULL);

Unfortunately, it did not work as it does with text files.

fflush(stdin); did not work either and is not pretty anyway.

My goal is to prevent users from typing in anything while the text is being written out and to ignore/close input buffering (stdin) temporarily. Also, it would be great to disable outputting (flushing) user inputs during printing as it gets displayed on Linux terminal.

Advertisement

Answer

You may do this by interacting with TTY directly. Look into source code of passwd or similar utilities for inspiration.

Function below clears TTY input buffer (error handling omitted). You need to call it just before reading user input.

#include <sys/ioctl.h>
#include <termios.h>

void clear_user_input() {
  if (isatty(STDIN_FILENO)) {
    int fd = open(ttyname(STDIN_FILENO), O_RDONLY);
    ioctl(fd, TCFLSH, TCIFLUSH);
    close(fd);
  }
}
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement