Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I clear EOF on stdin ($*IN) after gettig it with get / prompt in Raku?

In my program, I'd like to read a line from $*IN in a loop, and for this I can use either get or prompt; however, I noticed that if I end my input immediately with EOF (e.g., with Ctrl-D in Linux / MacOS) then any subsequent uses of get or prompt for reading another line from $*IN will cause it to return Nil, meaning it still gets EOF from $*IN.

Example:

dd get;
dd get;

with an immediate EOF (ctrl-d), the program ends and outputs two Nil's.

This problem doesn't happen if something is entered other than just a EOF.

Curiously, this problem also doesn't happen with slurp. I.e.,

dd slurp;
dd slurp;

After the first ctrl-d, "" is printed by the first dd and then it waits for input due to the second slurp.

I think this is also them same problem with - https://github.com/rakudo/rakudo/issues/4196

like image 417
cowbaymoo Avatar asked Apr 05 '21 05:04

cowbaymoo


People also ask

Is there a way to flush the input buffer in stdin?

It seemes like stdin does not have any EOF set, it only requires another input when the end is reached. At least at windows you need to explicitly generate EOF for stdio with Ctrl+Z. Er, no. Your loop waits until the user generates an EOF ( ^D or ^Z ), while the OP asked for a way to flush the input buffer.

How do I trigger EOF in a program?

You can generally "trigger EOF" in a program running in a terminal with a CTRL + D keystroke right after the last input flush. What does EOF mean? How can I trigger it? EOF means End-Of-File. "Triggering EOF" in this case roughly means "making the program aware that no more input will be sent".

Why C = getchar() does not return EOF in Linux?

Yes, exactly right, because in /dev/null there is no actual character to be read , hence it c = getchar() will return -1 code, and program will quit right away. Again command doesn't return EOF. EOF is just constant variable equal to -1 , which we use to compare return code of getchar function.

How to check if stdin has some input before running?

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. should meet your needs. while (getchar () != EOF); sets me in an infinite loop requiring another and another input.


1 Answers

According to this Perl 5 answer, you can reopen STDIN after receiving an EOF by opening /dev/tty:

use v6;
print "Input line: ";
my $line = get;
if ($line === Any) {
    say "got EOF..";
    say "Reopening STDIN..";
    my $fh = open "/dev/tty", :r, chomp => $*IN.chomp, nl-in => $*IN.nl-in,
        encoding => $*IN.encoding;
    print "Enter new line: ";
    my $line = $fh.get();
    say "Got line: {$line}";
}
else {
    say "Not EOF, got line: {$line}";
}

the above works, but I am not sure how to reassign the reopened STDIN handle to $*IN..

I tried the following:

$*IN = IO::Handle.new(path => IO::Path.new("/dev/tty"), :r,
                        chomp => $*IN.chomp, nl-in => $*IN.nl-in,
                        encoding => $*IN.encoding);

but it did not reopen $*IN..

Edit

I also tried:

print "Input line: ";
my $line = get;
if ($line === Any) {
    say "got EOF..";
    say "Reopening STDIN..";
    $*IN.close;
    $*IN = open "/dev/tty", :r, chomp => $*IN.chomp, nl-in => $*IN.nl-in,
        encoding => $*IN.encoding;
    my $line = get;
    say "Got line: {$line}";
}
else {
    say "Not EOF, got line: {$line}";
}

but it did not work:

Input line: got EOF..
Reopening STDIN..
Cannot do 'get' on a handle in binary mode
  in block <unit> at ./11.raku line 12

Edit 2

I think I found the problem, in the above script you have to use my $line = $*IN.get instead of my $line = get (I am not sure why, looks like it could be a bug)

like image 139
Håkon Hægland Avatar answered Oct 18 '22 03:10

Håkon Hægland