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));
}
| [reply] [d/l] |
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.
| [reply] [d/l] [select] |