sid_com
sid_com

Reputation: 25117

Term::ReadKey, "Strg+D" and STDIN

When I type after Enter a string: for example a, b, c and then two times Ctrl+D I get an endless loop which doesn't halt on ReadKey and which I can not stop with the Q key?

#!/usr/bin/env perl
use warnings;
use 5.10.1;
use Term::ReadKey;

while( 1 ) {
    my $c;
    say "Press the \"q\" key to quit.";
    print "Press the \"e\" key to enter a string: ";
    {
        $|++;
        Term::ReadKey::ReadMode 'ultra-raw';
        $c = ReadKey 0;
        Term::ReadKey::ReadMode 'restore';        
    }
    exit if ord( $c ) == 3; # Control C
    last if $c eq 'q'; 
    if ( $c eq 'e' ) {
        print "\nEnter a string: ";
        my $string = <>;
        if ( not defined $string ) {
            say "Undefined";
        }
        else {
            chomp $string;
            say "You entered |$string|";
        }
    }
    say "Still running";
}

Upvotes: 1

Views: 536

Answers (2)

amon
amon

Reputation: 57640

After you type the two Ctrl-D (EOT), your programm will only receive NUL-bytes. And an infinity of them. Unfortunately you have an unconditional read in an infinite loop. Either you change that (e.g. give the user a lesson if he types something other than q or e and exit if he didn't get it after the third try), or you implement control characters correctly. Your module strips all control characters from the input before you even get it, but it provides the neccessary hooks. I urge you to add Ctrl-C as well (it only works when a line is expected, not when a char is being read).

Also, why not compare the input characters with string equality? $c eq "q" reads nicer.

Upvotes: 2

Unk
Unk

Reputation: 1103

The only line that will terminate your loop is this one:

last if ord( $c ) == 113;

So, the only way to escape the loop is to enter 'q' when the prompt asks you to enter 'e'.

Presumably you want an appropriately placed last inside your if statement, so that ctrl-d and/or any text will terminate.

Upvotes: 0

Related Questions