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

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)); }

Replies are listed 'Best First'.
Re: Re: Re: Re: Re: IPC::Open3 and blocking filehandles
by sgifford (Prior) on Oct 20, 2003 at 05:31 UTC
    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.