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