C: ncurses, initscr() changes behaviour of getchar()? - c

I am just playing around with ncurses and so, and I discovered a really weird behaviour.
When i use initscr() from the ncurses lib, and afterwards i use a normal getchar(), then the program terminates after pressing the first key.
The normal getchar() behaviour I would expect, is that i can type (more or less) as long till I press return.
#include "curses.h"
int main()
{
initscr();
getchar();
//endwin();
return 0;
}
Can anyone explain me why this happens?

curses initializes the terminal input to raw mode (which in turn makes the connected stream act as if it is unbuffered), so that curses can detect single-character input. getchar assumes that the input is buffered, so that you would press Enter to end an input line. In raw mode, getchar returns right away, because a read call will find something as soon as you press a key.
Besides endwin, you could use other curses functions for switching back/forth between the terminal's raw/cooked modes (see the manual for reset_shell_mode and reset_prog_mode).

Related

How getchar() works when it is used as condition in while loop

I cant understand how the following code really works.
int main() {
char ch;
while((ch=getchar())!='\n')
{
printf("test\n");
}
return 0;
}
Lets say we give as an input "aaa". Then we get the word "test" as an output in 3 seperate lines.
Now my question is, for the first letter that we type, 'a', does the program goes inside the while loop and remembers that it has to print something when the '\n' character is entered? Does it store the characters somewhere and then traverses them and executes the body of the while loop? Im lost.
There are many layers between the user writing input into a terminal, and your program receiving that input.
Typically the terminal itself have a buffer, which is flushed and sent to the operating system when the user presses the Enter key (together with a newline from the Enter key itself).
The operating system will have some internal buffers where the input is stored until the application reads it.
Then in your program the getchar function itself reads from stdin which is usually also buffered, and the characters returned by getchar are taken one by one from that stdin buffer.
And as mentioned in a comment to your question, note that getchar returns an int, which is really important if you ever want to compare what it returns against EOF (which is an int constant).
And you really should compare against EOF, otherwise you won't detect if there's an error or the user presses the "end-of-file" key sequence (Ctrl-D on POSIX systems like Linux or macOS, or Ctrl-Z on Windows).
What you see is due to the I/O line buffering.
The getchar() functions doesn't receive any input until you press the enter. This add the \n completing the line.
Only at this point the OS will start to feed characters to the getchar(), that for each input different from \n prints the test message.
Apparently the printout is done together after you press the enter.
You can change this behavior by modifying the buffering mode with the function setvbuf(). Setting the mode as _IONBF you can force the stream as unbuffered, giving back each character as it is pressed on the keyboard (or at least on an *nix system, MS is not so compliant).

K&R book 1.5.1 File Copying

I have looked around the site regarding this K&R example and the answers seem to revolve around 'why is this a type int or what is EOF?' kinda guys. I believe that I understand those.
It's the results that I don't understand. I had expected this code to take a single character, print it and then wait for another character or EOF.
The results that I see are the input waiting until I press return, then everything that I typed shows up and the more waiting for input.
Is the while loop just 'looping' until I end the text stream with the carrage return and then shows what putchar(c) has been hiding somewhere?
The code is:
#include <stdio.h>
/* copy input to output: 1st version */
main()
{
int c;
c = getchar();
while(c != EOF) {
putchar(c);
c = getchar();
}
}
Now, if I sneak a putchar(c) before on the line just before the while, I sort of get what I expected. I still must enter a text stream and press return. The result is the first character of the stream and the program exits.
Evidently there is a big picture gap for me going on.
Thank you for your help
By default, stdin and stdout are buffered. That means that they save up batches of characters and send them at once for efficiency. Typically, the batch is saved up until there's no more room in the buffer or until there's a newline or EOF in the stream.
When you call getchar(), you're asking from characters from stdin. Supposed you type A, that character is saved in the buffer and then the system waits for more input. If you type B, that character goes into the buffer next. Perhaps after that, you hit Enter, and a newline is put in the buffer. But the newline also interrupts the buffering process, so the original call to getchar() returns the first character in the buffer (A). On the next iteration, you call getchar() again, and it immediately returns the next character in the buffer (B). And so on.
So it's not that your while loop is running until you end the line, it's that the first call to getchar() (when the buffer is empty) is waiting until it has either a full buffer or it has seen a newline.
When you interleave output functions, like putchar(), most C runtime libraries will "flush" stdin when you do something that sends data to stdout (and vice versa). (The intent is to make sure the user sees a prompt before the program waits for input.) That's why you started seeing different behavior when you added the putchar() calls.
You can manually flush a buffer using the flush() function. You can also control the size of the buffer used by the standard streams using setvbuf().
As Han Passant pointed out in the comments, a newline doesn't "terminate the stream." To get an EOF on stdin, you have to type Ctrl+D (or, on some systems, Ctrl+Z). An EOF will also flush the buffer. If you've redirected a file or the output from another program to stdin, the EOF will happen once that input is exhausted.
While it's true that K&R C is very old, and even ANSI C isn't as common today as it was, everything about buffering with stdin and stdout is effectively the same in the current standards and even in C++. I think the only significant change is that the C standards now explicitly call out the desirability of having stdin and stdout cause the other to flush.
I appreciate your answer, and the buffering as you describe is very helpful and interesting.
Evidently, I also must have mis-read/understood, K&R. They define a text stream as ". . . consists of zero or more characters followed by a new line character," which I took to mean the return/enter key; ending it, and then allowing output.
Also, I would like to thank all of you who offered helpful comments.
By the way, I clearly understood that I had to enter ^D to generate EOF, which terminates the program. I appreciate that you are all top level programmers, and thank you for your time. I guess that I will need to find another place to discuss what the text that R&R wrote regarding this exercise is all about.

