How to make stdin file descriptor ready when pressing a key? - c

I have a custom _kbhit() function used for non-blocking character input.
_kbhit() function uses select() to check if stdin is ready to read.
But finally I have stdin ready if only I pressed RETURN.
How to make it work when I press any key?
void set_conio_terminal_mode()
{
struct termios new_termios;
/* take two copies - one for now, one for later */
tcgetattr(0, &new_termios);
/* register cleanup handler, and set the new terminal mode */
atexit(reset_terminal_mode);
cfmakeraw(&new_termios);
tcsetattr(0, TCSANOW, &new_termios);
}
int _kbhit()
{
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
return select(1, &fds, NULL, NULL, &tv);
}
static char _getch(void) {
int r;
unsigned char c;
if ((r = read(0, &c, sizeof(c))) < 0) {
return r;
} else {
return c;
}
}
int main( int argc, char *argv[] )
{
set_conio_terminal_mode();
while (1) {
if (_kbhit()) {
inputbuffer[inputlen] = _getch();
if (inputbuffer[inputlen] >= 0x20 && inputbuffer[inputlen] < 0x7F) {
putchar(inputbuffer[inputlen]);
inputlen++;
}
}
}
}
I expected that this code will output echo, but it outputs entire string just after I press RETURN.

I think the problem is that - despite your initialization of the terminal attributes using cfmakeraw() - stdout is still in line-buffered mode.
Try setting standard output to unbuffered mode.
setbuf(stdout, NULL);
which is equivalent to
setvbuf(stdout, NULL, _IONBF, 0);
This avoids the need to call fflush(stdout); after every putchar(inputbuffer[inputlen]);.
There may be a way of accomplishing this using tcsetattr() instead of setvbuf(), buf I am not familiar with it.

Related

Linux timeout for read() on named pipe

