http://qs321.pair.com?node_id=282322

ajdelore has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to find a way to do time-limited input of a list of words. Basically:

use strict; print "Prompt: "; my $end = time() + 10; my $input; while ($end > time()) { $input .= <STDIN>; } my @words = split /\s+/, $input; print "$_\n" foreach @words;

This works OK. If I press enter after every word, once I am over the time limit it stops taking input. However, I do not want to rely on the user pressing enter.

What I think would work is to set $/ to whitespace. I tried using $/ = '\s'; with no luck -- \s is for regexes, IIRC.

Obviously, a user could sit in the middle of a word for as long as they want, but for my purposes that is OK. As long as whitespace is the separator, they can't cheat by entering 100 words on the same line before pressing enter.

Although, if monks have any ideas about how to stop input at 10 seconds regardless of wether the user was in the middle of a word or not, I'd love to hear them.

</ajdelore>

Replies are listed 'Best First'.
Re: Time-limited input on STDIN
by adrianh (Chancellor) on Aug 08, 2003 at 22:20 UTC

    Something like:

    use strict; use warnings; use Term::ReadKey; sub timed_input { my $end_time = time + shift; my $string; do { my $key = ReadKey(1); $string .= $key if defined $key; } while (time < $end_time); return $string }; my @words = split ' ', timed_input(10);

    should do the job.

      Hi Adrian,

      Just wanted to say thanks. Although it was not my query originally, I found your method worked in the situation I needed, whereas the other methods utilising SIG don't seem to work under ActivePerl on Windows.

      Just one tweak: a line before the return to prevent it complaining about uninitialised values:

      $string= defined $string ? $string : "No input" ;

      Thanks again. :)

Re: Time-limited input on STDIN
by jamesduncan (Novice) on Aug 08, 2003 at 22:33 UTC
    I may be reading the problem wrong, but you could try using alarm and $SIG{ALRM} inside an eval block.
    #!/usr/bin/perl use strict; use warnings; my $text; print "Prompt: "; alarm(10); eval { local $SIG{ALRM} = sub { die }; $text = <STDIN>; }; print "done accepting text\n";
    James.

      You should use alarm(0) after the entry of data to turn off the alarm. Ottherwise, your program will be alarm'd even though you entered text in the allowed amount of time. See perldoc -f alarm for details.

      --Bob Niederman, http://bob-n.com

      Thanks, this worked great. ++ to jamesduncan and bobn.

      One minor note: I did have to set local $/ = undef; within the eval block -- otherwise, it was finishing as soon as I pressed enter after a word.

      </ajdelore>

Use POE, was Re: Time-limited input on STDIN
by RMGir (Prior) on Aug 09, 2003 at 09:51 UTC
    It probably looks like overkill for your project, but you should consider looking into POE.

    It would allow you to completely separate your timeout rules from your input processing.

    There's a decent introduction to POE available. Matt Sergeant wrote up a good tutorial as well. (All of these are from the recent Documentation for POE? thread.)

    I only started looking at POE this week, and I'm REALLY impressed with how easy it makes many things.


    --
    Mike