Subject: v07i022: TeX DVI driver for TTY's, etc. Newsgroups: mod.sources Approved: mirror!rs Submitted by: seismo!enea!ttds!zap (Svante Lindahl) Mod.sources: Volume 7, Issue 22 Archive-name: texdvi2tty [ I have only verified that this unpacks correctly. Non-4.[23] sites note: this script uses 'echo -n' --r$ ] : This shar archive as submitted to mod.sources contains the : following files: README : dvitty.1 : Makefile : dvitty.p : sys.h : sys.c : : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. echo 'Extracting README' sed 's/^X//' > README << '+ END-OF-FILE README' Xdvitty is intended for previewing dvi-files on text-only devices X(terminals and lineprinters). The output is not very pretty many Xtimes, but it still saves quite a lot of work, especially if you Xhave a little ways to walk to a laserprinter, for example. X XThe program was originally written in Hedrick-Pascal, running on XTOPS-20, and was later ported to UNIX (BSD, Berkeley-pascal). X XIt is not very smart in all situations, but still serves it pur- Xpose fairly well. X XFor information on how to use see the man-page. X XBefore compiling and installing inspect the "compile-time cust- Xomization constants" and change them to suit your site. XThese constants configure default pager and a little more. X XPlease report complaints, suggestions, bugs and/or fixes to: X XSvante Lindahl, NADA, KTH Numerical Analysis & Computer Science XUUCP: {seismo,mcvax}!enea!ttds!zap Royal Institute of Technology, Sweden XARPA: enea!ttds!zap@seismo.CSS.GOV EAN: zap@cs.kth.sunet X XThe TOPS-20 version of the program can also be obtained from the above Xaddress. + END-OF-FILE README chmod 'u=rw,g=rw,o=r' 'README' echo ' -rw-rw-r-- 1 zap 1050 Aug 15 22:11 README (as sent)' echo -n ' ' /bin/ls -l README echo 'Extracting dvitty.1' sed 's/^X//' > dvitty.1 << '+ END-OF-FILE dvitty.1' X.TH DVITTY Local "7 June 1986" X.SH NAME Xdvitty \- preview a dvi\-file on an ordinary ascii terminal X.SH SYNOPSIS X.B dvitty X[ options ] dvi\-file X.SH DESCRIPTION X.I dvitty Xconverts a TeX DVI\-file to a format that is apprporiate for terminals Xand lineprinters. The program is intended to be used for Xpreliminary proofreading of TeX:ed documents. XBy default the output is directed to the terminal, Xpossibly through a pager (depending on how the program was installed), Xbut it can be directed to a file or a pipe. X.PP XThe output leaves much to be desired, but is still Xusefull if you want to avoid walking to the Xlaserprinter (or whatever) for each iteration of your Xdocument. X.br XSince X.I dvitty Xproduces output for terminals and lineprinters the Xrepresentation of documents is naturally quite primitive. XFontchanges are totally ignored, which implies that Xspecial symbols, such as mathematical symbols, get mapped into the Xcharacters at the corresponding positions in the "standard" fonts. X.PP XIf the width of the output text requires more columns than fits Xin one line (c.f. the \-w option) it is broken into several lines by X.I dvitty Xalthough they will be printed as one line on regular TeX output Xdevices (e.g.laserprinters). To show that a broken line is really Xjust one logical line an asterisk (``*'') in the last position Xmeans that the logical line is continued on the next physical Xline output by X.I dvitty. XSuch a continuation line is started with a a space and an asterisk Xin the first two columns. X.PP XOptions may be specified in the environment variable DVITTY. XAny option on the commandline, conflicting with one in the Xenvironment, will override the one from the environment. X.PP X.B Options: X.PP X.TP X.B \-o file XWrite output to file ``file''. X.TP X.B \-p list XPrint the pages chosen by list. XNumbers refer to TeX\-page numbers (known as \\count0). XAn example of format for list is ``1,3:6,8'' Xto choose pages 1, 3 through 6 and 8. XNegative numbers can be used exactly as in TeX, Xe g \-1 comes before \-4 as in ``\-p-1:-4,17''. X.TP X.B \-P list XLike \-p except that page numbers refer to Xthe sequential ordering of the pages in the dvi\-file. XNegative numbers don't make a lot of sense here... X.TP X.B \-w n XSpecify terminal width X.I n. XLegal range 16\-132. XDefault is 80. If your terminal has the Xability to display in 132 columns it might Xbe a good idea to use \-w132 and toggle the Xterminal into this mode as output will Xprobably look somewhat better. X.TP X.B \-q XDon't pipe the output through a pager. XThis may be the default on some systems X(depending on the whims of the SA installing the program). X.TP X.B \-f XPipe through a pager, $PAGER if defined, or whatever your SA compiled Xin (often ``more''). This may be the default, but it is still okay Xto redirect output with ``>'', the pager will not be used if output Xis not going to a terminal. X.TP X.B \-Fprog XUse ``prog'' as program to pipe output into. Can be used to choose an Xalternate pager (e g ``-Fless''). X.TP X.B \-l XMark pagebreaks with the two-character sequence ``^L''. The defualt is Xto mark them with a formfeed character. X.TP X.B \-u XDon't make any attempts to find special Scandinavian characters. XIf such characters are in the text they will map to ``a'' and ``o''. XThis is probably the default outside of Scandinavia. (The SA made Xthe decision when the program was installed.) X.TP X.B \-s XTry to find the special Scandinavian characters that on most (?) Xterminals in Scandinavia are mapped to ``{|}[\\]''. XThis can be the default, and output from files not containing these Xspecial characters will be identical regardless of this option. X.SH FILES X/usr/ucb/more \ \ \ \ Xprobably the default pager. X.SH ENVIRONMENT XPAGER \ \ \ \ \ \ \ \ \ \ \ \ Xthe pager to use. X.br XDVITTY \ \ \ \ \ \ \ \ \ \ \ Xcan be set to hold commandline options. X.SH "SEE ALSO" XTeX, dvi2ps X.SH AUTHOR XSvante Lindahl, Royal Institute of Technology, Stockholm X.br X{seismo, mcvax}!enea!ttds!zap X.SH BUGS XBlanks between words get lost quite easy. This is less Xlikely if you are using a wider output than the default 80. X.PP XOnly one file may be specified on the commandline. + END-OF-FILE dvitty.1 chmod 'u=rw,g=rw,o=r' 'dvitty.1' echo ' -rw-rw-r-- 1 zap 4127 Aug 15 20:02 dvitty.1 (as sent)' echo -n ' ' /bin/ls -l dvitty.1 echo 'Extracting Makefile' sed 's/^X//' > Makefile << '+ END-OF-FILE Makefile' Xall: dvitty X Xdvitty: sys.o dvitty.o X pc -O -w -o dvitty dvitty.o sys.o X Xdvitty.o: dvitty.p X pc -c -w -O dvitty.p X Xsys.o: sys.c X cc -c -O sys.c + END-OF-FILE Makefile chmod 'u=rw,g=r,o=r' 'Makefile' echo ' -rw-r--r-- 1 zap 143 Aug 8 00:32 Makefile (as sent)' echo -n ' ' /bin/ls -l Makefile echo 'Extracting dvitty.p' sed 's/^X//' > dvitty.p << '+ END-OF-FILE dvitty.p' X(****************************************************************************** X * bogart:/usr/alla/zap/dvitty/dvitty.p 1986-08-15 20:24:31, X * Version to be sent to mod.sources ready. X * New option since last version: X * -Fprog Pipe output to prog. Can be used to get a different X * pager than the default. X * bogart:/usr/alla/zap/dvitty/dvitty.p 1986-01-13 21:49:31, X * Environment variable DVITTY is read and options can be set from it. X * These are the currently implemented options: X * -ofile Write output to file, else write to stdout, X * possibly piped through a pager if stdout is a tty. X * -plist Print pages whos TeX-page-number are in list. X * List is on the form 1,3:6,8 to choose pages X * 1,3-6 and 8. TeX-nrs can be negative: -p-1:-4,4 X * -Plist Print pages whos sequential number are in list. X * -wn Print the lines with width n characters, default is X * 80. Wider lines gives better results. X * -q Don't try to pipe to a pager. X * -f Try to pipe to a pager if output is a tty. X * Default of -q and -f is a compile time option, a constant. X * -l Write '^L' instead of formfeed between pages. X * -u Don't try to find Scandinavian characters (they will X * print as a:s and o:s if this option is choosen). X * -s Scandinavian characters printed as }{|][\. X * Default of -s and -u is a compile time option, a constant. X * bogart:/usr/alla/zap/dvitty/dvitty.p 1986-01-10 18:51:03, X * Argument parsing, and random access functions (external, in C) X * and other OS-dependent stuff (in C). Removed private 'pager' & X * tries to pipe through PAGER (environment var) or, if PAGER not X * defined, /usr/ucb/more. Some changes for efficency. X * bogart:/usr/alla/svante/dvitty/dvitty.p 1985-07-15 20:51:00, X * The code for processing dvi-files running on UNIX (UCB-Pascal) X * but no argument parsing. X * VERA::SS:DVITTY.PAS.140, 30-Mar-85 05:43:56, X * Edit: Svante Lindahl X * VERA::SS:DVITTY.PAS.136, 15-Jan-85 13:52:59, X * Edit: Svante Lindahl, final Twenex version !!!?? X * VERA::SS:DVITTY.PAS.121, 14-Jan-85 03:10:22, X * Edit: Svante Lindahl, cleaned up and fixed a lot of little things X * VERA::SS:DVITTY.PAS.25, 15-Dec-84 05:29:56, X * Edit: Svante Lindahl, COMND-interface, including command line scanning X * VERA::SS:DVITTY.PAS.23, 10-Dec-84 21:24:41, X * Edit: Svante Lindahl, added command line scanning with Rscan-JSYS X * VERA::DVITTY.PAS.48, 8-Oct-84 13:26:30, X * Edit: Svante Lindahl, fixed switch-parsing, destroyed by earlier patches X * VERA::DVITTY.PAS.45, 29-Sep-84 18:29:53, X * Edit: Svante Lindahl X * X * dvitty - get an ascii representation of a dvi-file, suitable for ttys X * X * This program, and any documentation for it, is copyrighted by Svante X * Lindahl. It may be copied for non-commercial use only, provided that X * any and all copyright notices are preserved. X * X * Please report any bugs and/or fixes to: X * X * UUCP: {seismo,mcvax,cernvax,diku,ukc,unido}!enea!ttds!zap X * ARPA: enea!ttds!zap@seismo.CSS.GOV X * or Svante_Lindahl_NADA%QZCOM.MAILNET@MIT-MULTICS.ARPA X * EAN: zap@cs.kth.sunet X *) X Xprogram dvitty(input, output); X Xconst Copyright = 'dvitty.p Copyright (C) 1984, 1985, 1986 Svante Lindahl.'; X X X {-----------------------------------------------------------------------} X { The following two constants may be toggled before compilation to } X { customize the default behaviour of the program for your site. } X { Whichever their settings are, the defaults can be overridden at } X { runtime. } X {-----------------------------------------------------------------------} X X defscand = true; { default is Scandinavian, toggle this if you } X { don't have terminals with Scand. nat. chars } X defpage = true; { default: try to pipe through a pager (like } X { more) if stdout is tty and no -o switch } X pathlen = 40; { length of string for path to pager program } X defpath = '/usr/ucb/more '; { pathlen chars } X X {------------------ end of customization constants ---------------------} X X versionid = 2; { version number of dvifiles that pgm handles } X stackmax = 100; { allows 100 dvi-pushes } X verticalepsilon = 450000; { crlf when increasing v more than this } X X rightmargin = 152; { nr of columns allowed to the right of h=0 } X leftmargin = -50; { give some room for negative h-coordinate } X X stringlength = 100; { size of char-arrays for strings } X X advance = true; { if advancing h when outputing a rule } X stay = false; { if not advancing h when outputing a rule } X X absolute = 0; X relative = 1; X X chffd = 12; { formfeed } X chspc = 32; { space } X chdel = 127; { delete } X X { some dvi op-codes (digit at end tells dvi-version-#) } X nop2 = 138; { no-op } X bop2 = 139; { beginning of page } X eop2 = 140; { end of page } X post2 = 248; { post-amble } X pre2 = 247; { pre-amble } X postpost2 = 249; { post-post-amble } X lastchar = 127; { highest char-code } X X{-----------------------------------------------------------------------------} X Xtype ubyte = 0..255; { dvi-files consists of eight-bit-bytes } X sbyte = -128..127; { UCB-pascal reads 16 bits if unsigned byte } X X string = packed array [1..stringlength] of char; X pathtype = packed array [1..pathlen] of char; X charset = set of char; X X stackitem = record X hh, vv, ww, xx, yy, zz : integer; X end; X stacktype = record { stack for dvi-pushes } X items : array [1..stackmax] of stackitem; X top : 0..stackmax; X end; { stacktype } X X lineptr = ^linetype; X linetype = record { the lines of text to be output to outfile } X vv : integer; { vertical position of the line } X charactercount : integer; { pos of last char on line } X prev : lineptr; { preceding line } X next : lineptr; { succeding line } X text : packed array [leftmargin..rightmargin] of char; X end; { linetype } X X printlistptr = ^printlisttype; X printlisttype = record { list of pages selected for output } X pag : integer; { the nr of the page } X all : boolean; { pages in intervall selected } X prv : printlistptr; { previous item in list } X nxt : printlistptr; { next item in list } X adr : integer; { nr of byte in file where bop is } X end; { printlisttype } X X useagecodetype= (wrnge, { width switch arg out of range } X ign, { ignore cause, print'Usage:..' } X nan, { not a number where one expected } X gae, { garbage at end } X bdlst, { bad page-numberlist } X onef, { only one dvifile allowed } X bdopt, { bad option } X lngpth, { pathname too long (for -F) } X noarg); { argument expected } X X errorcodetype = (illop, { illegal op-code } X stkof, { stack over-flow } X stkuf, { stack under-flow } X stkrq, { stack requirement } X badid, { id is not right } X bdsgn, { signature is wrong } X fwsgn, { too few signatures } X nopre, { no pre-amble where expected } X nobop, { no bop-command where expected } X nopp, { no postpost where expected } X bdpre, { unexpected preamble occured } X bdbop, { unexpected bop-command occured } X bdpst, { unexpected post-command occured } X bdpp, { unexpected postpost } X nopst, { no post-amble where expected } X illch, { character code out of range } X filop, { cannot access file } X filcr); { cannot creat file } X X DVIfiletype = file of sbyte; X X{-----------------------------------------------------------------------------} X Xvar opcode : ubyte; { dvi-opcodes } X foo : integer; { utility variable, "register" } X X h, v : integer; { coordinates, horizontal and vertical } X w, x, y, z : integer; { horizontal and vertical amounts } X X outputtofile : boolean; { tells if output goes to file or stdout } X pager : boolean; { tells if output is piped to a pager } X pageswitchon : boolean; { true if user-set pages to print } X sequenceon : boolean; { false if pagesw-nrs refers to TeX-nrs } X scascii : boolean; { if true make Scand. nat. chars right } X noffd : boolean; { if true output ^L instead of formfeed } X ttywidth : integer; { max nr of chars per printed line } X path : pathtype; { name of the pager to run } X pathpgm : boolean; { use 'defpath' if this is true } X X maxpagewidth : integer; { width of widest page in file } X charwidth : integer; { aprox width of charachter } X X currentpage : printlistptr; { current page to print } X firstpage : printlistptr; { first page selected } X lastpage : printlistptr; { last page selected } X currentline : lineptr; { pointer to current line on current page } X firstline : lineptr; { pointer to first line on current page } X lastline : lineptr; { pointer to last line on current page } X firstcolumn : integer; { 1st column with something to print } X X stack : stacktype; X X DVIfile : DVIfiletype; X ERRfile : text; X DVIfilename : string; X OUTfilename : string; X X{-----------------------------------------------------------------------------} X X#include "sys.h" { headers for external C-routines } X X{-----------------------------------------------------------------------------} X Xprocedure errorexit(errorcode : errorcodetype); X begin X write(ERRfile,'dvitty: '); X case errorcode of X illop : writeln(ERRfile,'Illegal op-code found: ',opcode:0); X stkof : writeln(ERRfile,'Stack overflow.'); X stkuf : writeln(ERRfile,'Stack underflow.'); X stkrq : writeln(ERRfile,'Too much stack required : ',foo:0); X badid : writeln(ERRfile,'Id-byte is not correct: ',opcode:0); X bdsgn : writeln(ERRfile,'Bad signature: ',foo:0,' (not 223).'); X fwsgn : writeln(ERRfile,foo:0,' signature bytes (min. 4).'); X nopre : writeln(ERRfile,'Missing preamble.'); X nobop : writeln(ERRfile,'Missing beginning-of-page command.'); X nopp : writeln(ERRfile,'Missing post-post command.'); X bdpre : writeln(ERRfile,'Preamble occured inside a page.'); X bdbop : writeln(ERRfile,'BOP-command occured inside a page.'); X bdpst : writeln(ERRfile,'Postamble occured before end-of-page.'); X bdpp : writeln(ERRfile,'Postpost occured before post-command.'); X nopst : writeln(ERRfile,'Missing postamble.'); X illch : writeln(ERRfile,'Character code out of range, 0..127'); X filop : writeln(ERRfile,'Cannot open dvifile'); X filcr : writeln(ERRfile,'Cannot create outfile'); X end; X if outputtofile then delete(output); X exit(-1); X end; { errorexit } X X{-----------------------------------------------------------------------------} X Xprocedure usage(uerr : useagecodetype); X begin X if uerr<>ign then begin X write(ERRfile,'dvitty: '); X case uerr of X ign : writeln(ERRfile, Copyright); X wrnge : writeln(ERRfile,'width arg out of range:16-132'); X nan : writeln(ERRfile,'numeric argument expected'); X gae : writeln(ERRfile,'garbage at end of argument'); X bdlst : writeln(ERRfile,'mal-formed list of pagenumbers'); X onef : writeln(ERRfile,'only one infile argument allowed'); X noarg : writeln(ERRfile,'option argument expected'); X lngpth : writeln(ERRfile,'path too long for -F'); X bdopt : writeln(ERRfile,'bad option'); X end; X end; X writeln(ERRfile,'Usage: dvitty [ options ] dvifile[.dvi]'); X writeln(ERRfile,'Options are:'); X writeln(ERRfile, X ' -ofile Write output to file, else write to stdout.'); X writeln(ERRfile, X ' -plist Print pages whos TeX-page-number are in list.'); X writeln(ERRfile, X ' -Plist Print pages whos sequential number are in list.'); X writeln(ERRfile, X ' -wn Print the lines with width n characters, default 80.'); X write(ERRfile,' -f Try to pipe to a pager if output is a tty'); X if defpage then writeln(ERRfile,' (default).') X else writeln(ERRfile,'.'); X write(ERRfile,' -q Don''t try to pipe to a pager'); X if defpage then writeln(ERRfile,'.') X else writeln(ERRfile,' (default).'); X writeln(ERRfile, X ' -l Write ''^L'' instead of formfeed between pages.'); X write(ERRfile, X ' -u National Swedish characters printed as aaoAAO'); X if defscand then writeln(ERRfile,'.') X else writeln(ERRfile,' (default).'); X write(ERRfile, X ' -s National Swedish characters printed as }{|][\'); X if defscand then writeln(ERRfile,' (default).') X else writeln(ERRfile,'.'); X exit(1); X end; { usage } X X{-----------------------------------------------------------------------------} X Xprocedure getname(var str : string); X var i : integer; X begin X i:=stringlength; X while (i>1) and (str[i]=' ') do i:=i-1; X if (i=1) and (str[1]=' ') then usage(ign); X if not ((i>=5) and (str[i]='i') and (str[i-1]='v') X and (str[i-2]='d') and (str[i-3]='.')) then begin X str[i+1]:='.'; X str[i+2]:='d'; X str[i+3]:='v'; X str[i+4]:='i'; X end; X DVIfilename:=str; X end; { getname } X X{-----------------------------------------------------------------------------} X Xfunction getinteger(var j: integer; var str : string; def : integer) : integer; X var cum : integer; X sgn : boolean; X begin X if not (str[j] in ['0'..'9','-']) then getinteger:=def X else begin X cum:=0; X sgn:=false; X if str[j]='-' then begin X sgn:=true; X j:=j+1; X end; X if not (str[j] in ['0'..'9']) then getinteger:=def X else begin X while str[j] in ['0'..'9'] do begin X cum:=cum*10+ord(str[j])-ord('0'); X j:=j+1; X end; X if sgn then getinteger:=-cum else getinteger:=cum; X end; X end; X end; { getinteger } X X{-----------------------------------------------------------------------------} X Xprocedure getpages(j : integer; var str : string); X var i : integer; X X procedure plcnxt(pagnr : integer); { place page-nr next in list } X begin X currentpage:=lastpage; X currentpage^.pag:=pagnr; X new(lastpage); X lastpage^.all:=false; X lastpage^.nxt:=nil; X lastpage^.pag:=0; X currentpage^.nxt:=lastpage; X end; { plcnxt } X X begin { getpages } X pageswitchon:=true; X new(firstpage); X firstpage^.all:=false; X firstpage^.nxt:=nil; X firstpage^.pag:=0; X lastpage:=firstpage; X currentpage:=firstpage; X if not (str[j] in ['1'..'9','-']) then usage(nan); X foo:=getinteger(j,str,0); X while foo<>0 do begin X plcnxt(foo); X if str[j]=',' then begin X j:=j+1; X if not (str[j] in ['1'..'9','-']) then usage(nan); X end else if str[j]=':' then begin X j:=j+1; X if not (str[j] in ['1'..'9','-']) then usage(nan); X foo:=getinteger(j,str,0); X if currentpage^.pag<0 then begin X if (foo>0) then begin X currentpage^.all:=true; X plcnxt(foo); X end else if foo' ' then usage(gae); X currentpage:=firstpage; X end; { getpages } X X{-----------------------------------------------------------------------------} X Xprocedure setoption(optch : char; var optset, optwarg : charset; X var str : string; var i : integer; j : integer); X var k : integer; X begin X while optch in optset do begin X case optch of X 'q' : pager:=false; X 'f' : pager:=true; X 'l' : noffd:=true; X 's' : scascii:=true; X 'u' : scascii:=false; X 'p' : begin X optset:=optset-['P']; { can't have both -P & -p } X getpages(j, str); X end; X 'P' : begin X sequenceon:=true; X optset:=optset-['p']; { can't have both -P & -p } X getpages(j, str); X end; X 'w' : begin X if not (str[j] in ['0'..'9','-']) then usage(nan); X ttywidth:=getinteger(j, str, 80); X if str[j]<>' ' then usage(gae); X if (ttywidth<16) or (ttywidth>132) then usage(wrnge); X end; X 'o' : begin X for k:=1 to stringlength-j+1 do X OUTfilename[k]:=str[j+k-1]; X for k:=stringlength-j+2 to stringlength do X OUTfilename[k]:=' '; X outputtofile:=true; X j:=stringlength; X end; X 'F' : begin X for k:=1 to pathlen do X path[k]:=str[k+j-1]; X if path[pathlen]<>' ' then usage(lngpth); X j:=stringlength; X pathpgm:=false; X end; X end; X optch:=str[j]; X j:=j+1; X if optch in optwarg then if str[j]=' ' then begin X i:=i+1; X if i>=argc then usage(noarg); X argv(i, str); X j:=1; X end; X end; X end; { setoption } X X{-----------------------------------------------------------------------------} X Xprocedure getargs; X var i, j : integer; X str : string; X DVIfilenamefound : boolean; X optset, optwarg : charset; X optch : char; X begin X if argc<=1 then usage(ign); X pageswitchon:=false; { default: all pages } X sequenceon:=false; { default: selected pages are TeX-numbered } X outputtofile:=false; { default: write to stdout } X noffd:=false; { default: print formfeed between pages } X scascii:=defscand; { default: see compile time adjustable const } X pager:=defpage; { default: see compile time adjustable const } X path:=defpath; { default: use the default path to the pager } X pathpgm:=true; { default: - " - } X ttywidth:=80; { default } X DVIfilenamefound:=false; X optset:=['w','p','P','o','u','s','q','l','f','F']; { legal options } X optwarg:=['w','p','P','o','F']; { options with args } X i:=0; X while envargs(optch, str) do { get options from environ var DVITTY } X setoption(optch, optset, optwarg, str, i, 1); X i:=1; X while i'-' then begin X if DVIfilenamefound then usage(onef); X getname(str); X DVIfilenamefound:=true; X end else if optch in optset then begin X j:=3; X if (optch in optwarg) and (str[j]=' ') then begin X i:=i+1; X if i>=argc then usage(noarg); X argv(i, str); X j:=1; X end; X setoption(optch, optset, optwarg, str, i, j); X end else usage(bdopt); X i:=i+1; X end; X if not DVIfilenamefound then usage(ign) X end; { getargs } X X{-----------------------------------------------------------------------------} X Xfunction getbyte : integer; { get next byte from dvi-file } X var b : sbyte; X begin X read(DVIfile, b); X if b<0 then getbyte:=b+256 else getbyte:=b X end; { getbyte } X X{-----------------------------------------------------------------------------} X Xfunction get2 : integer; { returns the next two bytes, unsigned } X begin X foo:=getbyte; X get2:=foo*256+getbyte X end; { get2 } X X{-----------------------------------------------------------------------------} X Xfunction get3 : integer; { returns the next three bytes, unsigned } X begin X foo:=getbyte; X foo:=foo*256+getbyte; X get3:=foo*256+getbyte X end; { get3 } X X{-----------------------------------------------------------------------------} X Xfunction signedbyte : integer; { returns next byte fr dvi-file, signed } X var b : sbyte; X begin X read(DVIfile, b); X signedbyte:=b; X end; { signedbyte } X X{-----------------------------------------------------------------------------} X Xfunction signed2 : integer; { returns the next two bytes, signed } X begin X read(DVIfile, foo); X signed2:=foo*256+getbyte X end; { signed2 } X X{-----------------------------------------------------------------------------} X Xfunction signed3 : integer; { returns the next three bytes, signed } X begin X read(DVIfile, foo); X foo:=foo*256+getbyte; X signed3:=foo*256+getbyte X end; { signed3 } X X{-----------------------------------------------------------------------------} X Xfunction signed4 : integer; { returns the next four bytes, signed } X begin X read(DVIfile, foo); X foo:=foo*256+getbyte; X foo:=foo*256+getbyte; X signed4:=foo*256+getbyte X end; { signed4 } X X{-----------------------------------------------------------------------------} X Xfunction imin(a, b : integer) : integer; { returns the least of two int:s } X begin X if anop2; X skipnoops:=(opcode=goal) X end; { skipnoops } X X{-----------------------------------------------------------------------------} X Xfunction getline : lineptr; { returns an initialized line-object } X var i : integer; X temp : lineptr; X begin X new(temp); X with temp^ do begin X charactercount:=leftmargin-1; prev:=nil; next:=nil; X for i:=leftmargin to rightmargin do text[i]:=' ' X end; X getline:=temp X end; { getline } X X{-----------------------------------------------------------------------------} X Xfunction findline : lineptr; { find line where text should go, } X var temp : lineptr; { generate a new line if needed } X begin X if ((v>currentline^.vv) and (currentline=lastline)) X or ((vverticalepsilon) then begin X temp:=getline; X with temp^ do begin X prev:=lastline; X vv:=v; X lastline^.next:=temp; X lastline:=temp X end X end else begin X temp:=lastline; X while (temp^.vv>v) and (temp<>firstline) do temp:=temp^.prev; X if abs(temp^.vv-v)>verticalepsilon then begin X if temp^.next^.vv-v < verticalepsilon then temp:=temp^.next X else if (temp=firstline) and (vverticalepsilon X then currentline:=findline; X if (ord(ch) in [11..17, 25..31, 92, 123..126]) then X case ord(ch) of X 11 : begin outchar('f'); ch:='f' end; { ligature } X 12 : begin outchar('f'); ch:='i' end; { ligature } X 13 : begin outchar('f'); ch:='l' end; { ligature } X 14 : begin outchar('f'); X outchar('f'); ch:='i' end; { ligature } X 15 : begin outchar('f'); X outchar('f'); ch:='l' end; { ligature } X 16 : ch:='i'; X 17 : ch:='j'; X 25 : begin outchar('s'); ch:='s' end; { German double s } X 26 : begin outchar('a'); ch:='e' end; { Dane/Norw ae } X 27 : begin outchar('o'); ch:='e' end; { Dane/Norw oe } X 28 : if scascii then ch:='|' { Dane/Norw /o } X else ch:='o'; X 29 : begin outchar('A'); ch:='E' end; { Dane/Norw AE } X 30 : begin outchar('O'); ch:='E' end; { Dane/Norw OE } X 31 : if scascii then ch:='\' { Dane/Norw /O } X else ch:='O'; X 92 : ch:='"'; { beginnig qoute } X 123 : ch:='-'; X 124 : ch:='_'; X 125 : ch:='"'; X 126 : ch:='"'; X end; X j:=round((h/maxpagewidth)*(ttywidth-1)+1.0); X if j>rightmargin then j:=rightmargin X else if j=leftmargin then begin X j:=foo; X case ord(text[j]) of X 127 : if ch='a' then ch:='{' else { dots } X if ch='A' then ch:='[' else X if ch='o' then ch:='|' else X if ch='O' then ch:='\'; X 23 : if ch='a' then ch:='}' else { circle } X if ch='A' then ch:=']' X end; { case } X end; X end; X end; X {----------------- end of 'Scandinavian code' ----------------} X if foo=leftmargin-1 then while (text[j]<>' ') and (j=chspc) or (ord(ch)=23))) or X (not scascii and (ord(ch)>=chspc) and (ord(ch)<>chdel)) then X begin X if jcharactercount then charactercount:=j; X if j127 from current font } X { note that the parameter is a dummy, since ascii-chars are<=127 } X begin X outchar('#') X end; { setchar } X X{-----------------------------------------------------------------------------} X Xprocedure putcharacter(charnr : integer); { output character, don't change h } X var saveh : integer; X begin X saveh:=h; X if (charnr>=0) and (charnr<=lastchar) then outchar(chr(charnr)) X else setchar(charnr); X h:=saveh; X end; { putcharacter } X X{-----------------------------------------------------------------------------} X Xprocedure rule(moving : boolean; rulewt, ruleht : integer); X { output a rule (vertical or horizontal), increment h if moving is true } X var ch : char; { character to set rule with } X saveh, savev, wt : integer; X X procedure ruleaux; { recursive procedure that does the job } X var lmh, rmh : integer; X begin X wt:=rulewt; X lmh:=h; { save left margin } X if h<0 then begin { let rules that start at negative h } X wt:=wt-h; { start at coordinate 0, but let it } X h:=0; { have the right length } X end; X while wt>0 do begin { output the part of the rule that } X rmh:=h; { goes on this line } X outchar(ch); X wt:=wt-(h-rmh); { decrease the width left on line } X end; X ruleht:=ruleht-verticalepsilon; { decrease the height } X if ruleht>verticalepsilon then begin { still more vertical? } X rmh:=h; { save current h (right margin) } X h:=lmh; { restore left margin } X v:=v-(verticalepsilon+(verticalepsilon div 10)); X ruleaux; X h:=rmh; { restore right margin } X end; X end; { ruleaux } X X begin { rule -- starts up the recursive routine } X if not moving then saveh:=h; X if (ruleht<=0) or (rulewt<=0) then h:=h+rulewt X else begin X savev:=v; X if (ruleht div rulewt)>0 then ch:='!' X else if ruleht>(verticalepsilon div 2) then ch:='=' X else ch:='_'; X ruleaux; X v:=savev; X end; X if not moving then h:=saveh; X end; { rule } X X{-----------------------------------------------------------------------------} X Xprocedure fontdef(param : integer); { ignore font-definition command } X begin X setpos(DVIfile, param+12, relative); X setpos(DVIfile, getbyte+getbyte, relative); X end; { fontdef } X X{-----------------------------------------------------------------------------} X Xprocedure horizontalmove(amount : integer; var worx : integer); X begin X if amount<>worx then X if abs(amount)<=(charwidth div 4) then worx:=amount X else begin X foo:=3*charwidth div 4; X if amount>0 then worx:=((amount+foo) div charwidth)*charwidth X else worx:=((amount-foo) div charwidth)*charwidth; X end; X h:=h+worx X end; { horizontalmove } X X{-----------------------------------------------------------------------------} X Xfunction inlist(pagenr : integer) : boolean; { ret true if in list of pages } X begin X inlist:=false; X while (currentpage^.pag<0) and (currentpage^.pag<>pagenr) X and not currentpage^.all and (currentpage^.nxt<>nil) do X currentpage:=currentpage^.nxt; X if (currentpage^.all and (pagenr0 then begin X while (currentpage^.pag<>pagenr) and (currentpage^.nxt<>nil) do X currentpage:=currentpage^.nxt; X if currentpage^.pag=pagenr then inlist:=true X end X end; { inlist } X X{-----------------------------------------------------------------------------} X Xfunction bop(var pagecounter, backpointer, pagenr : integer) : boolean; X begin X pagecounter:=pagecounter+1; X pagenr:=signed4; X setpos(DVIfile, 36, relative); X backpointer:=signed4; X if pageswitchon then X if sequenceon then bop:=inlist(pagecounter) X else bop:=inlist(pagenr) X else bop:=true; X end; { bop } X X{-----------------------------------------------------------------------------} X Xprocedure initpage(backpointer, pagenr, pagecounter : integer); X begin X h:=0; v:=0; { initialize coordinates } X x:=0; w:=0; y:=0; z:=0; { initialize amounts } X stack.top:=0; { initialize stack } X currentline:=getline; { initialize list of lines } X currentline^.vv:=0; X firstline:=currentline; X lastline:=currentline; X firstcolumn:=rightmargin; X if pageswitchon then X if (sequenceon and (pagecounter<>firstpage^.pag)) X or (not sequenceon and (pagenr<>firstpage^.pag)) then X if noffd then writeln('^L') else writeln(chr(chffd)); X if not pageswitchon then if backpointer<>-1 then X if noffd then writeln('^L') else writeln(chr(chffd)); X end; { initpage } X X{-----------------------------------------------------------------------------} X Xprocedure dover2page; X begin X opcode:=getbyte; X while opcode<>eop2 do begin { process page until eop reached } X if opcode>postpost2 then errorexit(illop) X else if opcode<=lastchar then outchar(chr(opcode)) X else if opcode in [128..170, 235..249] then X case opcode of X 128 : setchar(getbyte); X 129 : setchar(get2); X 130 : setchar(get3); X 131 : setchar(signed4); X 132 : rule(advance, signed4, signed4); X 133 : putcharacter(getbyte); X 134 : putcharacter(get2); X 135 : putcharacter(get3); X 136 : putcharacter(signed4); X 137 : rule(stay, signed4, signed4); X nop2: ; { no-op } X bop2: errorexit(bdbop); X 141 : with stack do begin { push } X if top>stackmax-1 then errorexit(stkof); X top:=top+1; X with items[top] do begin X hh:=h; vv:=v; ww:=w; X xx:=x; yy:=y; zz:=z; X end; X end; X 142 : with stack do begin { pop } X if top=0 then errorexit(stkuf); X with items[top] do begin X h:=hh; v:=vv; w:=ww; X x:=xx; y:=yy; z:=zz; X end; X top:=top-1; X end; X 143 : h:=h+signedbyte; X 144 : h:=h+signed2; X 145 : h:=h+signed3; X 146 : h:=h+signed4; X 147 : horizontalmove(w, w); X 148 : horizontalmove(signedbyte, w); X 149 : horizontalmove(signed2, w); X 150 : horizontalmove(signed3, w); X 151 : horizontalmove(signed4, w); X 152 : horizontalmove(x, x); X 153 : horizontalmove(signedbyte, x); X 154 : horizontalmove(signed2, x); X 155 : horizontalmove(signed3, x); X 156 : horizontalmove(signed4, x); X 157 : v:=v+signedbyte; X 158 : v:=v+signed2; X 159 : v:=v+signed3; X 160 : v:=v+signed4; X 161 : v:=v+y; X 162 : begin y:=signedbyte; v:=v+y end; X 163 : begin y:=signed2; v:=v+y end; X 164 : begin y:=signed3; v:=v+y end; X 165 : begin y:=signed4; v:=v+y end; X 166 : v:=v+z; X 167 : begin z:=signedbyte; v:=v+z end; X 168 : begin z:=signed2; v:=v+z end; X 169 : begin z:=signed3; v:=v+z end; X 170 : begin z:=signed4; v:=v+z end; X 235, 236, 237, { ignore font changes } X 238 : setpos(DVIfile, opcode-234, relative); X 239 : setpos(DVIfile, getbyte, relative); X 240 : setpos(DVIfile, get2, relative); X 241 : setpos(DVIfile, get3, relative); X 242 : setpos(DVIfile, signed4, relative); X 243,244,245, X 246 : fontdef(opcode-242); X pre2 : errorexit(bdpre); X post2 : errorexit(bdpst); X postpost2: errorexit(bdpp); X end; X opcode:=getbyte X end X end; { dover2page } X X{-----------------------------------------------------------------------------} X Xprocedure eop; { 'end of page', writes lines of page to output file } X var i, j : integer; X ch : char; X begin X if stack.top<>0 then X writeln(ERRfile, 'dvitty: warning - stack not empty at eop.'); X currentline:=firstline; X repeat X with currentline^ do begin X if currentline<>firstline then begin X foo:=((vv-prev^.vv) div verticalepsilon)-1; X if foo>0 then foo:=imin(foo, 3); X for i:=1 to foo do writeln; X end; X if charactercount>=leftmargin then begin X i:=firstcolumn; j:=1; foo:=ttywidth-2; X repeat X ch:=text[i]; X if (ord(ch)>=chspc) and (ord(ch)<>chdel) then X write(ch); X if j>foo then if charactercount>i+1 then begin X writeln('*'); X write(' *'); X j:=2 X end; X i:=i+1; j:=j+1 X until i>charactercount; X end X end; X writeln; X currentline:=currentline^.next; X until currentline^.next=nil; X end; { eop } X X{-----------------------------------------------------------------------------} X Xprocedure skipver2page; { skip past one page } X begin X opcode:=getbyte; X while opcode<>eop2 do begin X if opcode>postpost2 then errorexit(illop) X else if opcode in [128..170, 235..249] then X case opcode of X nop2,141, 142, 147, 152, 161, 166 : ; X 128, 133, 143, 148, 153, 157, 162, 167, 235 : X setpos(DVIfile, 1, relative); X 129, 134, 144, 149, 154, 158, 163, 168, 236 : X setpos(DVIfile, 2, relative); X 130, 135, 145, 150, 155, 159, 164, 169, 237 : X setpos(DVIfile, 3, relative); X 131, 136, 146, 151, 156, 160, 165, 170, 238 : X setpos(DVIfile, 4, relative); X 132, 137 : setpos(DVIfile, 8, relative); X 139 : errorexit(bdbop); X 239 : setpos(DVIfile, getbyte, relative); X 240 : setpos(DVIfile, get2, relative); X 241 : setpos(DVIfile, get3, relative); X 242 : setpos(DVIfile, signed4, relative); X 243,244,245, X 246 : fontdef(opcode-242); X pre2 : errorexit(bdpre); X post2 : errorexit(bdpst); X postpost2 : errorexit(bdpp); X end; X opcode:=getbyte; X end; X end; { skipver2page } X X{-----------------------------------------------------------------------------} X Xprocedure dopages; { process the pages in the DVI-file } X var pagecounter, backpointer, pagenr : integer; X begin X setpos(DVIfile, 0, absolute); { read the dvifile from the start } X pagecounter:=0; X if not skipnoops(pre2) then errorexit(nopre); X opcode:=getbyte; { check id in preamble, ignore rest of it } X if opcode<>versionid then errorexit(badid); X setpos(DVIfile, 12, relative); X setpos(DVIfile, getbyte, relative); X if not skipnoops(bop2) then errorexit(nobop) { should be at start } X else while opcode<>post2 do begin { of page now } X if opcode<>bop2 then errorexit(nobop) X else begin X if not bop(pagecounter, backpointer, pagenr) then skipver2page X else begin X initpage(backpointer, pagenr, pagecounter); X dover2page; X eop; X end; X repeat opcode:=getbyte until opcode<>nop2 X end X end; X end; { dopages } X X{-----------------------------------------------------------------------------} X Xprocedure postamble; { find and process postamble, use random access } X var size, count : integer; X begin X size:=sizef(DVIfile); { get size of file } X count:=-1; X repeat { back file up past signature bytes (223), to id-byte } X if size=0 then errorexit(nopst); X size:=size-1; X setpos(DVIfile, size, absolute); X opcode:=getbyte; X count:=count+1; { has to be at least 4 sign-bytes } X until opcode<>223; X if count<4 then begin foo:=count; errorexit(fwsgn); end; X if opcode<>versionid then errorexit(badid); X setpos(DVIfile, size-4, absolute); { back up to back-pointer } X setpos(DVIfile, signed4, absolute); { back up to start of postamble } X if getbyte<>post2 then errorexit(nopst); X setpos(DVIfile, 20, relative); X maxpagewidth:=signed4; X charwidth:=maxpagewidth div ttywidth; X foo:=get2; X if foo>stackmax then errorexit(stkrq); { too much stack required } X end; { postamble } X X(***************************************************************************** X * X * M A I N X *) X Xbegin X rewrite(ERRfile, '/dev/tty'); { get a pascal file } X tostderr(ERRfile); { and redirect it to stderr } X getargs; { read the command line arguments } X if not readp(DVIfilename) then X errorexit(filop); { can't open dvifile } X reset(DVIfile, DVIfilename); X if outputtofile then begin { open the outfile } X if not writep(OUTfilename) then X errorexit(filcr); { can't create outfile } X rewrite(output, OUTfilename); X pager:=false; X end else X if ttyp(output) and pager then { try to pipe to a pager } X pager:=popenp(output, path, pathpgm); X postamble; { seek and process the postamble } X dopages; { time to do the actual work! } X if pager then pcloseit(output); { have to use pclose if popened } Xend. + END-OF-FILE dvitty.p chmod 'u=rw,g=rw,o=r' 'dvitty.p' echo ' -rw-rw-r-- 1 zap 47572 Aug 15 20:29 dvitty.p (as sent)' echo -n ' ' /bin/ls -l dvitty.p echo 'Extracting sys.h' sed 's/^X//' > sys.h << '+ END-OF-FILE sys.h' Xprocedure exit(i : integer); external; { in libc } X Xprocedure setpos(var f : DVIfiletype; p, m : integer); external; X Xfunction sizef(var f : DVIfiletype) : integer; external; X Xprocedure delete(var f : text); external; X Xfunction readp(var filename : string) : boolean; external; X Xfunction writep(var filename : string) : boolean; external; X Xprocedure tostdout(var f :text); external; X Xprocedure tostderr(var f : text); external; X Xfunction ttyp(var f :text) : boolean; external; X Xfunction popenp(var f :text; var path : pathtype; X pathpgm : boolean) : boolean; external; X Xprocedure pcloseit(var f :text); external; X Xfunction envargs(var optch :char; var str :string) : boolean; external; + END-OF-FILE sys.h chmod 'u=rw,g=r,o=r' 'sys.h' echo ' -rw-r--r-- 1 zap 720 Aug 8 00:22 sys.h (as sent)' echo -n ' ' /bin/ls -l sys.h echo 'Extracting sys.c' sed 's/^X//' > sys.c << '+ END-OF-FILE sys.c' X#include X#include X#include X X#define NAMSIZ 76 X#define SYNC 0x004 /* 1 => window is out of sync */ X Xtypedef enum {FALSE, TRUE} bool; X Xstruct iorec { X char *fileptr; /* ptr to file window */ X long lcount; /* number of lines printed */ X long llimit; /* maximum number of text lines */ X FILE *fbuf; /* FILE ptr */ X struct iorec *fchain; /* chain to next file */ X struct iorec *flev; /* ptr to associated file variable */ X char *pfname; /* ptr to name of file */ X short funit; /* file status flags */ X unsigned short fblk; /* index into active file table */ X long fsize; /* size of elements in the file */ X char fname[NAMSIZ]; /* name of associated UNIX file */ X char buf[BUFSIZ]; /* I/O buffer */ X char window[1]; /* file window element */ X}; X Xsetpos(f, p, m) /* seek on a pascal file */ Xstruct iorec *f; Xint p, m; X{ X f->funit |= SYNC; X (void) fseek (f->fbuf, (long) p, m); X} X Xint Xsizef(f) /* return size of file */ Xstruct iorec *f; X{ X struct stat st; X X (void) fstat (fileno(f->fbuf), &st); X return (st.st_size); X} X Xdelete(f) /* remove a link to a file */ Xstruct iorec *f; X{ X (void) unlink (f->pfname); X} X Xbool Xreadp(filename) /* check if a file may be read */ Xchar *filename; X{ X register char *p; X register bool ok; X X for(p=filename; *p!=' '; p++) /* pascal strings are space-padded */ X ; X *p='\0'; /* make it a C-string */ X if (access(filename, 04) == 0) /* check if we can read this file */ X ok=TRUE; X else X ok=FALSE; X *p=' '; /* "re-pasclify" the string */ X return(ok); X} X Xbool Xwritep(filename) /* check if a file may be written */ Xchar *filename; X{ X register char *p; X register bool ok; X int f; X X for(p=filename; *p!=' '; p++) /* pascal strings are space-padded */ X ; X *p='\0'; /* make it a C-string */ X if ((f=creat(filename, 0666)) >= 0) { /* can we create this file?*/ X (void) close(f); X ok = TRUE; X } else X ok = FALSE; X *p=' '; /* "re-pasclify" the string */ X return(ok); X} X Xtostdout(f) /* make file appear on stdout */ Xstruct iorec *f; X{ X (void) fflush (f->fbuf); X f->fbuf = stdout; X} X Xtostderr(f) /* make file appear on stderr */ Xstruct iorec *f; X{ X (void) fflush (f->fbuf); X f->fbuf = stderr; X} X Xbool Xttyp(f) /* is file associated with a tty? */ Xstruct iorec *f; X{ X if (isatty(fileno(f->fbuf))==1) X return(TRUE); X else X return(FALSE); X} X Xbool Xpopenp(f, path, pthpgm) /* can this file be piped into a */ Xstruct iorec *f; /* pager (like more)? */ Xchar *path; Xbool pthpgm; X{ X char *getenv(), *p; X FILE *popen(), *g; X X if (pthpgm==FALSE) { /* -Fpath option used */ X for(p=path; *p !=' ' && *p != '\0'; p++) X ; X *p = '\0'; X } else if ((p=getenv("PAGER"))==NULL) { /* find prefered pager */ X for(p=path; *p !=' ' && *p != '\0'; p++) X ; /* didn't have one, use */ X *p = '\0'; /* the default one for pgm */ X } else X path = p; /* default pager from env */ X if ((g=popen(path, "w"))!=NULL) { /* get a pipe to the pager */ X (void) fflush (f->fbuf); /* make output to f go to */ X f->fbuf = g; /* the pager */ X return(TRUE); X } else X return(FALSE); /* couldn't do it */ X} X Xpcloseit(f) /* popend stream has to be */ Xstruct iorec *f; /* pclosed */ X{ X (void) pclose (f->fbuf); X} X Xbool Xenvargs(optch, str) Xchar *optch, *str; X{ X char *getenv(), *q; X static char *p; X static int foo = 0; X X switch (foo) { X case 0: if ((p=getenv("DVITTY"))==NULL) /* 1st time only, get var */ X return(FALSE); /* sorry, no var */ X foo++; /* remember we've been here to next call */ X /* fall through */ X default: X if (*p!=' ' && *p!='\0') /* anything here? */ X *optch = *p++; /* yes, it's our optchar */ X else X return(FALSE); /* sorry, no more */ X q=str; /* get args or whatever */ X while (*p!=' ' && *p!='\0') X *q++ = *p++; X *q=' '; /* the pascal program wants ' ' */ X while (*p==' ') /* step to next or end */ X p++; X return(TRUE); X } X} + END-OF-FILE sys.c chmod 'u=rw,g=r,o=r' 'sys.c' echo ' -rw-r--r-- 1 zap 3999 Aug 8 00:24 sys.c (as sent)' echo -n ' ' /bin/ls -l sys.c exit 0