Going back to normal terminal I/O after closing ncurses window

In a game I made I create an ncurses window using initscr(), then the user plays the game and when the game ends the program closes the window using endwin() and then prints some statements and gets input from the user using printf and scanf, respectively. My problem is that whenever the game ends scanf always executes before printf. So it waits for a response, and once the user enters the response it prints everything that was before and after the scanf statement. Here is some example code:
...
endwin();
system("clear"); /* Clears terminal window */
printf("New high score!\nPlease enter your first name: ");
scanf("%s",name);
... /* file I/O stuff */
printf("Congratulations, %s!",name);
As you can see, the printf statement is before the scanf statement but for some reason scanf executes first. I tested the code without an ncurses window and I get the desired result. Does anyone know what is causing this?
Nothing to do with curses.
This statement is obviously wrong since using curses makes a difference, as the question states:
As you can see, the printf statement is before the scanf statement but
for some reason scanf executes first. I tested the code without an
ncurses window and I get the desired result. Does anyone know what is
causing this?
While it is right that fflush(stdout) gives the desired result, that does not answer the question.
What is causing this is presumably the implementation-defined standard I/O characteristic to flush a line buffered stdout when input is requested (sometimes documented in man setbuf), and curses setting stdout to fully buffered, thereby disabling the automatic flush.
You can read about it in the manual page where it discusses NCURSES_NO_SETBUF:
to get good performance, most curses implementations change the output buffering from line-oriented to buffer-oriented (so that the library can make larger, more efficient writes)
because that meant that all writes to the standard output would be buffered, it was a nuisance. ncurses provided an option (the environment variable) to override the buffering.
that changed in 2012, by eliminating the stdout buffering altogether to solve a problem with signal handling.
however, "eliminating" the buffering means that ncurses uses its own buffer. It'll flush that in endwin, but doesn't flush stdout when switching to/from curses mode.
a few applications required modification to flush stdout.
The 2012 change for ncurses was part of the ncurses6 release in August 2015. The OP's question is in terms of ncurses5.9 (or earlier), since it describes an application where the standard output is buffered.

Recover stdin from eof in C

I am using the C code below to read user input from a terminal. If the user inputs EOF, e.g. by pressing ^C, stdin is closed and subsequent attempts to read from it, e.g. via getchar() or scanf(), will cause an exception.
Is there anything I can do in C to "recover" my program, in the sense that if some user accidently inputs EOF, this will be ignored, so I can read from stdin again?
#include <stdio.h>
int main(void)
{
int res_getchar=getchar();
getchar();
return 0;
}
If I understand the situation correctly - you're reading from a terminal via stdin, the user types ^D, you want to discard that and ask again for input - you have two options, one more portable (and quite simple) but less likely to work, and one less portable (and considerably more programming) but certain to work.
The clearerr function is standard C, and is documented to clear both the sticky error and sticky EOF flags on a FILE object; if your problem is that the C library isn't bothering to call read again once it's indicated EOF once, this may help.
If this solves your immediate problem, make sure that if you get some number of EOFs in a row (four to ten, say) you give up and quit, because if stdin is not a terminal, or if the terminal has genuinely been closed down, that EOF condition is never going to go away, and you don't want your program to get stuck in an infinite loop when that happens.
On POSIX-compliant systems only (i.e. "not Windows"), you can use cfmakeraw to disable the input preprocessing that turns ^D into an EOF indication.
Doing this means you also have to handle a whole lot of other stuff yourself; you may instead want to use a third-party library that handles it for you, e.g. readline (GPL) or editline (BSD). If your program is any sort of nontrivial interactive command interpreter, using one of these libraries is strongly encouraged, as it will provide a much nicer user experience.
Using ungetc() to push back a character can clear the EOF indicator for a stream.
C99 ยง7.19.7.11 The ungetc function
int ungetc(int c, FILE *stream);
A successful call to the ungetc function clears the end-of-file indicator for the stream. The value of the file position indicator for the stream after reading or discarding all pushed-back characters shall be the same as it was before the characters were pushed back.
In a word, no. You read EOF when the OS has closed stdin.
I am sure there are Platform-dependent ways to preserve some info that would let you reconstruct stdin after it was closed -- ie, open a new stream connected to the keyboard and assign it to stdin -- but there's definitely no portable way.

Catching the EOF keystroke without pressing Enter C

I am writing a program which has a main menu, with a couple functions which I am allowing the user to access by typing in a number for one menu selections. For that, I am using _getch(). I need to be able to exit the program when the user enters the EOF key, but _getch() does not actually catch the EOF keystroke. I know I can get it to work by using getchar() instead of _getch(), but I would prefer not to have the user be forced to press enter after every function selection.
Is there a way to get _getch() to catch EOF? This is for Windows if it is of any importance, any help is really appreciated, as I have been unable to find anything out there.
The standard C input stream stdio is line buffered, and there is no defined way to forcibly flush it. If you want to avoid this and read from the buffer as every new character is entered, you have to use some OS specific magic, which is what _getch from conio.h tries to do.
There are other implementations out there of getch-type functions, for instance getch from the PDCurses library.

Resources