non-buffering stdin reading
My test application is
#include <sys/types.h> #include <sys/wait.h> #include <signal.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> int main(int argc, char *argv[], char *envp[]) { int fd[2]; if(pipe(fd) < 0) { printf("Can\'t create pipe\n"); exit(-1); } pid_t fpid = fork(); if (fpid == 0) { close(0); close(fd[1]); char *s = (char *) malloc(sizeof(char)); while(1) if (read(fd[0], s, 1)) printf("%i\n", *s); } close(fd[0]); char *c = (char *) malloc(sizeof(char)); while (1) { if (read(0, c, 1) > 0) write(fd[1], c, 1); } return 0; }
I want to see char-code after each entered char. But in fact *s is printed only after '\n' in the console. So seems like stdin (file with desc 0) is buffered. But the read function is buffer-less, isn't it? Where am I wrong.
UPD: I use linux.
So the solution is
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <termios.h> int main(int argc, char *argv[], char *envp[]) { int fd[2]; if(pipe(fd) < 0) { printf("Can\'t create pipe\n"); exit(-1); } struct termios term, term_orig; if(tcgetattr(0, &term_orig)) { printf("tcgetattr failed\n"); exit(-1); } term = term_orig; term.c_lflag &= ~ICANON; term.c_lflag |= ECHO; term.c_cc[VMIN] = 0; term.c_cc[VTIME] = 0; if (tcsetattr(0, TCSANOW, &term)) { printf("tcsetattr failed\n"); exit(-1); } pid_t fpid = fork(); if (fpid == 0) { close(0); close(fd[1]); char *s = (char *) malloc(sizeof(char)); while(1) if (read(fd[0], s, 1)) printf("%i\n", *s); } close(fd[0]); char *c = (char *) malloc(sizeof(char)); while (1) { if (read(0, c, 1) > 0) write(fd[1], c, 1); } return 0; }
Answers
Unfortunately, the behavior you're looking for is not possible with standard ANSI C, and the default mode for UNIX terminal I/O is line-oriented, which means you will always need an inputted \n character to retrieve the input. You'll need to use terminal I/O facilities that let you program in non-canonical mode, so that each key-press triggers an event. On Linux/UNIX, you can look into the <termios.h> header, or the ncurses library.