Suppose I create a named pipe on a Linux system:
$ mkfifo my_pipe
The next thing I want to do is write a little monitor program which tries to read() from my_pipe, but times out after a while. In the following pseudo-code, I have used a fictional function wait_for_avail(fd, timeout_ms):
int fd = open("my_pipe", O_RDONLY);
while (1) {
//Fictional wait_for_avail(fd, timeout_ms). Is there a real function
//that has this behaviour?
int rc = wait_for_avail(fd, 500);
if (rc == 1) {
char buf[64];
read(fd, buf, 64);
//do something with buf
} else {
fprintf(stderr, "Timed out while reading from my_pipe\n");
//do something else in the program
}
}
I thought poll with the POLLIN flag might work, but it does not. From my simple trials, I have found that it simply waits until another process has opened the named pipe for writing (but not for data to be available, i.e. read() would not block). By the way, for some reason, poll ignores your timeout and just seems to block forever until another process opens the pipe.
The only other solution I can think of is to open() the file with O_NONBLOCK, and sort of manually watch the time going by as I constantly try read()ing with a count of 0 bytes.
Is there a better solution out there?
EDIT: The process I have here blocks on opening the named pipe. However, if you use the O_NONBLOCK flag, the file opens right away. At that point, poll() can be used to wait (with an optional timeout) for the other end of the pipe to be opened for writing.
However, this still does have the behaviour of implementing a timeout for the read() function. It still appears to block as soon as you call read() (even if the pipe was opened with O_NONBLOCK)
Your idea about opening the fifo in non-blocking mode is correct. If you do that, poll()/select()/etc. can be used to wait for the other end to be opened, or timeout first.
The following example program just runs in an infinite loop waiting for other programs to write to my_pipe and echos the written text, with the occasional status update when there's no data or writer:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
while (1) {
int fd = open("my_pipe", O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror("open");
return EXIT_FAILURE;
}
struct pollfd waiter = {.fd = fd, .events = POLLIN};
while (1) {
// 10 second timeout
switch (poll(&waiter, 1, 10 * 1000)) {
case 0:
puts("The fifo timed out.");
break;
case 1:
if (waiter.revents & POLLIN) {
char buffer[BUFSIZ];
ssize_t len = read(fd, buffer, sizeof buffer - 1);
if (len < 0) {
perror("read");
return EXIT_FAILURE;
}
buffer[len] = '\0';
printf("Read: %s\n", buffer);
} else if (waiter.revents & POLLERR) {
puts("Got a POLLERR");
return EXIT_FAILURE;
} else if (waiter.revents & POLLHUP) {
// Writer closed its end
goto closed;
}
break;
default:
perror("poll");
return EXIT_FAILURE;
}
}
closed:
if (close(fd) < 0) {
perror("close");
return EXIT_FAILURE;
}
}
}
After a lot of help and patience from #Shawn, I managed to come up with an answer I found satisfying. Here are the contents of a file called pipe_watcher.c:
#include <stdio.h> //printf etc.
#include <errno.h> //errno
#include <string.h> //perror
#include <signal.h> //SIGALRM, sigaction, sigset
#include <time.h> //timer_create, timer_settime
#include <fcntl.h> //open, O_RDONLY
#include <unistd.h> //close
/* This code demonstrates how you can monitor a named pipe with timeouts on the
* read() system call.
*
* Compile with:
*
* gcc -o pipe_watcher pipe_watcher.c -lrt
*
* And run with:
*
* ./pipe_watcher PIPE_FILENAME
*/
//Just needed a dummy handler
void sigalrm_handler(int s) {
return;
}
int main(int argc, char **argv) {
//Check input argument count
if (argc != 2) {
puts("Usage:\n");
puts("\t./pipe_watcher PIPE_FILENAME");
return -1;
}
//Create a timer object
timer_t clk;
int rc = timer_create(CLOCK_REALTIME, NULL, &clk);
if (rc < 0) {
perror("Could not create CLOCK_REALTIME timer");
return -1;
}
//Create some time values for use with timer_settime
struct itimerspec half_second = {
.it_interval = {.tv_sec = 0, .tv_nsec = 0},
.it_value = {.tv_sec = 0, .tv_nsec = 500000000}
};
struct itimerspec stop_timer = {
.it_interval = {.tv_sec = 0, .tv_nsec = 0},
.it_value = {.tv_sec = 0, .tv_nsec = 0}
};
//Set up SIGALRM handler
struct sigaction sigalrm_act = {
.sa_handler = sigalrm_handler,
.sa_flags = 0
};
sigemptyset(&sigalrm_act.sa_mask);
rc = sigaction(SIGALRM, &sigalrm_act, NULL);
if (rc < 0) {
perror("Could not register signal handler");
timer_delete(clk);
return -1;
}
//We deliberately omit O_NONBLOCK, since we want blocking behaviour on
//read(), and we're willing to tolerate dealing with the blocking open()
int fd = open(argv[1], O_RDONLY);
if (fd < 0) {
char msg[80];
sprintf(msg, "Could not open [%s]", argv[1]);
perror(msg);
timer_delete(clk);
return -1;
}
puts("File opened");
while (1) {
//Buffer to read() into
char buf[80];
int len;
//Set up a timer to interrupt the read() call after 0.5 seconds
timer_settime(clk, 0, &half_second, NULL);
//Issue read() system call
len = read(fd, buf, 80);
//Check for errors. The else-if checks for EOF
if (len < 0) {
if (errno == EINTR) {
//This means we got interrupted by the timer; we can keep going
fprintf(stderr, "Timeout, trying again\n");
continue;
} else {
//Something really bad happened. Time to quit.
perror("read() failed");
//No point waiting for the timer anymore
timer_settime(clk, 0, &stop_timer, NULL);
break;
}
} else if (len == 0) {
puts("Reached end of file");
break;
}
//No error or EOF; stop the timer and print the results
timer_settime(clk, 0, &stop_timer, NULL);
write(STDOUT_FILENO, buf, len);
}
//Cleanup after ourselves
timer_delete(clk);
close(fd);
return 0;
}
The technique is to set up a timer before a (blocking) read() call. Then, we can simply check the return value of read() to see if it was interrupted due to a timeout, if a general error occurred, if EOF was reached, or if it successfully read data.
There's only one snag: you can't open the file in non-blocking mode; this causes open() to block until another process opens the pipe for writing. However, in my application this is actually a desirable feature. You could also set up SIGALRM to enforce a timeout on the open(), or maybe do it in another thread.
In fact, this technique should work with any other system call, so I might put together a little helper library to make this pattern easier to use.
EDIT
One more thing: it is very important to not use the SA_RESTART flag when registering the signal handler. Otherwise, even if a system call is interrupted by a signal, Linux will try it again after the signal is handled.

