Strange behavior in terminal raw mode - c

I'm following a tutorial for making a text editor .
So far it's been tinkering with raw mode . The following code is supposed to turn off canonical mode , and output each keypress.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
struct termios orig_termios;
void disableRawMode() { … }
void enableRawMode() { … }
int main() {
enableRawMode();
char c;
while (read(STDIN_FILENO, &c, 1) == 1 && c != 'q') {
if (iscntrl(c)) {
printf("%d\n", c);
} else {
printf("%d ('%c')\n", c, c);
}
}
return 0;
}
I originally forgot to add "\n" after the printf() statements, and the result was that I only got the outputted characters after the program terminates , ie after pressing q in this example .
However after adding "\n", the terminal outputs each letter as pressed.
Could anyone be so kind and explain why is it behaving this way?

Raw-mode is the concern of the terminal but buffer management of stdout occurs before reaching the terminal.
By default, when file-descriptor 1 (STDOUT_FILENO) is link to a terminal, then stdout uses a line-buffering policy.
This means that the output buffer of stdout is flushed to the file-descriptor 1 when a \n is written (or when it is full).
Only at this moment the characters can reach the terminal which can react in different ways depending on its configuration.
In your example, the characters just stay in memory until the process terminates (stdout is flushed at this moment).

Commonly, when a C program starts with the standard output stream connected to a terminal, the stream is line buffered. This means characters printed with printf or standard library methods are kept in a buffer until \n is printed (ending the line, hence “line buffered”), the buffer is full, when the stream is manually flushed (as with fflush), or when input is solicited on stream that is unbuffered or that is line buffered but requires characters from “the host environment” (notably a human).
The terminal setting is irrelevant as the characters are kept in an internal buffer of the standard C library implementation and are not sent to the terminal until one of the above events.
You can set the stream to unbuffered by calling setvbuf(stdout, NULL, _IONBF, 0) before performing any other operation on stdout.

Related

C: printf still not flushing before while loop, even with new line character in format string [duplicate]

This question already has answers here:
What are the rules of automatic stdout buffer flushing in C?
(5 answers)
Is stdout line buffered, unbuffered or indeterminate by default?
(1 answer)
Closed 3 years ago.
I have read many questions with people asking why printf did not work before a while loop; the answer was that it was not flushing stdout because they did not have a new line character in their format string. However, the following simple code is still not producing output for me:
#include <stdio.h>
int main() {
printf("Hello world!\n");
while (1);
return 0;
}
However, adding fflush(stdout); after the printf call produces output. The new line character is supposed to make this unnecessary, so why does it not work without it?
It's quite common for stdout to be line-buffered when connected to a terminal (flushed on line feed), and block-buffered otherwise (flushed when buffer is full).
For example,
#include <stdio.h>
#include <unistd.h>
int main(void) {
printf("foo\n");
sleep(5);
return 0;
}
Test:
$ ./a
foo
[5s pause]
$ ./a | cat
[5s pause]
foo
(gcc on Linux)
I'm using mingw with Eclipse on Windows.
It seems that Eclipse is connecting the stdout of your program to a pipe so it can collect the output and display it in its window. Your program thus uses block buffering for stdout.
A very good answer by #schot here.
He said :
The C99 standard does not specify if the three standard streams are unbuffered or line buffered: It is up to the implementation. All UNIX implementations I know have a line buffered stdin. On Linux, stdout is line buffered and stderr unbuffered.
One way to be sure that your line(s) will be printed directly is making stdout unbuffered:
setbuf(stdout, NULL);
/* or */
setvbuf(stdout, NULL, _IONBF, 0);
But you can only do this once, and it must be before you write to stdout or perform any other operantion on it. (C99 7.19.5.5 2)
Additional Info :
Shouldn't a new line character flush the output?
-It depends, if the output device is determined to be interactive (e.g. a terminal) the newline flush the buffer. Otherwise new line(s) don't flush the buffer.
What constitutes an interactive device is implementation-defined (C99 section 5.1.2.3/6) 

How can i make getchar() function hold backspace

