diff options
Diffstat (limited to 'font/devpdf/util')
-rw-r--r-- | font/devpdf/util/BuildFoundries.pl | 578 |
1 files changed, 578 insertions, 0 deletions
diff --git a/font/devpdf/util/BuildFoundries.pl b/font/devpdf/util/BuildFoundries.pl new file mode 100644 index 0000000..2815c37 --- /dev/null +++ b/font/devpdf/util/BuildFoundries.pl @@ -0,0 +1,578 @@ +#!/usr/bin/perl +# +# BuildFoundries: Given a Foundry file, generate groff font description +# files and a "download" file so gropdf can embed fonts in PDF output. +# +# Copyright (C) 2011-2020 Free Software Foundation, Inc. +# Written by Deri James <deri@chuzzlewit.myzen.co.uk> +# +# This file is part of groff. +# +# groff is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# groff is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +use strict; +use Getopt::Long; +use warnings; + +my $pathsep='@PATH_SEPARATOR@'; + +my $check=0; +my $dirURW=''; +my $beStrict=0; + +GetOptions("check" => \$check, "dirURW=s" => \$dirURW, + "strict" => \$beStrict); + +(my $progname = $0) =~s @.*/@@; +my $where=shift||''; +my @d=(split(':',shift||'../devps')); +my $devps=\@d; +chdir $where if $where ne ''; +my (%flg,@downloadpreamble,%download); +my $GSpath=FindGSpath(); +my $lct=0; +my $foundry=''; # the default foundry +my $notFoundFont=0; + +if ($check) +{ + CheckFoundry("Foundry.in"); + exit $notFoundFont; +} +else +{ + LoadDownload("download"); # not required + LoadFoundry("Foundry"); + WriteDownload(); +} +exit 0; + + + +sub LoadFoundry +{ + my $fn=shift; + my $foundrypath; + $notFoundFont=0; + + open(F,"<$fn") or Die("file '$fn' not found or not readable"); + + while (<F>) + { + chomp; + $lct++; + s/\r$//; # in case edited in windows + + s/\s*#.*?$//; # remove comments + + next if $_ eq ''; + + if (m/^[A-Za-z]=/) + { + my (@f)=split('='); + $flg{$f[0]}=$f[1]; + next; + } + + my (@r)=split('\|'); + + if (lc($r[0]) eq 'foundry') + { + Warn("\nThe path(s) used for searching:\n".join(':',@{$foundrypath})."\n") if $notFoundFont; + $foundry=uc($r[1]); + $foundrypath=[]; + push(@{$foundrypath},$dirURW) if $dirURW; + push(@{$foundrypath},(split(':',$r[2])),@{$devps}); + foreach my $j (0..$#{$foundrypath}) + { + if (defined($foundrypath->[$j]) + && $foundrypath->[$j]=~m'\s*\(gs\)') + { + splice(@{$foundrypath},$j,1,@{$GSpath}); + } + } + $notFoundFont=0; + } + else + { + # 0=groff font name + # 1=IsBase Y/N (one of PDFs 14 base fonts) + # 2=afmtodit flag + # 3=map file + # 4=encoding file + # 5=font file + + my $gfont=($foundry eq '')?$r[0]:"$foundry-$r[0]"; + + if ($r[2] eq '') + { + # Don't run afmtodit; just copy the groff font + # description file for grops. + my $gotf=1; + my $gropsfnt=LocateFile($devps,$r[0],0); + if ($gropsfnt ne '' and -r "$gropsfnt") + { + my $psfont=UseGropsVersion($gropsfnt); + # To be embeddable in PDF, the font file name itself + # needs to be located and written to "download". + if (!PutDownload($psfont, + LocatePF($foundrypath,$r[5]), + uc($r[1]))) + { + if (uc($r[1]) ne 'Y') + { + $gotf=0; + my $fns=join(', ',split('!',$r[5])); + Warn("groff font '$gfont' will not be" + . " available for PDF output; unable" + . " to locate font file(s): $fns"); + $notFoundFont=1; + unlink $gfont; + } + } + Notice("copied grops font $gfont") if $gotf; + + } + else + { + Warn("Can't read grops font '$r[0]' for Foundry '$foundry'"); + } + } + else + { + # Use afmtodit to create a groff font description file. + my $afmfile=LocateAF($foundrypath,$r[5]); + if (!$afmfile) { + my $sub=\&Warn; + $sub=\&Die if ($beStrict); + &$sub("cannot locate AFM file for font '$gfont'"); + next; + } + my $psfont=RunAfmtodit($gfont,$afmfile,$r[2],$r[3],$r[4]); + + if ($psfont) + { + if (!PutDownload($psfont,LocatePF($foundrypath,$r[5]),uc($r[1]))) + { + unlink $gfont; # Unable to find the postscript file for the font just created by afmtodit + } + else + { + Notice("generated $gfont"); + } + } + else + { + Warn("Failed to create groff font '$gfont' by running afmtodit"); + $notFoundFont=1; + } + } + } + } + + close(F); + Warn("\nThe path(s) used for searching:\n".join(':',@{$foundrypath})."\n") if $notFoundFont; +} + +sub RunAfmtodit +{ + my $gfont=shift; + my $afmfile=shift; + my $flags=shift; + my $map=shift||''; + my $enc=shift||''; + my $psfont=''; + + $enc="-e 'enc/$enc'" if $enc; + $map="'map/$map'" if $map; + + my $cmd='afmtodit -c -dDESC'; + + foreach my $f (split('',$flags)) + { + if (!exists($flg{$f})) + { + Warn("Can't use undefined flag '$f' in calling afmtodit for groff font '$gfont'"); + return(''); + } + + $cmd.=" $flg{$f}"; + } + + system("$cmd $enc '$afmfile' $map $gfont"); + + if ($?) + { + unlink $gfont; + return(''); + } + + if (open(GF,"<$gfont")) + { + my (@gf)=(<GF>); + my @ps=grep(/^internalname /,@gf); + if ($#ps == 0) # Just 1 match + { + (undef,$psfont)=split(' ',$ps[0],2); + chomp($psfont); + } + else + { + Warn("Unexpected format for grops font '$gfont' for Foundry '$foundry' - ignoring"); + } + + close(GF); + } + + return($psfont); +} + +sub LocateAF +{ + my $path=shift; + my $file=shift; + + return(LocateFile($path,$file,1)); +} + +sub LocatePF +{ + my $path=shift; + my $file=shift; + + return(LocateFile($path,$file,0)); +} + +sub LocateFile +{ + my $path=shift; + my $files=shift; + my $tryafm=shift; + return(substr($files,1)) if substr($files,0,1) eq '*'; + + foreach my $p (@{$path}) + { + next if !defined($p) or $p eq ';' or $p eq ':'; + $p=~s/^\s+//; + $p=~s/\s+$//; + $p=~s@/+$@@; + + next if $p=~m/^\%rom\%/; # exclude %rom% paths (from (gs)) + + foreach my $file (reverse(split('!',$files))) + { + if ($tryafm) + { + if (!($file=~s/\..+$/.afm/)) + { + # no extenaion + $file.='.afm'; + } + } + + if ($file=~m'/') + { + # path given with file name so no need to search the paths + + if (-r $file) + { + return($file); + } + + if ($tryafm and $file=~s'type1/'afm/'i) + { + if (-r "$file") + { + return($file); + } + } + + return(''); + } + + if ($path eq '(tex)') + { + my $res=`kpsewhich $file`; + return '' if $?; + chomp($res); + return($res); + } + + if (-r "$p/$file") + { + return("$p/$file"); + } + + my $ap=$p; + + if ($tryafm and $ap=~s'type1/'afm/'i) + { + if (-r "$ap/$file") + { + return("$ap/$file"); + } + } + } + } + + return(''); +} + +sub FindGSpath +{ + my (@res)=`@GHOSTSCRIPT@ -h 2>/dev/null`; + return [] if $?; + my $buildpath=[]; + my $stg=1; + + foreach my $l (@res) + { + chomp($l); + + if ($stg==1 and $l=~m/^Search path:/) + { + $stg=2; + } + elsif ($stg == 2) + { + if (substr($l,0,1) ne ' ') + { + $stg=3; + } + else + { + $l=~s/^\s+//; + $pathsep=';' if substr($l,-1) eq ';'; + push(@{$buildpath},(split("$pathsep",$l))); + } + } + } + + return($buildpath); +} + +sub UseGropsVersion +{ + my $gfont=shift; + my $psfont=''; + my (@gfa)=split('/',$gfont); + my $gfontbase=pop(@gfa); + + if (open(GF,"<$gfont")) + { + my (@gf)=(<GF>); + my @ps=grep(/^internalname /,@gf); + if ($#ps == 0) # Just 1 match + { + (undef,$psfont)=split(' ',$ps[0],2); + chomp($psfont); + } + else + { + Warn("Unexpected format for grops font '$gfont' for Foundry '$foundry' - ignoring"); + } + + close(GF); + + if ($psfont) + { + if (open(GF,">$gfontbase")) + { + local $"=''; + print GF "@gf"; + close(GF); + } + else + { + $psfont=''; + Warn("Failed to create new font '$gfont' for Foundry '$foundry'"); + } + } + else + { + Warn("Failed to locate postscript internalname in grops font '$gfont' for Foundry '$foundry'"); + } + + close(GF); + } + else + { + Warn("Failed to open grops font '$gfont' for Foundry '$foundry'"); + } + + return($psfont); +} + +sub PutDownload +{ + my $psfont=shift; + my $pffile=shift; + my $IsBase14=shift; + my $key="$foundry $psfont"; + + delete($download{$key}), return 0 if ($pffile eq ''); + + $pffile='*'.$pffile if $IsBase14 eq 'Y'; # This signals to gropdf to only edmbed if -e given + $download{$key}=$pffile; + + return 1; +} + +sub LoadDownload +{ + my $fn=shift; + + return if !open(F,"<$fn"); + + while (<F>) + { + chomp; + s/\r$//; # in case edited in windows + + if (substr($_,0,1) eq '#' or $_ eq '') + { + # Preserve comments at top of download file + + push(@downloadpreamble,$_); + next; + } + + s/\s*#.*?$//; # remove comments + + next if $_ eq ''; + + my (@r)=split(/\t+/); + my $key=$r[1]; + $key="$r[0] $r[1]"; + $download{$key}=$r[2]; + } + + close(F); +} + +sub WriteDownload +{ + print join("\n",@downloadpreamble),"\n"; + + foreach my $k (sort keys %download) + { + my ($f,$ps)=split(/ /,$k); + print "$f\t$ps\t$download{$k}\n"; + } +} + +sub Notice { + my $msg=shift; + Msg("notice: $msg"); +} + +sub Warn { + my $msg=shift; + Msg("warning: line $lct: $msg"); +} + +sub Die { + my $msg=shift; + Msg("error: $msg"); + exit 2; +} + +sub Msg { + my $msg=shift; + print STDERR "$progname: $msg\n"; +} + +sub CheckFoundry +{ + my $fn=shift; + my $foundrypath=[]; + $notFoundFont=0; + + open(F,"<$fn") or Die("file '$fn' not found or not readable"); + + while (<F>) + { + chomp; + s/\r$//; # in case edited in windows + + s/\s*#.*?$//; # remove comments + + next if $_ eq ''; + + if (m/^[A-Za-z]=/) + { + next; + } + + my (@r)=split('\|'); + + if (lc($r[0]) eq 'foundry') + { + $foundry=uc($r[1]); + $foundrypath=[]; + push(@{$foundrypath},$dirURW) if $dirURW; + push(@{$foundrypath},(split(':',$r[2])),$devps); + foreach my $j (0..$#{$foundrypath}) + { + if ($foundrypath->[$j]=~m'\s*\(gs\)') + { + splice(@{$foundrypath},$j,1,@{$GSpath}); + } + } + $notFoundFont=0; + } + else + { + # 0=groff font name + # 1=IsBase Y/N (one of PDFs 14 base fonts) + # 2=afmtodit flag + # 3=map file + # 4=encoding file + # 5=font file + + my $gfont=($foundry eq '')?$r[0]:"$foundry-$r[0]"; + + if ($r[2] eq '') + { + # Don't run afmtodit, just copy the grops font file + + my $gotf=1; + my $gropsfnt=LocateFile([$devps],$r[0],0); + + if ($gropsfnt ne '' and -r "$gropsfnt") + { + + } + else + { + $notFoundFont|=1; + } + } + else + { + # We need to run afmtodit to create this groff font + $notFoundFont|=2 if !LocateAF($foundrypath,$r[5]); + $notFoundFont|=1 if !LocatePF($foundrypath,$r[5]); + } + } + } + + close(F); +} + +# Local Variables: +# fill-column: 72 +# mode: CPerl +# End: +# vim: set cindent noexpandtab shiftwidth=4 softtabstop=4 textwidth=72: |