PROGRAM RNF(INPUT, OUTPUT , INFILE, OUTFILE); { RNF: Text formatter for document prepartation. } { Originally written for Cyber by Bob Foster at U. of Illinois. This version derives from Software Consulting Services production RNF 18-Dec-84 running on VAX VMS ver 4. Enhancements to VAX version by John McGrath. This is a well-written program, easy to maintain, adapt, and enhance; unfortunately there are few comments. } { Adapted to Turbo Pascal and Prospero Pro Pascal (only minor changes required) by Willett Kempton, May 1985 and May 1986. } { Very few compiler or operating system dependencies are used, and this program can easily be ported to most Pascal systems on most computers. } { Normally RNF is run directly to the printer; there has not been a serious attempt at speed optimization since the printer limits run speed. If it is frequently used to write to files, it can be sped up by using MOVE in place of DO loops in DOJUST and ADDWORD. } CONST version = ' 7 June 86 '; VPAGE = 1; VCH = 2; VHL = 3; VLIST = 9; (* NEXT IS 20 *) VLM = 20; VRM = 21; VSP = 22; VNMP = 23; VOLNO = 24; vcr = 25; VANSI = 26; NextVariable = 27; (* NEXT IS 27 *) VARMAX = 140; MACCHR = '.'; VARCHR = '$'; CMDCHR = '.'; NOPAGE = FALSE; { set true to make WRITELNs, not PAGE, do page eject } TABMAX = 16; LINLEN = 160; MAXENP = 20; HLMAX = 5; CHRMOD = 128; LowerCaseConvert = -32 (* ord('A') - ord('a') *); FIGMAX = 10; MaxParms = 8; VHLMAX = 5; MaxErrors = 63; maxhash = 82; AlfaBlanks = ' '; AlfaLen = 10; StackMax = 20; StgTblSize = 10000; { this may need to be smaller on CP/M-80 } paocBUG = true; { true if "write(paoc:len);" does not work according to ISO } { false for Cyber, VMS, Prospero, true for Turbo and UCSD } TYPE alfa = PACKED ARRAY [1 .. AlfaLen] OF CHAR; StgRange = 1 .. StgTblSize; VARTYP = (VITEM, VARRAY); RELOPR = (EQ, GT, LT, NE, GE, LE, BADRELOP); ENRANGE = 0 .. MAXENP; SIGN = (PLUS, MINUS, UNSIGNED, INVALID); SYMTYP = (WORD, COMMAND, VARS, NONE); LLEN = 0 .. LINLEN; LALEN = 1 .. LINLEN; LineFlags = packed array [llen] of boolean; JUSLIN = RECORD NDX: LLEN; POS: ARRAY [LALEN] OF INTEGER END; ALINE = PACKED ARRAY [LALEN] OF CHAR; LINE = RECORD LEN: LLEN; LIN, OverLin: ALINE; CENTER, BBAR: BOOLEAN; HasOverPrinting, HasBoldPrinting, HasUnderscore: boolean; USflag, BoldFlag: LineFlags; END; CMDTYP = (CBLANK, cinclude, CCR, CBREAK, CRESPAG, CRES, CESCCHR, CCENTER, CJUST, CUL, CLMAR, CRMAR, CFILL, CSIG, CPAGE, CSUP, CSTD, CPS, CSAV, CP, CPP, CAP, CI, CSP, CS, CTP, CCH, CHL, CNMP, CPNO, CTITLE, CST, CATITLE, CLIST, CLE, CELIST, CFIG, CBAR, CBB, CEB, CU, CT, CTAB, CTABS, CRT, CRIGHT, CLINES, CMACRO, CX, CVAR, CINC, CASIS, CDEC, (* END OF CMDTYP SET *) CFLAG, CBOLD, CCASEFLAG, CFLAGCAPS, CFLAGOVER, CFLAGSIG, CLOWER, CUPPER, CPERIOD, CSAVPAG, CFRCPAGE, CTOP, CMID, CBOT, CARRAY, CFMT, CIF, CDOT, CREM, CUPP, CUSB, NOTCMD); CharType = (UpArrow, ucLetter, lcLetter, LeftAngle, EndSentence, UnderScore, NumberSign, BackSlash, MiscChar, ArithChar, OtherChar); CharRange = char; { Prospero limits char to 0..127, thus to use } { full 8-bit set need ChrRange = '00' .. 'FF' } ENVIRON = RECORD J, F, PR, SG, UN, Bl: BOOLEAN; PM, SP: INTEGER; LM, RM, PS, PT: LLEN; TB: PACKED ARRAY [1 .. TABMAX] OF LLEN END; MACTYP = (HEADER, PARM); PMAC = ^ MAC; StringLocation = -1 .. StgTblSize; StgDescription = record ActiveMacro: pmac; StgPosition, StgBegin, StgEnd: StringLocation; end; MAC = RECORD ON: BOOLEAN; NM: alfa; MT: MACTYP; NP: 0 .. MaxParms; MacroBegin, MacroEnd: StringLocation; MA: PMAC; END; {}{VAX} { string80 = packed array [1..80] of char;} {}{Turbo, Prospero } string80 = string[80]; OutflType = text; VAR INFILE, inclfile: text; OUTFILE: OutFlType; {} InputName, {} inclname: string80; SYMTYPE: SYMTYP; TopOfStack: integer; StgStack: array [0 .. StackMax] of StgDescription; StgMarker: integer (* free space pointer from end *); FreeStgIndx: integer (* free space pointer from beginning *); StgTable: packed array [StgRange] of char; SYL, OTL, TMPL, ADDSYL: LINE; FREEMACP: PMAC; CMDS: ARRAY [CMDTYP] OF alfa; CMDTYPE: CMDTYP; perfect: array [0 .. maxhash] of cmdtyp; letperfect: array ['A' .. 'Z'] of integer; InitialPageEject, HandFeed, AP, asis, ATITLE, BAR, BB, bold, DoInclFl, ESCCHR, FILL, FLAG, FLAGCAPS, FLAGOVER, FLAGSIG, HOLDBB, JUSTIT, LOWER, PARA, PERIOD, PQEND, PREL, RIGHT, SIGBL, SUP, UL, UNDL, USB, XTRABL, YES: Boolean; ILNO, INCLNO, OETXT, OVETXT, OEPAG, OVBTXT, PMAR: INTEGER; JUST: JUSLIN; ENSTK: ARRAY [ENRANGE] OF ENVIRON; ENP: ENRANGE; PARSPACE, PARTEST, SPACING: INTEGER; PAGENV: ENVIRON; DEFRB: INTEGER; FORCE, FIRSTCH: BOOLEAN; FIGP: 0 .. FIGMAX; FIGN: ARRAY [1 .. FIGMAX] OF INTEGER; RIGHTSPACE: 0 .. 136; TABS: ARRAY [1 .. TABMAX] OF LLEN; RT, T, DOT: BOOLEAN; BREAKSET, OPTBRKSET, CRSET: SET OF CBLANK .. CDEC; EMPTY: BOOLEAN; MACLSTP, DefrFrcPgMacP, FrcPgMacP, ParagMacP, CarRtnMacP, MidMacP, TTLMACP, STLMACP, ChapterMacP, CHTMACP: PMAC; NOTMACRO: BOOLEAN; LASTCUP: integer; XTEND: BOOLEAN; LASTLEN, LASTSLEN: LLEN; VID: ARRAY [1 .. VARMAX] OF ALFA; VAL: ARRAY [1 .. VARMAX] OF INTEGER; VTY: ARRAY [1 .. VARMAX] OF VARTYP; VUP: ARRAY [1 .. VARMAX] OF 1 .. VARMAX; VARNDX, TV: 1 .. VARMAX; PUSHED: BOOLEAN; PAGSAV: LINE; PAGOTL: BOOLEAN; ARELOPR: ARRAY [RELOPR] OF ALFA; DangerPoint: integer; EXPRERR, SHOWEXPR: BOOLEAN; ITEMSET, TERMSET: SET OF ' ' .. '_'; RomanChars: packed array [1 .. 26] of char; RomanValue: array [1 .. 13] of integer; ROMLC: BOOLEAN; EOFINPUT: BOOLEAN; ErrorsOnLine: integer; ErrorSet: set of 0 .. MaxErrors; StartToken: integer; VarName: alfa; ERRORCOUNT: INTEGER; LineCount: integer; MakeUpper, MakeLower: packed array [CharRange] of char; CharCategory: array [CharRange] of CharType; EmptyFlags: LineFlags; {}{Turbo} { Page must be manually declared on Turbo Pascal } { use chr(12) or the page eject code for your printer, or set NOPAGE true } procedure page(var f:text); begin writeln(f,chr(12)) end; {}{Prospero} { Halt must be manually declared in Prospero Pro Pascal } { procedure halt; procedure ExitProg(retcode:integer); external; begin ExitProg(1); end; } procedure WritePAOC ( var L: ALINE; width: integer); { Write a Packed Array Of Char, with a field width. This procedure is } { necessary only because some Pascal compilers ignore field width on PAOCs. } var i : integer; begin if not paocBUG THEN write(outfile,L:width) { ISO standard: VAX, Prospero, UNIX etc. } ELSE for i:= 1 to width do write(outfile, L[i]); { Turbo, MT+, UCSD } end (* WritePAOC *); function FileExists (filename:string80) : boolean; { Return true if file is available. Highly compiler-specific } var fl : text; begin {}{VMS}{ open (File_Variable:=Fl,File_Name:=filename, } {}{VMS}{ History := old,error:=continue); FileExists := (Status(fl) = 0); } (*$I-*) {}{Turbo} assign(fl,filename); reset(fl); FileExists:= IOResult=0; close(fl); (*$I+*) {}{Prospero} { FileExists := fstat(filename); } end (* fileexists *); function BoolOrd(BoolExp: boolean): integer; forward; function ForceUpperCase(achar: char): char; forward; procedure StackToMacro(StartAt: integer; var StartMacro, FinishMacro: StringLocation); forward; procedure Error(ErrNum: integer); forward; function TestOk(BoolExp: Boolean; ErrNum: integer): Boolean; forward; PROCEDURE CLRTAB; forward; PROCEDURE SAVENV(VAR E: ENVIRON); forward; procedure PushText(p: pmac); forward; PROCEDURE CLRLINE; forward; PROCEDURE SETSTD; forward; PROCEDURE RESENV(VAR E: ENVIRON); forward; { VAX segment %include 'RNF0.pas' } { overlay } { CP/M-80 requires overlay } (*$IRNF0.pas *) { VAX segment %include 'RNF1.pas' } { overlay } { CP/M-80 requires overlay } (*$IRNF1.pas *) { VAX segment } { overlay } { CP/M-80 requires overlay } procedure ProcessLine; var LastTop: integer; LineIndex, CurLinIndx: integer; {VAX} { %include 'RNF2.PAS' %include 'RNF3.PAS' } (*$IRNF2.pas *) (*$IRNF3.pas *) begin (* ProcessLine *) if EofInput then fin else with StgStack[TopOfStack] do if asis and (TopOfStack = 0) then begin if StgTable[StgBegin] = '!' then begin StgPosition := StgEnd; asis := false end else BEGIN with otl do begin LineIndex := VAL[VLM]; for CurLinIndx := StgBegin to StgEnd do begin LIN[LineIndex] := StgTable[CurLinIndx]; LineIndex := LineIndex + 1; end; LIN[LineIndex] := ' '; len := LineIndex; while ((LineIndex > 1) and (LIN[LineIndex] = ' ')) do LineIndex := LineIndex - 1; if LineIndex > val[vrm] + 1 then begin StartToken := val[vrm] + 1; Error(54) (* Error - Asis text past right margin *); end; end; StgPosition := StgEnd; EMPTY := FALSE; PUTLINE; END; end else begin if ap and (StgTable[StgBegin] = ' ') and (StgPosition = StgBegin) THEN PushText(ParagMacP); GETSYM; IF SYMTYPE = NONE THEN BLANKLINE ELSE repeat CASE SYMTYPE OF WORD: PUTWORD; VARS: PUTVAR; COMMAND: begin LastTop := TopOfStack; if CMDTYPE in OPTBRKSET then BREAK; if CMDTYPE in CRSET then CR; (* the above break may force (stack) a page eject. Do it first *) if (LastTop <> TopOfStack) and (TopOfStack < StackMax) then begin StgStack[TopOfStack + 1] := StgStack[TopOfStack]; TopOfStack := TopOfStack - 1; (* put the current symbol under the top of stack *) PushSyl(syl); (* and push both down *) TopOfStack := TopOfStack + 2; end else DoCommand(CMDTYPE) end END; GETSYM; until symtype = none; ENDLINE; end; end; {VMS %include 'RNF4.PAS'} (*$IRNF4.pas *) BEGIN (*RNF*) WRITELN(' RNF Text Formatter. ', version); INI; LineCount := 0; repeat ErrorsOnLine := 0; ErrorSet := []; getcur; ProcessLine; if ErrorSet <> [] then WriteErrorMessages; until eofinput; writeln; writeln(' Lines read: ', LineCount - 1: 1, '.'); if ErrorCount = 0 then writeln(' No Errors detected.') else WRITELN( ' Errors detected: ', ErrorCount); WRITELN( ' Last page processed: ', VAL[VPAGE]); {}CLOSE(OUTFILE); END (*RNF*).