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