+sub filter_st_isok ($) {
+ my ($ch) = @_;
+ my $st = $ch->{St};
+ return !$st || $ch->{SigOK}{($st & ~128)};
+}
+
+sub processpcfgz ($$$$) {
+ my ($inpcfgz,$outpcfgz,$logfile,$what) = @_;
+ print $reportfh "processing $inpcfgz to $outpcfgz\n" if $verbose>=2;
+ my $current = new IO::File $inpcfgz, '<' or die "$inpcfgz $!";
+ my ($usread,$uswrite);
+ my ($reader,$writer);
+ my @children;
+ my %ch;
+ foreach my $proc (['gunzip'], ['pcf2bdf'], [],
+ ['bdftopcf'],['',qw(gzip -1 -n)]) {
+ my $isfinal = (@$proc && $proc->[0] eq '');
+ if (!$isfinal) {
+ $reader = new IO::Handle or die $!;
+ $writer = new IO::Handle or die $!;
+ new IO::Pipe($reader,$writer) or die $!;
+ } else {
+ shift @$proc;
+ $reader = undef;
+ $writer = new IO::File $outpcfgz, '>' or die "$outpcfgz $!";
+ }
+ if (@$proc) {
+ my $exe = $proc->[0];
+ my $child = fork; defined $child or die $!;
+ if (!$child) {
+ open STDIN, '<&', $current or die $!;
+ open STDOUT, '>&', $writer or die $!;
+ if (!$isfinal) {
+ close $reader or die $!;
+ }
+ close $usread or die $! if $usread;
+ close $uswrite or die $! if $uswrite;
+ exec $exe @$proc or die "$exe $!";
+ }
+ my $ch = {
+ Pid => $child,
+ Exe => $exe,
+ Stage => (!$exe ? 'self' : defined $usread ? 'out' : 'in'),
+ SigOK => { },
+ };
+ push @children, $ch;
+ $ch{$exe} = $ch;
+ close $current or die $!;
+ close $writer or die $!;
+ $current = $reader;
+ } else {
+ $usread = $current;
+ $uswrite = $writer;
+ $current = $reader;
+ }
+ }
+ my $r = processbdf($usread,$uswrite,$logfile,$what);
+ my $none = $r !~ m/^\d/;
+
+ $ch{'gunzip'}{SigOK}{13} = 1;
+ # ... we never care if pcf2bdf didn't want all the output from gunzip
+
+ if ($none || !$r) {
+ # We're not going to install or use this so we can kill our
+ # input and output filters. We kill the input filters so that
+ # we don't risk waiting for them. (If the input filter died
+ # for some other reason then sending it a KILL now won't
+ # affect its exit status.) We kill the output filters (before
+ # we close the output pipe) so we don't produce messages from
+ # our output filters about corrupted data.
+ flush $uswrite or die $!;
+
+ foreach my $ch (@children) {
+ if ($ch->{Stage} ne 'self') {
+ kill 9, $ch->{Pid} or die "$ch->{Pid} $ch->{Exe} $!";
+ $ch->{SigOK}{9} = 1;
+ }
+ }
+ $ch{'pcf2bdf'}{SigOK}{13} = 1;
+ # ... we might not have read all the output from pcf2bdf, which is OK
+ }
+ close $uswrite or die $!;
+ close $usread or die $!;
+
+ foreach my $ch (@children) {
+ $!=0; waitpid($ch->{Pid}, 0) == $ch->{Pid} or
+ die "$ch->{Pid} $ch->{Exe} $!";
+ $ch->{St} = $?;
+ }
+
+ if ($tolerate_bad_fonts &&
+ $r eq 'no bdf data' &&
+ filter_st_isok($ch{'gunzip'}) &&
+ ($ch{'pcf2bdf'}{St} & ~128) == 6)
+ {
+ $r = "pcf2bdf failed ($ch{'pcf2bdf'}{St})";
+ print STDERR "warning: $r: skipping $inpcfgz\n";
+ $ch{'pcf2bdf'}{SigOK}{6} = 1;
+ }
+ foreach my $ch (@children) {
+ if (!filter_st_isok($ch)) {
+ die "update-xfonts-traditional:".
+ " $ch->{Exe} [$ch->{Pid}] for $inpcfgz".
+ " failed $ch->{St}".
+ " (".(join ' ', keys %{ $ch->{SigOK} })." ok)\n";
+ }
+ }
+ return $r;
+}