File Coverage

blib/lib/TeX/DVI/Parse.pm
Criterion Covered Total %
statement 80 105 76.1
branch 13 26 50.0
condition 3 9 33.3
subroutine 18 28 64.2
pod 0 5 0.0
total 114 173 65.9


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             TeX::DVI::Parse - parse TeX's DVI output file
5              
6             =cut
7              
8             package TeX::DVI::Parse;
9              
10 1     1   1956 use FileHandle;
  1         12908  
  1         7  
11              
12             $VERSION = '1.01';
13              
14             sub make_dim
15             {
16 9 50   9 0 20 if (scalar(@_) == 8) {
17 0         0 return make_dim(@_[0 .. 3]), make_dim(@_[4 .. 7]);
18             }
19 9         10 my $result = shift;
20 9         16 while (@_) { $result = $result * 256 + shift; }
  21         43  
21 9         20 $result;
22             }
23             sub make_fnt_def
24             {
25 4     4 0 5 my $in_buffer = pop @_;
26 4         15 my ($c, $s, $d, $a, $l, $buffer) = unpack "NNNCCa*", $in_buffer;
27 4         6 my $len = $a + $l;
28 4         26 return @_, ($c, $s, $d, $a, $l), unpack "a${len}a*", $buffer;
29             }
30             sub make_special
31             {
32 0     0 0 0 my ($num, $len, $buffer) = @_;
33 0         0 return $num, $len, unpack "a${len}a*", $buffer;
34             }
35             @COMMANDS = (
36             ( [ "set_char", sub { ( $_[0], @_ ); } ] ) x 128,
37             [ "set_char", "C" ],
38             [ "set_char", "CC", 2 ],
39             [ "set_char", "CCC", 3 ],
40             [ "set_char", "cCCC", 4 ],
41             [ "set_rule", "cCCCcCCC", 8 ],
42             [ "put_char", "C" ],
43             [ "put_char", "CC", 2 ],
44             [ "put_char", "CCC", 3 ],
45             [ "put_char", "CCCC", 4 ],
46             [ "put_rule", "cCCCcCCC", 8 ],
47             "nop",
48             [ "bop", "NNNNNNNNNNcCCC", 4 ],
49             "eop",
50             "push",
51             "pop",
52             [ "right", "c" ],
53             [ "right", "cC", 2 ],
54             [ "right", "cCC", 3 ],
55             [ "right", "cCCC", 4 ],
56             "move_w",
57             [ "move_w", "c" ],
58             [ "move_w", "cC", 2 ],
59             [ "move_w", "cCC", 3 ],
60             [ "move_w", "cCCC", 4 ],
61             "move_x",
62             [ "move_x", "c" ],
63             [ "move_x", "cC", 2 ],
64             [ "move_x", "cCC", 3 ],
65             [ "move_x", "cCCC", 4 ],
66             [ "down", "c" ],
67             [ "down", "cC", 2 ],
68             [ "down", "cCC", 3 ],
69             [ "down", "cCCC", 4 ],
70             "move_y",
71             [ "move_y", "c" ],
72             [ "move_y", "cC", 2 ],
73             [ "move_y", "cCC", 3 ],
74             [ "move_y", "cCCC", 4 ],
75             "move_z",
76             [ "move_z", "c" ],
77             [ "move_z", "cC", 2 ],
78             [ "move_z", "cCC", 3 ],
79             [ "move_z", "cCCC", 4 ],
80             ( [ "fnt_num", sub { ($_[0], $_[0] - 171, $_[-1]); } ] ) x 64,
81             [ "fnt_num", "C" ],
82             [ "fnt_num", "CC", 2 ],
83             [ "fnt_num", "CCC", 3 ],
84             [ "fnt_num", "cCCC", 4 ],
85             [ "special", "C", \&make_special ],
86             [ "special", "CC", 2, \&make_special ],
87             [ "special", "CCC", 3, \&make_special ],
88             [ "special", "CCCC", 4, \&make_special ],
89             [ "fnt_def", "C", \&make_fnt_def ],
90             [ "fnt_def", "CC", 2, \&make_fnt_def ],
91             [ "fnt_def", "CCC", 3, \&make_fnt_def ],
92             [ "fnt_def", "cCCC", 4, \&make_fnt_def ],
93             [ "preamble", "CNNNC",
94             sub { my $buffer = pop @_;
95             return @_, unpack "a$_[5]a*", $buffer; } ],
96             [ "post", "NNNNNNnn" ],
97             [ "post_post", "NCa*"],
98             "undefined_command",
99             );
100              
101             sub new
102             {
103 1     1 0 941 my $class = shift;
104 1         3 my $self = {};
105 1         3 my $filename = shift;
106 1         12 $self->{'fh'} = new FileHandle($filename);
107 1         152 binmode $self->{'fh'};
108 1         3 bless $self, $class;
109 1         5 $self;
110             }
111             sub parse
112             {
113 1     1 0 574 my $self = shift;
114 1         4 my $oldselect = select;
115 1         5 local $/ = undef;
116             ## print STDERR "Parse started\n";
117 1         51 my $buffer = $self->{'fh'}->getline();
118             ## print STDERR "File loaded\n";
119 1         68 while (length $buffer > 0)
120             {
121 48         54 my $ord = ord $buffer;
122 48         75 $buffer = substr $buffer, 1;
123 48         78 my $command = $COMMANDS[$ord];
124 48 100 66     214 if (ref $command and ref $command eq 'ARRAY')
125             {
126 38         76 my @list = ( $ord, $buffer );
127 38         39 my $i = 1;
128 38 100       156 if (not ref $command->[1])
129             {
130 16         106 @list = ($ord, unpack $command->[1] . "a*", $buffer);
131 16         28 $i = 2;
132             }
133 38         74 while (defined $command->[$i])
134             {
135 36 100       57 if (ref $command->[$i])
136 27         35 { @list = &{$command->[$i]}(@list); }
  27         52  
137             else
138             {
139 9         17 my $buffer = pop @list;
140 9         22 my @num = splice @list, -$command->[$i];
141 9         18 push @list, make_dim(@num), $buffer;
142             }
143 36         88 $i++;
144             }
145 38         53 $buffer = pop @list;
146 38         42 my $can;
147 38 50       258 if ($can = $self->can($command->[0]))
148 38         162 { &$can($self, @list) };
149             }
150             else
151             {
152 10         10 my $can;
153 10 50       36 if ($can = $self->can($command))
154 10         19 { &$can($self, $ord) };
155             }
156             }
157 1         10 select($oldselect);
158             ## print STDERR "Parse finished\n";
159             }
160              
161             package TeX::DVI::Print;
162             @ISA = qw( TeX::DVI::Parse );
163              
164             sub set_char
165             {
166 19     19   24 my ($self, $ord, $char) = @_;
167 19         35 print "Set ch\t$ord, $char";
168 19 50 33     83 print " '", chr $char, "'" if $char >= 32 and $char <= 255;
169 19         59 print "\n";
170             }
171             sub set_rule
172             {
173 0     0   0 my ($self, $ord, $height, $width) = @_;
174 0         0 print "Set rul\t$ord, height: $height, width: $width\n";
175             }
176             sub put_char
177             {
178 0     0   0 my ($self, $ord, $char) = @_;
179 0         0 print "Put ch\t$ord, $char";
180 0 0 0     0 print " '", chr $ord, "'" if $ord >= 32 and $ord <= 255;
181 0         0 print "\n";
182             }
183             sub put_rule
184             {
185 0     0   0 my ($self, $ord, $height, $width) = @_;
186 0         0 print "Put rul\t$ord, height: $height, width: $width\n";
187             }
188             sub nop
189 0     0   0 { my ($self, $ord) = @_; print "Nop\t$ord\n"; }
  0         0  