Display something every x seconds with different output

I want to output the ASCII Code of the last key I pressed, every x second.
As example:
If i press a(97), the terminal should show the 97 every x second. When I now press the w(119), the program now should print the 119 instead of the 97.
So far my program just prints the first key I've pressed.
Here are the main and the other method:
int main(int argc, char const *argv[]){
printf("Hello World!");
while(1){
movePlayer();
fflush(stdout);
sleep(1);
}
return 0;
}
void movePlayer(){
system("/bin/stty raw");
int input = getchar(); //support_readkey(1000);
//fprintf(stdout, "\033[2J");
//fprintf(stdout, "\033[1;1H");
printf("\b%d",input);
system("/bin/stty cooked");
}
EDIT:
With a little bit of testing i've now a method which solves my problem
int read_the_key(int timeout_ms) {
struct timeval tv = { 0L, timeout_ms * 1000L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
int r = select(1, &fds, NULL, NULL, &tv);
if (!r) return 0;
return getchar();
}
getchar() waits for only one character, so this:
while(1){
movePlayer(); // getchar() and printf() here
fflush(stdout);
sleep(1);
}
causes this behavior. You read one character, you print it in movePlayer(). Then you flush the output buffer and go to sleep. Then you just repeat, which means that you have to input again.
Store the input and print it again, if you wish. However, your function will always wait for new input to arrive.
Here is an attempt with read() as suggested, but it will have similar behavior to your code as it is now:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int old_c = -1;
char c[1] = {0};
void movePlayer();
int main(int argc, char const *argv[]){
while(1) {
movePlayer();
fflush(stdout);
sleep(1);
}
return 0;
}
void movePlayer(){
system("/bin/stty raw");
if(read(STDIN_FILENO, c, sizeof(c)) > 0)
old_c = (int)c[0];
if(old_c == -1)
old_c = (int)c[0];
printf("\b%d", old_c);
system("/bin/stty cooked");
}
Please read read() from stdin to go on. You can tell read() for how many characters to wait and then return, but how will you know if the user intends to input a new character to command read() to wait for user's input?
As a result, I would say that you can not do what you wish, at least as far as I can tell, with a simple approach. You could have your program feed the stale input to stdin, so that your program has the impression it reads user's input. However, in case the user actually inputs fresh input, your program should handle that case carefully.
You can setup SIGALARM handler, setup alarm after x seconds and display what getchar returns in handler

C termios and printf issue

I'm using Lubuntu with LXterminal.
I have (somewhat) unashamedly copied the basis for this code from a stack overflow answer that gives details on c non-blocking keyboard input.
This is the first part:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <termios.h>
using namespace std;
struct termios orig_termios;
void reset_terminal_mode()
{
tcsetattr(0, TCSANOW, &orig_termios);
}
void set_conio_terminal_mode()
{
struct termios new_termios;
/* take two copies - one for now, one for later */
tcgetattr(0, &orig_termios);
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
/* register cleanup handler, and set the new terminal mode */
atexit(reset_terminal_mode);
cfmakeraw(&new_termios);
tcsetattr(0, TCSANOW, &new_termios);
}
int kbhit()
{
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
return select(1, &fds, NULL, NULL, &tv);
}
int getch()
{
int r;
unsigned char c;
if ((r = read(0, &c, sizeof(c))) < 0) {
return r;
} else {
return c;
}
}
Here is one main function that shows some strange behavior.
int main(int argc, char *argv[])
{
unsigned int stor;
set_conio_terminal_mode();
for(int i = 0; i < 6; i++){
while (!kbhit()) {} /* wait */
stor = getch(); /* consume the character */
reset_terminal_mode();
printf("\033[38;33m%i \033[38;0m", stor);
set_conio_terminal_mode();
}
printf("more text\n");
}
What this main loop does is it gets 6 character blocks (ex. ENTER 6 times or arrow key twice.) However, where it says printf there is no printout until the program finishes.
This can be seen better when you add
while(1){}
to the end of the main function.
So what's going on here? Is there some sort of magic that happens at the end of the program that releases all of the printf functions?
How do I make it printf when the program is still running?
Apparently, you are victim of excessive buffering.
Try to disable buffering using setvbuf.
To completely disable buffering on stdout:
setvbuf(stdout, (char *)NULL, _IONBF, 0);
To enable buffering for each line:
setvbuf(stdout, (char *)NULL, _IOLBF, 0);
// or
setlinebuf(stdout);

breaking loop with keypress in linux c

I need to write a program in C language which will be doing something like this:
For example, when I will press "a", terminal will be writing that typed character in the unending loop like this: aaaaaaaaaaaaaaaa...until another key, for example "b" will be pressed. Final output should look like this: aaaaaaaaabbbbbbq (q should terminate the program).
My code here:
int main(int argc, char** argv) {
int c;
static struct termios staryTermios, novyTermios;
tcgetattr(STDIN_FILENO, &staryTermios);
novyTermios = staryTermios;
novyTermios.c_lflag &= ~(ICANON);
tcsetattr(STDIN_FILENO, TCSANOW, &novyTermios);
while ((c = getchar()) != 'q') {
putchar(c);
}
tcsetattr( STDIN_FILENO, TCSANOW, &staryTermios);
return 0;
}
this version writes the typed characters only once and then it waits for another keypress
To achieve the result you want, you need to make the standard input non-blocking. You can do that with this minor adaptation of your code. It worked fine on Mac OS X 10.7.5. Note that getchar() returns EOF when there's no character ready to read (which will be most of the time; neither you nor I can type fast enough to matter to a modern computer). I'm mildly concerned that on some systems, once getchar() has returned EOF once when there was no character to read, it might never return anything other than EOF again, but that wasn't a problem for Mac OS X.
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
static void err_exit(const char *msg);
int main(void)
{
int c;
int oc = '\0';
struct termios staryTermios, novyTermios;
int oflags, nflags;
if (tcgetattr(STDIN_FILENO, &staryTermios) != 0)
err_exit("tcgetattr() failed");
novyTermios = staryTermios;
novyTermios.c_lflag &= ~(ICANON);
if (tcsetattr(STDIN_FILENO, TCSANOW, &novyTermios) != 0)
err_exit("tcsetattr() failed to set standard input");
oflags = fcntl(STDIN_FILENO, F_GETFL);
if (oflags < 0)
err_exit("fcntl() F_GETFL failed");
nflags = oflags;
nflags |= O_NONBLOCK;
if (fcntl(STDIN_FILENO, F_SETFL, nflags) == -1)
err_exit("fcntl() F_SETFL failed");
while ((c = getchar()) != 'q')
{
if (c != EOF)
oc = c;
if (oc != '\0')
putchar(oc);
}
if (tcsetattr(STDIN_FILENO, TCSANOW, &staryTermios) != 0)
err_exit("tcsetattr() failed to reset standard input");
putchar('\n');
return 0;
}
static void err_exit(const char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}
I guess you will need two threads which will both be accessing a common variable. The job of one thread would be to continuously print the common variable. The job of the second would be to wait for input from the keyboard and update the variable accordingly.

Can I make ungetc unblock a blocking fgetc call?

I would like to stuff an 'A' character back into stdin using ungetc on receipt of SIGUSR1. Imagine that I have a good reason for doing this.
When calling foo(), the blocking read in stdin is not interrupted by the ungetc call on receipt of the signal. While I didn't expect this to work as is, I wonder if there is a way to achieve this - does anyone have suggestions?
void handler (int sig)
{
ungetc ('A', stdin);
}
void foo ()
{
signal (SIGUSR1, handler);
while ((key = fgetc (stdin)) != EOF)
{
...
}
}
Rather than try to get ungetc() to unblock a blocking fgetc() call via a signal, perhaps you could try not having fgetc() block to begin with and wait for activity on stdin using select().
By default, the line discipline for a terminal device may work in canonical mode. In this mode, the terminal driver doesn't present the buffer to userspace until the newline is seen (Enter key is pressed).
To accomplish what you want, you can set the terminal into raw (non-canonical) mode by using tcsetattr() to manipulate the termios structure. This should case the blocking call to fgetc() to immediately return the character inserted with ungetc().
void handler(int sig) {
/* I know I shouldn't do this in a signal handler,
* but this is modeled after the OP's code.
*/
ungetc('A', stdin);
}
void wait_for_stdin() {
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fileno(stdin),&fdset);
select(1, &fdset, NULL, NULL, NULL);
}
void foo () {
int key;
struct termios terminal_settings;
signal(SIGUSR1, handler);
/* set the terminal to raw mode */
tcgetattr(fileno(stdin), &terminal_settings);
terminal_settings.c_lflag &= ~(ECHO|ICANON);
terminal_settings.c_cc[VTIME] = 0;
terminal_settings.c_cc[VMIN] = 0;
tcsetattr(fileno(stdin), TCSANOW, &terminal_settings);
for (;;) {
wait_for_stdin();
key = fgetc(stdin);
/* terminate loop on Ctrl-D */
if (key == 0x04) {
break;
}
if (key != EOF) {
printf("%c\n", key);
}
}
}
NOTE: This code omits error checking for simplicity.
Clearing the ECHO and ICANON flags respectively disables echoing of characters as they are typed and causes read requests to be satisfied directly from the input queue. Setting the values of VTIME and VMIN to zero in the c_cc array causes the read request (fgetc()) to return immediately rather than block; effectively polling stdin. This causes key to get set to EOF so another method for terminating the loop is necessary. Unnecessary polling of stdin is reduced by waiting for activity on stdin using select().
Executing the program, sending a SIGUSR1 signal, and typing
t e s t results in the following output1:
A
t
e
s
t
1) tested on Linux
It is not entirely clear what your goal is, but is this what you are looking for?
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
int handle = 0;
void handler (int sig) {
handle = 1;
}
void foo () {
int key;
signal (SIGUSR1, handler);
while ((key = fgetc (stdin)) != EOF) {
printf("%c\n",key);
if (handle) {
handle = 0;
ungetc('A',stdin);
}
}
}
int main(void) {
printf("PID: %d\n",getpid());
foo();
}
It produces this output:
PID: 8902
test (typed on stdin)
t
A
e
s
t
FILE*s are not async safe.
You cannot operate on a FILE* in a signal handler while someone else also uses that same FILE*. functions you can all in a signal handler is stated here:
http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html . (It might be
different on a windows machine, but still any FILE* are not safe there either.
This is essentially the same as #Jamie's answer, slightly changed to support your desire to process the A before the t, but it's too hard to type code into a comment box, so I've posted this answer separately.
int insert_an_A = 0;
void handler(int sig) { insert_an_A = 1; }
void process_char(char c) { ... }
int main(int argc, char **argv) {
int c;
/* skip signal setup */
while ((c = fgetc(stdin)) != EOF) {
if (insert_an_A) {
process_char('A');
insert_an_A = 0;
}
process_char(c);
}
}
If you want to process an handler received during the call to fgetc that returns EOF, you should also check insert_an_A after exiting the while loop.
Note also that in general the best practice for signal handlers is to set a global variable and return from the handler. Elsewhere in your program, look for that variable changing and react appropriately.

Resources