DVIDOC, a postprocessor for DVI files (Part 2 of 2)
SKY
ken at rochester.ARPA
Fri Dec 26 09:02:33 AEST 1986
if (k>0)and(buffer[buf_ptr]="/")and
(buffer[buf_ptr+1]>"0")and(buffer[buf_ptr+1]<="9") then
begin incr(buf_ptr); vert_resolution:=k/get_integer;
end
else begin print('Type a ratio of positive integers;');
print_ln(' (1 line per mm would be 254/10).');
goto 4;
end;
end
@ @<Determine the desired |new_mag|@>=
5: write(term_out,'New magnification (default=0 to keep the old one): ');
new_mag:=0; input_ln; buf_ptr:=0;
if buffer[0]<>" " then
if (buffer[0]>="0")and(buffer[0]<="9") then new_mag:=get_integer
else begin write(term_out,'Type a positive integer to override ');
write_ln(term_out,'the magnification in the DVI file.');
goto 5;
end
@* Defining fonts.
\.{DVIDOC} reads the postamble first and loads
all of the fonts defined there; then it processes the pages. In this
case, a \\{fnt\_def} command should match a previous definition if and only
if the \\{fnt\_def} being processed is not in the postamble.
A global variable |in_postamble| is provided to tell whether we are
processing the postamble or not.
@<Glob...@>=
@!in_postamble:boolean; {are we reading the postamble?}
@ @<Set init...@>=
in_postamble:=false;
@ The following subroutine does the necessary things when a \\{fnt\_def}
command is being processed.
@p procedure define_font(@!e:integer); {|e| is an external font number}
var f:0..max_fonts;
@!p:integer; {length of the area/directory spec}
@!n:integer; {length of the font name proper}
@!c,@!q,@!d:integer; {check sum, scaled size, and design size}
@!r:0..name_length; {index into |cur_name|}
@!j,@!k:0..name_size; {indices into |names|}
@!mismatch:boolean; {do names disagree?}
begin if nf=max_fonts then abort('DVIDOC capacity exceeded (max fonts=',
max_fonts:1,')!');
@.DVIDOC capacity exceeded...@>
font_num[nf]:=e; f:=0;
while font_num[f]<>e do incr(f);
@<Read the font parameters into position for font |nf|, and
print the font name@>;
if in_postamble then
begin if f<nf then print_ln('---this font was already defined!');
@.this font was already defined@>
end
else begin if f=nf then print_ln('---this font wasn''t loaded before!');
@.this font wasn't loaded before@>
end;
if f=nf then @<Load the new font, unless there are problems@>
else @<Check that the current font definition matches the old one@>;
end;
@ @<Check that the current...@>=
begin if font_check_sum[f]<>c then
print_ln('---check sum doesn''t match previous definition!');
@.check sum doesn't match@>
if font_scaled_size[f]<>q then
print_ln('---scaled size doesn''t match previous definition!');
@.scaled size doesn't match@>
if font_design_size[f]<>d then
print_ln('---design size doesn''t match previous definition!');
@.design size doesn't match@>
j:=font_name[f]; k:=font_name[nf]; mismatch:=false;
while j<font_name[f+1] do
begin if names[j]<>names[k] then mismatch:=true;
incr(j); incr(k);
end;
if k<>font_name[nf+1] then mismatch:=true;
if mismatch then print_ln('---font name doesn''t match previous definition!');
@.font name doesn't match@>
print_ln(' ')
end
@ @<Read the font parameters into position for font |nf|...@>=
c:=signed_quad; font_check_sum[nf]:=c;@/
q:=signed_quad; font_scaled_size[nf]:=q;@/
d:=signed_quad; font_design_size[nf]:=d;@/
p:=get_byte; n:=get_byte;
if font_name[nf]+n+p>name_size then
abort('DVIDOC capacity exceeded (name size=',name_size:1,')!');
@.DVIDOC capacity exceeded...@>
font_name[nf+1]:=font_name[nf]+n+p;
print('Font ',e:1,': ');
if n+p=0 then print('null font name!')
@.null font name@>
else for k:=font_name[nf] to font_name[nf+1]-1 do names[k]:=get_byte;
incr(nf); print_font(nf-1); decr(nf)
@ @<Load the new font, unless there are problems@>=
begin @<Move font name into the |cur_name| string@>;
open_tfm_file;
if eof(tfm_file) then
print('---not loaded, TFM file can''t be opened!')
@.TFM file can\'t be opened@>
else begin if (q<=0)or(q>=@'1000000000) then
print('---not loaded, bad scale (',q:1,')!')
@.bad scale@>
else if (d<=0)or(d>=@'1000000000) then
print('---not loaded, bad design size (',d:1,')!')
@.bad design size@>
else if in_TFM(q) then @<Finish loading the new font info@>;
end;
print_ln(' ');
end
@ @<Finish loading...@>=
begin font_space[nf]:=q div 6; {this is a 3-unit ``thin space''}
if (c<>0)and(tfm_check_sum<>0)and(c<>tfm_check_sum) then
begin print_ln('---beware: check sums do not agree!');
@.beware: check sums do not agree@>
@.check sums do not agree@>
print_ln(' (',c:1,' vs. ',tfm_check_sum:1,')');
print(' ');
end;
print('---loaded at size ',q:1,' DVI units');
d:=round((100.0*horiz_conv*q)/(true_horiz_conv*d));
if d<>100 then
begin print_ln(' '); print(' (this font is magnified ',d:1,'%)');
end;
@.this font is magnified@>
incr(nf); {now the new font is officially present}
font_space[nf]:=0; {for |out_space| and |out_vmove|}
end
@ If |p=0|, i.e., if no font directory has been specified, \.{DVIDOC}
is supposed to use the default font directory, which is a
system-dependent place where the standard fonts are kept.
The string variable |default_directory| contains the name of this area.
@^system dependencies@>
@d default_directory_name=='TeXfonts:' {change this to the correct name}
@d default_directory_name_length=9 {change this to the correct length}
@<Glob...@>=
@!default_directory:packed array[1..default_directory_name_length] of char;
@ @<Set init...@>=
default_directory:=default_directory_name;
@ The string |cur_name| is supposed to be set to the external name of the
\.{TFM} file for the current font. This usually means that we need to,
at most sites, append the
suffix ``.tfm''.
@^system dependencies@>
@<Move font name into the |cur_name| string@>=
for k:=1 to name_length do cur_name[k]:=' ';
r:=0;
for k:=font_name[nf] to font_name[nf+1]-1 do
begin incr(r);
if r+4>name_length then
abort('DVIDOC capacity exceeded (max font name length=',
name_length:1,')!');
@.DVIDOC capacity exceeded...@>
cur_name[r]:=xchr[names[k]];
end;
cur_name[r+1]:='.'; cur_name[r+2]:='t'; cur_name[r+3]:='f'; cur_name[r+4]:='m'
@* Low level output routines.
Characters set by the \.{DVI} file are placed in |page_buffer|, a two
dimensional array of characters with one element for each print
position on the page. The |page_buffer| is cleared at the beginning
of each page and printed at the end of each page.
|doc_file|, the file to which the document is destined, is an ordinary text
file.
To optimize the initialization and printing of |page_buffer|, a high
water mark line number, |page_hwm|, is kept to indicate the last line
that contains any printable characters, and for each line a high water
mark character number, |line_hwm|, is kept to indicate the location of
the last printable character in the line.
@<Glob...@>=
@!doc_file:text_file;
@!page_buffer:packed array[1..page_width_max,1..page_length_max] of ASCII_code;
{storage for a document page}
@!line_hwm:array[1..page_length_max] of 0..page_width_max;
{high water marks for each line}
@!page_hwm: 0..page_length_max; {high water mark for page}
@ |doc_file| needs to be opened.
@<Set initial values@>=
argv(2, cur_name);
if test_access(write_access_mode, no_file_path) then
rewrite(doc_file, cur_name)
else begin
error('Cannot write output file');
goto done;
end;
@ The |flush_page| procedure will print the |page_buffer|.
@p procedure flush_page;
var i:0..page_width_max; j:0..page_length_max;
begin
for j := 1 to page_hwm do begin
for i := 1 to line_hwm[j] do
write (doc_file, xchr[page_buffer[i,j]]);
write_ln (doc_file) end;
write (doc_file, chr(12)) {end the page with a form feed}
end;
@ The |empty_page| procedure will empty the |page_buffer| data structure.
@p procedure empty_page;
begin page_hwm := 0 end;
@ And the |out_char| procedure puts something into it. The usual printable
ASCII characters will be put into the buffer as is. Non-printable characters,
including the blank, will be put into the buffer as question mark chracters.
@p procedure out_char(p,hh,vv:integer);
var i:1..page_width_max; j:1..page_length_max;
{|hh| and |vv| range from zero up while |i| and |j| range from one up.}
k: integer;
c: ASCII_code;
begin
if
(p>" ")and(p<="~") then c:=p
else c:=xord['?'];
if
(hh>page_width_max-1) or (vv>page_length_max-1) then begin
print_ln(' ');
print('Character "', xchr[c], '" set at column ', hh+1:1);
print_ln( ' and row ', vv+1:1, ',');
print('outside the range of DVIDOC (');
@.outside the range of DVIDOC@>
print(page_width_max:1, ',', page_length_max:1, ').');
print_ln(' ') end
else begin
i := hh + 1;
j := vv + 1;
if j>page_hwm then begin {initialize any as yet untouched lines}
for k := page_hwm+1 to j do line_hwm[k]:=0;
page_hwm := j end;
if i>line_hwm[j] then begin {initialize any as yet untouched characters}
for k := line_hwm[j]+1 to i do page_buffer[k,j] := xord[' '];
line_hwm[j] := i end;
page_buffer[i,j] := c {put the character in its place} end
end;
@* Translation to symbolic form.
The main work of \.{DVIDOC} is accomplished by the |do_page| procedure,
which produces the output for an entire page, assuming that the |bop|
command for that page has already been processed. This procedure is
essentially an interpretive routine that reads and acts on the \.{DVI}
commands.
@ The definition of \.{DVI} files refers to six registers,
$(h,v,w,x,y,z)$, which hold integer values in \.{DVI} units. In practice,
we also need registers |hh| and |vv|, the pixel analogs of $h$ and $v$,
since it is not always true that |hh=horiz_pixel_round(h)| or
|vv=vert_pixel_round(v)|.
The stack of $(h,v,w,x,y,z)$ values is represented by eight arrays
called |hstack|, \dots, |zstack|, |hhstack|, and |vvstack|.
@<Glob...@>=
@!h,@!v,@!w,@!x,@!y,@!z,@!hh,@!vv:integer; {current state values}
@!hstack,@!vstack,@!wstack,@!xstack,@!ystack,@!zstack:
array [0..stack_size] of integer; {pushed down values in \.{DVI} units}
@!hhstack,@!vvstack:
array [0..stack_size] of integer; {pushed down values in pixels}
@ Three characteristics of the pages (their |max_v|, |max_h|, and
|max_s|) are specified in the postamble, and a warning message
is printed if these limits are exceeded. Actually |max_v| is set to
the maximum height plus depth of a page, and |max_h| to the maximum width,
for purposes of page layout. Since characters can legally be set outside
of the page boundaries, it is not an error when |max_v| or |max_h| is
exceeded. But |max_s| should not be exceeded.
The postamble also specifies the total number of pages; \.{DVIDOC}
checks to see if this total is accurate.
@<Glob...@>=
@!max_v:integer; {the value of |abs(v)| should probably not exceed this}
@!max_h:integer; {the value of |abs(h)| should probably not exceed this}
@!max_s:integer; {the stack depth should not exceed this}
@!max_v_so_far,@!max_h_so_far,@!max_s_so_far:integer; {the record high levels}
@!total_pages:integer; {the stated total number of pages}
@!page_count:integer; {the total number of pages seen so far}
@ @<Set init...@>=
max_v:=@'17777777777-99; max_h:=@'17777777777-99; max_s:=stack_size+1;@/
max_v_so_far:=0; max_h_so_far:=0; max_s_so_far:=0; page_count:=0;
@ Before we get into the details of |do_page|, it is convenient to
consider a simpler routine that computes the first parameter of each
opcode.
@d four_cases(#)==#,#+1,#+2,#+3
@d eight_cases(#)==four_cases(#),four_cases(#+4)
@d sixteen_cases(#)==eight_cases(#),eight_cases(#+8)
@d thirty_two_cases(#)==sixteen_cases(#),sixteen_cases(#+16)
@d sixty_four_cases(#)==thirty_two_cases(#),thirty_two_cases(#+32)
@p function first_par(o:eight_bits):integer;
begin case o of
sixty_four_cases(set_char_0),sixty_four_cases(set_char_0+64):
first_par:=o-set_char_0;
set1,put1,fnt1,xxx1,fnt_def1: first_par:=get_byte;
set1+1,put1+1,fnt1+1,xxx1+1,fnt_def1+1: first_par:=get_two_bytes;
set1+2,put1+2,fnt1+2,xxx1+2,fnt_def1+2: first_par:=get_three_bytes;
right1,w1,x1,down1,y1,z1: first_par:=signed_byte;
right1+1,w1+1,x1+1,down1+1,y1+1,z1+1: first_par:=signed_pair;
right1+2,w1+2,x1+2,down1+2,y1+2,z1+2: first_par:=signed_trio;
set1+3,set_rule,put1+3,put_rule,right1+3,w1+3,x1+3,down1+3,y1+3,z1+3,
fnt1+3,xxx1+3,fnt_def1+3: first_par:=signed_quad;
nop,bop,eop,push,pop,pre,post,post_post,undefined_commands: first_par:=0;
w0: first_par:=w;
x0: first_par:=x;
y0: first_par:=y;
z0: first_par:=z;
sixty_four_cases(fnt_num_0): first_par:=o-fnt_num_0;
end;
end;
@ Here are two other subroutines that we need: They compute the number of
pixels in the height or width of a rule. Characters and rules will line up
properly if the sizes are computed precisely as specified here. (Since
|horiz_conv| and |vert_conv|
are computed with some floating-point roundoff error, in a
machine-dependent way, format designers who are tailoring something for a
particular resolution should not plan their measurements to come out to an
exact integer number of pixels; they should compute things so that the
rule dimensions are a little less than an integer number of pixels, e.g.,
4.99 instead of 5.00.)
@p function horiz_rule_pixels(x:integer):integer;
{computes $\lceil|horiz_conv|\cdot x\rceil$}
var n:integer;
begin n:=trunc(horiz_conv*x);
if n<horiz_conv*x then horiz_rule_pixels:=n+1 @+ else horiz_rule_pixels:=n;
end;
function vert_rule_pixels(x:integer):integer;
{computes $\lceil|vert_conv|\cdot x\rceil$}
var n:integer;
begin n:=trunc(vert_conv*x);
if n<vert_conv*x then vert_rule_pixels:=n+1 @+ else vert_rule_pixels:=n;
end;
@ Strictly speaking, the |do_page| procedure is really a function with
side effects, not a `\&{procedure}'\thinspace; it returns the value |false|
if \.{DVIDOC} should be aborted because of some unusual happening. The
subroutine is organized as a typical interpreter, with a multiway branch
on the command code followed by |goto| statements leading to routines that
finish up the activities common to different commands. We will use the
following labels:
@d fin_set=41 {label for commands that set or put a character}
@d fin_rule=42 {label for commands that set or put a rule}
@d move_right=43 {label for commands that change |h|}
@d move_down=44 {label for commands that change |v|}
@d show_state=45 {label for commands that change |s|}
@d change_font=46 {label for commands that change |cur_font|}
@ Some \PASCAL\ compilers severely restrict the length of procedure bodies,
so we shall split |do_page| into two parts, one of which is
called |special_cases|. The different parts communicate with each other
via the global variables mentioned above, together with the following ones:
@<Glob...@>=
@!s:integer; {current stack size}
@!ss:integer; {stack size to print}
@!cur_font:integer; {current internal font number}
@ Here is the overall setup.
@p @t\4@>@<Declare the function called |special_cases|@>@;
function do_page:boolean;
label fin_set,fin_rule,move_right,show_state,done,9998,9999;
var o:eight_bits; {operation code of the current command}
@!p,@!q:integer; {parameters of the current command}
@!a:integer; {byte number of the current command}
i,j:integer; {for loop indices for setting rules}
@!hhh:integer; {|h|, rounded to the nearest pixel}
begin empty_page; cur_font:=nf; {set current font undefined}
s:=0; h:=0; v:=0; w:=0; x:=0; y:=0; z:=0; hh:=0; vv:=0;
{initialize the state variables}
while true do @<Translate the next command in the \.{DVI} file;
|goto 9999| with |do_page=true| if it was |eop|;
|goto 9998| if premature termination is needed@>;
9998: print_ln('!'); do_page:=false;
9999: end;
@
@<Translate the next command...@>=
begin a:=cur_loc;
o:=get_byte; p:=first_par(o);
if eof(dvi_file) then bad_dvi('the file ended prematurely');
@.the file ended prematurely@>
@<Start translation of command |o| and |goto| the appropriate label to
finish the job@>;
fin_set: @<Finish a command that either sets or puts a character, then
|goto move_right| or |done|@>;
fin_rule: @<Finish a command that either sets or puts a rule, then
|goto move_right| or |done|@>;
move_right: @<Finish a command that sets |h:=h+q|, then |goto done|@>;
show_state: ;
done: ;
end
@ The multiway switch in |first_par|, above, was organized by the length
of each command; the one in |do_page| is organized by the semantics.
@<Start translation...@>=
if o<set_char_0+128 then @<Translate a |set_char| command@>
else case o of
four_cases(set1): begin out_char(p,hh,vv); goto fin_set;
end;
set_rule: begin goto fin_rule;
end;
put_rule: begin goto fin_rule;
end;
@t\4@>@<Cases for commands |nop|, |bop|, \dots, |pop|@>@;
@t\4@>@<Cases for horizontal motion@>@;
othercases if special_cases(o,p,a) then goto done at +else goto 9998
endcases
@ @<Declare the function called |special_cases|@>=
function special_cases(@!o:eight_bits;@!p,@!a:integer):boolean;
label change_font,move_down,done,9998;
var q:integer; {parameter of the current command}
@!k:integer; {loop index}
@!bad_char:boolean; {has a non-ASCII character code appeared in this \\{xxx}?}
@!pure:boolean; {is the command error-free?}
@!vvv:integer; {|v|, rounded to the nearest pixel}
begin pure:=true;
case o of
four_cases(put1): begin goto done;
end;
@t\4@>@<Cases for vertical motion@>@;
@t\4@>@<Cases for fonts@>@;
four_cases(xxx1): @<Translate an |xxx| command and |goto done|@>;
pre: begin error('preamble command within a page!'); goto 9998;
end;
@.preamble command within a page@>
post,post_post: begin error('postamble command within a page!'); goto 9998;
@.postamble command within a page@>
end;
othercases begin error('undefined command ',o:1,'!');
goto done;
@.undefined command@>
end
endcases;
move_down: @<Finish a command that sets |v:=v+p|, then |goto done|@>;
change_font: @<Finish a command that changes the current font,
then |goto done|@>;
9998: pure:=false;
done: special_cases:=pure;
end;
@ @<Cases for commands |nop|, |bop|, \dots, |pop|@>=
nop: begin goto done;
end;
bop: begin error('bop occurred before eop!'); goto 9998;
@.bop occurred before eop@>
end;
eop: begin
if s<>0 then error('stack not empty at end of page (level ',
s:1,')!');
@.stack not empty...@>
do_page:=true; flush_page; goto 9999;
end;
push: begin
if s=max_s_so_far then
begin max_s_so_far:=s+1;
if s=max_s then error('deeper than claimed in postamble!');
@.deeper than claimed...@>
@.push deeper than claimed...@>
if s=stack_size then
begin error('DVIDOC capacity exceeded (stack size=',
stack_size:1,')'); goto 9998;
end;
end;
hstack[s]:=h; vstack[s]:=v; wstack[s]:=w;
xstack[s]:=x; ystack[s]:=y; zstack[s]:=z;
hhstack[s]:=hh; vvstack[s]:=vv; incr(s); ss:=s-1; goto show_state;
end;
pop: begin
if s=0 then error('Pop illegal at level zero!')
else begin decr(s); hh:=hhstack[s]; vv:=vvstack[s];
h:=hstack[s]; v:=vstack[s]; w:=wstack[s];
x:=xstack[s]; y:=ystack[s]; z:=zstack[s];
end;
ss:=s; goto show_state;
end;
@ Rounding to the nearest pixel is best done in the manner shown here, so as
to be inoffensive to the eye: When the horizontal motion is small, like a
kern, |hh| changes by rounding the kern; but when the motion is large, |hh|
changes by rounding the true position |h| so that accumulated rounding errors
disappear.
@d out_space==if abs(p)>=font_space[cur_font] then
begin hh:=horiz_pixel_round(h+p);
end
else hh:=hh+horiz_pixel_round(p);
q:=p; goto move_right
@<Cases for horizontal motion@>=
four_cases(right1):begin out_space;
end;
w0,four_cases(w1):begin w:=p; out_space;
end;
x0,four_cases(x1):begin x:=p; out_space;
end;
@ Vertical motion is done similarly, but with the threshold between
``small'' and ``large'' increased by a factor of five. The idea is to make
fractions like ``$1\over2$'' round consistently, but to absorb accumulated
rounding errors in the baseline-skip moves.
@d out_vmove==if abs(p)>=5*font_space[cur_font] then vv:=vert_pixel_round(v+p)
else vv:=vv+vert_pixel_round(p);
goto move_down
@<Cases for vertical motion@>=
four_cases(down1):begin out_vmove;
end;
y0,four_cases(y1):begin y:=p; out_vmove;
end;
z0,four_cases(z1):begin z:=p; out_vmove;
end;
@ @<Cases for fonts@>=
sixty_four_cases(fnt_num_0): begin
goto change_font;
end;
four_cases(fnt1): begin
goto change_font;
end;
four_cases(fnt_def1): begin
define_font(p); goto done;
end;
@ @<Translate an |xxx| command and |goto done|@>=
begin print('xxx'''); bad_char:=false;
for k:=1 to p do
begin q:=get_byte;
if (q<" ")or(q>"~") then bad_char:=true;
print(xchr[q]);
end;
print('''');
if bad_char then error('non-ASCII character in xxx command!');
@.non-ASCII character...@>
goto done;
end
@ @<Translate a |set_char|...@>=
begin
out_char(p,hh,vv)
end
@ @<Finish a command that either sets or puts a character...@>=
if p<0 then p:=255-((-1-p) mod 256)
else if p>=256 then p:=p mod 256; {width computation for oriental fonts}
@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
if (p<font_bc[cur_font])or(p>font_ec[cur_font]) then q:=invalid_width
else q:=char_width(cur_font)(p);
if q=invalid_width then
begin error('character ',p:1,' invalid in font ');
@.character $c$ invalid...@>
print_font(cur_font);
if cur_font<>nf then print('!'); {font |nf| has `\.!' in its name}
end;
if o>=put1 then goto done;
if q=invalid_width then q:=0
else hh:=hh+char_pixel_width(cur_font)(p);
goto move_right
@ @<Finish a command that either sets or puts a rule...@>=
q:=signed_quad;
if (p>0) and (q>0) then
for i:=hh to hh+horiz_rule_pixels(q)-1 do
for j:=vv downto vv-vert_rule_pixels(p)+1 do
out_char(xord['-'],i,j);
if o=put_rule then goto done;
hh:=hh+horiz_rule_pixels(q); goto move_right
@ Since \.{DVIDOC} is intended to diagnose strange errors, it checks
carefully to make sure that |h| and |v| do not get out of range.
Normal \.{DVI}-reading programs need not do this.
@d infinity==@'17777777777 {$\infty$ (approximately)}
@d max_drift=2 {we insist that abs|(hh-pixel_round(h))<=max_drift|}
@<Finish a command that sets |h:=h+q|, then |goto done|@>=
if (h>0)and(q>0) then if h>infinity-q then
begin error('arithmetic overflow! parameter changed from ',
@.arithmetic overflow...@>
q:1,' to ',infinity-h:1);
q:=infinity-h;
end;
if (h<0)and(q<0) then if -h>q+infinity then
begin error('arithmetic overflow! parameter changed from ',
q:1, ' to ',(-h)-infinity:1);
q:=(-h)-infinity;
end;
hhh:=horiz_pixel_round(h+q);
if abs(hhh-hh)>max_drift then
if hhh>hh then hh:=hhh-max_drift
else hh:=hhh+max_drift;
h:=h+q;
if abs(h)>max_h_so_far then
begin if abs(h)>max_h+99 then
begin error('warning: |h|>',max_h:1,'!');
@.warning: |h|...@>
max_h:=abs(h);
end;
max_h_so_far:=abs(h);
end;
goto done
@ @<Finish a command that sets |v:=v+p|, then |goto done|@>=
if (v>0)and(p>0) then if v>infinity-p then
begin error('arithmetic overflow! parameter changed from ',
@.arithmetic overflow...@>
p:1,' to ',infinity-v:1);
p:=infinity-v;
end;
if (v<0)and(p<0) then if -v>p+infinity then
begin error('arithmetic overflow! parameter changed from ',
p:1, ' to ',(-v)-infinity:1);
p:=(-v)-infinity;
end;
vvv:=vert_pixel_round(v+p);
if abs(vvv-vv)>max_drift then
if vvv>vv then vv:=vvv-max_drift
else vv:=vvv+max_drift;
v:=v+p;
if abs(v)>max_v_so_far then
begin if abs(v)>max_v+99 then
begin error('warning: |v|>',max_v:1,'!');
@.warning: |v|...@>
max_v:=abs(v);
end;
max_v_so_far:=abs(v);
end;
goto done
@ @<Finish a command that changes the current font...@>=
font_num[nf]:=p; cur_font:=0;
while font_num[cur_font]<>p do incr(cur_font);
goto done
@* Skipping pages.
@ Global variables called |old_backpointer| and |new_backpointer|
are used to check whether the back pointers are properly set up.
Another one tells whether we have already found the starting page.
@<Glob...@>=
@!old_backpointer:integer; {the previous |bop| command location}
@!new_backpointer:integer; {the current |bop| command location}
@!started:boolean; {has the starting page been found?}
@ @<Set init...@>=
old_backpointer:=-1; started:=false;
@ @<Pass a |bop| command, setting up the |count| array@>=
new_backpointer:=cur_loc-1; incr(page_count);
for k:=0 to 9 do count[k]:=signed_quad;
if signed_quad<>old_backpointer
then print_ln('backpointer in byte ',cur_loc-4:1,
' should be ',old_backpointer:1,'!');
@.backpointer...should be p@>
old_backpointer:=new_backpointer
@* Using the backpointers.
First comes a routine that illustrates how to find the postamble quickly.
@<Find the postamble, working back from the end@>=
n:=dvi_length;
if n<53 then bad_dvi('only ',n:1,' bytes long');
@.only n bytes long@>
m:=n-4;
repeat if m=0 then bad_dvi('all 223s');
@.all 223s@>
move_to_byte(m); k:=get_byte; decr(m);
until k<>223;
if k<>id_byte then bad_dvi('ID byte is ',k:1);
@.ID byte is wrong@>
move_to_byte(m-3); q:=signed_quad;
if (q<0)or(q>m-33) then bad_dvi('post pointer ',q:1,' at byte ',m-3:1);
@.post pointer is wrong@>
move_to_byte(q); k:=get_byte;
if k<>post then bad_dvi('byte ',q:1,' is not post');
@.byte n is not post@>
post_loc:=q; first_backpointer:=signed_quad
@ Note that the last steps of the above code save the locations of the
the |post| byte and the final |bop|. We had better declare these global
variables, together with another one that we will need shortly.
@<Glob...@>=
@!post_loc:integer; {byte location where the postamble begins}
@!first_backpointer:integer; {the pointer following |post|}
@!start_loc:integer; {byte location of the first page to process}
@ The next little routine shows how the backpointers can be followed
to move through a \.{DVI} file in reverse order. Ordinarily a \.{DVI}-reading
program would do this only if it wants to print the pages backwards or
if it wants to find a specified starting page that is not necessarily the
first page in the file; otherwise it would of course be simpler and faster
just to read the whole file from the beginning.
@<Count the pages and move to the starting page@>=
q:=post_loc; p:=first_backpointer; start_loc:=-1;
if p>=0 then
repeat {now |q| points to a |post| or |bop| command; |p>=0| is prev pointer}
if p>q-46 then
bad_dvi('page link ',p:1,' after byte ',q:1);
@.page link wrong...@>
q:=p; move_to_byte(q); k:=get_byte;
if k=bop then incr(page_count)
else bad_dvi('byte ',q:1,' is not bop');
@.byte n is not bop@>
for k:=0 to 9 do count[k]:=signed_quad;
if start_match then start_loc:=q;
p:=signed_quad;
until p<0;
if start_loc<0 then abort('starting page number could not be found!');
move_to_byte(start_loc+1); old_backpointer:=start_loc;
for k:=0 to 9 do count[k]:=signed_quad;
p:=signed_quad; started:=true
@* Reading the postamble.
Now imagine that we are reading the \.{DVI} file and positioned just
four bytes after the |post| command. That, in fact, is the situation,
when the following part of \.{DVIDOC} is called upon to read, translate,
and check the rest of the postamble.
@p procedure read_postamble;
var k:integer; {loop index}
@!p,@!q,@!m:integer; {general purpose registers}
begin post_loc:=cur_loc-5;
@.Postamble starts at byte n@>
if signed_quad<>numerator then
print_ln('numerator doesn''t match the preamble!');
@.numerator doesn't match@>
if signed_quad<>denominator then
print_ln('denominator doesn''t match the preamble!');
@.denominator doesn't match@>
if signed_quad<>mag then if new_mag=0 then
print_ln('magnification doesn''t match the preamble!');
@.magnification doesn't match@>
max_v:=signed_quad; max_h:=signed_quad;@/
max_s:=get_two_bytes; total_pages:=get_two_bytes;@/
@<Process the font definitions of the postamble@>;
@<Make sure that the end of the file is well-formed@>;
end;
@ When we get to the present code, the |post_post| command has
just been read.
@<Make sure that the end of the file is well-formed@>=
q:=signed_quad;
if q<>post_loc then
print_ln('bad postamble pointer in byte ',cur_loc-4:1,'!');
@.bad postamble pointer@>
m:=get_byte;
if m<>id_byte then print_ln('identification in byte ',cur_loc-1:1,
@.identification...should be n@>
' should be ',id_byte:1,'!');
k:=cur_loc; m:=223;
while (m=223)and not eof(dvi_file) do m:=get_byte;
if not eof(dvi_file) then bad_dvi('signature in byte ',cur_loc-1:1,
@.signature...should be...@>
' should be 223')
else if cur_loc<k+4 then
print_ln('not enough signature bytes at end of file (',
@.not enough signature bytes...@>
cur_loc-k:1,')');
@ @<Process the font definitions...@>=
repeat k:=get_byte;
if (k>=fnt_def1)and(k<fnt_def1+4) then
begin p:=first_par(k); define_font(p); print_ln(' '); k:=nop;
end;
until k<>nop;
if k<>post_post then
print_ln('byte ',cur_loc-1:1,' is not postpost!')
@.byte n is not postpost@>
@* The main program.
Now we are ready to put it all together. This is where \.{DVIDOC} starts,
and where it ends.
@p begin
if (argc <> 3) then
begin
error('Usage: dvidoc <dvi-file> <doc-file>');
goto done;
end;
initialize; {get all variables initialized}
dialog; {set up all the options}
@<Process the preamble@>;
@<Find the postamble, working back from the end@>;
in_postamble:=true; read_postamble; in_postamble:=false;
@<Count the pages and move to the starting page@>;
if not in_postamble then @<Translate up to |max_pages| pages@>;
final_end:end.
@ The main program needs a few global variables in order to do its work.
@<Glob...@>=
@!k,@!m,@!n,@!p,@!q:integer; {general purpose registers}
@ A \.{DVI}-reading program that reads the postamble first need not look at the
preamble; but \.{DVIDOC} looks at the preamble in order to do error
checking, and to display the introductory comment.
@<Process the preamble@>=
argv(1, cur_name);
if test_access(read_access_mode, no_file_path) then begin
open_dvi_file;
if eof(dvi_file) then begin
error('DVI file not found');
goto done;
end;
end
else begin
error('Cannot open input file');
goto done;
end;
p:=get_byte; {fetch the first byte}
if p<>pre then bad_dvi('First byte isn''t start of preamble!');
@.First byte isn't...@>
p:=get_byte; {fetch the identification byte}
if p<>id_byte then
print_ln('identification in byte 1 should be ',id_byte:1,'!');
@.identification...should be n@>
@<Compute the conversion factor@>;
p:=get_byte; {fetch the length of the introductory comment}
print('''');
while p>0 do
begin decr(p); print(xchr[get_byte]);
end;
print_ln('''')
@ The conversion factors |horiz_conv| and
|vert_conv| are figured as follows: There are exactly
|n/d| \.{DVI} units per decimicron, and 254000 decimicrons per inch,
and |horiz_resolution| or |vert_resolution| characters per inch. Then we have to adjust this
by the stated amount of magnification.
@<Compute the conversion factor@>=
numerator:=signed_quad; denominator:=signed_quad;
if numerator<=0 then bad_dvi('numerator is ',numerator:1);
@.numerator is wrong@>
if denominator<=0 then bad_dvi('denominator is ',denominator:1);
@.denominator is wrong@>
horiz_conv:=(numerator/254000.0)*(horiz_resolution/denominator);
vert_conv:=(numerator/254000.0)*(vert_resolution/denominator);
mag:=signed_quad;
if new_mag>0 then mag:=new_mag
else if mag<=0 then bad_dvi('magnification is ',mag:1);
@.magnification is wrong@>
true_horiz_conv:=horiz_conv; horiz_conv:=true_horiz_conv*(mag/1000.0);
true_vert_conv:=vert_conv; vert_conv:=true_vert_conv*(mag/1000.0);
@ The code shown here uses a convention that has proved to be useful:
If the starting page was specified as, e.g., `\.{1.*.-5}', then
all page numbers in the file are displayed by showing the values of
counts 0, 1, and~2, separated by dots. Such numbers can, for example,
be displayed on the console of a printer when it is working on that
page.
@<Translate up to...@>=
begin while max_pages>0 do
begin decr(max_pages);
print('Page ');
for k:=0 to start_vals do
begin print(count[k]:1);
if k<start_vals then print('.')
else print_ln(' ');
end;
if not do_page then bad_dvi('page ended unexpectedly');
@.page ended unexpectedly@>
repeat k:=get_byte;
if (k>=fnt_def1)and(k<fnt_def1+4) then
begin p:=first_par(k); define_font(p); k:=nop;
end;
until k<>nop;
if k=post then
begin in_postamble:=true; goto done;
end;
if k<>bop then bad_dvi('byte ',cur_loc-1:1,' is not bop');
@.byte n is not bop@>
@<Pass a |bop|...@>;
end;
done:end
@* System-dependent changes.
This section should be replaced, if necessary, by changes to the program
that are necessary to make \.{DVIDOC} work at a particular installation.
It is usually best to design your change file so that all changes to
previous sections preserve the section numbering; then everybody's version
will be consistent with the printed program. More extensive changes,
which introduce new sections, can be inserted here; then only the index
itself will get a new section number.
@^system dependencies@>
@* Index.
Pointers to error messages appear here together with the section numbers
where each ident\-i\-fier is used.
SHAR_EOF
if test 91548 -ne "`wc -c < 'dvidoc.web'`"
then
echo shar: "error transmitting 'dvidoc.web'" '(should have been 91548 characters)'
fi
fi
echo shar: "extracting 'dvityext.c'" '(6497 characters)'
if test -f 'dvityext.c'
then
echo shar: "will not over-write existing file 'dvityext.c'"
else
cat << \SHAR_EOF > 'dvityext.c'
/*
External procedures for use with dvidoc.
Adapted from those used in dvip.
Written by H. Trickey, 9/3/83.
Implement the following procedures (as declared in Pascal)
procedure opendvifile;
function getbyte: integer;
function signedbyte: integer;
function gettwobytes: integer;
function signedpair: integer;
function getthreebytes: integer;
function signedtrio: integer;
function signedquad: integer;
function curpos(var f:bytefile):integer;
procedure setpos(var f:bytefile;n:integer);
procedure setpaths;
function testaccess(accessmode:integer; filepath:integer):boolean;
Declaration for eofdvifile changed from int to char to match
Pascal boolean, otherwise fails on 68000's (byte ordering problem).
Ken Yap, Feb 1986
*/
#include <stdio.h>
#include <strings.h>
#include "texpaths.h"
static FILE *dvif;
extern char eofdvifile; /* needs to be set true when this happens */
extern int curloc; /* needs to be incremented by getbyte, signedbyte */
#define namelength 100 /* should agree with dvitype.ch */
extern char curname[],realnameoffile[]; /* these have size namelength */
/* open the dvifile, using the name in realnameoffile */
opendvifile()
{
register int i;
for (i = namelength - 1; i >= 0; --i)
if (realnameoffile[i] == ' ')
realnameoffile[i] = '\0';
else
break;
if (!(dvif=fopen(realnameoffile,"r")))
eofdvifile = 1;
else
eofdvifile = 0;
}
/* return unsigned version of next byte in dvifile */
int getbyte()
{
register int c;
if ((c = getc(dvif))==EOF) {
eofdvifile = 1;
return(0);
}
curloc++;
return(c);
}
/* return signed version of next byte in dvifile */
int signedbyte()
{ register int c;
if ((c = getc(dvif))==EOF) {
eofdvifile = 1;
return(0);
}
curloc++;
if (c>127) return(c-256);
return(c);
}
/* return unsigned value of next two bytes (high order first) */
int gettwobytes()
{
register int a,b;
a = getc(dvif);
eofdvifile = ((b = getc(dvif))==EOF);
curloc += 2;
return((a << 8) | b);
}
/* return signed value of next two bytes (high order first) */
int signedpair()
{
register int a,b;
if ( (a = getc(dvif)) > 127) a -= 256; /* sign extend */
eofdvifile = ((b = getc(dvif))==EOF);
curloc += 2;
return((a << 8) | b);
}
/* return unsigned value of next three bytes */
int getthreebytes()
{
register int a,b,c;
a = getc(dvif);
b = getc(dvif);
eofdvifile = ((c = getc(dvif))==EOF);
curloc +=3;
return((a << 16) | (b << 8) | c);
}
/* return signed value of next three bytes */
int signedtrio()
{
register int a,b,c;
if ( (a = getc(dvif)) > 127) a -= 256;
b = getc(dvif);
eofdvifile = ((c = getc(dvif))==EOF);
curloc +=3;
return((a << 16) | (b << 8) | c);
}
/* return value of next four bytes */
int signedquad()
{
register int a,b,c,d;
a = getc(dvif);
b = getc(dvif);
c = getc(dvif);
eofdvifile = ((d = getc(dvif))==EOF);
curloc += 4;
return((a << 24) | (b << 16) | (c << 8) | d);
}
/* seek to byte n of file f: actually, assume f is for dvifile */
setpos(f,n)
int f; /* not really, but we ignore it */
int n;
{
if (n>=0) {
fseek(dvif,(long) n,0);
eofdvifile = 0;
}
else {
fseek(dvif, (long) n, 2);
eofdvifile = 1;
}
}
/* return current byte offset in file f (again, assume dvifile) */
int curpos(f)
int f;
{
return((int) ftell(dvif));
}
char *fontpath;
char *getenv();
/*
* setpaths is called to set up the pointer fontpath
* as follows: if the user's environment has a value for TEXFONTS
* then use it; otherwise, use defaultfontpath.
*/
setpaths()
{
register char *envpath;
if ((envpath = getenv("TEXFONTS")) != NULL)
fontpath = envpath;
else
fontpath = defaultfontpath;
}
/*
* testaccess(amode,filepath)
*
* Test whether or not the file whose name is in the global curname
* can be opened for reading (if mode=READACCESS)
* or writing (if mode=WRITEACCESS).
*
* The filepath argument is one of the ...FILEPATH constants defined below.
* If the filename given in curname does not begin with '/', we try
* prepending all the ':'-separated areanames in the appropriate path to the
* filename until access can be made, if it ever can.
*
* The realnameoffile global array will contain the name that yielded an
* access success.
*/
#define READACCESS 4
#define WRITEACCESS 2
#define NOFILEPATH 0
#define FONTFILEPATH 3
typedef enum {FALSE, TRUE} bool;
bool
testaccess(amode,filepath)
int amode,filepath;
{
register bool ok;
register char *p;
char *curpathplace;
int f;
switch(filepath) {
case NOFILEPATH: curpathplace = NULL; break;
case FONTFILEPATH: curpathplace = fontpath; break;
}
if (curname[0]=='/') /* file name has absolute path */
curpathplace = NULL;
do {
packrealnameoffile(&curpathplace);
if (amode==READACCESS)
/* use system call "access" to see if we could read it */
if (access(realnameoffile,READACCESS)==0) ok = TRUE;
else ok = FALSE;
else {
/* WRITEACCESS: use creat to see if we could create it, but close
the file again if we're OK, to let pc open it for real */
f = creat(realnameoffile,0666);
if (f>=0) ok = TRUE;
else ok = FALSE;
if (ok)
close(f);
}
} while (!ok && curpathplace != NULL);
if (ok) { /* pad realnameoffile with blanks, as Pascal wants */
for (p = realnameoffile; *p != '\0'; p++)
/* nothing: find end of string */ ;
while (p < &(realnameoffile[namelength]))
*p++ = ' ';
}
return (ok);
}
/*
* packrealnameoffile(cpp) makes realnameoffile contain the directory at *cpp,
* followed by '/', followed by the characters in curname up until the
* first blank there, and finally a '\0'. The cpp pointer is left pointing
* at the next directory in the path.
* But: if *cpp == NULL, then we are supposed to use curname as is.
*/
packrealnameoffile(cpp)
char **cpp;
{
register char *p,*realname;
realname = realnameoffile;
if ((p = *cpp)!=NULL) {
while ((*p != ':') && (*p != '\0')) {
*realname++ = *p++;
if (realname == &(realnameoffile[namelength-1]))
break;
}
if (*p == '\0') *cpp = NULL; /* at end of path now */
else *cpp = p+1; /* else get past ':' */
*realname++ = '/'; /* separate the area from the name to follow */
}
/* now append curname to realname... */
p = curname;
while (*p != ' ') {
if (realname >= &(realnameoffile[namelength-1])) {
fprintf(stderr,"! Full file name is too long\n");
break;
}
*realname++ = *p++;
}
*realname = '\0';
}
SHAR_EOF
if test 6497 -ne "`wc -c < 'dvityext.c'`"
then
echo shar: "error transmitting 'dvityext.c'" '(should have been 6497 characters)'
fi
fi
echo shar: "extracting 'dvityext.h'" '(577 characters)'
if test -f 'dvityext.h'
then
echo shar: "will not over-write existing file 'dvityext.h'"
else
cat << \SHAR_EOF > 'dvityext.h'
procedure opendvifile;
external;
function getbyte: integer;
external;
function signedbyte: integer;
external;
function gettwobytes: integer;
external;
function signedpair: integer;
external;
function getthreebytes: integer;
external;
function signedtrio: integer;
external;
function signedquad: integer;
external;
function curpos(var f:bytefile):integer;
external;
procedure setpos(var f:bytefile;n:integer);
external;
procedure setpaths;
external;
function testaccess(accessmode:integer; filepath:integer): boolean;
external;
procedure exit(i:integer);
external;
SHAR_EOF
if test 577 -ne "`wc -c < 'dvityext.h'`"
then
echo shar: "error transmitting 'dvityext.h'" '(should have been 577 characters)'
fi
fi
echo shar: "extracting 'texpaths.h'" '(853 characters)'
if test -f 'texpaths.h'
then
echo shar: "will not over-write existing file 'texpaths.h'"
else
cat << \SHAR_EOF > 'texpaths.h'
/*
* This file defines the default paths that will be used for TeX software.
* (These paths are used if the user's environment doesn't specify paths.)
*
* Paths should be colon-separated and no longer than MAXINPATHCHARS-1
* (for defaultinputpath) or MAXOTHPATHCHARS (for other default paths).
*/
#define MAXINPATHCHARS 700 /* maximum number of chars in an input path */
#define defaultinputpath ".:/usr/lib/tex/macros"
/* this should always start with "." */
#define MAXOTHPATHCHARS 100 /* other paths should be much shorter */
#define defaultfontpath "/usr/lib/tex/fonts"
/* it is probably best not to include "." here to prevent confusion
by spooled device drivers that think they know where the fonts
really are */
#define defaultformatpath ".:/usr/lib/tex/macros"
#define defaultpoolpath ".:/usr/lib/tex"
SHAR_EOF
if test 853 -ne "`wc -c < 'texpaths.h'`"
then
echo shar: "error transmitting 'texpaths.h'" '(should have been 853 characters)'
fi
fi
echo shar: "extracting 'doc.pl'" '(7419 characters)'
if test -f 'doc.pl'
then
echo shar: "will not over-write existing file 'doc.pl'"
else
cat << \SHAR_EOF > 'doc.pl'
(COMMENT OSU DOC file font)
(COMMENT Derived from amtt)
(CODINGSCHEME TEX TYPEWRITER TEXT)
(DESIGNSIZE R 13.76574)
(COMMENT DESIGNSIZE IS IN POINTS)
(COMMENT OTHER SIZES ARE MULTIPLES OF DESIGNSIZE)
(CHECKSUM O 10653670734)
(SEVENBITSAFEFLAG TRUE)
(FONTDIMEN
(SLANT R 0.0)
(SPACE R 0.5249996)
(STRETCH R 1.049999)
(SHRINK R 0.0)
(XHEIGHT R 0.4305553)
(QUAD R 0.5249996)
(EXTRASPACE R 0.5249996)
)
(LIGTABLE
(LABEL O 47)
(LIG O 47 O 42)
(STOP)
(LABEL O 140)
(LIG O 140 O 42)
(STOP)
)
(CHARACTER O 41
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER O 42
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER O 43
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER O 44
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 45
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 46
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER O 47
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER O 50
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 51
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 52
(CHARWD R 0.5249996)
(CHARHT R 0.5208330)
)
(CHARACTER O 53
(CHARWD R 0.5249996)
(CHARHT R 0.5097217)
)
(CHARACTER O 54
(CHARWD R 0.5249996)
(CHARHT R 0.1000003)
(CHARDP R 0.1111106)
)
(CHARACTER O 55
(CHARWD R 0.5249996)
(CHARHT R 0.5097217)
)
(CHARACTER O 56
(CHARWD R 0.5249996)
(CHARHT R 0.1000003)
)
(CHARACTER O 57
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER C 0
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C 1
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C 2
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C 3
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C 4
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C 5
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C 6
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C 7
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C 8
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C 9
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER O 72
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER O 73
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
(CHARDP R 0.1111106)
)
(CHARACTER O 74
(CHARWD R 0.5249996)
(CHARHT R 0.5555553)
)
(CHARACTER O 75
(CHARWD R 0.5249996)
(CHARHT R 0.4156246)
)
(CHARACTER O 76
(CHARWD R 0.5249996)
(CHARHT R 0.5555553)
)
(CHARACTER O 77
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER O 100
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C A
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C B
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C C
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C D
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C E
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C F
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C G
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C H
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C I
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C J
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C K
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C L
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C M
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C N
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C O
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C P
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C Q
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
(CHARDP R 0.1111106)
)
(CHARACTER C R
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C S
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C T
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C U
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C V
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C W
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C X
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C Y
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C Z
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER O 133
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 134
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 135
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 136
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER O 137
(CHARWD R 0.5249996)
(CHARHT R 0.5381946)
)
(CHARACTER O 140
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C a
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C b
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C c
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C d
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C e
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C f
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C g
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
(CHARDP R 0.2222223)
)
(CHARACTER C h
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C i
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C j
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
(CHARDP R 0.2222223)
)
(CHARACTER C k
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C l
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
(CHARACTER C m
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C n
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C o
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C p
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
(CHARDP R 0.2222223)
)
(CHARACTER C q
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
(CHARDP R 0.2222223)
)
(CHARACTER C r
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C s
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C t
(CHARWD R 0.5249996)
(CHARHT R 0.5659723)
)
(CHARACTER C u
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C v
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C w
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C x
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER C y
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
(CHARDP R 0.2222223)
)
(CHARACTER C z
(CHARWD R 0.5249996)
(CHARHT R 0.4305553)
)
(CHARACTER O 173
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 174
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 175
(CHARWD R 0.5249996)
(CHARHT R 0.6944446)
(CHARDP R 0.0833330)
)
(CHARACTER O 176
(CHARWD R 0.5249996)
(CHARHT R 0.6111106)
)
SHAR_EOF
if test 7419 -ne "`wc -c < 'doc.pl'`"
then
echo shar: "error transmitting 'doc.pl'" '(should have been 7419 characters)'
fi
fi
exit 0
# End of shell archive
More information about the Comp.sources.unix
mailing list