190             sub bop
191             {
192 1     1   3 my ($self, $ord, @numbers) = @_;
193 1         2 $prev_page = pop @numbers;
194 1         14 print "Bop\t$ord, id: [@numbers], previous page: $prev_page\n";
195             }
196             sub eop
197 1     1   3 { my ($self, $ord) = @_; print "Eop\t$ord\n"; }
  1         5  
198             sub push
199 4     4   7 { my ($self, $ord) = @_; print "Push\t$ord\n"; }
  4         17  
200             sub pop
201 4     4   7 { my ($self, $ord) = @_; print "Pop\t$ord\n"; }
  4         16  
202             sub right
203 3     3   5 { my ($self, $ord, $value) = @_; print "Right\t$ord, value: $value\n"; }
  3         16  
204             sub move_w
205             {
206 2     2   3 my ($self, $ord, $value) = @_;
207 2 100       6 $value = 'no_b' unless defined $value;
208 2         16 print "Move w\t$ord, value: $value\n";
209             }
210             sub move_x
211             {
212 0     0   0 my ($self, $ord, $value) = @_;
213 0 0       0 $value = 'no_b' unless defined $value;
214 0         0 print "Move x\t$ord, value: $value\n";
215             }
216             sub down
217             {
218 4     4   10 my ($self, $ord, $value) = @_;
219 4         45 print "Down\t$ord, value: $value\n";
220             }
221             sub move_y
222             {
223 0     0   0 my ($self, $ord, $value) = @_;
224 0 0       0 $value = 'no_b' unless defined $value;
225 0         0 print "Move y\t$ord, value: $value\n";
226             }
227             sub move_z
228             {
229 0     0   0 my ($self, $ord, $value) = @_;
230 0 0       0 $value = 'no_b' unless defined $value;
231 0         0 print "Move z\t$ord, value: $value\n";
232             }
233             sub fnt_num
234             {
235 3     3   5 my ($self, $ord, $k) = @_;
236 3         16 print "Fnt num\t$ord, k: $k\n";
237             }
238             sub special
239             {
240 0     0   0 my ($self, $ord, $len, $text) = @_;
241 0         0 print "Spec\t$ord, len: $len\n\t`$text'\n";
242             }
243             sub fnt_def
244             {
245 4     4   6 my ($self, $ord, $k, $c, $s, $d, $a, $l, $name) = @_;
246 4         23 print "Fnt def\t$ord, k: $k, name: $name\n";
247             }
248             sub preamble
249             {
250 1     1   3 my ($self, $ord, $i, $num, $den, $mag, $k, $text) = @_;
251 1         25 print "Pream\t$ord, i: $i, num: $num, den: $den, mag: $mag, k: $k\n\t`$text'\n";
252             }
253             sub post
254             {
255 1     1   3 my ($self, $ord, $prev, $num, $den, $mag, $l, $u, $s, $t) = @_;
256 1         11 print "Post\t$ord, prev: $prev, num: $num, den: $den, mag: $mag, \n\tl: $l, u: $u, s: $s, t: $t\n";
257             }
258             sub post_post
259             {
260 1     1   3 my ($self, $ord, $q, $i, $rest) = @_;
261 1         5 print "PPost\t$ord, q: $q, i: $i\n";
262 1 50       12 print "\tWrong end of DVI\n"
263             unless $rest =~ /^\337{4,7}$/;
264             }
265             sub undefined_command
266             {
267 0     0     print "Undefined command\n";
268             }
269             1;
270              
271             =head1 SYNOPSIS
272              
273             use TeX::DVI::Parse;
274             my $dvi_parse = new TeX::DVI::Parse("test.dvi");
275             $dvi_parse->parse();
276              
277             =head1 DESCRIPTION
278              
279             I have created this module on request from Mirka Misáková. She wanted
280             to do some post-processing on the DVI file and I said that it will be
281             better to parse the DVI file directly, instead of the output of the
282             B program.
283              
284             As the result there is this module B that recognizes
285             all commands from the DVI file and for each command found it calls
286             method of appropriate name, if defined in the class.
287              
288             The example above is not very reasonable because the core
289             B module doesn't itself define any methods for the
290             DVI commands. You will probably want to inherit a new class and define
291             the functions yourself:
292              
293             packages My_Parse_DVI;
294             use TeX::DVI::Parse;
295             @ISA = qw( TeX::DVI::Parse );
296              
297             sub set_char
298             {
299             my ($self, $ord, $char) = @_;
300             ## print the info or something;
301             }
302              
303             As an example there is class B coming in this file,
304             so you can do
305              
306             use TeX::DVI::Parse;
307             my $dvi_parse = new TeX::DVI::Print("test.dvi");
308             $dvi_parse->parse();
309              
310             and get listing of DVI's content printed in (hopefully) readable form.
311              
312             =head2 Methods
313              
314             For creating new classes, a documentation of expected methods names
315             and their parameters is necessary, so here is the list. The names come
316             from the B documentation and that is also the basic reference
317             for the meaning of the parameters. Note that each method receives as
318             the first two parameters I<$self> and I<$ord>, reference to the parsing
319             object and the byte value of the command as found in the DVI file.
320             These are mandatory so only the other parameters to each method are
321             listed below.
322              
323             =over 4
324              
325             =item set_char -- typeset character and shift right by its width
326              
327             I<$char> -- specifies the ordinal value of the character.
328              
329             =item put_char -- as B but without moving
330              
331             I<$char> -- ordinal value of the character.
332              
333             =item set_rule -- typeset black rectangle and shift to the right
334              
335             I<$height>, I<$width> -- dimensions of the rectangle.
336              
337             =item put_rule -- as B without moving
338              
339             I<$height>, I<$width> -- dimensions of the rectangle.
340              
341             =item nop -- no operation
342              
343             no parameter
344              
345             =item bop -- begin of page
346              
347             I<$number[0]> .. I<$number[9]>, I<$prev_page> -- the ten numbers
348             that specify the page, the pointer to the start of the previous page.
349              
350             =item eop -- end of page
351              
352             no parameter
353              
354             =item push -- push to the stack
355              
356             no parameter
357              
358             =item pop -- pop from the stack
359              
360             no parameter
361              
362             =item right -- move right
363              
364             I<$value> -- how much to move.
365              
366             =item move_w, move_x, down, move_y, move_z -- move position
367              
368             all take one parameter, I<$value>.
369              
370             =item fnt_def -- define font
371              
372             I<$k>, I<$c>, I<$s>, I<$d>, I<$a>, I<$l>, I<$n> -- number of the font,
373             checksum, scale factor, design size, length of the directory and length
374             of the filename, name of the font.
375              
376             =item fnt_num -- select font
377              
378             I<$k> -- number of the font.
379              
380             =item special -- generic DVI primitive
381              
382             I<$k>, I<$x> -- length of the special and its data.
383              
384             =item preamble
385              
386             I<$i>, I<$num>, I<$den>, I<$mag>, I<$k>, I<$x> -- ID of the format,
387             numerator and denumerator of the multiplication fraction,
388             magnification, length of the comment and comment.
389              
390             =item post -- postamble
391              
392             I<$p>, I<$num>, I<$den>, I<$mag>, I<$l>, I<$u>, I<$s>, I<$t> -- pointer
393             to the last page, the next three are as in preamble, maximal dimensions
394             (I<$l> and I<$u>), maximal depth of the stack and the final page number.
395              
396             =item post_post -- post postamble
397              
398             I<$q>, I<$i>, I<$dummy> -- pointer to the postamble, ID and the last fill.
399              
400             =item undefined_command -- for byte that has no other meaning
401              
402             no parameter
403              
404             =back
405              
406             =head1 VERSION
407              
408             1.01
409              
410             =head1 AVAILABLE FROM
411              
412             http://www.adelton.com/perl/TeX-DVI/
413              
414             =head1 AUTHOR
415              
416             (c) 1996--2011 Jan Pazdziora.
417              
418             All rights reserved. This package is free software; you can
419             redistribute it and/or modify it under the same terms as Perl itself.
420              
421             Contact the author at jpx dash perl at adelton dot com.
422              
423             =head1 SEE ALSO
424              
425             Font::TFM(3), TeX::DVI(3), perl(1).
426              
427             =cut
428