0

When you read from stdin using getchar, fgets or some similar function, if you type some text and then put an eof (control+d in linux) you cannot delete the previous text. For example, if I type 'program' and then enter eof by pressing control+d, I can't delete what I typed before, i.e. program.

#include<string.h>
#include<stdlib.h>

int main() {

    char buffer[1024] = "";
    printf("> ");
    if(fgets(buffer,sizeof(buffer),stdin) == NULL){
        puts("eof");
    }
    else{
        puts(buffer);
    }

    return 0;
}

How can this be avoided?

Kevin Martins
  • 590
  • 7
  • 20
theriver
  • 325
  • 2
  • 9
  • By discarding the previous string? Usually, signalling the end of input does not mean "delete what I previously typed". I don't really understand what you are asking. – Weather Vane Jun 08 '19 at 19:09
  • 4
    Pressing control-D in Linux does not signal EOF. It actually means “Complete the current read operation.” At that point, if characters have been typed, they are immediately sent to the program, whereas the system would usually wait until Enter is pressed. If no characters have been typed, the read operation completes with zero characters read, which some I/O routines treat as an EOF, and that is why programs may seem to receive an EOF when control-D is pressed at the start of a line of input. Since the data is sent to the program, of course there is no way to undo it—it has already been sent. – Eric Postpischil Jun 08 '19 at 19:11
  • 1
    There are ways to change the default behavior of the terminal. But why do you want to do this? If you merely want to change how your program behaves, there may be better solutions. – Eric Postpischil Jun 08 '19 at 19:12
  • @WeatherVane Why can't I delete the text I type after pressing control+D? – theriver Jun 08 '19 at 19:12
  • @theriver That's like asking why you cannot edit an sms after you sent it. – klutt Jun 08 '19 at 19:13
  • What did you try? If the text was already entered, then simply forget it. If, as in the program, you have already printed it, then you need to change the strategy. – Weather Vane Jun 08 '19 at 19:14
  • @Broman but you can edit a message of telegram right? Well, there's got to be some way to do it. – theriver Jun 08 '19 at 19:21
  • 1
    Exactly why do you want to do this? I'm sorry, but I cannot see any reason to do so. Sounds like an XY-problem. – klutt Jun 08 '19 at 19:25
  • Related: https://stackoverflow.com/questions/52794780/using-fgets-with-stdin-as-input-d-fails-to-signal-eof – S.S. Anne Jun 08 '19 at 19:49
  • See [Canonical and non-canonical terminal input](https://stackoverflow.com/questions/358342/canonical-vs-non-canonical-terminal-input) – Jonathan Leffler Jun 08 '19 at 21:33

3 Answers3

2

The readline function of The GNU Readline Library I think is my best option to do the job. It's pretty simple to use but it uses dynamic memory to host the string so you have to use the free function to free up the memory. You can find more information by opening a terminal and typing 'man readline'.
The code would look like this:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <readline/readline.h>

int main() {

    char *ptr = readline("> ");
    if(!ptr){
        puts("eof");
    }
    else{
        puts(ptr);
    }
    free(ptr);

    return 0;
}

To be able to use readline with gcc you must pass it -lreadline

theriver
  • 325
  • 2
  • 9
1

When fgets reads a line, what will happen is that it will read characters from the specified stream until it encounters a '\n' or EOF, until it has read the specified maximum size to read or a read error occurs. It does not see what you are doing on your keyboard at all. It only sees the stream, but it is the terminal that sends the data to the stream.

What's happening when you are editing the input has absolutely nothing to do with fgets. That's the terminals job.

As Eric Postpischil wrote in the comments:

Pressing control-D in Linux does not signal EOF. It actually means “Complete the current read operation.” At that point, if characters have been typed, they are immediately sent to the program, whereas the system would usually wait until Enter is pressed. If no characters have been typed, the read operation completes with zero characters read, which some I/O routines treat as an EOF, and that is why programs may seem to receive an EOF when control-D is pressed at the start of a line of input. Since the data is sent to the program, of course there is no way to undo it—it has already been sent.

I guess there is some way to alter the behavior of pressing C-d, but then you need to decide what it should do instead. If you want it to do "nothing" instead of sending the data to stdin I cannot really see what you have won. The only use case I can see with this is if you for some reason are having a problem with accidentally pressing C-d from time to time.

One thing you could do is to take complete control of every keystroke. Then you would have to write code to move the cursor every time the user presses a key, and also write code to remove characters when the user is pressing backspace. You can use a library like ncurses for this.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
klutt
  • 30,332
  • 17
  • 55
  • 95
  • The readline function (man readline) of The GNU Readline Library I think is my best option to do the job. – theriver Jun 08 '19 at 20:34
  • 1
    @theriver I tried it out and it works. You should add your own answer with that. Supply some example code. But do also write in your question WHY you want to do this. As the question is now, it looks like you want to do it for the lulz, and such questions tend to get downvoted. – klutt Jun 08 '19 at 20:43
0

It can't be avoided. Simply put, Ctrl+D ends the current read operation.

If you want to ignore this, make your own fgets based on fgetc and have it ignore end-of-file.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76