• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 152
  • Last Modified:

parsing input from endless input?

Im making a perl program that is running as a subprogram of something else,
the stdin and stdout for this perl program are directed towards the perl's parent program. So stdin/out is actually coming from the parent.

The problem is is that I need to get a bunch of lines of input and then process them, but the way the system is set up, I can't do "@all = <STDIN>" because the stdin never has an EOF signal, if I DO do it, it will just wait for ever thinking more input will be coming...

Is there a way to read in until the program isn't being passed anything more, that is, check that stdin isn't returning anything more.

I would like to know because, the input that comes in could vary in length, so I can't just read in 'X' times and stop.


Thanks
0
ServerOverflow
Asked:
ServerOverflow
  • 3
  • 2
  • 2
  • +4
1 Solution
 
ServerOverflowAuthor Commented:
Perhaps is there a way to read stdin and then if nothing happens after (say 5 seconds) stop reading?
0
 
wilcoxonCommented:
You should be able to use $SIG{ALARM} to break out of reading from <IN>.  You should be able to find more info in perldoc (or on perldoc.com) or in Programming Perl.
0
 
blinkie23Commented:
try this.  this script will exit after 5 seconds if no input is received on STDIN.  if input is received, it will exit if no input is received for 2 seconds at any point.  the 2 second timer restarts each time input is received.  modify it to your liking.

#!/usr/bin/perl

$SIG{ALRM} = sub { break; };

alarm 5;
while(<STDIN>){
    alarm 2;
    print;
}
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
ServerOverflowAuthor Commented:
Hmmm ok, blinkie that stops just like you said, very nice, but how can I get it to just exit the loop and continue on with the rest of the code?

right now it exits the program and I've tried changing the SIGALRM line to last, but no matter what it just exits... very annoying...


Thanks...
0
 
blinkie23Commented:
that is annoying... but if i put code after my while statement, it executes it normally for either alarm signal that is caught.  i'm not sure why it works for me, and not you.  i am on a unix platform, maybe you're on a windows one?  ... can you troubleshoot the problem out more?  confirm that both the breaks exit the program, or just one of the breaks cause an exit.
0
 
mikezoneCommented:

Perhaps this:

  #! /usr/bin/perl

  my @processed_data;
  my @unprocessed_data;

  $SIG{ ALRM } = sub {
    process_data();
    alarm( 2 );
  };

  alarm( 2 );
  while( <STDIN> ) {
    push @unprocessed_data, $_;
  }

  sub process_data {
    @processed_data = (); # Remove this line if you don't want incremental processing.
    foreach (@unprocessed_data) {
      my $processed_data = "> $_";
      push @processed_data, $processed_data;
    }
    @unprocessed_data = ();

    # ===== DO SOMETHING WITH PROCESSED DATA
    open FILE, ">>processed.txt";
    print FILE @processed_data;
    close FILE;
  }

What this does:

The alarm is set just before the program gets into the while loop and starts reading data and sending it to a stack (@unprocessed_data), which holds the data for processing. When the alarm goes off, the program's flow of control switches to the alarm handler, which processes the data, and transfers the processed data to another stack. It also empties the unprocessed data stack. The neat part is that the signal handler resets the alarm, so it will happen in timely increments.

To do what you mentioned that you wanted to do, you might try to set a flag:

  #! /usr/bin/perl

  my $exit = undef;
  $SIG{ ALRM } = sub { $exit = 1 };

  alarm( 5 );
  while( <STDIN> && ! $exit ) {
    print;
  }

It may be that the last() is confused about what scoping it's in. Labels may fix this, but flags are, IMHO, more readable.

  #! /usr/bin/perl

  $SIG{ ALRM } = sub { last INPUT_LOOP; }

  INPUT_LOOP: while( <STDIN> ) {
    print;
  }

Hope this helps,

- m.
0
 
perldorkCommented:
You could also try using eval to do the equivalent of a try/catch:


eval {
    alarm(3);
    $SIG{ALRM} = sub { die "timeout\n" };

    while(1) {
        print "hi\n";
        sleep(2);
    }
};

if ($@ =~ /timeout/) {
    print "Timed out!\n";
} else {
    die $@;
}

0
 
perldorkCommented:
Sorry .. should have been this:

$|++;

eval {
    alarm(3);
    $SIG{ALRM} = sub { die "timeout\n" };

    while(1) {
        print "hi\n";
        sleep(2);
    }
};

if ($@ =~ /timeout/) {
    print "Timed out!\n";
} elsif (defined $@) {
    die $@;
}
0
 
ItatsumakiCommented:
The solutions posted above are pretty good.  Just as a dumb question: any reason why the parent program can't pass in some indicator that it's done giving data?  That would be a bit cleaner than waiting a certain number of seconds, I think.

Just an idea,
Tats
0
 
kblack05Commented:
Use next instead of die.
if ($@ =~ /timeout/) {
   print "Timed out!\n";
} elsif (defined $@) {
   next "";
}


~Kelly W. Black
0
 
ServerOverflowAuthor Commented:
Ok thanks guys, all of them were good,
blinkie was the first to answer and that worked after putting the whole thing inside an eval{} expression so im giving it to him ;)


btw. I didnt make the parent program and I dont have source code so I can't change the way it sends its children messages, pretty lame I know, gotta love programmers that don't think ahead...


Thanks to EVERYONE!
0

Featured Post

Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

  • 3
  • 2
  • 2
  • +4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now