-- Presser.mesa; edit by Johnsson; June 26, 1980 2:33 PM -- Converted to Laurel by Ken Pier, July 29, 1981 10:03 PM -- Last Edited by Pier, August 10, 1981 8:16 PM DIRECTORY csD: FROM "CoreStreamDefs", InlineDefs USING [LongDiv, LongMult, HighByte, LowByte], MiscDefs USING [SetBlock, Zero], Press USING [ defaultBottom, defaultCharWidth, defaultHeight, defaultLeft, defaultLineHeight, defaultLineLeading, defaultRight, defaultTabSpacing, defaultTop, defaultWidth, FontIndex, FontSlope, FontWeight, magicNonPrintingWidth, Mica, Mode, numberOfFonts, pageHeight, pageWidth, Points, pointsPerInch], PressFormat USING [ BYTE, DDV, EFont, ENop, EResetSpace, ESetX, ESetY, EShow, EShowRectangle, EShowShort, ESpaceX, ESpaceXShort, ESpaceY, ESpaceYShort, FE, LCToDouble, Mica, micasPerInch, PartType, PE, PETypeFont, PETypePage, PressPasswd], PressUtilities USING [FindFontWidths], StringDefs USING [MesaToBcplString, AppendDecimal, AppendString], SystemDefs USING [ AllocateHeapNode, AllocateHeapString, AllocateSegment, FreeHeapNode, FreeHeapString, FreeSegment], PrintDefs USING[PError], TimeDefs USING [ AppendDayTime, UnpackDT, DefaultTime, PackedTime, CurrentDayTime]; Presser: PROGRAM IMPORTS PrintDefs, InlineDefs, MiscDefs, PressFormat, PressUtilities, csD, StringDefs, SystemDefs, TimeDefs EXPORTS Press = BEGIN OPEN Press, PressFormat; wppr: CARDINAL = 256; -- words per press record bppr: CARDINAL = 2*wppr; recordsPerEntityList: CARDINAL = 10; wordsPerEntityList: CARDINAL = recordsPerEntityList*wppr; bytesPerEntityList: CARDINAL = recordsPerEntityList*bppr; recordsPerItemList: CARDINAL = 2; wordsPerItemList: CARDINAL = recordsPerItemList*wppr; BYTE: TYPE = [0..377B]; CR: CHARACTER = 15C; FF: CHARACTER = 14C; SP: CHARACTER = 40C; TAB: CHARACTER = 11C; onePoint: Mica = micasPerInch/pointsPerInch; -- big buffers EntityIndex: TYPE = [0..bytesPerEntityList); entityList: POINTER TO PACKED ARRAY EntityIndex OF BYTE _ NIL; entityIndex: EntityIndex; partsPerRecord: CARDINAL = wppr/SIZE[PressFormat.PE]; partsPerDocument: CARDINAL = recordsPerItemList*partsPerRecord; PartIndex: TYPE = [0..partsPerDocument); -- is 127 pages/doc enough? partList: POINTER TO ARRAY PartIndex OF PressFormat.PE _ NIL; partIndex: PartIndex _ 0; UserFontInfo: TYPE = RECORD [ family: STRING, -- mostly for debugging name: FamilyName, -- BCPL string body in caps size: Points, -- pointers below are NIL if not used yet portrait, landscape: ARRAY FontFace OF POINTER TO PressFontInfo]; WidthArray: TYPE = ARRAY CHARACTER OF Mica; PressFontInfo: TYPE = RECORD [ index: FontIndex, -- the one we feed to press face: FontFace, fBBox, fBBoy, width, height: Mica _ NULL, widths: POINTER TO WidthArray, -- NIL if not used yet rotation: CARDINAL, user: POINTER TO UserFontInfo]; -- to build Font Directory FamilyName: TYPE = PACKED ARRAY [0..20) OF BYTE; FontFace: TYPE = [0..2*2); -- should really be 2*3*3, See FontFormats memo initialized: BOOLEAN _ FALSE; Initialize: PUBLIC PROCEDURE = BEGIN i: FontIndex; Reset[]; userFonts _ SystemDefs.AllocateHeapNode[numberOfFonts*SIZE[UserFontInfo]]; pressFonts _ SystemDefs.AllocateHeapNode[numberOfFonts*SIZE[PressFontInfo]]; FOR i IN FontIndex DO userFonts[i] _ [NIL, , 0, [NIL, NIL, NIL, NIL], [NIL, NIL, NIL, NIL]]; pressFonts[i] _ [0, 0, 0, 0, 0, 0, NIL, 0, NIL]; ENDLOOP; entityList _ SystemDefs.AllocateSegment[wordsPerEntityList]; MiscDefs.Zero[entityList, wordsPerEntityList]; partList _ SystemDefs.AllocateSegment[wordsPerItemList]; MiscDefs.Zero[partList, wordsPerItemList]; initialized _ TRUE; END; Reset: PUBLIC PROCEDURE = BEGIN OPEN SystemDefs; i: FontIndex; active _ FALSE; KillString[@pageHeader]; KillString[@pageTrailer]; KillString[@documentFileName]; KillString[@documentUserName]; KillString[@documentCreationDate]; IF userFonts # NIL THEN BEGIN FOR i IN FontIndex DO KillString[@userFonts[i].family]; ENDLOOP; FreeHeapNode[userFonts]; userFonts _ NIL; END; IF pressFonts # NIL THEN BEGIN FlushFontBuffers[]; FreeHeapNode[pressFonts]; pressFonts _ NIL; END; IF entityList # NIL THEN BEGIN FreeSegment[entityList]; entityList _ NIL; END; IF partList # NIL THEN BEGIN FreeSegment[partList]; partList _ NIL; END; pageActive _ paperActive _ active _ initialized _ FALSE; END; lineLeading: Mica _ defaultLineLeading; tabWidth: Mica _ defaultTabSpacing; vSpaceWidth: BOOLEAN _ FALSE; -- TRUE after SetWidthOfSpace spaceWidth: Mica; documentFileName: STRING _ NIL; -- max length 51 documentUserName: STRING _ NIL; -- max length 31 documentCreationDate: STRING _ NIL; -- max length 39 pageHeader, pageTrailer: STRING _ NIL; headerPageNumbers, trailerPageNumbers: BOOLEAN _ FALSE; numberOfCopies: CARDINAL _ 1; SetDocumentCreationDate: PUBLIC PROCEDURE [date: STRING] = {MakeMeACopy[@documentCreationDate, date]}; SetDocumentUserName: PUBLIC PROCEDURE [user: STRING] = {MakeMeACopy[@documentUserName, user]}; SetHeaderText: PUBLIC PROCEDURE [header: STRING, pageNumbers: BOOLEAN] = {MakeMeACopy[@pageHeader, header]; headerPageNumbers _ pageNumbers}; SetTrailerText: PUBLIC PROCEDURE [trailer: STRING, pageNumbers: BOOLEAN] = {MakeMeACopy[@pageTrailer, trailer]; trailerPageNumbers _ pageNumbers}; SetNumberOfCopies: PUBLIC PROCEDURE [copies: CARDINAL] = {numberOfCopies _ copies}; PutFontInTable: PUBLIC PROCEDURE [ index: FontIndex, family: STRING, size: Points] = BEGIN IF userFonts = NIL THEN PrintDefs.PError[BadParameters]; IF index~ IN FontIndex THEN PrintDefs.PError[BadParameters]; IF family.length~ IN [1..19] THEN PrintDefs.PError[BadParameters]; -- only 20 bytes words MakeMeACopy[@userFonts[index].family, family]; userFonts[index].size _ size; FOR i: CARDINAL IN [0..20) DO userFonts[index].name[i] _ 0; ENDLOOP; userFonts[index].name[0] _ family.length; FOR i: CARDINAL IN [0..family.length) DO SELECT family[i] FROM IN ['A..'Z], IN ['0..'9] => userFonts[index].name[i + 1] _ LOOPHOLE[family[i]]; IN ['a..'z] => userFonts[index].name[i + 1] _ LOOPHOLE[family[i], BYTE] - 40B; ENDCASE => PrintDefs.PError[BadParameters]; ENDLOOP; END; SetMargins: PUBLIC PROCEDURE [l, r, t, b: Mica] = BEGIN IF pageActive THEN PrintDefs.PError[BadParameters]; leftMargin _ l; rightMargin _ r; topMargin _ t; bottomMargin _ b; IF landscape THEN BEGIN height _ pageWidth - rightMargin - leftMargin; width _ pageHeight - topMargin - bottomMargin; END ELSE BEGIN height _ pageHeight - topMargin - bottomMargin; width _ pageWidth - rightMargin - leftMargin; END; width _ width - (numberOfColumns - 1)*(spaceBetweenColumns); width _ LOOPHOLE[width, CARDINAL]/numberOfColumns; END; SetCurrentTabWidth: PUBLIC PROCEDURE [tab: Mica] = {tabWidth _ tab}; SetCurrentLineLeading: PUBLIC PROCEDURE [lead: Mica] = BEGIN lineLeading _ lead; END; active: BOOLEAN _ FALSE; pressFile: csD.StreamHandle _ NIL; Start: PUBLIC PROCEDURE [docName: STRING, file: csD.StreamHandle] = BEGIN IF active THEN RETURN; IF ~initialized THEN Initialize[]; pressFile _ file; MakeMeACopy[@documentFileName, docName]; IF documentCreationDate = NIL THEN BEGIN OPEN TimeDefs; time: STRING = [18]; AppendDayTime[time, UnpackDT[DefaultTime]]; MakeMeACopy[@documentCreationDate, time]; END; IF documentUserName = NIL THEN MakeMeACopy[@documentUserName, "NoName"L]; IF documentFileName = NIL THEN MakeMeACopy[@documentFileName, "NoName"L]; IF documentFileName.length > 51 THEN documentFileName.length _ 51; currentRecordNumber _ 0; csD.Reset[pressFile]; entityIndex _ partIndex _ 0; FOR i: FontIndex IN FontIndex DO userFonts[i].portrait _ [NIL, NIL, NIL, NIL]; userFonts[i].landscape _ [NIL, NIL, NIL, NIL]; ENDLOOP; currentPageNumber _ 1; lineActive _ pageActive _ paperActive _ FALSE; currentX _ 0; currentY _ height; BeSureFontZeroExists[]; active _ TRUE; END; Finish: PUBLIC PROCEDURE = BEGIN fd: POINTER = entityList; -- build Font Directory in random buffer fp: POINTER TO PressFormat.FE _ fd; dd: POINTER TO PressFormat.DDV = fd; -- build Document Directory in random buffer now: TimeDefs.PackedTime _ TimeDefs.CurrentDayTime[]; numberOfPartRecords, firstPartRecord: CARDINAL; IF lineActive THEN EndCurrentLine[]; IF pageActive THEN EndCurrentPage[]; IF paperActive THEN EndCurrentPaper[]; -- send Font Directory MiscDefs.Zero[fd, wppr]; firstDataRecordOfPaper _ currentRecordNumber; -- for AppendPartItem FOR i: CARDINAL IN FontIndex DO IF pressFonts[i].user # NIL THEN BEGIN fp^ _ PressFormat.FE[ length: SIZE[PressFormat.FE], set: 0, -- we only use one font set fno: pressFonts[i].index, destm: 0, destn: 177B, fam: pressFonts[i].user.name, face: pressFonts[i].face, source: 0, siz: pressFonts[i].user.size, rotn: pressFonts[i].rotation]; fp _ fp + SIZE[PressFormat.FE]; IF fp = fd + wppr THEN -- opps, record exactly full BEGIN [] _ csD.WriteBlock[pressFile, fd, 0, bppr]; MiscDefs.Zero[fd, wppr]; fp _ fd; END; END; ENDLOOP; [] _ csD.WriteBlock[pressFile, fd, 0, bppr]; AppendPartItem[PressFormat.PETypeFont, 0]; -- send off Part Directory firstPartRecord _ currentRecordNumber; numberOfPartRecords _ (partIndex*SIZE[PressFormat.PE] + wppr - 1)/wppr; [] _ csD.WriteBlock[pressFile, partList, 0, numberOfPartRecords*bppr]; -- send off Document Directory - use entity buffer MiscDefs.SetBlock[p: dd, l: wppr, v: -1]; dd.Passwd _ PressFormat.PressPasswd; -- General Password dd.nRecs _ firstPartRecord + numberOfPartRecords + 1; -- total number of records dd.nParts _ partIndex; dd.pdStart _ firstPartRecord; dd.pdRecs _ numberOfPartRecords; dd.Backp _ 0; -- ?? funny backpointer dd.date _ PressFormat.LCToDouble[now]; dd.fCopy _ 1; dd.lCopy _ numberOfCopies; -- first, last copy dd.fPage _ 1; dd.lPage _ 0; -- first, last page StringDefs.MesaToBcplString[documentFileName, LOOPHOLE[@dd.FileStr]]; StringDefs.MesaToBcplString[documentUserName, LOOPHOLE[@dd.CreatStr]]; StringDefs.MesaToBcplString[documentCreationDate, LOOPHOLE[@dd.DateStr]]; currentRecordNumber _ currentRecordNumber + 1; [] _ csD.WriteBlock[pressFile, dd, 0, bppr]; csD.Checkpoint[pressFile];--flush everything to the disk active _ FALSE; END; Abort: PUBLIC PROCEDURE = {active _ FALSE}; String: PUBLIC PROCEDURE [s: STRING] = {FOR i: CARDINAL IN [0..s.length) DO Character[s[i]] ENDLOOP}; PieceOfLine: PUBLIC PROCEDURE [s: STRING, width: Mica] = BEGIN IF ~lineActive THEN BEGIN -- If we switch to a taller font, this test might miss. IF pageActive AND currentY < (currentFontPointer.height + lineLeading) THEN DoPageOverflow[]; BeginLine[]; END; FOR i: CARDINAL IN [0..s.length) DO csD.Write[pressFile, s[i]]; ENDLOOP; lineCharacters _ lineCharacters + s.length; currentX _ currentX + width; END; GetWidthOfString: PUBLIC PROCEDURE [s: STRING] RETURNS [w: Mica] = BEGIN w _ 0; FOR i: CARDINAL IN [0..s.length) DO w _ w + GetWidthOfCharacter[s[i]]; ENDLOOP; END; GetWidthOfCharacter: PUBLIC PROCEDURE [c: CHARACTER] RETURNS [w: Mica] = BEGIN IF vSpaceWidth AND c = SP THEN RETURN[spaceWidth]; w _ currentFontPointer.widths[c]; IF w = magicNonPrintingWidth THEN w _ 0; END; Character: PUBLIC PROCEDURE [c: CHARACTER] = BEGIN charWidth: Mica; SELECT c FROM CR => DoCR[]; FF => DoFF[]; TAB => DoTAB[]; ENDCASE => BEGIN IF vSpaceWidth AND c = SP THEN charWidth _ spaceWidth ELSE charWidth _ currentFontPointer.widths[c]; IF charWidth = magicNonPrintingWidth THEN charWidth _ 0; IF ~lineActive THEN BEGIN -- If we switch to a taller font, this test might miss. IF pageActive AND currentY < (currentFontPointer.height + lineLeading) THEN DoPageOverflow[]; BeginLine[]; END; IF (currentX + charWidth) > width AND c # SP THEN DoLineOverflow[]; csD.Write[pressFile, c]; lineCharacters _ lineCharacters + 1; currentX _ currentX + charWidth; END; END; DoTAB: PROCEDURE = BEGIN IF ~lineActive AND currentY < (currentFontPointer.height + lineLeading) THEN DoPageOverflow[]; -- else this TAB gets lost SkipSomeSpace[(((currentX + 20)/tabWidth) + 1)*tabWidth - currentX]; END; SkipSomeSpace: PUBLIC PROCEDURE [mica: Mica] = BEGIN IF mica = 0 THEN RETURN; IF ~pageActive THEN BeginPage[]; IF lineActive THEN FlushBuffer[] ELSE IF currentY < (currentFontPointer.height + lineLeading) THEN DoPageOverflow[]; currentX _ currentX + mica; IF currentX > width THEN BEGIN DoLineOverflow[]; RETURN; END; IF ~lineActive THEN RETURN; -- BeginLine will set position -- TAB - TAB will generate an extra Set-? IF landscape THEN AppendEntityByte[ESetY] ELSE AppendEntityByte[ESetX]; AppendEntityWord[currentX]; END; DoCR: PROCEDURE = BEGIN IF ~pageActive THEN BeginPage[]; IF lineActive THEN EndCurrentLine[]; currentX _ 0; currentY _ currentY - lineHeight - lineLeading; END; DoLineOverflow: PROCEDURE = BEGIN Character[CR]; -- Leave line active, but overflow test is done by PrintCharacter String["**"]; END; DoFF: PROCEDURE = -- FF, FF will get you an empty page {IF ~pageActive THEN BeginPage[]; EndCurrentPage[]}; DoPageOverflow: PROCEDURE = {EndCurrentPage[]; BeginPage[]}; -- leave page active landscape: BOOLEAN _ FALSE; numberOfColumns: CARDINAL _ 1; spaceBetweenColumns: Mica _ 0; height: Mica _ defaultHeight; width: Mica _ defaultWidth; currentX, currentY: Mica _ 0; leftMargin: Mica _ defaultLeft; rightMargin: Mica _ defaultRight; topMargin: Mica _ defaultTop; bottomMargin: Mica _ defaultBottom; SetMode: PUBLIC PROCEDURE [columns: CARDINAL, between: Mica, mode: Mode] = BEGIN numberOfColumns _ columns; spaceBetweenColumns _ between; SELECT mode FROM portrait => BEGIN landscape _ FALSE; height _ pageHeight - topMargin - bottomMargin; width _ pageWidth - rightMargin - leftMargin; END; landscape => BEGIN landscape _ TRUE; height _ pageWidth - rightMargin - leftMargin; width _ pageHeight - topMargin - bottomMargin; END; ENDCASE => PrintDefs.PError[PageModeError]; width _ width - (numberOfColumns - 1)*(spaceBetweenColumns); width _ LOOPHOLE[width, CARDINAL]/numberOfColumns; END; SetCurrentPosition: PUBLIC PROCEDURE [x, y: Mica] = BEGIN IF ~pageActive THEN BeginPage[]; IF lineActive THEN EndCurrentLine[]; currentX _ x; currentY _ y; END; GetCurrentPageNumber: PUBLIC PROCEDURE RETURNS [CARDINAL] = {RETURN[currentPageNumber]}; SetCurrentPageNumber: PUBLIC PROCEDURE [pn: CARDINAL] = {currentPageNumber _ pn}; GetCurrentPosition: PUBLIC PROCEDURE RETURNS [x, y: Mica] = {IF ~pageActive THEN BeginPage[]; RETURN[currentX, currentY]}; SetWidthOfSpace: PUBLIC PROCEDURE [w: Mica] = BEGIN IF ~pageActive THEN BeginPage[]; IF lineActive THEN EndCurrentLine[]; IF w < 2048 THEN AppendEntityWord[ (IF landscape THEN ESpaceYShort ELSE ESpaceXShort)*400B + w] ELSE BEGIN AppendEntityByte[IF landscape THEN ESpaceY ELSE ESpaceX]; AppendEntityWord[w]; END; vSpaceWidth _ TRUE; spaceWidth _ w; END; ResetWidthOfSpace: PUBLIC PROCEDURE = BEGIN IF ~pageActive THEN BeginPage[]; IF lineActive THEN EndCurrentLine[]; AppendEntityByte[EResetSpace]; vSpaceWidth _ FALSE; END; DrawRectangle: PUBLIC PROCEDURE [w, h: Mica] = BEGIN IF ~pageActive THEN BeginPage[]; IF lineActive THEN EndCurrentLine[]; AppendEntityByte[EShowRectangle]; AppendEntityWord[IF landscape THEN h ELSE w]; AppendEntityWord[IF landscape THEN w ELSE h]; END; -- lineActive means that we don't have to do a Set-x and Set-y -- lineCharacters#0 means that we need to do a Show-characters -- We don't know how high the line is until we have seen it go past. -- This kludge remembers the entityIndex for the Y data word so we can fix it later. -- When we switch fonts, we save the height of the tallest one. lineHeight: Mica _ defaultLineHeight; fixupXIndex, fixupYIndex: CARDINAL _ 0; lineActive: BOOLEAN _ FALSE; lineCharacters: CARDINAL _ 0; BeginLine: PROCEDURE = BEGIN IF ~pageActive THEN BeginPage[]; lineCharacters _ 0; lineHeight _ currentFontPointer.height; AppendEntityByte[ESetX]; fixupXIndex _ entityIndex; AppendEntityWord[IF landscape THEN height - currentY ELSE currentX]; AppendEntityByte[ESetY]; fixupYIndex _ entityIndex; AppendEntityWord[IF landscape THEN currentX ELSE currentY]; lineActive _ TRUE; END; -- called by SkipSomeSpace, EndCurrentLine, BeginPage (headers), and SetCurrentFont FlushBuffer: PROCEDURE = BEGIN SELECT lineCharacters FROM 0 => RETURN; IN [1..40B] => BEGIN AppendEntityByte[EShowShort + lineCharacters - 1]; END; IN [40B..400B] => BEGIN AppendEntityByte[EShow]; AppendEntityByte[lineCharacters]; END; ENDCASE => PrintDefs.PError[InternalError]; paperCharacters _ paperCharacters + lineCharacters; pageCharacters _ pageCharacters + lineCharacters; lineCharacters _ 0; END; EndCurrentLine: PROCEDURE = BEGIN temp: INTEGER; IF ~lineActive THEN PrintDefs.PError[InternalError]; FlushBuffer[]; temp _ currentY - lineHeight - lineLeading; IF landscape THEN BEGIN temp _ height - currentY; entityList[fixupXIndex] _ InlineDefs.HighByte[temp]; entityList[fixupXIndex + 1] _ InlineDefs.LowByte[temp]; END ELSE BEGIN entityList[fixupYIndex] _ InlineDefs.HighByte[temp]; entityList[fixupYIndex + 1] _ InlineDefs.LowByte[temp]; END; lineActive _ FALSE; END; pageActive: BOOLEAN _ FALSE; firstEntityIndexOfPage: CARDINAL _ 0; firstPageCharacter, pageCharacters: CARDINAL _ 0; currentPageNumber: CARDINAL _ 0; currentColumn: CARDINAL _ 0; -- starts at 0 BeginPage: PROCEDURE = BEGIN IF pageActive THEN PrintDefs.PError[InternalError]; IF ~paperActive THEN BeginPaper[]; firstEntityIndexOfPage _ entityIndex; firstPageCharacter _ paperCharacters; pageCharacters _ 0; pageActive _ TRUE; Headers[]; currentX _ 0; currentY _ height; IF currentFontPointer.index~ IN FontIndex THEN PrintDefs.PError[InternalError]; IF currentFontPointer.index # 0 THEN AppendEntityByte[EFont + currentFontPointer.index]; END; EndCurrentPage: PROCEDURE = BEGIN cardinal: CARDINAL; header, trailer: Mica _ 0; -- fudge for headers/trailers IF ~pageActive THEN PrintDefs.PError[InternalError]; IF lineActive THEN EndCurrentLine[]; Trailers[]; pageActive _ FALSE; -- header must start on a word boundry IF (entityIndex MOD 2) = 1 THEN AppendEntityByte[ENop]; -- build entity header AppendEntityWord[0]; -- type and font-set AppendEntityWord[0]; AppendEntityWord[firstPageCharacter]; -- begin byte AppendEntityWord[0]; AppendEntityWord[pageCharacters]; -- length IF landscape THEN BEGIN -- Xe, Ye AppendEntityWord[leftMargin]; AppendEntityWord[ bottomMargin + currentColumn*(width + spaceBetweenColumns)]; IF pageHeader # NIL THEN header _ 3*heightOfHeaderLine; IF pageTrailer # NIL THEN trailer _ 3*heightOfHeaderLine; AppendEntityWord[-header]; AppendEntityWord[0]; -- left, bottom AppendEntityWord[height + header + trailer]; -- width AppendEntityWord[width]; -- height END ELSE BEGIN -- Xe, Ye AppendEntityWord[leftMargin + currentColumn*(width + spaceBetweenColumns)]; AppendEntityWord[bottomMargin]; IF pageHeader # NIL THEN header _ 3*heightOfHeaderLine; IF pageTrailer # NIL THEN trailer _ 3*heightOfHeaderLine; AppendEntityWord[0]; AppendEntityWord[-trailer]; -- left, bottom AppendEntityWord[width]; -- width AppendEntityWord[height + header + trailer]; -- height END; cardinal _ entityIndex - firstEntityIndexOfPage; AppendEntityWord[1 + cardinal/2]; -- entity-length currentPageNumber _ currentPageNumber + 1; IF (currentColumn _ currentColumn + 1) = numberOfColumns THEN EndCurrentPaper[]; END; Headers: PROCEDURE = BEGIN buffer: STRING = [20]; fontPointer: POINTER TO PressFontInfo _ currentFontPointer; -- Each new page starts out in font 0, but we have to switch the pointer so that the width calculations work out ok. If not, and headers are in a bigger font than the current font, the page number will overflow its line. IF pageHeader = NIL THEN RETURN; currentFontPointer _ fontZeroPointer; currentX _ 0; currentY _ height + 3*heightOfHeaderLine; BeginLine[]; String[pageHeader]; FlushBuffer[]; StringDefs.AppendDecimal[buffer, currentPageNumber]; SkipSomeSpace[width - buffer.length*widthOfHeaderDigit - currentX]; String[buffer]; EndCurrentLine[]; currentFontPointer _ fontPointer; END; Trailers: PROCEDURE = BEGIN buffer: STRING = [20]; fontPointer: POINTER TO PressFontInfo _ currentFontPointer; IF pageTrailer = NIL THEN RETURN; IF currentFontPointer.index # 0 THEN AppendEntityByte[EFont + 0]; -- font 0 currentFontPointer _ fontZeroPointer; currentX _ 0; currentY _ 0 - 2*heightOfHeaderLine; BeginLine[]; String[pageTrailer]; FlushBuffer[]; StringDefs.AppendDecimal[buffer, currentPageNumber]; SkipSomeSpace[width - buffer.length*widthOfHeaderDigit - currentX]; String[buffer]; EndCurrentLine[]; currentFontPointer _ fontPointer; END; paperActive: BOOLEAN _ FALSE; currentRecordNumber: CARDINAL _ 0; firstDataRecordOfPaper: CARDINAL _ 0; paperCharacters: CARDINAL _ 0; BeginPaper: PROCEDURE = BEGIN IF paperActive THEN PrintDefs.PError[InternalError]; MiscDefs.Zero[entityList, wordsPerEntityList]; entityIndex _ 0; AppendEntityWord[0]; -- marker firstDataRecordOfPaper _ currentRecordNumber; paperActive _ TRUE; paperCharacters _ 0; currentColumn _ 0; END; EndCurrentPaper: PROCEDURE = BEGIN pad: CARDINAL; pb: RECORD[page: CARDINAL, byte: [0..777B]]; IF pageActive THEN EndCurrentPage[]; [pb.page, pb.byte] _ csD.MapPositionToPageByte[csD.GetPosition[pressFile]]; THROUGH [0..2 + (pb.byte MOD 2)) DO -- word boundary + 2 zeros csD.Write[pressFile, 0] ENDLOOP; [] _ csD.WriteBlock[pressFile, entityList, 0, entityIndex]; [pb.page, pb.byte] _ csD.MapPositionToPageByte[csD.GetPosition[pressFile]]; pad _ wppr - pb.byte/2; THROUGH [0..pad) DO csD.Write[pressFile, 0]; csD.Write[pressFile, 0]; ENDLOOP; AppendPartItem[PressFormat.PETypePage, pad]; paperActive _ FALSE; END; userFonts: POINTER TO ARRAY FontIndex OF UserFontInfo _ NIL; pressFonts: POINTER TO ARRAY FontIndex OF PressFontInfo _ NIL; currentFontPointer: POINTER TO PressFontInfo _ NIL; SetCurrentFont: PUBLIC PROCEDURE [ font: FontIndex, w: FontWeight, s: FontSlope] = BEGIN ff: FontFace _ 0; new: POINTER TO PressFontInfo; IF ~initialized THEN PrintDefs.PError[BadParameters]; IF font~ IN FontIndex OR userFonts[font].family = NIL THEN PrintDefs.PError[BadParameters]; SELECT w FROM medium => ff _ ff + 0; bold => ff _ ff + 2; --light => ff _ ff+4; ENDCASE => PrintDefs.PError[BadParameters]; SELECT s FROM regular => ff _ ff + 0; italic => ff _ ff + 1; ENDCASE => PrintDefs.PError[BadParameters]; --SELECT expansion FROM -- regular => ff _ ff+0; -- condensed => ff _ ff+6; -- expanded => ff _ ff+12; -- ENDCASE => PrintDefs.PError[BadParameters]; IF ~landscape THEN BEGIN IF userFonts[font].portrait[ff] = NIL THEN FindPressSlot[font, ff, w, s]; new _ userFonts[font].portrait[ff]; END ELSE BEGIN IF userFonts[font].landscape[ff] = NIL THEN FindPressSlot[font, ff, w, s]; new _ userFonts[font].landscape[ff]; END; IF new = currentFontPointer THEN RETURN; currentFontPointer _ new; IF lineActive THEN FlushBuffer[]; IF currentFontPointer.index~ IN FontIndex THEN PrintDefs.PError[InternalError]; IF ~pageActive THEN RETURN; AppendEntityByte[EFont + currentFontPointer.index]; -- Font lineHeight _ MAX[lineHeight, currentFontPointer.height]; END; FindPressSlot: PROCEDURE [ font: FontIndex, ff: FontFace, w: FontWeight, s: FontSlope] = BEGIN i: FontIndex; pf: POINTER TO PressFontInfo; rot: CARDINAL _ IF landscape THEN 60*90 ELSE 0; family: STRING = userFonts[font].family; points: Points = userFonts[font].size; FOR i IN FontIndex DO pf _ @pressFonts[i]; IF pf.user = NIL THEN EXIT; -- empty slot - use it IF pf.user = @userFonts[font] AND pf.face = ff AND pf.rotation = rot THEN EXIT; REPEAT FINISHED => PrintDefs.PError[MoreThan16Fonts]; ENDLOOP; IF pf.user = NIL THEN BEGIN OPEN pf; pf^ _ [index: i, face: ff, widths: SystemDefs.AllocateSegment[SIZE[WidthArray]], rotation: rot, user: @userFonts[font]]; -- initialize to something legal height _ PointsToMicas[userFonts[font].size]; width _ PointsToMicas[userFonts[font].size]; pressFonts[i].widths^ _ ALL[magicNonPrintingWidth]; [fBBox, fBBoy, width, ] _ PressUtilities.FindFontWidths[ family, points, w, s, pf.widths]; END; IF landscape THEN userFonts[font].landscape[ff] _ pf ELSE userFonts[font].portrait[ff] _ pf; END; PointsToMicas: PROCEDURE [p: Points] RETURNS [Mica] = BEGIN OPEN InlineDefs; RETURN[LongDiv[LongMult[micasPerInch, p], pointsPerInch]]; END; heightOfHeaderLine: Mica; widthOfHeaderDigit: Mica; fontZeroPointer: POINTER TO PressFontInfo _ NIL; BeSureFontZeroExists: PROCEDURE = BEGIN fontZero: FontIndex = FIRST[FontIndex]; i: FontIndex = FIRST[FontIndex]; c: CHARACTER; ff: FontFace _ 0; -- medium, regular IF userFonts[fontZero].family # NIL THEN -- try for normal font 0 BEGIN -- The client has already specified a font 0. -- Activate it now so it will be the press font 0 that we can use for page headers. SetCurrentFont[fontZero, medium, regular]; fontZeroPointer _ currentFontPointer; heightOfHeaderLine _ currentFontPointer.height; widthOfHeaderDigit _ currentFontPointer.widths['0]; RETURN; END; -- ARGH! The idiot user didn't give us any font 0. The default is Gacha 8. -- We brew up the constants so it will work without Fonts.widhts. PutFontInTable[fontZero, "Gacha", 8]; pressFonts[i] _ [i, ff, , , , , SystemDefs.AllocateSegment[200B], , @userFonts[fontZero]]; pressFonts[i].height _ defaultLineHeight; pressFonts[i].width _ defaultCharWidth; FOR c IN [40C..176C] DO pressFonts[i].widths[c] _ defaultCharWidth; ENDLOOP; IF landscape THEN BEGIN userFonts[fontZero].landscape[ff] _ @pressFonts[i]; pressFonts[i].rotation _ 90*60; END ELSE BEGIN userFonts[fontZero].portrait[ff] _ @pressFonts[i]; pressFonts[i].rotation _ 0; END; currentFontPointer _ @pressFonts[i]; fontZeroPointer _ currentFontPointer; heightOfHeaderLine _ currentFontPointer.height; widthOfHeaderDigit _ currentFontPointer.widths['0]; AppendEntityByte[EFont + i]; -- Font END; FlushFontBuffers: PUBLIC PROCEDURE = BEGIN FOR i: FontIndex IN FontIndex DO IF pressFonts[i].widths # NIL THEN SystemDefs.FreeSegment[pressFonts[i].widths]; pressFonts[i] _ [0, 0, 0, 0, 0, 0, NIL, 0, NIL]; ENDLOOP; END; AppendEntityByte: PROCEDURE [b: BYTE] = BEGIN IF entityIndex = bytesPerEntityList THEN PrintDefs.PError[ELBufferOverflow]; entityList[entityIndex] _ b; entityIndex _ entityIndex + 1; END; AppendEntityWord: PROCEDURE [w: INTEGER] = {AppendEntityByte[InlineDefs.HighByte[w]]; AppendEntityByte[InlineDefs.LowByte[w]]}; AppendPartItem: PROCEDURE [type: PressFormat.PartType, last: CARDINAL] = BEGIN pb: RECORD[page: CARDINAL, byte: [0..777B]]; [pb.page, pb.byte] _ csD.MapPositionToPageByte[csD.GetPosition[pressFile]]; IF partIndex = partsPerDocument THEN PrintDefs.PError[ELBufferOverflow]; partList[partIndex] _ [Type: type, pStart: firstDataRecordOfPaper, pRecs: pb.page - firstDataRecordOfPaper, Padding: last]; partIndex _ partIndex + 1; currentRecordNumber _ pb.page; END; KillString: PROCEDURE [where: POINTER TO STRING] = {IF where^ # NIL THEN {SystemDefs.FreeHeapString[where^]; where^ _ NIL}}; MakeMeACopy: PROCEDURE [where: POINTER TO STRING, newString: STRING] = BEGIN OPEN SystemDefs; KillString[where]; IF newString # NIL THEN BEGIN where^ _ AllocateHeapString[newString.length]; StringDefs.AppendString[where^, newString]; END; END; -- initialization END. LOG --Former errors MoreThan16Fonts: PUBLIC ERROR = CODE; ELBufferOverflow: PUBLIC ERROR = CODE; PartBufferOverflow: PUBLIC ERROR = CODE; BadParameters: PUBLIC ERROR = CODE; InternalError: PUBLIC ERROR = CODE; August 10, 1981 8:19 PM Defined EntityIndex and PartIndex, fixing bugs in index types Used InlineDefs.High/LowByte for AppendEntityWord