10

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

cowbaymoo
  • 1,202
  • 5
  • 14

1 Answers1

5

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)

Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174
  • Thanks for trying. This is definitely a bug of Rakudo. – cowbaymoo Apr 11 '21 at 21:05
  • 1
    Assigning a handle to `$*IN` won't automatically open it for you. Open the handle, or do e.g. `$*IN = $fh` – ugexe Apr 12 '21 at 15:31
  • @ugexe Unfortunately that does not work either. Assigning `$*IN = $fh` makes `get()` throw `Cannot do 'get' on a handle in binary mode` even if its `encoding` parameter shows `utf8`. [Here](https://pastebin.com/TxQ881Kx) is a link to the code I used. – Håkon Hægland Apr 12 '21 at 16:28
  • For me `$*IN = $fh` works on your example until I do a second cntrl+d – ugexe Apr 12 '21 at 17:59
  • @ugexe *"For me $*IN = $fh works on your example until I do a second cntrl+d"* Strange, [here](https://pastebin.com/FXTziZgQ) is the output I get (running [this](https://pastebin.com/TxQ881Kx) script). The only input I give is CTRL-D on the first prompt. – Håkon Hægland Apr 15 '21 at 10:49