#include<stdio.h>
int main(void)
{
int c;
while((c=getchar())!=EOF)
{
if(c==8) // 8 is ASCII value of backspace
printf("\\b");
}
}
Now I want to enter backspace and want getchar() function to return ASCII of backspace to c(int variable)
Note- I am not asking about getch function i know that getch command is able to read backspace
I only want to know whether getchar is able to read backspace or not
If yes,How?
How to do it please explain me
I am new to C programming
If the stream stdin reads from a file, getchar() will handle backspace characters ('\b' or 8 in ASCII) like any other regular character and return it to the caller.
The reason it does not do that when reading from the console (aka terminal or tty) is related to the configuration of the console itself. The console is in cooked mode by default, so as to handle echo, backspace and line buffering, but also signals such as SIGINT sent for Ctrl-C and many more subtile settings.
The C Standard does not provide any way to change the terminal modes, but POSIX systems have the stty command and the termios system calls available to C programs to do this.
Once you configure the console in raw mode, also set stdin to unbuffered mode with setvbuf(stdin, NULL, _IONBF, 0) so getchar() reads each byte from the console as it is typed.
Configuring the console is a complex issue, you may want to read this first: http://www.linusakesson.net/programming/tty/
If your system supports termios as standardized in POSIX.1-2001, then you can manipulate the standard input terminal to not buffer your input. Consider the following example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
/* SIGINT handler */
static volatile sig_atomic_t done = 0;
static void handle_done(int signum)
{
if (!done)
done = signum;
}
static int install_done(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_done;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
/* Reverting terminal back to original settings */
static struct termios terminal_config;
static void revert_terminal(void)
{
tcsetattr(STDIN_FILENO, TCSAFLUSH, &terminal_config);
}
int main(void)
{
int c;
/* Set up INT (Ctrl+C), TERM, and HUP signal handlers. */
if (install_done(SIGINT) ||
install_done(SIGTERM) ||
install_done(SIGHUP)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* Make terminal input noncanonical; not line buffered. Also disable echo. */
if (isatty(STDIN_FILENO)) {
struct termios config;
if (tcgetattr(STDIN_FILENO, &terminal_config) == 0 &&
tcgetattr(STDIN_FILENO, &config) == 0) {
config.c_lflag &= ~(ICANON | ECHO);
config.c_cc[VMIN] = 1; /* Blocking input */
config.c_cc[VTIME] = 0;
tcsetattr(STDIN_FILENO, TCSANOW, &config);
atexit(revert_terminal);
}
}
/* Set standard input unbuffered. */
setvbuf(stdin, NULL, _IONBF, 0);
printf("Press Ctrl+C to exit.\n");
fflush(stdout);
while (!done) {
c = fgetc(stdin);
if (c == EOF)
printf("Read EOF%s\n", ferror(stdin) ? " as an error occurred" : "");
else
printf("Read %d = 0x%02x\n", c, (unsigned int)c);
fflush(stdout);
}
return EXIT_SUCCESS;
}
The #define line tells your C library headers to expose POSIX.1 features for GNU-based systems.
The done flag is set whenever an INT (Ctrl+C), TERM, or HUP signal is received. (HUP signal is sent if you disconnect from the terminal, for example by closing the terminal window.)
The terminal_config structure will contain the original terminal settings, used by revert_terminal() registered as an at-exit function, to revert the terminal settings back to the original ones read at program startup.
The function isatty(STDIN_FILENO) returns 1 if standard input is a terminal. If so, we obtain the current terminal settings, and modify them for non-canonical mode, and ask that each read blocks until at least one character is read. (The I/O functions tend to get a bit confused if you set .c_cc[VMIN]=0 and .c_cc[VTIME]=0, so that if no input is pending, fgetc() returns 0. Typically it looks like an EOF to stdio.h I/O functions.)
Next, we tell the C library to not internally buffer standard input, using setvbuf(). Normally, the C library uses an input buffer for standard input, for efficiency. However, for us, it would mean the C library would buffer characters typed, and our program might not see them immediately when typed.
Similarly, standard output is also buffered for efficiency. The C library should flush all complete lines to the actual standard output, but we can use the fflush(stdout) call to ensure everything we've written to stdout is flushed to the actual standard output at that point.
In main(), we then have a simple loop, that reads keypresses, and prints them in decimal and hexadecimal.
Note that when a signal is delivered, for example the INT signal because you typed Ctrl+C, the delivery of the signal to our handle_done() signal handler interrupts the fgetc() call if one is pending. This is why you see Read EOF when you press Ctrl+C; if you check ferror(stdin) afterwards, you'll see it returns nonzero (which indicates an error occurred). The "error" in this case is EINTR, "interrupted by a signal".
Also note that when you press some certain keys, like cursor or function keys, you'll see multiple characters generated, usually beginning with 27 and 91 (decimal; 0x1B 0x5B in hexadecimal; "\033[" if expressed as a C string literal). These are usually, but not always, ANSI escape sequences. In general, they are terminal-specific codes that one can obtain via tigetstr(), tigetnum(), and tigetflag() using the terminfo database.
A much more portable way to do this, is to use a Curses library; either ncurses on most systems, or PDCurses on Windows machines. Not only do they provide a much easier interface, but it does it in a terminal-specific way, for maximum compatibility across systems.
C programs using the Curses functions can be compiled against any Curses library, so the same C source file can be compiled and run on Linux, Mac, and Windows machines. However, ncurses does contain quite a few extensions, which may not be provided by other Curses libraries like PDCurses.

why doesn't this c programme print the first printf statement?

#include<stdio.h>
#include <unistd.h>
int main(){
while(1)
{
fprintf(stdout,"hello-out");
fprintf(stderr,"hello-err");
sleep(1);
}
return 0;
}
On compiling this programme in gcc and on executing it only prints hello-err and not hello-out.Why is that so?Can someone please explain the reason behind it?
If you add a '\n' to your message it will (or should), ie. "hello-out\n".
The reason being is that stdout is buffered in order to be more efficient, whereas stderr doesn't buffer it's output and is more appropriate for error messages and things that need to be printed immediately.
stdout will usually be flushed when:
A newline (\n) is to be printed
You read in from stdin
fflush() is called on it
EDIT: The other thing I wanted to add before my computer crashed...twice...was that you can also use setbuf(stdout, NULL); to disable buffering of stdout. I've done that before when I've had to use write() (Unix) and didn't want my output to be buffered.
It doesn't always print out the output to stdout because by design stdout is BUFFERED output, and stderr is unbuffered. In general, the for a buffered output stream, the stream is not dumped until the system is "free" to do so. So data can continue buffering for a long while, before it gets flushed. If you want to force the buffer to flush you can do so by hand using fflush
#include<stdio.h>
#include <unistd.h>
int main(){
while(1)
{
fprintf(stdout,"hello-out");
fflush(stdout); /* force flush */
fprintf(stderr,"hello-err");
sleep(1);
}
return 0;
}
Update: stdout is linebuffered when connected to a terminal, and simply buffered otherwise (e.g. a redirect or a pipe)
You forgot newlines (noted \n) in your strings. Or you need to call fflush(NULL); or at least fflush(stdout); before sleep(1);
And fprintf(stdout, ...) is the same as printf(...)
You need to output newlines or to call fflush because (at least on Linux) the stdout FILE buffer is line-buffered. This means that the C library is buffering data, and will really output it (using the write Linux system call) when the buffer is full enough, or when you flush it either with a new line, or by calling fflush. Buffering is needed because system calls are costly (calling write for every byte to be output is really too slow). Read also the man page of setbuf

How to write redirected output to file inside loop in C?

I am writing a C program on unix which should redirect it's output to the file, and write to it some text every second in infinite loop:
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
int outDes = open("./output.txt", O_APPEND | O_WRONLY);
dup2(outDes, 1);
while(1) {
printf("output text\n");
sleep(1);
}
}
But it writes nothing to the output file. I tried to change the 'while' loop for 'for' with 10 loops, and I found that it writes all 10 lines to the file at once after the series ends. It is not very good for me, while I need to have an infinite loop.
When I'm not redirecting output, it is all ok, and new line appears every second on terminal.
I also tried to put one
printf("text\n");
before redirecting output to the file. Then the program wrote the lines to the file in real time, which is good, but wrote there the first (non redirected) line too. I don't want this first line in my output file, I don't understand how it could be written into file when output was not redirected yet (maybe redirect remained there since last run?), and how it could cause that the lines are suddenly written in real time.
Can anyone explain me how does it work?
You are not checking the return value of open() and dup2(). If either open() or dup2() failed, it won't write anything in output.txt.
if (outDes < -1) {
perror("open");
return 1;
}
if (dup2(outDes, 1) == -1) {
perror("dup2");
return 1;
}
stdio streams are buffered, and the writes happen in memory before being done on the real file description.
Try adding a fflush(stdout) after printf().
You're running afoul of a poorly documented DWIMmy feature in many Unix C libraries. The first time you write to stdout or stderr, the library probes the underlying file descriptor (with isatty(3)). If it's a (pseudo-)terminal, the library puts the FILE in "line buffered" mode, meaning that it'll buffer input until a newline is written and then flush it all to the OS. But if the file descriptor is not a terminal, it puts the FILE in "fully buffered" mode, where it'll buffer something like BUFSIZ bytes of output before flushing them, and pays no attention to line breaks.
This is normally the behavior you want, but if you don't want it (as in this case), you can change it with setvbuf(3). This function (although not the behavior I described above) is ISO standard C. Here's how to use it in your case.
#include <stdio.h>
#include <unistd.h>
int
main(void)
{
if (freopen("output.txt", "a", stdout)) {
perror("freopen");
return 1;
}
if (setvbuf(stdout, 0, _IOLBF, 0)) {
perror("setvbuf");
return 1;
}
for (;;) {
puts("output text");
sleep(1);
}
/* not reached */
}

Why does printf() not print anything before sleep()?

I'm just learning C with Kernighan and Ritchie's book; I'm in the basics of the fourth chapter ("Functions and Program Structure"). The other day I became curious about the sleep() function, so tried to use it like this:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf(" I like cows.");
sleep(5);
return 0;
}
The problem is the output of the program, it looks like it does the sleep() first and then the printf(), in other words, it waits five seconds and then prints the string. So I thought, maybe the program gets to sleep() so fast that it doesn't let printf() have his work done like I want, that is print the string and then sleep.
How can I show the string and then put the program to sleep?
The compiler is GCC 3.3.5 (propolice) in OpenBSD 4.3.
printf() writes to stdout (the default output stream) which is usually line buffered. The buffer isn't flushed by the time sleep is called so nothing is displayed, when the program exits all streams are automatically flushed which is why it prints right before exiting. Printing a newline will usually cause the stream to be flushed, alternatively you could use the fflush function:
int main(void)
{
printf(" I like cows.\n");
sleep(5);
return 0;
}
or:
int main(void)
{
printf(" I like cows.");
fflush(stdout);
sleep(5);
return 0;
}
If you are printing to a stream that is not line buffered, as may be the case if stdout is redirected or you are writing to a file, simply printing a newline probably won't work. In such cases you should use fflush if you want the data written immediately.
Your problem is that printf (and anything else that uses the stdio library to write to stdout (standard output)) is buffered - line buffered if it goes to the console, and size buffered if it goes to a file. If you do a fflush(stdout); after the printf, it will do what you want. You could try just adding a newline ('\n') to your string, and that would do the right thing as long as you don't redirect standard output to a file.
I'm not 100% sure, but I think stderr isn't buffered, which can cause confusion because you might see output you made to stderr before output you previously made to stdout.
Buffering means that all the output is stored in a place (called buffer) and is output after a certain amount of data is present in it. This is done for efficiency reasons.
Some (most?) implementations clear the buffer after a newline when writing to the console, so you can also try
printf(" I like cows.\n");
instead of the call to fflush()
I implemented time encounter as following;
for (int i = 1; i <= 60; i++) {
printf("%02d", i);
fflush(stdout);
sleep(1);
printf("\b\b");
}

Resources