File Coverage

lib/PostScript/Resources.pm
Criterion Covered Total %
statement 125 171 73.1
branch 41 104 39.4
condition 8 19 42.1
subroutine 16 17 94.1
pod 3 4 75.0
total 193 315 61.2


line stmt bran cond sub pod time code
1             # RCS Status : $Id: Resources.pm,v 1.12 2004/12/18 16:40:52 jv Exp $# Author : Johan Vromans
2             # Created On : Januari 1999
3             # Last Modified By: Johan Vromans
4             # Last Modified On: Thu Oct 23 14:11:52 2003
5             # Update Count : 187
6             # Status : Released
7              
8             ################ Module Preamble ################
9              
10             package PostScript::Resources;
11              
12 1     1   2327 use strict;
  1         2  
  1         36  
13              
14 1     1   51 BEGIN { require 5.005; }
15              
16 1     1   759 use IO qw(File);
  1         887  
  1         7  
17 1     1   11440 use File::Basename;
  1         2  
  1         133  
18 1     1   6 use File::Spec;
  1         2  
  1         28  
19              
20 1     1   5 use vars qw($VERSION);
  1         3  
  1         1679  
21             $VERSION = "1.03";
22              
23             my $ResourcePath = "."; # default standard resource path
24             my $defupr = "PSref.upr"; # principal resource file
25             my $fn; # file currently being loaded
26             my $fh; # handle of file currently being loaded
27             my $section; # section currently being loaded
28             my $exclusive; # last loaded file was exclusive
29             my $rscidx; # current resource index
30              
31             my $trace;
32             my $debug;
33             my $verbose;
34             my $error;
35              
36             sub new {
37 1     1 1 216 my $class = shift;
38 1   50     20 my (%atts) = (path => $ENV{"PSRESOURCEPATH"} || "::",
39             stdpath => $ResourcePath,
40             error => 'die', # 'die', 'warn' or 'ignore'
41             verbose => 0,
42             trace => 0,
43             debug => 0,
44             @_);
45              
46 1         5 $debug = lc($atts{debug});
47 1   33     7 $trace = $debug || lc($atts{trace});
48 1   33     8 $verbose = $trace || lc($atts{verbose});
49 1         3 $error = lc($atts{error});
50              
51 1         2 my $self = {};
52 1         3 bless $self, $class;
53              
54             # Get the resource paths.
55 1         3 my $path = $atts{path};
56 1         3 $path =~ s|::|:$atts{stdpath}:|g;
57 1         3 $path =~ s|^:||;
58              
59             # According to the specs, the file names are either literal,
60             # absolute or relative. In the latter case, the current prefix
61             # (which defaults to the directory of the .upr file) must be
62             # appended.
63             # To avoid lots of unnecessary file name parsing, each prefix
64             # will be stored in a prefix array, and the index in this array
65             # will be prepended to each file name entry.
66             # The costly filename manipulation will only be done when a
67             # filename needs to be returned (sub _buildfilename).
68              
69             # Create the prefix array and reset the index.
70 1         7 $self->{prefix} = [];
71 1         3 $rscidx = 0;
72              
73             # Process the entries in the list.
74 1         5 foreach my $rsc ( split (":", $path) ) {
75              
76 1 50       4 print STDERR ("rsc#$rscidx: $rsc \n") if $debug;
77              
78 1 50       18 if ( -d $rsc ) {
79 1 50       4 print STDERR ("rsc#$rscidx: $rsc \n") if $debug;
80              
81             # Directory.
82 1         2 $exclusive = 0;
83              
84             # First check for a PSres.upr, and load it if possible.
85 1         29 $fn = File::Spec->catfile ($rsc, "PSres.upr");
86 1 50       12 if ( -f $fn ) {
87 0 0       0 print STDERR ("rsc#$rscidx: load $fn\n") if $debug;
88 0         0 $rscidx++;
89 0         0 eval { _loadFile ($self) };
  0         0  
90 0 0       0 if ( $@ ) {
91 0 0       0 die ($@) if $error eq "die";
92 0 0       0 warn ($@) if $error eq "warn";
93 0         0 next;
94             }
95             }
96              
97             # Unless PSres.upr was an exclusive resource, load all
98             # files with .upr extension.
99 1 50       6 unless ( $exclusive ) {
100 1         1 my $dh = do { local *DH };
  1         6  
101 1         40 opendir ($dh, $rsc);
102 1         57 my @files = grep (/\.upr$/, readdir ($dh));
103 1         19 closedir ($dh);
104 1         4 foreach my $file ( @files ) {
105             # Skip the PSres.upr. It is already loaded.
106 2 50       15 next if $file eq "PSres.upr";
107              
108 2         26 $fn = File::Spec->catfile ($rsc, $file);
109 2 50       7 print STDERR ("rsc#$rscidx: load $fn\n") if $debug;
110 2         4 $rscidx++;
111 2         3 eval { _loadFile ($self) };
  2         7  
112 2 50       13 if ( $@ ) {
113 0 0       0 die ($@) if $error eq "die";
114 0 0       0 warn ($@) if $error eq "warn";
115 0         0 next;
116             }
117             }
118             }
119             }
120             else {
121              
122             # File. This is _not_ defined in the specs.
123              
124 0         0 $fn = $rsc;
125 0 0       0 print STDERR ("rsc#$rscidx: load $fn\n") if $debug;
126 0         0 $rscidx++;
127 0         0 eval { _loadFile ($self) };
  0         0  
128 0 0       0 if ( $@ ) {
129 0 0       0 die ($@) if $error eq "die";
130 0 0       0 warn ($@) if $error eq "warn";
131 0         0 next;
132             }
133             }
134             }
135              
136 1         8 $self;
137             }
138              
139             sub FontAFM ($$) {
140 1     1 1 8 my ($self, $font) = @_;
141 1 50       10 return _buildfilename ($self, $font)
142             if defined ($font = $self->{FontAFM}->{$font});
143 0         0 undef;
144             }
145              
146             sub FontOutline ($$) {
147 1     1 1 10 my ($self, $font) = @_;
148 1 50       10 return _buildfilename ($self, $font)
149             if defined ($font = $self->{FontOutline}->{$font});
150 0         0 undef;
151             }
152              
153             sub _buildfilename ($$) {
154 2     2   5 my ($self, $name) = @_;
155 2         2 my $i;
156 2         14 ($i, $name) = unpack ("IA*", $name);
157 2 50       9 return $1 if $name =~ /^=(.*)$/;
158 2 50       21 return $name if File::Spec->file_name_is_absolute ($name);
159 2         49 File::Spec->canonpath (File::Spec->catfile ($self->{prefix}->[$i], $name));
160             }
161              
162             sub _loadFile ($) {
163              
164 2     2   4 my ($self) = @_;
165              
166 2         4 my $data; # data
167              
168 2         3 eval { # so we can use die
169              
170 2         16 $fh = new IO::File; # font file
171 2         115 my $sz = -s $fn; # file size
172              
173 2 50       9 $fh->open ($fn) || die ("$fn: $!\n");
174 2 50       103 print STDERR ($fn, ": Loading Resources\n") if $verbose;
175              
176             # Read in the data.
177 2         48 my $line = <$fh>;
178 2 50       16 die ($fn."[$.]: Unrecognized file format\n")
179             unless $line =~ /^PS-Resources-(Exclusive-)?([\d.]+)/;
180 2         7 $exclusive = defined $1;
181 2         5 my $version = $2;
182              
183             # The resources file is organised in sections, each starting
184             # with the section name and terminated by a line with just
185             # a period.
186             # Following the first PS-Resources line, the sections are
187             # enumerated, e.g.:
188             #
189             # PS-Resources-1.0
190             # FontAFM
191             # FontOutlines
192             # FontFamily
193             # FontPrebuilt
194             # FontBDF
195             # FontBDFSizes
196             # .
197             #
198             # Optionally, the name of the resource directory follows. It
199             # is preceded with a slash, e.g.:
200             #
201             # //usr/share/psresources
202             #
203             # This is then followed by each of the sections, e.g.:
204             #
205             # FontAFM
206             # ... afm info ...
207             # .
208             # FontOutlines
209             # ... outlines info ...
210             # .
211             # FontFamily
212             # ... family info ...
213             # .
214             #
215             # Backslash escapes are NOT handled, except for continuation.
216             #
217             # We have a _loadXXX subroutine for each section, where XXX is
218             # the section name. Flexible and extensible.
219             #
220             # The current approach is to ignore the first section.
221              
222 2         9 $self->_skipSection ($fh);
223              
224             # Then, load the sections from the file, skipping unknown ones.
225              
226 2         3 my $checkdir = 1;
227 2         14 while ( defined ($section = _readLine ($self, $fh)) ) {
228 4         13 chomp ($section);
229 4 50 66     17 if ( $checkdir && $section =~ /^\/(.*)/ ) {
230 0         0 $self->{prefix}->[$rscidx] = $1;
231 0         0 $checkdir = 0;
232 0         0 next;
233             }
234 4         5 $checkdir = 0;
235 4 50       6 my $loader = defined &{"_load$section"} ? "_load$section" :
  4         24  
236             "_skipSection";
237 1     1   6 no strict 'refs';
  1         1  
  1         1018  
238 4 50 33     12 die ($fn."[$.]: Premature end of $section section\n")
239             if $fh->eof || !$loader->($self);
240             }
241              
242             };
243              
244             # Set the dfeault value for the directory prefix, if necessary.
245 2   33     305 $self->{prefix}->[$rscidx] ||= dirname ($fn);
246              
247 2         15 $fh->close;
248 2 50       42 die ($@) if $@;
249 2         5 $self;
250             }
251              
252             sub _readLine () {
253             # Read a line, handling continuation lines.
254 22     22   192 my $line;
255 22         27 while ( 1 ) {
256 22 100       68 return undef if $fh->eof;
257 20         143 $line .= <$fh>;
258 20 50       58 if ( $line =~ /^(.*)\\$/ ) {
259 0         0 $line = $1;
260 0         0 redo;
261             }
262 20 50       43 $line = $1 if $line =~ /^(.*)%/; # remove comments
263 20         83 $line =~ s/\s+$//; # remove trailing blanks
264 20 50       226 next unless $line =~ /\S/; # skip empty lines
265 20         86 return $line;
266             }
267 0         0 continue { $line = "" }
268 0         0 undef;
269             }
270              
271             sub _loadFontAFM ($) {
272 2     2   27 my ($self) = @_;
273 2 50       8 print STDERR ($fn, "[$.]: Loading section $section\n") if $trace;
274              
275 2         4 my $afm;
276 2 100       18 $afm = $self->{FontAFM} = {}
277             unless defined ($afm = $self->{FontAFM});
278              
279 2         3 my $line;
280 2         10 my $rscidx = pack ("I", $rscidx);
281 2         18 while ( defined ($line = _readLine ()) ) {
282 6 100       30 return 1 if $line =~ /^\.$/;
283              
284             # PostScriptName=the/file.afm
285 4 50       23 if ( $line =~ /^([^=]+)=(.*)$/ ) {
286 4 50       28 $afm->{$1} = $rscidx.$2 unless $afm->{$1};
287 4         10 next;
288             }
289 0 0       0 warn ($fn, "[$.]: Invalid FontAFM entry\n")
290             unless $error eq "ignore";
291             }
292 0         0 return 1;
293             }
294              
295             sub x_loadFontFamily ($) {
296 0     0 0 0 my ($self) = @_;
297 0 0       0 print STDERR ($fn, "[$.]: Loading section $section\n") if $trace;
298              
299 0         0 my $fam;
300 0 0       0 $fam = $self->{FontFamily} = {}
301             unless defined ($fam = $self->{FontFamily});
302              
303 0         0 my $line;
304 0         0 while ( defined ($line = _readLine ()) ) {
305 0 0       0 return 1 if $line =~ /^\.$/;
306              
307             # Familiyname=Type1,PostScriptName1,Type2,PostScriptName2,...
308 0 0       0 if ( $line =~ /^([^=]+)==?(.*)$/ ) {
309 0         0 $fam->{$1} = { split (',', $2) };
310 0         0 next;
311             }
312 0 0       0 warn ($fn, "[$.]: Invalid FontFamily entry\n")
313             unless $error eq "ignore";
314             }
315 0         0 return 1;
316             }
317              
318             sub _loadFontOutline ($) {
319 2     2   17 my ($self) = @_;
320 2 50       7 print STDERR ($fn, "[$.]: Loading section $section\n") if $trace;
321              
322 2         3 my $pfa;
323 2 100       10 $pfa = $self->{FontOutline} = {}
324             unless defined ($pfa = $self->{FontOutline});
325              
326 2         4 my $line;
327 2         6 my $rscidx = pack ("I", $rscidx);
328 2         5 while ( defined ($line = _readLine ()) ) {
329 4 100       25 return 1 if $line =~ /^\.$/;
330              
331             # PostScriptName=the/file.pfa
332 2 50       14 if ( $line =~ /^([^=]+)=(.*)$/ ) {
333 2 50       13 $pfa->{$1} = $rscidx.$2 unless $pfa->{$1};
334 2         5 next;
335             }
336 0 0       0 warn ($fn, "[$.]: Invalid FontOutline entry\n")
337             unless $error eq "ignore";
338             }
339 0         0 return 1;
340             }
341              
342             sub _skipSection ($) {
343 2     2   4 my ($self) = (@_);
344 2   50     243 $section ||= "list";
345 2 50       8 print STDERR ($fn, "[$.]: Skipping section $section\n") if $trace;
346              
347 2         3 my $line;
348 2         13 while ( defined ($line = _readLine ()) ) {
349 6 100       25 return 1 if $line =~ /^\.$/;
350             }
351 0           return 1;
352             }
353              
354             1;
355              
356             __END__