-- 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 .