I have a large program, a text twist game with graphics in c. somewhere in my code i use kbhit() i did this code to clear my input buffer:
while ((c = getchar()) != '\n' && c != EOF);
This code works and wait for me to hit enter key to exit from the loop. The problem is, the loop waits me to hit enter, any other key will output in the screen (unreadable). My question, is there any other way to clear the input buffer without pressing anything, like using fflush to clear output buffer?
Assuming you're on some kind of Unix variant....
There are two things you need to clear here:
The FILE * input buffer managed by the C library.
The OS input buffer that your program has not yet read.
The first can be cleared with fflush, just like output streams, except that the data is simply discarded rather than written out.
The second requires some low-level OS I/O calls. In general you should not mix these with the FILE * I/O functions, but they should be safe between fflush and any other read/get operation.
First, you'll need to use select to see if a read operation would block. This effectively checks to see if the OS buffer is clear. If the read would not block, then you do a one-character read, and repeat the select. The key point is that you have to check if there is data to read before you read and discard it, or else it will block until there is data to read.
The code might look something like this (untested):
fflush(stdin);
int stdinin_fd = fileno(stdin);
while (1) {
fdset readset;
FD_ZERO(&readset);
FD_SET(stdin_fd, &readset);
struct timeval timeout = {0, 0};
int result = select(stdin_fd+1, &readset, NULL, NULL, timeout);
if (result == 1) {
char c;
read(stdin_fd, &c, 1);
} else if (result == 0
|| (result == -1 && errno != EINTR)) {
break;
} // else loop
}
It might be possible use a larger read-size when clearing the OS buffers, which would be more efficient, but I'm not sure about the portability of that, and anyway I'm assuming there won't be much data to clear.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 months ago.
Improve this question
I am trying to read input from stdin with fread(). However i am have a problem, the loop will not terminate and instead keeps reading.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "argument err");
return -1;
}
FILE *in = fopen(argv[1], "w");
if (in == NULL) {
fprintf(stderr, "failed to open file");
return -1;
}
char buffer[20];
size_t ret;
while ((ret = fread(buffer, 1, 20, stdin)) > 0) {
if (fwrite(buffer, 1, ret, in) != ret) {
if (ferror(in) != 0) {
perror("write err:");
}
}
}
return 0;
}
How can i make this loop terminate when EOF is reached? i have tried using ctrl+D but that just seems like a strange way to stop taking input.
I guess what i want is to use fread() to read multiple arbitrary amounts of data in chunks of 20 bytes and then somehow stop.
How can i make this loop terminate when EOF is reached?
When do you think EOF is reached? Really. When you are providing input interactively, how is the system or the program supposed to know that you've entered all the data you want the program to consume?
i have tried using ctrl+D but that just seems like a strange way to stop taking input.
It is exactly the way to signal a soft EOF to a POSIX terminal. Since you want the loop to stop when EOF is encountered, it seems absolutely natural to me to use ctrl+D for the purpose when providing data interactively. That's not the only way you could signal the end of the input, but it has a lot going for it.
I guess what i want is to use fread() to read multiple arbitrary amounts of data in chunks of 20 bytes and then somehow stop.
Again: how is the program supposed to know when it has consumed all the "multiple arbitrary amounts" of data that you decide to provide on a given run? An EOF signal is an eminently reasonable choice for multiple reasons, and the way to deliver that from a POSIX terminal interface is ctrl+D.
As pointed out before you are reading from an eternal stream, this means that stdin don't naturally have a EOF (or <=0) value.
If you want your loop to terminate, you will have to add a termination condition, like a certain character, word or all type of value. After that you could use a break or a return in some case. You could also search if your terminal emulator support the insertion of an EOF value into the stdin, which is pretty common (But very platform dependent).
ADD: On my system, typical linux, CTRL+D is for an EOF insertion in stdin. It seems that you found this out yourself, and if you want your program to know where to stop you will need to use this.
You cand also send a signal to your program, usually done with a shortcut like CTRL+D, CTRL+C, CTRL+T etc... there is all sort of signal, which can be sent by your system or/and your TE and you just have to implement in your program the corresponding signal receiver.
How can i make this loop terminate when EOF is reached? i have tried using ctrl+D but that just seems like a strange way to stop taking input.
fread and fwrite are there to read data records, so they (both) take the number of records to read and the size of the record. If the available data doesn't fit on a full record, you will not get the full record at all (indeed, the routines return the number of full records read, and the partial read will be waiting for the next fread() call.)
All the calls in stdio.h package are buffered, so the buffer holds the data that has been read (from the system) but not yet consumed by the user, and so, this makes me to wonder why are you trying to use a buffer to read data that is already buffered?
EOF is produced when you are trying to read one record and the fread() call results in a true end of file from the system (this normally requires two calls, the first to complete the remaining data, the second resulting in no data ---zero bytes--- returned from the system) So you have to distinguish two cases:
fread() returns 0 in case it has read something, but is not enough to complete a record.
fread() returns EOF in case it has read nothing (the true end of file is reached)
As I've said above, fread() & fwrite() will read/write full records (this is useful when your data is a struct with a fixed length, but normally not when you can have extra data at the end)
The way to terminate the loop should be something like this:
while ((ret = fread(buffer, 1, 20, stdin)) >= 0) {
if (fwrite(buffer, 1, ret, in) != ret) {
if (ferror(in) != 0) {
perror("write err:");
}
}
}
/* here you can have upto 19 bytes in the buffer that cannot
* be read with that record length, but you can read individually
* with fgetc() calls. */
so, if you read half a record (at end of file) only at the next fread() it will detect the end of file (by reading nothing) and you will be free of ending. (beware that the extra data that doesn't fill a full buffer, still needs to be read by other means)
The cheapest and easiest way to solve this problem (to copy a file from one descriptor to another) is described in K&R (in the first edition) and has not yet have better code to void it, is this:
int c;
while ((c = fgetc(in)) != EOF)
fputc(c, out);
while it seems to read the characters one by one, it actually makes a call to read(2) to completely fill a full buffer of data, and return just one character, next characters will be taken from the buffer, saving calls to read(), and the same happens to fputc() (it fills the buffer until it's full, then flushes it, in a single call to write()).
Many people has tried to defeat the code above, without any measurable gain in efficience. So, my hint is be simple, that the world is complicated enough to force you to go complex.
I have this code which acts as a pipe between two shell invocations.
It reads from a pipe, and writes into a different one.
#include <stdio.h>
#include <stdlib.h>
#define BUFF_SIZE (0xFFF)
/*
* $ cat /tmp/redirect.txt |less
*/
int main(void)
{
FILE *input;
FILE *output;
int c;
char buff[BUFF_SIZE];
size_t nmemb;
input = popen("cat /tmp/redirect.txt", "r");
output = popen("less", "w");
if (!input || !output)
exit(EXIT_FAILURE);
#if 01
while ((c = fgetc(input)) != EOF)
fputc(c, output);
#elif 01
do {
nmemb = fread(buff, 1, sizeof(buff), input);
fwrite(buff, 1, nmemb, output);
} while (nmemb);
#elif 01
while (feof(input) != EOF) {
nmemb = fread(buff, 1, sizeof(buff), input);
fwrite(buff, 1, nmemb, output);
}
#endif
/*
* EDIT: The previous implementation is incorrect:
* feof() return non-zero if EOF is set
* EDIT2: Forgot the !. This solved the problem.
*/
#elif 01
while (feof(input)) {
nmemb = fread(buff, 1, sizeof(buff), input);
fwrite(buff, 1, nmemb, output);
}
#endif
pclose(input);
pclose(output);
return 0;
}
I want it to be efficient, so I want to implement it with fread()&fwrite(). There are the 3 way I tried.
The first one is implemented with fgetc()&fputc() so it will be very slow. However it works fine because it checks for EOF so it will wait until cat (or any shell invocation I use) finishes its job.
The second one is faster, but I'm concerned that I don't check for EOF so if there is any moment when the pipe is empty (but the shell invocation hasn't finished, so may not be empty in the future), it will close the pipe and end.
The third implementation is what I would like to do, and it relatively works (all the text is received by less), but for some reason it gets stuck and doesn't close the pipe (seems like it never gets the EOF).
EDIT: Third implementation is buggy. Fourth tries to solve the bug, but now less doesn't receive anything.
How should this be properly done?
First of all, to say that I think you are having problems more with buffering, than with efficiency. That is a common problem when first dealing with the stdio package.
Second, the best (and simplest) implementation of a simple data copier from input to output is the following snippet (copied from K&R first ed.).
while((c = fgetc(input)) != EOF)
fputc(c, output);
(well, not a literal copy, as there, K&R use stdin and stdout as FILE* descriptors, and they use the simpler getchar(); and putchar(c); calls.) When you try to do better than this, normally you incur in some false assumptions, as the fallacy of the lack of buffering or the number of system calls.
stdio does full buffering when the standard output is a pipe (indeed, it does full buffering always except when the file descriptor gives true to the isatty(3) function call), so you should do, in the case you want to see the output as soon as it is available, at least, no output buffering (with something like setbuf(out, NULL);, or fflush()) your output at some point, so it doesn't get buffered in the output while you are waiting in the input for more data.
What it seems to be is that you see that the output for the less(1) program is not visible, because it is being buffered in the internals of your program. And that is exactly what is happening... suppose you feed your program (which, despite of the handling of individual characters, is doing full buffering) doesn't get any input until the full input buffer (BUFSIZ characters) have been feeded to it. Then, a lot of single fgetc() calls are done in a loop, with a lot of fputc() calls are done in a loop (exactly BUFSIZ calls each) and the buffer is filled at the output. But this buffer is not written, because it need one more char to force a flush. So, until you get the first two BUFSIZ chunks of data, you don't get anything written to less(1).
A simple, and efficient way is to check after fputc(c, out); if the char is a \n, and flush output with fflush(out); in that case, and so you'll write a line of output at a time.
fputc(c, out);
if (c == '\n') fflush(out);
If you don't do something, the buffering is made in BUFSIZ chunks, and normally, not before you have such an amount of data in the output side. And remember always to fclose() things (well, this is handled by stdio), or you can lose output in case your process gets interrupted.
IMHO the code you should use is:
while ((c = fgetc(input)) != EOF) {
fputc(c, output);
if (c == '\n') fflush(output);
}
fclose(input);
fclose(output);
for the best performance, while not blocking unnecessarily the output data in the buffer.
BTW, doing fread() and fwrite() of one char, is a waste of time and a way to complicate things a lot (and error prone). fwrite() of one char will not avoid the use of buffers, so you won't get more performance than using fputc(c, output);.
BTW(bis) if you want to do your own buffering, don't call stdio functions, just use read(2) and write(2) calls on normal system file descriptors. A good approach is:
int input_fd = fileno(input); /* input is your old FILE * given by popen() */
int output_fd = fileno(output);
while ((n = read(input_fd, your_buffer, sizeof your_buffer)) > 0) {
write(output_fd, your_buffer, n);
}
switch (n) {
case 0: /* we got EOF */
...
break;
default: /* we got an error */
fprintf(stderr, "error: read(): %s\n", strerror(errno));
...
break;
} /* switch */
but this will awaken your program only when the buffer is fully filled with data, or there's no more data.
If you want to feed your data to less(1) as soon as you have one line for less, then you can disable completely the input buffer with:
setbuf(input, NULL);
int c; /* int, never char, see manual page */
while((c == fgetc(input)) != EOF) {
putc(c, output);
if (c == '\n') fflush(output);
}
And you'll get less(1) working as soon as you have produced a single line of output text.
What are you exactly trying to do? (This would be nice to know, as you seem to be reinventing the cat(1) program, but with reduced functionality)
Simplest solution:
while (1) {
nmemb = fread(buff, 1, sizeof buff, input);
if (nmemb < 1) break;
fwrite(buff, 1, nmemb, output);
}
Similarly, for the getc() case:
while (1) {
c = getc(input);
if (c == EOF) break;
putc(c, output);
}
Replacing fgetc() by getc() will give performance equivalent to the fread()case. (getc() will (often) be a macro, avoiding function-call overhead). [just take a look at the generated assembly.
I have read about 5-10 different advices how to clear stdin, but none of them suits my needs. The thing is that fflush(stdin) worked perfectly at my computer, but unfortunately it doesn't seem to work everywhere, so I need something with the same functionality. Every other way I tried clears stdin when it is not empty but requires user input when stdin IS empty, which means it requires input in a moment I dont want to get any (+ it discards it anyway).
The question is: Can I somehow make sure, that stdin IS empty before I require user input? (and if not, THEN and only then clear it somehow?)
something like:
if (stdin is NOT empty)
while (getchar() != '\n')
continue;
EDIT: the thing is that I load characters from stdin one by one and at some point, a part of the input from previous iteration might or might not get discarded. either way, I need to have clear stdin before I ask the user for another input to be processed. Clearing the buffer itself is not such a big deal, the problem is what happens when the input is empty when the program gets to the point of clearing stdin, because in that moment the program needs another input which is going to be eaten by the clearing function. Thats what I want to get rid of. (when I could use fflush(stdin); I just knew, that for the next line of my program the stdin WILL be empty no matter what, no questions asked...)
How to clear stdin before getting new input?
.. so I need something with the same functionality.
With portable C this is not possible.
Instead suggest a different (and more usual C) paradigm:
Insure previous input functions consumes all the previous input.
fgets() (or *nix getline()) is the typical approach and solves most situations.
Or roll your own. The following reads an entire line, but does not save extra input.
int mygetline(char *buf, size_t size) {
assert(size > 0 && size <= INT_MAX);
size_t i = 0;
int ch;
while ((ch = fgetc(stdin)) != EOF) { // Read until EOF ...
if (i + 1 < size) {
buf[i++] = ch;
}
if (ch == '\n') { // ... or end of line
break;
}
}
buf[i] = '\0';
if (i == 0) {
return EOF;
}
return i;
}
From a similar question, Use poll() with fds.fd set to 0 (stdin), fds.events set to POLLIN, nfds set to 1, and timeout set to zero. After calling poll(), fds.revents will be set to zero if the buffer is empty, and to POLLIN otherwise.
struct pollfd fds = {0, POLLIN, 0};
poll(&fds, 1, 0);
if(fds.revents == POLLIN}
printf("stdin buffer is not empty");
This solution will work on posix-compliant systems, but not Windows. Use select() for portability.
TL;DR fflush(stdin) invokes undefined behavior as per the standard, you should never use it.
Coming to your code (logic), instead of looking for a newline, you can look for EOF. It does not have a prerequisite that stdin should have some input before running this loop.
Something like
while (getchar() != EOF); //; is not a mistake
should meet your needs.
Use only fgets() to read stdin.
Use a large enough buffer and/or test for full lines.
Using fgets() you never have to worry about extra characters in stdin.
// read characters until 'X'
while (((ch = getchar()) != EOF) && (ch != 'X')) putchar(ch);
// discard X and the rest of the line
fflush(stdin); // UB except for Windows
// read full line
char tmp[1000], *p;
if (!fgets(tmp, sizeof tmp, stdin)) /* deal with error */;
if (!*tmp) /* embedded NUL detected: input is not a text file */;
if (tmp[strlen(tmp) - 1] != '\n') /* partial line */;
p = tmp;
while (*p && *p != 'X') putchar(*p++);
// ignore the X and all the subsequent characters
The select module offers a function called select that achieves exactly what you're looking for. select.select takes three arguments:
select.select(rlist, wlist, xlist)
Each argument should be a list of file descriptors (such as [sys.sdtin]) and it then waits until a specific IO operation is available. The IO operations are read, write or some other exception on the given file descriptors. It returns a tuple of corresponding lists populated with the file descriptors that are ready.
So, if there is input waiting in sys.stdin then the function would behave like so:
>>> import select
>>> import sys
>>>
>>> select.select([sys.stdin], [], [])
([sys.stdin], [], [])
>>>
By itself, this doesn't solve your problem because by default the function will wait until an IO operation is available. Importantly, however, select.select has an optional timeout argument denoting how long it will wait before giving up. We simply have to set the timeout to zero and we can check for input without blocking the program flow.
Let's see an example where there is no input waiting in sys.stdin:
>>> import select
>>> import sys
>>>
>>> timeout = 0
>>> select.select([sys.stdin], [], [], timeout)
([], [], [])
>>>
Knowing that we only want the first element of that tuple (the input streams) we're ready to make a useful if statement:
if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
print('Input is waiting to be read.')
That means clearing the input stream just needs some iteration:
while sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
sys.stdin.readline()
And we can of course use this on any input stream, so lets put it in a function:
def clear_input(stream, timeout=0):
'''Takes an input stream and discards each line in the buffer.
The given timeout denotes how long in seconds to wait for
further input when none is available.
'''
while stream in select.select([stream], [], [], timeout)[0]:
stream.readline()
So let's demonstrate our function to achieve what you ask for in your question:
import select
import sys
import time
def clear_input(stream, timeout=0):
while stream in select.select([stream], [], [], timeout)[0]:
stream.readline()
if __name__ == '__main__':
print('Type some lines now. They will be ignored.')
time.sleep(5)
print('Clearing input.')
clear_input(sys.stdin)
user_input = raw_input('Please give some fresh input: ')
print(user_input)
The clear_input function can be used as a non-blocking way to clear input streams and should work in Python2 and Python3.
I am trying to detect the Ctrl+D user input, which I know returns EOF. Right now, I know the code waits for input from the stdin stream, but is there a way to let the program continue until the Ctrl+D command is in stdin? The program should continue running past the if statement if Ctrl+D isn't inputted.
char buffer[];
if (fgets(buffer, 10, stdin) == NULL{
//write to file
}
You want to stop your program when the user presses Ctrl+D without actually reading stdin? In this case, you should consider using Ctrl+C instead. But first I will write something about non-blocking I/O, since this is what you are asking for.
There is no way to achieve nonblocking I/O in standard C. However, you could use POSIX-functions like select or fcntl in combination with read. There are other questions about it on StackOverflow which should provide all information you need. This question for example.
If you want to handle Ctrl+C instead, you can use thesignal function:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
volatile bool shouldRun = true;
void sighandler(int) {
shouldRun = false;
}
int main(int argc, char *argv[]) {
if (signal(SIGINT, &sighandler) == SIG_ERR) {
fprintf(stderr, "Could not set signal handler\n");
return EXIT_FAILURE;
}
printf("Program started\n");
while (shouldRun) {
// Do something...
}
printf("Program is shutting down.\n");
return EXIT_SUCCESS;
}
Note that signal handlers (i.e. sighandler) might interrupt your thread at any moment. This means they are prone to race conditions. You must even avoid acquiring any locks within a signal handler. This means just calling printf within a signal handler can cause a deadlock. Just setting boolean flags as shown in the example is fine, though. There are solutions like signal masks and the self pipe trick to circumvent these limitations, but they should not be necessary here.
Since the machine generates EOF on Ctrl+D, you should be checking fgets() for NULL, as fgets() is obliged to return NULL on end of file.
line = fgets(l, BUFFSIZE, stdin)
if (line == NULL)
continue;
On most operating systems, stdin is buffered one line at a time, and any attempt to read it (without going into low-level nasties) will stop until either a line or EOF is available. If you don't mind this, and just want to check for EOF without reading-in any waiting input if EOF is not present, you could use ungetc:
#include <stdio.h>
int check_for_EOF() {
if (feof(stdin)) return 1;
int c = getc(stdin);
if (c == EOF) return 1;
ungetc(c, stdin);
}
int main() {
printf("Start typing:\n");
while (!check_for_EOF()) {
int bytes_typed = 0;
while (getchar() != '\n') bytes_typed++;
printf("You typed a line of %d bytes\n", bytes_typed);
}
printf("You typed EOF\n");
}
You are only guaranteed one character of push-back from ungetc, although most implementations give you much more. And it works only if you're not going to seek the stream later (which is the case with stdin). Notice also that I'm calling it "bytes typed", not "characters typed": Chinese, Japanese and Korean characters for example cannot fit into the char type of most C implementations, and it would depend how the console encodes them when you type (if you have a CJK input method set up or can copy/paste some, you can try it on the above program and see).
It is too much to post here and you are not specific what you have currently and what you want. So here gives you a general idea of how to do it:
Put that if statement inside a forked process or other thread
Send a posix signal to your (parent) process when the key is captured
Add signal handler in your program
If you just wanna terminate the program when C-d is entered, just send a SIGKILL in step 2 and ignore step 3.
If you do not know any term above, Google is your friend
I've included an example program using getchar() below, for reference (not that anyone probably needs it), and feel free to address concerns with it if you desire. But my question is:
What exactly is going on when the program calls getchar()?
Here is my understanding (please clarify or correct me):
When getchar is called, it checks the STDIN buffer to see if there is any input.
If there isn't any input, getchar sleeps.
Upon wake, getchar checks to see if there is any input, and if not, puts it self to sleep again.
Steps 2 and 3 repeat until there is input.
Once there is input (which by convention includes an 'EOF' at the end), getchar returns the first character of this input and does something to indicate that the next call to getchar should return the second letter from the same buffer? I'm not really sure what that is.
When there are no more characters left other than EOF, does getchar flush the buffer?
The terms I used are probably not quite correct.
#include <stdio.h>
int getLine(char buffer[], int maxChars);
#define MAX_LINE_LENGTH 80
int main(void){
char line[MAX_LINE_LENGTH];
int errorCode;
errorCode = getLine(line, sizeof(line));
if(errorCode == 1)
printf("Input exceeded maximum line length of %d characters.\n", MAX_LINE_LENGTH);
printf("%s\n", line);
return 0;
}
int getLine(char buffer[], int maxChars){
int c, i = 0;
while((c = getchar()) != EOF && c != '\n' && i < maxChars - 1)
buffer[i++] = c;
buffer[i++] = '\0';
if(i == maxChars)
return 1;
else
return 0;
}
Step 2-4 are slightly off.
If there is no input in the standard I/O buffer, getchar() calls a function to reload the buffer. On a Unix-like system, that normally ends up calling the read() system call, and the read() system call puts the process to sleep until there is input to be processed, or the kernel knows there will be no input to be processed (EOF). When the read returns, the code adjusts the data structures so that getchar() knows how much data is available. You description implies polling; the standard I/O system does not poll for input.
Step 5 uses the adjusted pointers to return the correct values.
There really isn't an EOF character; it is a state, not a character. Even though you type Control-D or Control-Z to indicate 'EOF', that character is not inserted into the input stream. In fact, those characters cause the system to flush any typed characters that are still waiting for 'line editing' operations (like backspace) to change them so that they are made available to the read() system call. If there are no such characters, then read() returns 0 as the number of available characters, which means EOF. Then getchar() returns the value EOF (usually -1 but guaranteed to be negative whereas valid characters are guaranteed to be non-negative (zero or positive)).
So basically, rather than polling, is it that hitting Return causes a certain I/O interrupt, and then when the OS receives this, it wakes up any processes that are sleeping for I/O?
Yes, hitting Return triggers interrupts and the OS kernel processes them and wakes up processes that are waiting for the data. The terminal driver is woken by the kernel when interrupt occurs, and decides what to do with the character(s) that were just received. They may be stashed for further processing (canonical mode) or made available immediately (raw mode), etc. Assuming, of course, that the input is a terminal; if the input is from a disk file, it is simpler in many ways — or if it is a pipe, or …
Nominally, it isn't the terminal app that gets woken by the interrupt; it is the kernel that wakes first, then the shell running in the terminal app that is woken because there's data for it to read, and only when there's output does the terminal app get woken.
I say 'nominally' because there's an outside chance that in fact the terminal app does mediate the I/O via a pty (pseudo-tty), but I think it happens at the kernel level and the terminal application is involved fairly late in the process. There's a huge disconnect really between the keyboard where you type and the display where what you type appears.
See also Canonical vs non-canonical terminal input.