(****************************************************************************** * bogart:/usr/alla/zap/dvitty/dvitty.p 1986-09-21 01:54:52, * bugfixes from Tor Lillqvist (santra!tml) added. * bogart:/usr/alla/zap/dvitty/dvitty.p 1986-08-15 20:24:31, * Version to be sent to mod.sources ready. * New option since last version: * -Fprog Pipe output to prog. Can be used to get a different * pager than the default. * bogart:/usr/alla/zap/dvitty/dvitty.p 1986-01-13 21:49:31, * Environment variable DVITTY is read and options can be set from it. * These are the currently implemented options: * -ofile Write output to file, else write to stdout, * possibly piped through a pager if stdout is a tty. * -plist Print pages whos TeX-page-number are in list. * List is on the form 1,3:6,8 to choose pages * 1,3-6 and 8. TeX-nrs can be negative: -p-1:-4,4 * -Plist Print pages whos sequential number are in list. * -wn Print the lines with width n characters, default is * 80. Wider lines gives better results. * -q Don't try to pipe to a pager. * -f Try to pipe to a pager if output is a tty. * Default of -q and -f is a compile time option, a constant. * -l Write '^L' instead of formfeed between pages. * -u Don't try to find Scandinavian characters (they will * print as a:s and o:s if this option is choosen). * -s Scandinavian characters printed as }{|][\. * Default of -s and -u is a compile time option, a constant. * bogart:/usr/alla/zap/dvitty/dvitty.p 1986-01-10 18:51:03, * Argument parsing, and random access functions (external, in C) * and other OS-dependent stuff (in C). Removed private 'pager' & * tries to pipe through PAGER (environment var) or, if PAGER not * defined, /usr/ucb/more. Some changes for efficency. * bogart:/usr/alla/svante/dvitty/dvitty.p 1985-07-15 20:51:00, * The code for processing dvi-files running on UNIX (UCB-Pascal) * but no argument parsing. * VERA::SS:DVITTY.PAS.140, 30-Mar-85 05:43:56, * Edit: Svante Lindahl * VERA::SS:DVITTY.PAS.136, 15-Jan-85 13:52:59, * Edit: Svante Lindahl, final Twenex version !!!?? * VERA::SS:DVITTY.PAS.121, 14-Jan-85 03:10:22, * Edit: Svante Lindahl, cleaned up and fixed a lot of little things * VERA::SS:DVITTY.PAS.25, 15-Dec-84 05:29:56, * Edit: Svante Lindahl, COMND-interface, including command line scanning * VERA::SS:DVITTY.PAS.23, 10-Dec-84 21:24:41, * Edit: Svante Lindahl, added command line scanning with Rscan-JSYS * VERA::DVITTY.PAS.48, 8-Oct-84 13:26:30, * Edit: Svante Lindahl, fixed switch-parsing, destroyed by earlier patches * VERA::DVITTY.PAS.45, 29-Sep-84 18:29:53, * Edit: Svante Lindahl * * dvitty - get an ascii representation of a dvi-file, suitable for ttys * * This program, and any documentation for it, is copyrighted by Svante * Lindahl. It may be copied for non-commercial use only, provided that * any and all copyright notices are preserved. * * Please report any bugs and/or fixes to: * * Internet: zap@nada.kth.se UUCP: {uunet,mcvax}!enea!nada.kth.se!zap *) program dvitty(input, output); const Copyright = 'dvitty.p Copyright (C) 1984, 1985, 1986 Svante Lindahl.'; {-----------------------------------------------------------------------} { The following two constants may be toggled before compilation to } { customize the default behaviour of the program for your site. } { Whichever their settings are, the defaults can be overridden at } { runtime. } {-----------------------------------------------------------------------} defscand = true; { default is Scandinavian, toggle this if you } { don't have terminals with Scand. nat. chars } defpage = true; { default: try to pipe through a pager (like } { more) if stdout is tty and no -o switch } pathlen = 40; { length of string for path to pager program } defpath = '/usr/ucb/more '; { pathlen chars } {------------------ end of customization constants ---------------------} versionid = 2; { version number of dvifiles that pgm handles } stackmax = 100; { allows 100 dvi-pushes } verticalepsilon = 450000; { crlf when increasing v more than this } rightmargin = 152; { nr of columns allowed to the right of h=0 } leftmargin = -50; { give some room for negative h-coordinate } stringlength = 100; { size of char-arrays for strings } advance = true; { if advancing h when outputing a rule } stay = false; { if not advancing h when outputing a rule } absolute = 0; relative = 1; chffd = 12; { formfeed } chspc = 32; { space } chdel = 127; { delete } { some dvi op-codes (digit at end tells dvi-version-#) } nop2 = 138; { no-op } bop2 = 139; { beginning of page } eop2 = 140; { end of page } post2 = 248; { post-amble } pre2 = 247; { pre-amble } postpost2 = 249; { post-post-amble } lastchar = 127; { highest char-code } {-----------------------------------------------------------------------------} type ubyte = 0..255; { dvi-files consists of eight-bit-bytes } sbyte = -128..127; { UCB-pascal reads 16 bits if unsigned byte } string = packed array [1..stringlength] of char; pathtype = packed array [1..pathlen] of char; charset = set of char; stackitem = record hh, vv, ww, xx, yy, zz : integer; end; stacktype = record { stack for dvi-pushes } items : array [1..stackmax] of stackitem; top : 0..stackmax; end; { stacktype } lineptr = ^linetype; linetype = record { the lines of text to be output to outfile } vv : integer; { vertical position of the line } charactercount : integer; { pos of last char on line } prev : lineptr; { preceding line } next : lineptr; { succeding line } text : packed array [leftmargin..rightmargin] of char; end; { linetype } printlistptr = ^printlisttype; printlisttype = record { list of pages selected for output } pag : integer; { the nr of the page } all : boolean; { pages in intervall selected } nxt : printlistptr; { next item in list } end; { printlisttype } useagecodetype= (wrnge, { width switch arg out of range } ign, { ignore cause, print'Usage:..' } nan, { not a number where one expected } gae, { garbage at end } bdlst, { bad page-numberlist } onef, { only one dvifile allowed } bdopt, { bad option } lngpth, { pathname too long (for -F) } noarg); { argument expected } errorcodetype = (illop, { illegal op-code } stkof, { stack over-flow } stkuf, { stack under-flow } stkrq, { stack requirement } badid, { id is not right } bdsgn, { signature is wrong } fwsgn, { too few signatures } nopre, { no pre-amble where expected } nobop, { no bop-command where expected } nopp, { no postpost where expected } bdpre, { unexpected preamble occured } bdbop, { unexpected bop-command occured } bdpst, { unexpected post-command occured } bdpp, { unexpected postpost } nopst, { no post-amble where expected } illch, { character code out of range } filop, { cannot access file } filcr); { cannot creat file } DVIfiletype = file of sbyte; {-----------------------------------------------------------------------------} var opcode : ubyte; { dvi-opcodes } foo : integer; { utility variable, "register" } h, v : integer; { coordinates, horizontal and vertical } w, x, y, z : integer; { horizontal and vertical amounts } outputtofile : boolean; { tells if output goes to file or stdout } pager : boolean; { tells if output is piped to a pager } pageswitchon : boolean; { true if user-set pages to print } sequenceon : boolean; { false if pagesw-nrs refers to TeX-nrs } scascii : boolean; { if true make Scand. nat. chars right } noffd : boolean; { if true output ^L instead of formfeed } ttywidth : integer; { max nr of chars per printed line } path : pathtype; { name of the pager to run } pathpgm : boolean; { use 'defpath' if this is true } maxpagewidth : integer; { width of widest page in file } charwidth : integer; { aprox width of charachter } currentpage : printlistptr; { current page to print } firstpage : printlistptr; { first page selected } lastpage : printlistptr; { last page selected } currentline : lineptr; { pointer to current line on current page } firstline : lineptr; { pointer to first line on current page } lastline : lineptr; { pointer to last line on current page } firstcolumn : integer; { 1st column with something to print } stack : stacktype; DVIfile : DVIfiletype; ERRfile : text; DVIfilename : string; OUTfilename : string; {-----------------------------------------------------------------------------} #include "sys.h" { headers for external C-routines } {-----------------------------------------------------------------------------} procedure errorexit(errorcode : errorcodetype); begin write(ERRfile,'dvitty: '); case errorcode of illop : writeln(ERRfile,'Illegal op-code found: ',opcode:0); stkof : writeln(ERRfile,'Stack overflow.'); stkuf : writeln(ERRfile,'Stack underflow.'); stkrq : writeln(ERRfile,'Too much stack required : ',foo:0); badid : writeln(ERRfile,'Id-byte is not correct: ',opcode:0); bdsgn : writeln(ERRfile,'Bad signature: ',foo:0,' (not 223).'); fwsgn : writeln(ERRfile,foo:0,' signature bytes (min. 4).'); nopre : writeln(ERRfile,'Missing preamble.'); nobop : writeln(ERRfile,'Missing beginning-of-page command.'); nopp : writeln(ERRfile,'Missing post-post command.'); bdpre : writeln(ERRfile,'Preamble occured inside a page.'); bdbop : writeln(ERRfile,'BOP-command occured inside a page.'); bdpst : writeln(ERRfile,'Postamble occured before end-of-page.'); bdpp : writeln(ERRfile,'Postpost occured before post-command.'); nopst : writeln(ERRfile,'Missing postamble.'); illch : writeln(ERRfile,'Character code out of range, 0..127'); filop : writeln(ERRfile,'Cannot open dvifile'); filcr : writeln(ERRfile,'Cannot create outfile'); end; if outputtofile then delete(output); exit(-1); end; { errorexit } {-----------------------------------------------------------------------------} procedure usage(uerr : useagecodetype); begin if uerr<>ign then begin write(ERRfile,'dvitty: '); case uerr of ign : writeln(ERRfile, Copyright); wrnge : writeln(ERRfile,'width arg out of range:16-132'); nan : writeln(ERRfile,'numeric argument expected'); gae : writeln(ERRfile,'garbage at end of argument'); bdlst : writeln(ERRfile,'mal-formed list of pagenumbers'); onef : writeln(ERRfile,'only one infile argument allowed'); noarg : writeln(ERRfile,'option argument expected'); lngpth : writeln(ERRfile,'path too long for -F'); bdopt : writeln(ERRfile,'bad option'); end; end; writeln(ERRfile,'Usage: dvitty [ options ] dvifile[.dvi]'); writeln(ERRfile,'Options are:'); writeln(ERRfile, ' -ofile Write output to file, else write to stdout.'); writeln(ERRfile, ' -plist Print pages whos TeX-page-number are in list.'); writeln(ERRfile, ' -Plist Print pages whos sequential number are in list.'); writeln(ERRfile, ' -wn Print the lines with width n characters, default 80.'); write(ERRfile,' -f Try to pipe to a pager if output is a tty'); if defpage then writeln(ERRfile,' (default).') else writeln(ERRfile,'.'); write(ERRfile,' -q Don''t try to pipe to a pager'); if defpage then writeln(ERRfile,'.') else writeln(ERRfile,' (default).'); writeln(ERRfile, ' -l Write ''^L'' instead of formfeed between pages.'); write(ERRfile, ' -u National Swedish characters printed as aaoAAO'); if defscand then writeln(ERRfile,'.') else writeln(ERRfile,' (default).'); write(ERRfile, ' -s National Swedish characters printed as }{|][\'); if defscand then writeln(ERRfile,' (default).') else writeln(ERRfile,'.'); exit(1); end; { usage } {-----------------------------------------------------------------------------} procedure getname(var str : string); var i : integer; begin i:=stringlength; while (i>1) and (str[i]=' ') do i:=i-1; if (i=1) and (str[1]=' ') then usage(ign); if not ((i>=5) and (str[i]='i') and (str[i-1]='v') and (str[i-2]='d') and (str[i-3]='.')) then begin str[i+1]:='.'; str[i+2]:='d'; str[i+3]:='v'; str[i+4]:='i'; end; DVIfilename:=str; end; { getname } {-----------------------------------------------------------------------------} function getinteger(var j: integer; var str : string; def : integer) : integer; var cum : integer; sgn : boolean; begin if not (str[j] in ['0'..'9','-']) then getinteger:=def else begin cum:=0; sgn:=false; if str[j]='-' then begin sgn:=true; j:=j+1; end; if not (str[j] in ['0'..'9']) then getinteger:=def else begin while str[j] in ['0'..'9'] do begin cum:=cum*10+ord(str[j])-ord('0'); j:=j+1; end; if sgn then getinteger:=-cum else getinteger:=cum; end; end; end; { getinteger } {-----------------------------------------------------------------------------} procedure getpages(j : integer; var str : string); var i : integer; procedure plcnxt(pagnr : integer); { place page-nr next in list } begin currentpage:=lastpage; currentpage^.pag:=pagnr; new(lastpage); lastpage^.all:=false; lastpage^.nxt:=nil; lastpage^.pag:=0; currentpage^.nxt:=lastpage; end; { plcnxt } begin { getpages } pageswitchon:=true; new(firstpage); firstpage^.all:=false; firstpage^.nxt:=nil; firstpage^.pag:=0; lastpage:=firstpage; currentpage:=firstpage; if not (str[j] in ['1'..'9','-']) then usage(nan); foo:=getinteger(j,str,0); while foo<>0 do begin plcnxt(foo); if str[j]=',' then begin j:=j+1; if not (str[j] in ['1'..'9','-']) then usage(nan); end else if str[j]=':' then begin j:=j+1; if not (str[j] in ['1'..'9','-']) then usage(nan); foo:=getinteger(j,str,0); if currentpage^.pag<0 then begin if (foo>0) then begin currentpage^.all:=true; plcnxt(foo); end else if foo' ' then usage(gae); currentpage:=firstpage; end; { getpages } {-----------------------------------------------------------------------------} procedure setoption(optch : char; var optset, optwarg : charset; var str : string; var i : integer; j : integer); var k : integer; begin while optch in optset do begin case optch of 'q' : pager:=false; 'f' : pager:=true; 'l' : noffd:=true; 's' : scascii:=true; 'u' : scascii:=false; 'p' : begin optset:=optset-['P']; { can't have both -P & -p } getpages(j, str); end; 'P' : begin sequenceon:=true; optset:=optset-['p']; { can't have both -P & -p } getpages(j, str); end; 'w' : begin if not (str[j] in ['0'..'9','-']) then usage(nan); ttywidth:=getinteger(j, str, 80); if str[j]<>' ' then usage(gae); if (ttywidth<16) or (ttywidth>132) then usage(wrnge); end; 'o' : begin for k:=1 to stringlength-j+1 do OUTfilename[k]:=str[j+k-1]; for k:=stringlength-j+2 to stringlength do OUTfilename[k]:=' '; outputtofile:=true; j:=stringlength; end; 'F' : begin for k:=1 to pathlen do path[k]:=str[k+j-1]; if path[pathlen]<>' ' then usage(lngpth); j:=stringlength; pathpgm:=false; end; end; optch:=str[j]; j:=j+1; if optch in optwarg then if str[j]=' ' then begin i:=i+1; if i>=argc then usage(noarg); argv(i, str); j:=1; end; end; end; { setoption } {-----------------------------------------------------------------------------} procedure getargs; var i, j : integer; str : string; DVIfilenamefound : boolean; optset, optwarg : charset; optch : char; begin if argc<=1 then usage(ign); pageswitchon:=false; { default: all pages } sequenceon:=false; { default: selected pages are TeX-numbered } outputtofile:=false; { default: write to stdout } noffd:=false; { default: print formfeed between pages } scascii:=defscand; { default: see compile time adjustable const } pager:=defpage; { default: see compile time adjustable const } path:=defpath; { default: use the default path to the pager } pathpgm:=true; { default: - " - } ttywidth:=80; { default } DVIfilenamefound:=false; optset:=['w','p','P','o','u','s','q','l','f','F']; { legal options } optwarg:=['w','p','P','o','F']; { options with args } i:=0; while envargs(optch, str) do { get options from environ var DVITTY } setoption(optch, optset, optwarg, str, i, 1); i:=1; while i'-' then begin if DVIfilenamefound then usage(onef); getname(str); DVIfilenamefound:=true; end else if optch in optset then begin j:=3; if (optch in optwarg) and (str[j]=' ') then begin i:=i+1; if i>=argc then usage(noarg); argv(i, str); j:=1; end; setoption(optch, optset, optwarg, str, i, j); end else usage(bdopt); i:=i+1; end; if not DVIfilenamefound then usage(ign) end; { getargs } {-----------------------------------------------------------------------------} function getbyte : integer; { get next byte from dvi-file } var b : sbyte; begin read(DVIfile, b); if b<0 then getbyte:=b+256 else getbyte:=b end; { getbyte } {-----------------------------------------------------------------------------} function get2 : integer; { returns the next two bytes, unsigned } begin foo:=getbyte; get2:=foo*256+getbyte end; { get2 } {-----------------------------------------------------------------------------} function get3 : integer; { returns the next three bytes, unsigned } begin foo:=getbyte; foo:=foo*256+getbyte; get3:=foo*256+getbyte end; { get3 } {-----------------------------------------------------------------------------} function signedbyte : integer; { returns next byte fr dvi-file, signed } var b : sbyte; begin read(DVIfile, b); signedbyte:=b; end; { signedbyte } {-----------------------------------------------------------------------------} function signed2 : integer; { returns the next two bytes, signed } begin read(DVIfile, foo); signed2:=foo*256+getbyte end; { signed2 } {-----------------------------------------------------------------------------} function signed3 : integer; { returns the next three bytes, signed } begin read(DVIfile, foo); foo:=foo*256+getbyte; signed3:=foo*256+getbyte end; { signed3 } {-----------------------------------------------------------------------------} function signed4 : integer; { returns the next four bytes, signed } begin read(DVIfile, foo); foo:=foo*256+getbyte; foo:=foo*256+getbyte; signed4:=foo*256+getbyte end; { signed4 } {-----------------------------------------------------------------------------} function imin(a, b : integer) : integer; { returns the least of two int:s } begin if anop2; skipnoops:=(opcode=goal) end; { skipnoops } {-----------------------------------------------------------------------------} function getline : lineptr; { returns an initialized line-object } var i : integer; temp : lineptr; begin new(temp); with temp^ do begin charactercount:=leftmargin-1; prev:=nil; next:=nil; for i:=leftmargin to rightmargin do text[i]:=' ' end; getline:=temp end; { getline } {-----------------------------------------------------------------------------} function findline : lineptr; { find line where text should go, } var temp : lineptr; { generate a new line if needed } begin if ((v>currentline^.vv) and (currentline=lastline)) or ((vverticalepsilon) then begin temp:=getline; with temp^ do begin prev:=lastline; vv:=v; lastline^.next:=temp; lastline:=temp end end else begin temp:=lastline; while (temp^.vv>v) and (temp<>firstline) do temp:=temp^.prev; if abs(temp^.vv-v)>verticalepsilon then begin if temp^.next^.vv-v < verticalepsilon then temp:=temp^.next else if (temp=firstline) and (vverticalepsilon then currentline:=findline; if (ord(ch) in [11..17, 25..31, 92, 123..126]) then case ord(ch) of 11 : begin outchar('f'); ch:='f' end; { ligature } 12 : begin outchar('f'); ch:='i' end; { ligature } 13 : begin outchar('f'); ch:='l' end; { ligature } 14 : begin outchar('f'); outchar('f'); ch:='i' end; { ligature } 15 : begin outchar('f'); outchar('f'); ch:='l' end; { ligature } 16 : ch:='i'; 17 : ch:='j'; 25 : begin outchar('s'); ch:='s' end; { German double s } 26 : begin outchar('a'); ch:='e' end; { Dane/Norw ae } 27 : begin outchar('o'); ch:='e' end; { Dane/Norw oe } 28 : if scascii then ch:='|' { Dane/Norw /o } else ch:='o'; 29 : begin outchar('A'); ch:='E' end; { Dane/Norw AE } 30 : begin outchar('O'); ch:='E' end; { Dane/Norw OE } 31 : if scascii then ch:='\' { Dane/Norw /O } else ch:='O'; 92 : ch:='"'; { beginnig qoute } 123 : ch:='-'; 124 : ch:='_'; 125 : ch:='"'; 126 : ch:='"'; end; j:=round((h/maxpagewidth)*(ttywidth-1)+1.0); if j>rightmargin then j:=rightmargin else if j=leftmargin then begin j:=foo; case ord(text[j]) of 127 : if ch='a' then ch:='{' else { dots } if ch='A' then ch:='[' else if ch='o' then ch:='|' else if ch='O' then ch:='\'; 23 : if ch='a' then ch:='}' else { circle } if ch='A' then ch:=']' end; { case } end; end; end; {----------------- end of 'Scandinavian code' ----------------} if foo=leftmargin-1 then while (text[j]<>' ') and (j=chspc) or (ord(ch)=23))) or (not scascii and (ord(ch)>=chspc) and (ord(ch)<>chdel)) then begin if jcharactercount then charactercount:=j; if j127 from current font } { note that the parameter is a dummy, since ascii-chars are<=127 } begin outchar('#') end; { setchar } {-----------------------------------------------------------------------------} procedure putcharacter(charnr : integer); { output character, don't change h } var saveh : integer; begin saveh:=h; if (charnr>=0) and (charnr<=lastchar) then outchar(chr(charnr)) else setchar(charnr); h:=saveh; end; { putcharacter } {-----------------------------------------------------------------------------} procedure rule(moving : boolean; rulewt, ruleht : integer); { output a rule (vertical or horizontal), increment h if moving is true } var ch : char; { character to set rule with } saveh, savev, wt : integer; procedure ruleaux; { recursive procedure that does the job } var lmh, rmh : integer; begin wt:=rulewt; lmh:=h; { save left margin } if h<0 then begin { let rules that start at negative h } wt:=wt-h; { start at coordinate 0, but let it } h:=0; { have the right length } end; while wt>0 do begin { output the part of the rule that } rmh:=h; { goes on this line } outchar(ch); wt:=wt-(h-rmh); { decrease the width left on line } end; ruleht:=ruleht-verticalepsilon; { decrease the height } if ruleht>verticalepsilon then begin { still more vertical? } rmh:=h; { save current h (right margin) } h:=lmh; { restore left margin } v:=v-(verticalepsilon+(verticalepsilon div 10)); ruleaux; h:=rmh; { restore right margin } end; end; { ruleaux } begin { rule -- starts up the recursive routine } if not moving then saveh:=h; if (ruleht<=0) or (rulewt<=0) then h:=h+rulewt else begin savev:=v; if (ruleht div rulewt)>0 then ch:='!' else if ruleht>(verticalepsilon div 2) then ch:='=' else ch:='_'; ruleaux; v:=savev; end; if not moving then h:=saveh; end; { rule } {-----------------------------------------------------------------------------} procedure fontdef(param : integer); { ignore font-definition command } begin setpos(DVIfile, param+12, relative); setpos(DVIfile, getbyte+getbyte, relative); end; { fontdef } {-----------------------------------------------------------------------------} procedure horizontalmove(amount : integer; var worx : integer); begin if amount<>worx then if abs(amount)<=(charwidth div 4) then worx:=amount else begin foo:=3*charwidth div 4; if amount>0 then worx:=((amount+foo) div charwidth)*charwidth else worx:=((amount-foo) div charwidth)*charwidth; end; h:=h+worx end; { horizontalmove } {-----------------------------------------------------------------------------} function inlist(pagenr : integer) : boolean; { ret true if in list of pages } begin inlist:=false; while (currentpage^.pag<0) and (currentpage^.pag<>pagenr) and not currentpage^.all and (currentpage^.nxt<>nil) do currentpage:=currentpage^.nxt; if (currentpage^.all and (pagenr0 then begin while (currentpage^.pag<>pagenr) and (currentpage^.nxt<>nil) do currentpage:=currentpage^.nxt; if currentpage^.pag=pagenr then inlist:=true end end; { inlist } {-----------------------------------------------------------------------------} function bop(var pagecounter, backpointer, pagenr : integer) : boolean; begin pagecounter:=pagecounter+1; pagenr:=signed4; setpos(DVIfile, 36, relative); backpointer:=signed4; if pageswitchon then if sequenceon then bop:=inlist(pagecounter) else bop:=inlist(pagenr) else bop:=true; end; { bop } {-----------------------------------------------------------------------------} procedure initpage(backpointer, pagenr, pagecounter : integer); begin h:=0; v:=0; { initialize coordinates } x:=0; w:=0; y:=0; z:=0; { initialize amounts } stack.top:=0; { initialize stack } currentline:=getline; { initialize list of lines } currentline^.vv:=0; firstline:=currentline; lastline:=currentline; firstcolumn:=rightmargin; if pageswitchon then if (sequenceon and (pagecounter<>firstpage^.pag)) or (not sequenceon and (pagenr<>firstpage^.pag)) then if noffd then writeln('^L') else writeln(chr(chffd)); if not pageswitchon then if backpointer<>-1 then if noffd then writeln('^L') else writeln(chr(chffd)); end; { initpage } {-----------------------------------------------------------------------------} procedure dover2page; begin opcode:=getbyte; while opcode<>eop2 do begin { process page until eop reached } if opcode>postpost2 then errorexit(illop) else if opcode<=lastchar then outchar(chr(opcode)) else if opcode in [128..170, 235..249] then case opcode of 128 : setchar(getbyte); 129 : setchar(get2); 130 : setchar(get3); 131 : setchar(signed4); 132 : begin foo:=signed4; rule(advance, signed4, foo); end; 133 : putcharacter(getbyte); 134 : putcharacter(get2); 135 : putcharacter(get3); 136 : putcharacter(signed4); 137 : begin foo:=signed4; rule(stay, signed4, foo); end; nop2: ; { no-op } bop2: errorexit(bdbop); 141 : with stack do begin { push } if top>stackmax-1 then errorexit(stkof); top:=top+1; with items[top] do begin hh:=h; vv:=v; ww:=w; xx:=x; yy:=y; zz:=z; end; end; 142 : with stack do begin { pop } if top=0 then errorexit(stkuf); with items[top] do begin h:=hh; v:=vv; w:=ww; x:=xx; y:=yy; z:=zz; end; top:=top-1; end; 143 : h:=h+signedbyte; 144 : h:=h+signed2; 145 : h:=h+signed3; 146 : h:=h+signed4; 147 : horizontalmove(w, w); 148 : horizontalmove(signedbyte, w); 149 : horizontalmove(signed2, w); 150 : horizontalmove(signed3, w); 151 : horizontalmove(signed4, w); 152 : horizontalmove(x, x); 153 : horizontalmove(signedbyte, x); 154 : horizontalmove(signed2, x); 155 : horizontalmove(signed3, x); 156 : horizontalmove(signed4, x); 157 : v:=v+signedbyte; 158 : v:=v+signed2; 159 : v:=v+signed3; 160 : v:=v+signed4; 161 : v:=v+y; 162 : begin y:=signedbyte; v:=v+y end; 163 : begin y:=signed2; v:=v+y end; 164 : begin y:=signed3; v:=v+y end; 165 : begin y:=signed4; v:=v+y end; 166 : v:=v+z; 167 : begin z:=signedbyte; v:=v+z end; 168 : begin z:=signed2; v:=v+z end; 169 : begin z:=signed3; v:=v+z end; 170 : begin z:=signed4; v:=v+z end; 235, 236, 237, { ignore font changes } 238 : setpos(DVIfile, opcode-234, relative); 239 : setpos(DVIfile, getbyte, relative); 240 : setpos(DVIfile, get2, relative); 241 : setpos(DVIfile, get3, relative); 242 : setpos(DVIfile, signed4, relative); 243,244,245, 246 : fontdef(opcode-242); pre2 : errorexit(bdpre); post2 : errorexit(bdpst); postpost2: errorexit(bdpp); end; opcode:=getbyte end end; { dover2page } {-----------------------------------------------------------------------------} procedure eop; { 'end of page', writes lines of page to output file } var i, j : integer; ch : char; temp : lineptr; begin if stack.top<>0 then writeln(ERRfile, 'dvitty: warning - stack not empty at eop.'); currentline:=firstline; repeat with currentline^ do begin if currentline<>firstline then begin foo:=((vv-prev^.vv) div verticalepsilon)-1; if foo>0 then foo:=imin(foo, 3); for i:=1 to foo do writeln; end; if charactercount>=leftmargin then begin i:=firstcolumn; j:=1; foo:=ttywidth-2; repeat ch:=text[i]; if (ord(ch)>=chspc) and (ord(ch)<>chdel) then write(ch); if j>foo then if charactercount>i+1 then begin writeln('*'); write(' *'); j:=2 end; i:=i+1; j:=j+1 until i>charactercount; end end; writeln; temp:=currentline; currentline:=currentline^.next; dispose(temp); until currentline=nil; end; { eop } {-----------------------------------------------------------------------------} procedure skipver2page; { skip past one page } begin opcode:=getbyte; while opcode<>eop2 do begin if opcode>postpost2 then errorexit(illop) else if opcode in [128..170, 235..249] then case opcode of nop2,141, 142, 147, 152, 161, 166 : ; 128, 133, 143, 148, 153, 157, 162, 167, 235 : setpos(DVIfile, 1, relative); 129, 134, 144, 149, 154, 158, 163, 168, 236 : setpos(DVIfile, 2, relative); 130, 135, 145, 150, 155, 159, 164, 169, 237 : setpos(DVIfile, 3, relative); 131, 136, 146, 151, 156, 160, 165, 170, 238 : setpos(DVIfile, 4, relative); 132, 137 : setpos(DVIfile, 8, relative); 139 : errorexit(bdbop); 239 : setpos(DVIfile, getbyte, relative); 240 : setpos(DVIfile, get2, relative); 241 : setpos(DVIfile, get3, relative); 242 : setpos(DVIfile, signed4, relative); 243,244,245, 246 : fontdef(opcode-242); pre2 : errorexit(bdpre); post2 : errorexit(bdpst); postpost2 : errorexit(bdpp); end; opcode:=getbyte; end; end; { skipver2page } {-----------------------------------------------------------------------------} procedure dopages; { process the pages in the DVI-file } var pagecounter, backpointer, pagenr : integer; begin setpos(DVIfile, 0, absolute); { read the dvifile from the start } pagecounter:=0; if not skipnoops(pre2) then errorexit(nopre); opcode:=getbyte; { check id in preamble, ignore rest of it } if opcode<>versionid then errorexit(badid); setpos(DVIfile, 12, relative); setpos(DVIfile, getbyte, relative); if not skipnoops(bop2) then errorexit(nobop) { should be at start } else while opcode<>post2 do begin { of page now } if opcode<>bop2 then errorexit(nobop) else begin if not bop(pagecounter, backpointer, pagenr) then skipver2page else begin initpage(backpointer, pagenr, pagecounter); dover2page; eop; end; repeat opcode:=getbyte until opcode<>nop2 end end; end; { dopages } {-----------------------------------------------------------------------------} procedure postamble; { find and process postamble, use random access } var size, count : integer; begin size:=sizef(DVIfile); { get size of file } count:=-1; repeat { back file up past signature bytes (223), to id-byte } if size=0 then errorexit(nopst); size:=size-1; setpos(DVIfile, size, absolute); opcode:=getbyte; count:=count+1; { has to be at least 4 sign-bytes } until opcode<>223; if count<4 then begin foo:=count; errorexit(fwsgn); end; if opcode<>versionid then errorexit(badid); setpos(DVIfile, size-4, absolute); { back up to back-pointer } setpos(DVIfile, signed4, absolute); { back up to start of postamble } if getbyte<>post2 then errorexit(nopst); setpos(DVIfile, 20, relative); maxpagewidth:=signed4; charwidth:=maxpagewidth div ttywidth; foo:=get2; if foo>stackmax then errorexit(stkrq); { too much stack required } end; { postamble } (***************************************************************************** * * M A I N *) begin rewrite(ERRfile, '/dev/tty'); { get a pascal file } tostderr(ERRfile); { and redirect it to stderr } getargs; { read the command line arguments } if not readp(DVIfilename) then errorexit(filop); { can't open dvifile } reset(DVIfile, DVIfilename); if outputtofile then begin { open the outfile } if not writep(OUTfilename) then errorexit(filcr); { can't create outfile } rewrite(output, OUTfilename); pager:=false; end else if ttyp(output) and pager then { try to pipe to a pager } pager:=popenp(output, path, pathpgm); postamble; { seek and process the postamble } dopages; { time to do the actual work! } if pager then pcloseit(output); { have to use pclose if popened } end.