in reply to Re: Re: IPC::Open3 and blocking filehandles
in thread IPC::Open3 and blocking filehandles

This is still dependant on bc having its output ready within .01 seconds. If the system were very busy or otherwise bogged down and could't meet this deadline, you'd miss a line of output, and then would be off by a line until the program restarted.
  • Comment on Re: Re: Re: IPC::Open3 and blocking filehandles

Replies are listed 'Best First'.
Re: Re: Re: Re: IPC::Open3 and blocking filehandles
by zentara (Cardinal) on Oct 19, 2003 at 13:37 UTC
    Thanks for pointing out those flaws, sgifford. I did modify my method, so it didn't need to use the delay with select. It waits in a loop until output is available. This will give multiline output from READ, but now I'm stumped by another problem. It seems the output buffer which bc writes to with IPC::Open3 is limited to 4060 bytes. I've tried alot of things, but no matter what I do, bc stops output at 4060 bytes, but will give full output if run by itself from the command line. Try 123^12345 ; which if run from the commandline will output about 16k, but when run from IPC::Open3 will clip at 4060 bytes.
    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; require 'sys/ioctl.ph'; #interface to "bc" calculator my $pid = open3(\*WRITE, \*READ,\*ERROR,"bc"); #if \*ERROR is false, STDERR is sent to STDOUT while(1){ my($error,$answer,$rsize,$esize)=('','',0,0); print "Enter expression for bc, i.e. 2 + 2\n"; chomp(my $query = <STDIN>); #send query to bc print WRITE "$query\n"; #timing delay needed tp let bc output #select(undef,undef,undef,.01); #this while loop waits and eliminates need for above delay #but is limited to 4060 bytes from bc do { #see which filehandles have output from perldoc -q filehandle $esize = pack("L", 0); ioctl(\*ERROR, FIONREAD(), $esize) or die "Couldn't call ioctl: +$!\n"; $esize = unpack("L", $esize); print "esize-> $esize\n" unless ($esize < 1); $rsize = pack("L", 0); ioctl(\*READ, FIONREAD(), $rsize) or die "Couldn't call ioctl: $ +!\n"; $rsize = unpack("L", $rsize); print "rsize-> $rsize\n" unless ($rsize <1); #get the output from bc if($esize > 0){sysread(ERROR,$error,$esize); print "\e[1;31m ERRO +R-> $error \e[0m \n"} if($rsize > 0){sysread(READ,$answer,$rsize); print "Output->$quer +y = $answer\n"} } until(($esize > 0)or($rsize > 0)); }
      Probably bc is doing multiple write's, each outputting a portion of the number. To get all the chunks and put them back together, you'll need to put the select and read in a loop. The tricky part is knowing when to terminate the loop. You'll have to figure out some way to know when bc's done writing the number. I'm not sure what the exact output format is, but at a quick glance it looks like output ends at a newline that's not preceded by a backslash. That's a little tricky to scan for, especially if the backslash comes on one read and the escaped newline on the next, but I don't see any easier options.