Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non-blocking stdio

I'm working on a program which will be taking in user input from the console as well as printfing out in a separate thread. I want to avoid situations where the user is halfway through typing something in and a printf comes along and prints itself at the cursor.

Is there a way to do non-blocking io in c from the console window? Ideally, capturing keypresses or something like that such that what the user types doesn't appear on the screen. I'm developing in Ubuntu, and it's best if I don't have to use things like ncurses.

like image 638
Smashery Avatar asked Sep 18 '25 03:09

Smashery


2 Answers

using termios you can disable terminal echoing:

#include <termios.h>

struct termios oflags, nflags;
tcgetattr(fileno(stdin), &oflags);
nflags = oflags;
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;

if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
    /* handle error */
}

then before exit (use atexit) you must restore the terminal:

if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) {
    /* handle error */
}
like image 192
dfa Avatar answered Sep 20 '25 17:09

dfa


Here's an example of how to turn off echo from C, taken directly from an HP forum (and I haven't personally tested it):

Okay this should be a simple example of turning off echo:

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

#define STDIN_FDES 0

struct termios save;

int main(int argc, char *argv[])
{
int cc = 0;
char s_tmp[80],*p = NULL;
struct termios work;

cc = tcgetattr(STDIN_FDES,&save);
work = save;
work.c_lflag &= ~(ECHO);
cc = tcsetattr(STDIN_FDES,TCSANOW,&work);
(void) printf("\nEnter value: ");
(void) fflush(stdout);
p = fgets(s_tmp,sizeof(s_tmp),stdin);
if (p != NULL) (void) printf("Out -> %s\n",p);
cc = tcsetattr(STDIN_FDES,TCSANOW,&save);
return(cc);
}

NOTE: It is very important that you have signal handlers to catch SIGINT, SIGTERM, ... and reset the terminal using the original termios because the last tcsetattr() wins and this applies to the terminal device NOT simply the process. If you leave the process with echo off, it will be off in the shell as well.

Otherwise, if Bash is a suitable approach, apparently you can just do stty -echo.

like image 30
Mark Rushakoff Avatar answered Sep 20 '25 17:09

Mark Rushakoff