-- Compiler Press/nb -- last modified by m. stone December 2, 1981 9:31 PM -- implementing module for press file creation DIRECTORY PressDefs: FROM "PressDefs", PointDefs: FROM "PointDefs", Real: FROM "Real", StyleDefs: FROM "StyleDefs", GriffinFontDefs: FROM "GriffinFontDefs", AltoDefs: FROM "AltoDefs" USING [maxword], StreamDefs: FROM "streamDefs" USING [NewByteStream, Write, Append, GetIndex, FileLength, DiskHandle, StreamIndex, TruncateDiskStream], StringDefs: FROM "StringDefs" USING [AppendString, BcplSTRING, EquivalentString, AppendDecimal], TimeDefs: FROM "TimeDefs" USING [CurrentDayTime, UnpackDT, AppendFullDayTime, DefaultTime], OsStaticDefs: FROM "OsStaticDefs" USING [OsStatics], InlineDefs: FROM "InlineDefs" USING [LowHalf, HighHalf, LowByte, BITSHIFT, MesaToBcplLongNumber], GriffinMemoryDefs: FROM "GriffinMemoryDefs"; Press: PROGRAM IMPORTS StreamDefs, TimeDefs, StringDefs, GriffinMemoryDefs, InlineDefs, GriffinFontDefs,Real,PointDefs EXPORTS PressDefs = BEGIN OPEN PressDefs, GriffinMemoryDefs; BYTE: TYPE = [ 0 .. 255]; -- because they are so common in the press format BytesInSector: CARDINAL = 512; WordsInSector: CARDINAL = 256; SectorIndex: TYPE = RECORD [s: CARDINAL [0 .. 3000]]; PageDescriptor: TYPE = RECORD [ next: PageDescriptorHandle, start: SectorIndex, length: CARDINAL, -- length in sectors: first sector = 0 padding: BYTE -- unused words at end of last sector of page ]; PageDescriptorHandle: TYPE = POINTER TO PageDescriptor; lPageDescriptor: CARDINAL = SIZE [PageDescriptor]; Font: TYPE = RECORD [ next: FontHandle, setnum, font, m, n, face, source: BYTE, family: STRING, size, rotation: CARDINAL ]; FontHandle: TYPE = POINTER TO Font; lFont: CARDINAL = SIZE [Font]; EBIndex: TYPE = [0 .. 507]; EntityBody: TYPE = RECORD [ next: EntityBodyHandle, body: PACKED ARRAY EBIndex OF BYTE, lastbyte: EBIndex -- never "-1" because there's never an empty EntityBody ]; EntityBodyHandle: TYPE = POINTER TO EntityBody; lEntityBody: CARDINAL [0 .. WordsInSector] = SIZE [EntityBody]; -- EntityBody must fit in a sector Entity: TYPE = RECORD [ next: EntityHandle, fontset: CARDINAL, dlbeginbyte, dlbytelength: LONG CARDINAL, entitylength: CARDINAL, -- updated as entitybody chain is extended, and at end entitybody: EntityBodyHandle, -- contains actual commands finished: BOOLEAN ]; NilFontSet: CARDINAL = 177777B; -- indicates no fontset chosen yet EntityHandle: TYPE = POINTER TO Entity; lEntity: CARDINAL = SIZE [Entity]; pressMaxELength: CARDINAL = AltoDefs.maxword - LAST [EBIndex]/2 - 12; -- must fit in word pressMaxShortChars: CARDINAL = 32; pressRot0: CARDINAL = 0; pressRot90: CARDINAL = 5400; pressRot180: CARDINAL = 10800; pressRot270: CARDINAL = 16200; pressPassWord: CARDINAL = 27183; pressShowCharsShort: BYTE = 0; pressSkipCharsShort: BYTE = 40B; pressSetFont: BYTE = 160B; pressSetX: BYTE = 356B; pressSetY: BYTE = 357B; pressShowChars: BYTE = 360B; pressSetBrightness: BYTE = 370B; pressSetHue: BYTE = 371B; pressSetSaturation: BYTE = 372B; pressShowObject: BYTE = 373B; pressShowRect: BYTE = 376B; pressNop: BYTE = 377B; pressMoveTo: CARDINAL = 0; pressDrawTo: CARDINAL = 1; pressDrawCurve: CARDINAL = 2; PressError: PUBLIC SIGNAL = CODE; PressState: TYPE = {notbegun, begun, inpage, inobject}; pressState: PressState ← notbegun; -- these variables reflect the current press state pageList, currentPage: PageDescriptorHandle; -- list of page descriptors fontList: FontHandle; -- beginning of list of fonts used nextFontSet, nextFontNum, currentFontNum: CARDINAL; -- currentFontNum just mirrors internal press state -- nextFontSet and nextFontNum are next available entityList, currentEntity: EntityHandle; -- describe entity list for this page currentEntityBody: EntityBodyHandle; -- as above -- entityList = NIL until something is placed. currentColor: ColorDescriptor; -- current color for this page currentPressCoords: PressCoords; -- current press coords for this page objectStart: LONG CARDINAL; formName: STRING = [51]; pressCopies: CARDINAL; pressLowerLeft: PressCoords; diskHandle: StreamDefs.DiskHandle; PressDebug: PROCEDURE RETURNS [BOOLEAN] = BEGIN XBEGIN: CARDINAL = 700; YBEGIN: CARDINAL = 0; PATCHHEIGHT: CARDINAL = 1800; PATCHWIDTH: CARDINAL = 985; WHITESPACE: CARDINAL = 200; XMAX: CARDINAL = 20500; YMAX: CARDINAL = 26000; MAXHUE: CARDINAL = 239; MAXBRIGHT: CARDINAL = 255; MAXSAT: CARDINAL = 255; black: ColorDescriptor = [0, 0, 0]; gacha10: GriffinFontDefs.FontDescriptor = ["Gacha", 0, 0, 10]; pc: PressCoords; string: STRING = [50]; x, y: CARDINAL; saturation, hrange: INTEGER; color: ColorDescriptor; FOR saturation ← MAXSAT, saturation -MAXSAT/8 UNTIL saturation <= 0 DO FOR hrange ← 0, hrange+(MAXHUE+1)/2 UNTIL hrange >= MAXHUE DO IF saturation <= 10 THEN saturation ← 0; string.length ← 0; StringDefs.AppendString [string, "Sat"]; StringDefs.AppendDecimal [string, saturation]; StringDefs.AppendString [string, IF hrange = 0 THEN "A" ELSE "B"]; [] ← BeginPress [string, TRUE, 1]; BeginPage [PressCoords [26,300]];-- arbitrary pc [X] ← XBEGIN; pc [Y] ← YMAX+600; string.length ← 0; StringDefs.AppendString [string, "Saturation = "]; StringDefs.AppendDecimal [string, saturation]; ShowText [black, string, pc, or0,left, gacha10]; color.saturation ← saturation; FOR x ← XBEGIN, x+PATCHWIDTH+WHITESPACE UNTIL x>XMAX DO color.hue ← (x-XBEGIN)/(2*((XMAX - XBEGIN)/MAXHUE)) + hrange; string.length ← 0; StringDefs.AppendDecimal [string, color.hue]; pc [X] ← x + 200; pc [Y] ← YMAX + 100; ShowText [black, string, pc, or0,left, gacha10]; FOR y ← YBEGIN, y+PATCHHEIGHT+WHITESPACE UNTIL y>=YMAX DO color.brightness←(y-YBEGIN)/((YMAX-YBEGIN)/MAXBRIGHT); IF x = XBEGIN THEN BEGIN pc [X] ← 0; pc [Y] ← y + 800; string.length ← 0; StringDefs.AppendDecimal [string, color.brightness]; ShowText [black, string, pc, or0,left, gacha10]; END; ShowRectangle [color, PressCoords [x, y], PressCoord[PATCHWIDTH],PressCoord [PATCHHEIGHT]]; ENDLOOP ENDLOOP; EndPage; [] ← EndPress []; ENDLOOP; ENDLOOP; RETURN [TRUE]; END; --only works if no scale, translate between press and object space PressToScr: PROCEDURE[pc: PressCoords] RETURNS[scr: PointDefs.ScrPt]= BEGIN OPEN PointDefs; obj: ObjPt ← [pc[X],pc[Y]]; --convert to REAL; scr ← ObjToScr[obj]; END; --only works if no scale, translate between press and object space ScrToPress: PROCEDURE[scr: PointDefs.ScrPt] RETURNS[pc: PressCoords]= BEGIN OPEN PointDefs; obj: ObjPt ← ScrToObj[scr]; --convert to REAL; pc[X] ← Real.RoundI[obj[X]]; pc[Y] ← Real.RoundI[obj[Y]]; END; BeginPress: PUBLIC PROCEDURE [filestring: STRING ← , overwrite: BOOLEAN ← FALSE, copies: CARDINAL ← 1] RETURNS [BOOLEAN] = BEGIN IF pressState # notbegun THEN SIGNAL PressError; fontList ← NIL; currentPage ← pageList ← NIL; formName.length ← 0; StringDefs.AppendString [formName, filestring]; StringDefs.AppendString [formName, ".Press"]; pressCopies ← copies; diskHandle ← StreamDefs.NewByteStream [formName, StreamDefs.Write + StreamDefs.Append]; diskHandle.reset [diskHandle]; IF ~overwrite AND (StreamDefs.FileLength [diskHandle] # StreamDefs.StreamIndex [0, 0]) THEN BEGIN diskHandle.destroy [diskHandle]; diskHandle ← NIL; RETURN [FALSE] END; pressState ← begun; nextFontSet ← 1; nextFontNum ← 0; RETURN [TRUE]; END; EndPress: PUBLIC PROCEDURE RETURNS [BOOLEAN] = BEGIN creationdate: STRING = [50]; j: CARDINAL; -- used for loop control begindd, beginfontdir, beginpartdir: SectorIndex; partcount: CARDINAL ← 1; -- 1 for font part, more to come username: POINTER TO StringDefs.BcplSTRING; tempfont: FontHandle; -- used to scan font list temppartdescriptor: PageDescriptorHandle; IF pressState # begun THEN SIGNAL PressError; -- create dummy font if necessary IF fontList = NIL THEN BEGIN OPEN fontList; fontList ← Allocate [lFont]; next ← NIL; setnum ← font ← m ← face ← source ← 0; n ← 128; family ← AllocateString [20]; family.length ← 0; StringDefs.AppendString [family, "GACHA"]; size ← 10; rotation ← 0; END; -- write out font directory beginfontdir ← NextDiskSector []; WHILE fontList # NIL DO OPEN fontList; PutWord [16]; PutByte [setnum]; PutByte [font]; PutByte [m]; PutByte [n]; PutString [family, 20];FreeString [family]; PutByte [face]; PutByte [0]; -- face, source PutWord [size]; PutWord [rotation]; tempfont ← next; Free [fontList]; fontList ← tempfont ENDLOOP; -- write out part directory -- font directory entry beginpartdir ← NextDiskSector []; PutWord [1]; -- font directory part descriptor PutWord [beginfontdir]; PutWord [beginpartdir-beginfontdir]; PutWord [0]; -- this word ignored for font directory part descriptor -- rest of part directory WHILE pageList # NIL DO OPEN pageList; partcount ← partcount + 1; -- started out at 1 for font directory PutWord [0]; -- printed page part descriptor PutWord [start]; PutWord [length]; PutWord [padding]; temppartdescriptor ← next; Free [pageList]; pageList ← temppartdescriptor ENDLOOP; -- write out document directory begindd ← NextDiskSector []; -- record number where dd begins PutWord [pressPassWord]; PutWord [begindd+1]; PutWord [partcount]; PutWord [beginpartdir]; PutWord [begindd - beginpartdir]; PutWord [0]; PutLongWord [TimeDefs.CurrentDayTime []]; PutWord [1]; PutWord [pressCopies]; THROUGH [10 .. 177B] DO PutWord [177777B] ENDLOOP; -- form name saved from BeginPress PutString [formName, 52]; -- user name extracted from os statics username ← OsStaticDefs.OsStatics↑.UserName; PutByte [username.length]; FOR j IN [0 .. username.length) DO PutByte [LOOPHOLE [username.char [j], BYTE]]; ENDLOOP; THROUGH [username.length .. 30] DO PutByte [0] ENDLOOP; -- time synthesised right here TimeDefs.AppendFullDayTime[creationdate,TimeDefs.UnpackDT [TimeDefs.DefaultTime]]; PutString [creationdate, 40]; -- fill out file [] ← NextDiskSector []; -- all done pressState ← notbegun; IF diskHandle = NIL THEN RETURN [FALSE] ELSE StreamDefs.TruncateDiskStream [diskHandle]; RETURN [TRUE]; END; ShowText: PUBLIC PROCEDURE [color: ColorDescriptor, textstring: STRING, presscoords: PressCoords, orientation: StyleDefs.Orientation,anchor: StyleDefs.Anchor, font: GriffinFontDefs.FontDescriptor] = BEGIN OPEN PointDefs, GriffinFontDefs; i, twiddle: CARDINAL; rotation: CARDINAL=font.rotation; pt,showpt: PointDefs.ObjPt; presspt: PressCoords; char: CHARACTER; chheight,chwidth,height, width, baseline: CARDINAL; aligned, vertical: BOOLEAN; textdirection: CARDINAL = SELECT orientation FROM or0 => Rot0Degrees, or90 => Rot90Degrees, or180 => Rot180Degrees, or270 => Rot270Degrees, ENDCASE => ERROR; slen: CARDINAL = textstring.length; IF pressState # inpage THEN SIGNAL PressError; IF slen = 0 THEN RETURN; EnsureCurrentEntity; SetColor [color]; SetFont [font]; height ← StringHeight[textstring, @font, orientation]; width ← StringWidth[textstring, @font, orientation]; baseline ← BaseLine[@font]; pt ← TopLeft[[presscoords[X],presscoords[Y]], height, width, anchor, orientation, font.rotation]; vertical ← orientation = or90 OR orientation = or270; aligned ← IF vertical THEN rotation = Rot0Degrees OR rotation = Rot180Degrees ELSE rotation = Rot90Degrees OR rotation = Rot270Degrees; SELECT orientation FROM -- move to end if going backwards or180 => pt[X] ← pt[X]+width; or90 => pt[Y] ← pt[Y]-height; ENDCASE; IF textdirection = font.rotation THEN -- easy BEGIN SELECT rotation FROM Rot0Degrees=> pt[Y] ← pt[Y]-BaseLine[@font]; Rot90Degrees=> pt[X] ← pt[X]+baseline; Rot180Degrees=> pt[Y] ← pt[Y]-(MaxHeight[@font]-baseline); Rot270Degrees=> pt[X] ← pt[X]+(MaxHeight[@font]-baseline); ENDCASE; presspt ← [Real.RoundI[pt[X]],Real.RoundI[pt[Y]]]; SetXY [presspt]; IF slen > pressMaxShortChars THEN AppendBytesToEntity [pressShowChars, slen] ELSE AppendByteToEntity [pressShowCharsShort+slen-1]; FOR i IN [0 .. slen) DO PutByte [LOOPHOLE [textstring [i], BYTE]] ENDLOOP; InvalidXY; RETURN END; FOR i IN [0 .. slen) DO char ← textstring [i]; chwidth ← Width[char, @font]; chheight ← Height[char, @font]; twiddle ← IF vertical THEN (MaxWidth[@font] - chwidth)/2 ELSE (MaxHeight[@font] - chheight)/2; IF aligned THEN IF vertical THEN pt[X] ← pt[X] + twiddle ELSE pt[Y] ← pt[Y] - twiddle; SELECT orientation FROM or90 => pt[Y] ← pt[Y] + chheight; or180 => pt[X] ← pt[X] - chwidth; ENDCASE; showpt←pt; SELECT rotation FROM Rot0Degrees=> showpt[Y] ← showpt[Y]-baseline; Rot90Degrees=> BEGIN showpt[X] ← showpt[X]+baseline; showpt[Y] ← showpt[Y]-chheight; END; Rot180Degrees=> BEGIN showpt[Y] ← showpt[Y]-(MaxHeight[@font]-baseline); showpt[X] ← showpt[X]+chwidth; END; Rot270Degrees=> showpt[X] ← showpt[X]+(MaxHeight[@font]-baseline); ENDCASE; presspt ← [Real.RoundI[showpt[X]], Real.RoundI[showpt[Y]]]; SetXY [presspt]; AppendByteToEntity [pressShowCharsShort]; PutByte [LOOPHOLE [char, BYTE]]; InvalidXY; SELECT orientation FROM or0 => pt[X] ← pt[X] + chwidth; or270 => pt[Y] ← pt[Y] - chheight; ENDCASE; IF aligned THEN IF vertical THEN pt[X] ← pt[X] - twiddle ELSE pt[Y] ← pt[Y] + twiddle; ENDLOOP; END; ShowRectangle: PUBLIC PROCEDURE [color: ColorDescriptor, presscoords: PressCoords, width, height: PressCoord] = BEGIN IF pressState # inpage THEN SIGNAL PressError; EnsureCurrentEntity; SetColor [color]; SetXY [presscoords]; AppendByteToEntity [pressShowRect]; AppendWordToEntity [width]; AppendWordToEntity [height]; END; BeginObject: PUBLIC PROCEDURE [color: ColorDescriptor] = BEGIN IF pressState # inpage THEN SIGNAL PressError; EnsureCurrentEntity; -- so we'll know where object begins SetColor [color]; objectStart ← BytesPastBeginPrintedPage []; IF objectStart MOD 2 = 1 THEN BEGIN objectStart ← objectStart + 1; PutByte [0]; AppendByteToEntity [pressSkipCharsShort+0]; END; pressState ← inobject; END; EndObject: PUBLIC PROCEDURE = BEGIN objectlength: LONG CARDINAL = (BytesPastBeginPrintedPage [] - objectStart)/2; -- error if object longer than 64K words of DL (5000 curves) IF InlineDefs.HighHalf [objectlength] # 0 THEN SIGNAL PressError; IF pressState # inobject THEN SIGNAL PressError ELSE pressState ← inpage; AppendByteToEntity [pressShowObject]; AppendWordToEntity [InlineDefs.LowHalf [objectlength]]; END; MoveTo: PUBLIC PROCEDURE [presscoords: PressCoords] = BEGIN IF pressState # inobject THEN SIGNAL PressError; PutWord [pressMoveTo]; PutWord [presscoords [X]]; PutWord [presscoords [Y]]; END; DrawTo: PUBLIC PROCEDURE [presscoords: PressCoords] = BEGIN IF pressState # inobject THEN SIGNAL PressError; PutWord [pressDrawTo]; PutWord [presscoords [X]]; PutWord [presscoords [Y]]; END; DrawCurve: PUBLIC PROCEDURE [spline: PressSpline] = BEGIN OPEN spline; PutFloat: PROC [num: LONG CARDINAL] = BEGIN PutLongWord [LOOPHOLE[InlineDefs.MesaToBcplLongNumber[num]]]; END; IF pressState # inobject THEN SIGNAL PressError; PutWord [pressDrawCurve]; PutFloat[Cx]; PutFloat[Cy]; PutFloat[Bx]; PutFloat[By]; PutFloat[Ax]; PutFloat[Ay]; END; SetXY: PROCEDURE [coords: PressCoords] = BEGIN IF pressState # inpage THEN SIGNAL PressError; IF coords[X] # currentPressCoords [X] THEN BEGIN AppendByteToEntity[pressSetX]; AppendWordToEntity [coords [X]]; currentPressCoords [X] ← coords [X]; END; IF coords[Y] # currentPressCoords [Y] THEN BEGIN AppendByteToEntity[pressSetY]; AppendWordToEntity[coords [Y]]; currentPressCoords [Y] ← coords [Y]; END; END; InvalidXY: PROCEDURE = BEGIN currentPressCoords ← [30000, 30000] END; SetColor: PROCEDURE [color: ColorDescriptor] = BEGIN OPEN color; IF pressState # inpage THEN SIGNAL PressError; IF hue # currentColor.hue THEN BEGIN AppendBytesToEntity [pressSetHue, hue]; currentColor.hue ← hue; END; IF saturation # currentColor.saturation THEN BEGIN AppendBytesToEntity [pressSetSaturation, saturation]; currentColor.saturation ← saturation; END; IF brightness # currentColor.brightness THEN BEGIN AppendBytesToEntity [pressSetBrightness, brightness]; currentColor.brightness ← brightness; END; END; SetFont: PROCEDURE [font: GriffinFontDefs.FontDescriptor] = BEGIN OPEN PressDefs; rover: FontHandle ← fontList; UNTIL rover = NIL DO IF StringDefs.EquivalentString [rover.family, font.name] AND rover.rotation = font.rotation AND rover.face = font.face AND rover.size = font.points AND (rover.setnum = currentEntity.fontset OR currentEntity.fontset = NilFontSet) THEN BEGIN currentEntity.fontset ← rover.setnum; -- in case it was NilFontSet EXIT; END; rover ← rover.next; ENDLOOP; IF rover = NIL THEN BEGIN -- must add it rover ← Allocate [lFont]; IF nextFontNum<16 THEN nextFontNum ← nextFontNum+1 ELSE BEGIN nextFontSet ← nextFontSet + 1; nextFontNum ← 1; EndEntity []; EnsureCurrentEntity; END; rover.font ← nextFontNum-1; rover.next ← fontList; fontList ← rover; rover.setnum ← nextFontSet-1; rover.m ← 0; rover.n ← 128; rover.face ← font.face; rover.source ← 0; rover.family ← AllocateString [font.name.length]; rover.family.length ← 0; StringDefs.AppendString [rover.family, font.name]; rover.size ← font.points; rover.rotation ← font.rotation; END; IF currentFontNum # rover.font THEN BEGIN AppendByteToEntity [pressSetFont + rover.font]; currentFontNum ← rover.font END; END; BeginPage: PUBLIC PROCEDURE [lowerleft: PressCoords ← PressCoords [0,0]] = BEGIN prevpage: PageDescriptorHandle ← currentPage; currentPage ← Allocate [lPageDescriptor]; IF pressState # begun THEN SIGNAL PressError; IF pageList = NIL THEN pageList ← currentPage ELSE prevpage.next ← currentPage; currentPage.next ← NIL; currentPage.start ← NextDiskSector []; -- skip to next disk sector currentEntity ← entityList ← NIL; currentEntityBody ← NIL; currentColor ← ColorDescriptor [0, 0, 0]; currentPressCoords ← PressCoords [0, 0]; pressLowerLeft ← lowerleft; pressState ← inpage; END; EndPage: PUBLIC PROCEDURE = BEGIN temp: EntityHandle; IF pressState # inpage THEN SIGNAL PressError; IF BytesPastBeginPrintedPage [] MOD 2 = 1 THEN PutByte [0]; EndEntity []; PutWord [0]; WHILE entityList # NIL DO OPEN entityList; -- write commands WriteEntity [entityList]; -- write trailer IF fontset = NilFontSet THEN fontset ← 0; -- if it was free, set to 0 PutByte [0]; PutByte [fontset]; PutLongWord [dlbeginbyte]; PutLongWord [dlbytelength]; PutWord [pressLowerLeft [X]]; PutWord [pressLowerLeft [Y]]; PutWord [0]; PutWord [0]; PutWord [maxPressDistance - pressLowerLeft [Y]]; PutWord [maxPressDistance - pressLowerLeft [X]]; PutWord [entitylength+12]; temp ← next; Free [entityList]; entityList ← temp ENDLOOP; currentPage.padding ← BytesRemainingInSector []/2; currentPage.length ← NextDiskSector [] - currentPage.start; pressState ← begun; END; WriteEntity: PROCEDURE [entity: EntityHandle] = BEGIN OPEN entity; temp: EntityBodyHandle; j: EBIndex; WHILE entitybody # NIL DO OPEN entitybody; -- write out commands FOR j IN [0 .. lastbyte] DO PutByte [body [j]] ENDLOOP; temp ← next; FreeSegment [entitybody]; entitybody ← temp ENDLOOP; RETURN END; EnsureCurrentEntity: PROCEDURE = BEGIN IF currentEntity = NIL OR currentEntity.finished THEN BeginEntity []; END; AppendByteToEntity: PROCEDURE [b: BYTE] = BEGIN OPEN currentEntityBody; newelength: LONG CARDINAL; -- only used sometimes IF currentEntity = NIL OR currentEntity.finished OR pressState # inpage THEN SIGNAL PressError; IF currentEntityBody = NIL THEN BEGIN currentEntityBody ← currentEntity.entitybody ← AllocateSegment [lEntityBody]; next ← NIL; lastbyte ← 0; body [0] ← b; RETURN END; IF lastbyte = LAST [EBIndex] THEN BEGIN currentEntityBody ← next ← AllocateSegment [lEntityBody]; newelength ← currentEntity.entitylength + (LAST [EBIndex]+1)/2; IF newelength > pressMaxELength THEN SIGNAL PressError; currentEntity.entitylength ← InlineDefs.LowHalf [newelength]; lastbyte ← 0; next ← NIL; body [0] ← b; RETURN END; lastbyte ← lastbyte + 1; body [lastbyte] ← b; END; AppendBytesToEntity: PROCEDURE [b1, b2: BYTE] = BEGIN AppendByteToEntity [b1]; AppendByteToEntity [b2]; END; AppendWordToEntity: PROCEDURE [w: CARDINAL] = BEGIN AppendByteToEntity [InlineDefs.BITSHIFT [w, -8]]; AppendByteToEntity [InlineDefs.LowByte [w]]; END; EndEntity: PROCEDURE = BEGIN OPEN currentEntity; IF pressState # inpage THEN SIGNAL PressError; IF currentEntity = NIL OR finished THEN RETURN; IF currentEntityBody.lastbyte MOD 2 = 0 THEN AppendByteToEntity [pressNop]; dlbytelength ← BytesPastBeginPrintedPage [] - dlbeginbyte; entitylength ← entitylength + (currentEntityBody.lastbyte+1)/2; finished ← TRUE END; BeginEntity: PROCEDURE = BEGIN OPEN currentEntity; newentity: EntityHandle = Allocate [lEntity]; IF pressState # inpage THEN SIGNAL PressError; IF currentEntity # NIL THEN currentEntity.next ← newentity ELSE entityList ← newentity; currentEntity ← newentity; fontset ← NilFontSet; -- ie available dlbeginbyte ← BytesPastBeginPrintedPage []; entitylength ← 0; entitybody ← NIL; finished ← FALSE; next ← NIL; currentFontNum ← 0; END; -- private low-level disk access procedures PutByte: PROCEDURE [byte: CARDINAL [0 .. 255]] = BEGIN IF diskHandle # NIL THEN diskHandle.put [diskHandle, byte] END; PutWord: PROCEDURE [word: CARDINAL] = BEGIN IF diskHandle = NIL THEN RETURN; diskHandle.put [diskHandle, InlineDefs.BITSHIFT [word, -8]]; diskHandle.put [diskHandle, InlineDefs.LowByte [word]]; END; PutLongWord: PROCEDURE [word: LONG CARDINAL] = BEGIN OPEN InlineDefs; highhalf: CARDINAL = HighHalf [word]; lowhalf: CARDINAL = LowHalf [word]; IF diskHandle = NIL THEN RETURN; diskHandle.put [diskHandle, BITSHIFT [highhalf, -8]]; diskHandle.put [diskHandle, LowByte [highhalf]]; diskHandle.put [diskHandle, BITSHIFT [lowhalf, -8]]; diskHandle.put [diskHandle, LowByte [lowhalf]]; END; PutString: PROCEDURE [string: STRING, maxbytes: BYTE] = BEGIN OPEN string; i: CARDINAL; maxchars: CARDINAL = maxbytes-1; -- one byte for length charcount: CARDINAL = MIN [maxchars, length]; IF diskHandle = NIL THEN RETURN; diskHandle.put [diskHandle, length]; FOR i IN [0 .. charcount) DO diskHandle.put [diskHandle, string [i]]; ENDLOOP; THROUGH [charcount .. maxchars) DO diskHandle.put [diskHandle, 0] ENDLOOP; END; NextDiskSector: PROCEDURE RETURNS [SectorIndex] = BEGIN si: StreamDefs.StreamIndex; IF diskHandle = NIL THEN RETURN [SectorIndex [0]]; si ← StreamDefs.GetIndex [diskHandle]; IF si.byte # 0 THEN BEGIN THROUGH [si.byte .. 511] DO diskHandle.put [diskHandle, 0] ENDLOOP; si.page ← si.page+1 END; RETURN [SectorIndex [si.page]]; END; BytesRemainingInSector: PROCEDURE RETURNS [CARDINAL] = BEGIN temp: CARDINAL; IF diskHandle = NIL THEN RETURN [0]; temp ← BytesInSector - StreamDefs.GetIndex [diskHandle].byte; RETURN[IF temp=BytesInSector THEN 0 ELSE temp]; END; BytesPastBeginPrintedPage: PROCEDURE RETURNS [byte: LONG CARDINAL] = BEGIN si: StreamDefs.StreamIndex; IF diskHandle = NIL THEN RETURN [LONG [0]]; si ← StreamDefs.GetIndex [diskHandle]; RETURN [si.byte + BytesInSector*LONG [si.page - currentPage.start]] END; END .