Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!rochester!ken From: ken@rochester.ARPA (SKY) Newsgroups: net.sources Subject: DVIDOC, a postprocessor for DVI files (Part 2 of 2) Message-ID: <23447@rochester.ARPA> Date: Thu, 25-Dec-86 18:02:33 EST Article-I.D.: rocheste.23447 Posted: Thu Dec 25 18:02:33 1986 Date-Received: Thu, 25-Dec-86 22:45:57 EST Reply-To: ken@rochester.UUCP (SKY) Distribution: world Organization: U of Rochester, CS Dept, Rochester, NY Lines: 1719 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 @ @= 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. @= @!in_postamble:boolean; {are we reading the postamble?} @ @= 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); @; if in_postamble then begin if f 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 @ else @; end; @ @= 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 jnames[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 @ @= 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) @ @= begin @; 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 @; end; print_ln(' '); end @ @= 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} @= @!default_directory:packed array[1..default_directory_name_length] of char; @ @= 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@> @= 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. @= @!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. @= 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|. @= @!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. @= @!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} @ @= 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= @!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@>@@; 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 @; 9998: print_ln('!'); do_page:=false; 9999: end; @ @= 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@> @; fin_set: @; fin_rule: @; move_right: @; 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. @= if o 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@>@@; @t\4@>@@; othercases if special_cases(o,p,a) then goto done@+else goto 9998 endcases @ @= 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@>@@; @t\4@>@@; four_cases(xxx1): @; 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: @; change_font: @; 9998: pure:=false; done: special_cases:=pure; end; @ @= 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 @= 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 @= 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; @ @= 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; @ @= 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 @ @= begin out_char(p,hh,vv) end @ @= 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 (pfont_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 @ @= 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|} @= 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 @ @= 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 @ @= 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. @= @!old_backpointer:integer; {the previous |bop| command location} @!new_backpointer:integer; {the current |bop| command location} @!started:boolean; {has the starting page been found?} @ @= old_backpointer:=-1; started:=false; @ @= 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. @= 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. @= @!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. @= 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;@/ @; @; end; @ When we get to the present code, the |post_post| command has just been read. @= 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 cur_loc-k:1,')'); @ @= repeat k:=get_byte; if (k>=fnt_def1)and(knop; 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 '); goto done; end; initialize; {get all variables initialized} dialog; {set up all the options} @; @; in_postamble:=true; read_postamble; in_postamble:=false; @; if not in_postamble then @; final_end:end. @ The main program needs a few global variables in order to do its work. @= @!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. @= 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@> @; 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. @= 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. @= 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 repeat k:=get_byte; if (k>=fnt_def1)and(knop; 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@> @; 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 #include #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