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
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.
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".
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.
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With