-- PressObjects.mesa
-- Written by Joe Maleson
-- Last changed by Doug Wyatt, December 8, 1980 1:49 PM

--bad news: have to do fontwidths to input text, in case
--you have SetX,SetY,ShowChars,ShowChars....
DIRECTORY
AltoFileDefs USING [eofDA,FP,LD,vDA],
DirectoryDefs USING [DirectoryLookup],
DiscoDefs USING[ReadPageFromVDA,IndexFile,TransferBytes,DiskPosition],
InlineDefs,
MiscDefs,
Mopcodes USING [zLDIV],
PressDefs USING [EntityCommandTrailer,PartEntry,Page,Font,
ExternalFileDirectory,PressPassword,DocDir,ELCommand,
PressFileDescriptor,PressFontEntry,SetColor,SetFont,PutText,
PutRectangle,SetSpaceX,SetSpaceY,LookupFontName,missingWidth,
PutPressDotsData,WriteCommand,ResetSpace,
PressObject,PressPage,PressFont,PressDotsData,
ELShowCharactersShort,ELSkipCharactersShort,
ELShowCharactersAndSkip,ELSetSpaceXShort,
ELSetSpaceYShort,ELFont,
ELSkipControlBytesImmediate,ELAlternative,ELOnlyOnCopy,ELSetX,ELSetY,
ELShowCharacters,ELSkipCharacters,ELSkipControlBytes,
ELShowCharacterImmediate,ELSetSpaceX,ELSetSpaceY,ELResetSpace,
ELSpace,ELSetBrightness,ELSetHue,ELSetSaturation,ELShowObject,
ELShowDots,ELShowDotsOpaque,ELShowRectangle,ELNop,
DLSetCoding,DLSetMode,DLSetWindow,DLSetSize,DLMoveTo,DLDrawTo,
DLDrawCurve,DLDotsFollow,DLGetDotsFromFile,
DLGetDotsFromPressFile,DLSetSamplingProperties,DLSSPInputIntensity,
DLSSPOutputIntensity,DLSSPScreen,DLSSPDot,PressFilePointers],
StreamDefs USING [WriteBlock,StreamHandle,DiskHandle,
NewWordStream,Read,GetIndex],
StringDefs USING [EquivalentString,AppendChar,AppendString,AppendDecimal],
SystemDefs USING [AllocateSegment,FreeSegment,AllocateHeapNode,
FreeHeapNode,AllocateHeapString,FreeHeapString,PruneHeap];
PressObjects: PROGRAM
IMPORTS DirectoryDefs, InlineDefs, MiscDefs, PressDefs, SystemDefs, StreamDefs, StringDefs, DiscoDefs
EXPORTS PressDefs =
BEGIN
OPEN AltoFileDefs, DirectoryDefs, DiscoDefs, PressDefs, StreamDefs, SystemDefs;
PrintWidthError: BOOLEAN ← FALSE; --generally useless error message

--Stuff to handle flaky ShowCharacterImmediate
ELCommandBase: CARDINAL;
ELCommandOffset: CARDINAL;
LongDiv32
: PROCEDURE[CARDINAL,CARDINAL,CARDINAL] RETURNS[CARDINAL] =
MACHINE CODE BEGIN Mopcodes.zLDIV;END;

GetPressDotsData: PUBLIC PROCEDURE [obj: POINTER TO PressObject,dots: POINTER TO PressDotsData] =
BEGIN
dp: POINTER TO DiscoDefs.DiskPosition ← @dots.diskPosition;
data: PACKED ARRAY [0..1] OF [0..377B];
dataWord: POINTER TO CARDINAL ← LOOPHOLE[@data];
Read1: PROCEDURE RETURNS [UNSPECIFIED] =
BEGIN
TransferBytes[dp: dp,nBytes:1,data: LOOPHOLE[@data]];
RETURN[data[0]];
END;
Read2: PROCEDURE RETURNS [UNSPECIFIED] =
BEGIN
TransferBytes[dp: dp,nBytes:2,data: LOOPHOLE[@data]];
RETURN[dataWord↑];
END;

IF (obj.command # ELShowDots) AND (obj.command # ELShowDotsOpaque) THEN ERROR;
dots.fileName ← NIL;
dots.opaque ← obj.command = ELShowDotsOpaque;
dots.haveDot ← FALSE;
dots.frequency ← dots.min ← dots.max ← 0;
dots.diskPosition ← obj.diskPosition; --will be updated by Reads

DO SELECT Read1[] FROM
DLSetCoding =>
BEGIN
dots.nBitsPerPixel ← Read1[];
dots.displayPixels ← dots.nPixels ← Read2[];
dots.displayLines ← dots.nLines ← Read2[];
dots.passPixels ← dots.passLines ← 0;
END;
DLSetMode => dots.mode ← Read1[];
0 => --all the full word commands
SELECT Read1[] FROM
DLSetWindow=>
BEGIN
dots.passPixels ← Read2[];
dots.displayPixels ← Read2[];
dots.passLines ← Read2[];
dots.displayLines ← Read2[];
END;
DLSetSize=>
BEGIN
dots.micaWidth ← Read2[];
dots.micaHeight ← Read2[];
END;
DLDotsFollow=> EXIT;
DLGetDotsFromFile=>
BEGIN
offset: CARDINAL ← Read2[];
nameLen: CARDINAL ← Read1[];
fileName: STRING ← AllocateHeapString[nameLen];
i: CARDINAL;
FOR i IN [0..nameLen) DO fileName[i] ← Read1[];ENDLOOP;
fileName.length ← nameLen;
dots.fileName ← fileName;
EXIT;
END;
DLGetDotsFromPressFile=> EXIT;
DLSetSamplingProperties=>
BEGIN
nWords: INTEGER ← Read2[];
UNTIL nWords <= 0 DO SELECT Read2[] FROM
DLSSPInputIntensity =>
BEGIN
dots.min ← Read2[];
dots.max ← Read2[];
nWords ← nWords-3;
END;
DLSSPOutputIntensity => nWords ← nWords-4;
DLSSPScreen =>
BEGIN
dots.angle ← Read2[];
[] ← Read2[];
dots.frequency ← Read2[];
nWords ← nWords-4;
END;
DLSSPDot=>
BEGIN
nCells: CARDINAL;
dots.dotPosition ← dp↑;
nCells ← Read2[];
[] ← Read2[];[] ← Read2[];--skip nLines,nShifts
THROUGH [0..nCells) DO [] ← Read2[];ENDLOOP;--pass data
nWords ← nWords - (nCells+4);
END;
ENDCASE;
ENDLOOP; --parsing DLSetSamplingProperties
END; --case DLSetSamplingProperties
ENDCASE; --SELECT word commands
ENDCASE; --byte commands
ENDLOOP; -- for all DotsData
END;

PutPressPage: PUBLIC PROCEDURE[pfd: POINTER TO PressFileDescriptor,p: POINTER TO PressPage,dx: CARDINAL ← 0,dy: CARDINAL ← 0] =
BEGIN
obj: POINTER TO PressObject ← p.ObjectList;

UNTIL obj = NIL DO
SetColor[pfd,obj.hue,obj.sat,obj.br];
SELECT obj.command FROM
ELShowCharacters=>
BEGIN
string: STRING ← AllocateHeapString[obj.nDataBytes];
font: POINTER TO PressFont ← p.FontDir[obj.font];
dp: DiscoDefs.DiskPosition ← obj.diskPosition;
TransferBytes[dp: @dp,nBytes: obj.nDataBytes,data: LOOPHOLE[@string.text]];
string.length ← obj.nDataBytes;
IF obj.spaceX = 177777B THEN
BEGIN IF obj.spaceY = 177777B THEN ResetSpace[pfd]; END
ELSE SetSpaceX[pfd,obj.spaceX];
IF obj.spaceY # 177777B THEN SetSpaceY[pfd,obj.spaceY];
SetFont[pfd,font.Family,font.PointSize,font.Face,font.Rotation];
PutText[pfd,string,obj.micaX+dx,obj.micaY+dy];
FreeHeapString[string];
END;
ELShowObject=>
BEGIN
param: ARRAY [0..6) OF CARDINAL;
dp: DiscoDefs.DiskPosition ← obj.diskPosition;
data: POINTER TO ARRAY [0..0) OF CARDINAL ←
SystemDefs.AllocateSegment[(obj.nDataBytes+1)/2];
s: StreamDefs.StreamHandle ← pfd.outStream;
commIndex: CARDINAL ← 0;
IF InlineDefs.BITAND[StreamDefs.GetIndex[s].byte,1] = 1 THEN
BEGIN
s.put[s,0];param[0]←1;
WriteCommand[pfd,ELSkipCharactersShort,@param];
END;
param[0] ← obj.nDataBytes/2;
WriteCommand[pfd,ELShowObject,@param];
DiscoDefs.TransferBytes[dp: @dp,nBytes: obj.nDataBytes,data: LOOPHOLE[data]];
UNTIL commIndex >= obj.nDataBytes/2 DO
SELECT data[commIndex] FROM
DLMoveTo,DLDrawTo =>
BEGIN
data[commIndex+1] ← obj.micaX+dx+data[commIndex+1];
data[commIndex+2] ← obj.micaY+dy+data[commIndex+2];
commIndex ← commIndex+3;
END;
DLDrawCurve => commIndex ← commIndex+13;
ENDCASE => MiscDefs.CallDebugger["bad object"];
ENDLOOP;
[] ← StreamDefs.WriteBlock[s,data,obj.nDataBytes/2];
SystemDefs.FreeSegment[data];
END;
ELShowDots,ELShowDotsOpaque=>
BEGIN
dots: POINTER TO PressDotsData ← LOOPHOLE[obj+SIZE[PressObject]];
pixelsPerWord: CARDINAL ← 16/MAX[1,dots.nBitsPerPixel];
ScanInit[dots.diskPosition,dots.nPixels/pixelsPerWord];
PutPressDotsData[pfd,obj.micaX+dx,obj.micaY+dy,dots,nextScanLine];
ScanClose[];
END;
ELShowRectangle=>
BEGIN
PutRectangle[pfd,obj.micaX+dx,obj.micaY+dy,obj.spaceX,obj.spaceY];
END;
ENDCASE=> NULL;
obj ← obj.link;
ENDLOOP;

END;

dp: DiscoDefs.DiskPosition;
nw: CARDINAL;
sl: POINTER ← NIL;
ScanInit: PROCEDURE [diskPosition: DiscoDefs.DiskPosition, nWordsPerLine: CARDINAL ]=
BEGIN
dp ← diskPosition;
nw ← nWordsPerLine;
sl ← SystemDefs.AllocateSegment[nWordsPerLine];
END;

nextScanLine: PROCEDURE RETURNS [POINTER] =
BEGIN
DiscoDefs.TransferBytes[@dp,nw*2,sl];
RETURN[sl];
END;

ScanClose: PROCEDURE = BEGIN SystemDefs.FreeSegment[sl]; sl←NIL END;

GetPressPage: PUBLIC PROCEDURE[fileName: STRING,pageNumber: CARDINAL,p: POINTER TO PressPage] =
BEGIN
fp: FP;

p.ObjectList ← NIL;
IF NOT DirectoryLookup[fp: @fp,name: fileName,create: FALSE] THEN RETURN;

GetPressPageFromFP[@fp,pageNumber,p];
END;

GetPressPageFromFP: PUBLIC PROCEDURE [fp: POINTER TO FP,pageNumber: CARDINAL,p: POINTER TO PressPage,userProc: UNSPECIFIED ← 0] =
BEGIN
pfp: PressFilePointers;
nPages: CARDINAL ← OpenPressFileFromFP[fp,@pfp];

p.leftX ← p.bottomY ← 77777B;
p.rightX ← p.topY ← 0;
p.ObjectList ← NIL;
p.FontDir ← ALL[NIL];

IF pageNumber > nPages THEN RETURN;
ReadPressPage[@pfp,pageNumber,p,userProc];

ReleasePressFilePointers[@pfp];
END;

ReleasePressFilePointers: PUBLIC PROCEDURE [pfp: POINTER TO PressFilePointers] =
BEGIN OPEN pfp;

--free up storage
FreeSegment[PartDir];
FreeSegment[vDAs];
FreeSegment[FontDir];
fontWidthsStream.destroy[fontWidthsStream];
WHILE PruneHeap[] DO ENDLOOP;
END;

ReadPressPage: PUBLIC PROCEDURE [pfp: POINTER TO PressFilePointers,pageNumber: CARDINAL,p: POINTER TO PressPage,userProc: UNSPECIFIED ← 0] =
BEGIN OPEN pfp;
i: CARDINAL;
partDir: PartEntry ← PartDir[pageNumber-1];
nRecs,firstRec,currentRec: CARDINAL;
trailer: EntityCommandTrailer;
ectPointer: POINTER TO EntityCommandTrailer;
thisELend: CARDINAL;
buffer: ARRAY[0..512) OF UNSPECIFIED;
ELSize,ELDataTail,currentNWords: CARDINAL;
commands: POINTER;

nRecs ← 1;
firstRec ← partDir.RecordStart+partDir.RecordLength;
IF partDir.PaddingLength+SIZE[EntityCommandTrailer] > 256 THEN
BEGIN nRecs ← nRecs + 1;firstRec ← firstRec - 1;END;
FOR i IN [0..nRecs)
DO ReadPageFromVDA[@buffer+i*256,vDAs[firstRec+i]];ENDLOOP;

thisELend ← nRecs*256 - partDir.PaddingLength;
ectPointer ← LOOPHOLE[@buffer+thisELend-SIZE[EntityCommandTrailer]];
currentRec ← firstRec;

WHILE ectPointer.EntityLen # 0 DO
trailer ← ectPointer↑;

ELSize ← trailer.EntityLen-SIZE[EntityCommandTrailer];
ELDataTail ← thisELend-SIZE[EntityCommandTrailer];
commands ← AllocateSegment[ELSize];

DO
currentNWords ← MIN[ELDataTail,ELSize];
InlineDefs.COPY[from: @buffer+ELDataTail-currentNWords,nwords:
currentNWords,to:commands+ELSize-currentNWords];
IF ELDataTail >= ELSize THEN EXIT;
ELSize ← ELSize - currentNWords;
currentRec ← currentRec-1;
ReadPageFromVDA[@buffer,vDAs[currentRec]];
ELDataTail ← 256;
ENDLOOP;

--Stuff to handle flaky ShowCharacterImmediate
ELCommandBase ← currentRec;
ELCommandOffset ← (ELDataTail-currentNWords)*2;

ProcessCommands[pfp,commands,@trailer,p,@partDir,userProc];

SystemDefs.FreeSegment[commands];
firstRec ← firstRec - (255 + trailer.EntityLen - thisELend)/256;
thisELend ← (thisELend - trailer.EntityLen) MOD 256;
nRecs ← 1;
IF thisELend<SIZE[EntityCommandTrailer] THEN
BEGIN
nRecs ← nRecs + 1;
firstRec ← firstRec - 1;
thisELend ← thisELend+256;
END;
IF (currentRec # firstRec) OR (nRecs = 2) THEN
FOR i IN [0..nRecs)
DO ReadPageFromVDA[@buffer+i*256,vDAs[firstRec+i]];ENDLOOP;
currentRec←firstRec;
ectPointer ← LOOPHOLE[@buffer+thisELend-SIZE[EntityCommandTrailer]];
ENDLOOP;
--while EntityLen # 0

END;

OpenPressFile: PUBLIC PROCEDURE [fileName: STRING,pfp: POINTER TO PressFilePointers] RETURNS [nPages: CARDINAL] =
BEGIN
fp: FP;
pfp↑ ← [NIL,NIL,NIL,NIL];
IF NOT DirectoryLookup[fp: @fp,name: fileName,create: FALSE] THEN RETURN;
RETURN[OpenPressFileFromFP[@fp,pfp]];
END;

OpenPressFileFromFP: PUBLIC PROCEDURE [fp: POINTER TO FP,pfp: POINTER TO PressFilePointers] RETURNS [nPages: CARDINAL] =
BEGIN OPEN pfp;
i,j: CARDINAL;
docDir: DocDir;
leaderPage: LD;
fontDirIndex: CARDINAL;

pfp↑ ← [NIL,NIL,NIL,NIL];
ReadPageFromVDA[@leaderPage,fp.leaderDA];
IF leaderPage.eofFA.page = 0 --blank hint, find it yourself
OR leaderPage.eofFA.byte # 0 THEN --or may be smashed hint, good file
BEGIN
vDAs ← AllocateSegment[256*SIZE[vDA]];
IndexFile[fp.leaderDA,256,vDAs];
FOR i IN [0..256) DO
IF vDAs[i] = AltoFileDefs.eofDA THEN
BEGIN
leaderPage.eofFA.page ← i-1;
EXIT;
END;
ENDLOOP;
IF leaderPage.eofFA.page = 0 THEN MiscDefs.CallDebugger["file > 256 pages"];
END
ELSE --good hint
BEGIN
vDAs ← AllocateSegment[leaderPage.eofFA.page*SIZE[vDA]];
IndexFile[fp.leaderDA,leaderPage.eofFA.page,vDAs];
END;

fontWidthsStream ← NewWordStream["Fonts.WIDTHS",Read];

--read docDir
ReadPageFromVDA[@docDir,vDAs[leaderPage.eofFA.page-1]];
IF docDir.Password # PressPassword
THEN MiscDefs.CallDebugger["bad password"];

--read PartDir
PartDir ← AllocateSegment[256*docDir.partLength];
FOR i IN [1..docDir.partLength] DO
ReadPageFromVDA[PartDir+(i-1)*256,vDAs[docDir.partDirStart+i]];
ENDLOOP;

--interpret PartDir, reading fontDir
nPages ← 0;
FOR i IN [0..docDir.nParts) DO
SELECT PartDir[i].Type FROM
Page=>
BEGIN
nPages←nPages+1;
END;
Font=>
BEGIN
fontDirIndex ← i;
FontDir ← AllocateSegment[256*PartDir[i].RecordLength];
FOR j IN [1..PartDir[i].RecordLength] DO
ReadPageFromVDA[FontDir+(j-1)*256,vDAs[PartDir[i].RecordStart+j]];
ENDLOOP;
END;
ExternalFileDirectory=>BEGIN END;
ENDCASE;
ENDLOOP;

IF FontDir = NIL THEN MiscDefs.CallDebugger["no font dir in Press file"];
IF fontDirIndex # docDir.nParts THEN --reorganize
BEGIN
savedFontDir: PressDefs.PartEntry ← PartDir[fontDirIndex];
FOR i IN [fontDirIndex..docDir.nParts-1) DO PartDir[i] ← PartDir[i+1];ENDLOOP;
PartDir[docDir.nParts-1] ← savedFontDir;
END;
RETURN[nPages];
END;

ReleasePressPage: PUBLIC PROCEDURE [pressPage: POINTER TO PressPage] =
BEGIN
x: POINTER TO PressObject;
i: CARDINAL ← 0;
UNTIL pressPage.ObjectList = NIL DO
x ← pressPage.ObjectList.link;
IF pressPage.ObjectList.command IN [ELShowDots..ELShowDotsOpaque] THEN
BEGIN
pdd: POINTER TO PressDotsData ← LOOPHOLE[pressPage.ObjectList+
SIZE[PressObject]];
IF pdd.fileName#NIL THEN SystemDefs.FreeHeapString[pdd.fileName];
END;
FreeHeapNode[pressPage.ObjectList];
pressPage.ObjectList ← x;
ENDLOOP;
UNTIL pressPage.FontDir[i] = NIL DO
FreeSegment[pressPage.FontDir[i].Widths];
FreeHeapString[pressPage.FontDir[i].Family];
FreeHeapNode[pressPage.FontDir[i]];
i ← i+1;
ENDLOOP;
END;

GetFont: PUBLIC PROCEDURE [pfp: POINTER TO PressFilePointers,n: CARDINAL,pressPage: POINTER TO PressPage] RETURNS [index: CARDINAL,widths: POINTER TO ARRAY CHARACTER [0C..377C] OF INTEGER] =
BEGIN
fontIndex: CARDINAL ← 0;
i,j: CARDINAL;
f: POINTER TO PressFont;
bufx,bufy: POINTER;

str: STRING;

--look through font entries
FOR i ← 0,i+1 UNTIL pfp.FontDir[i].EntryLength = 0 DO
IF pfp.FontDir[i].Family[0] = 0C THEN
BEGIN
MiscDefs.CallDebugger["character entry in font part"];
LOOP;
END;

IF n # CARDINAL[pfp.FontDir[i].FontSet*16 + pfp.FontDir[i].Font] THEN LOOP;

--first, look through already processed fonts
str ← AllocateHeapString[LOOPHOLE[pfp.FontDir[i].Family[0]]];
FOR j IN [1..LOOPHOLE[pfp.FontDir[i].Family[0],CARDINAL]]
DO StringDefs.AppendChar[str,pfp.FontDir[i].Family[j]];
ENDLOOP;
UNTIL pressPage.FontDir[fontIndex] = NIL DO
--note that pressPage.FontDir[fontIndex].n may not have any
--relation to the desired font number "n", since they may come
--from different press files
--IF pressPage.FontDir[fontIndex].n = n THEN
IF StringDefs.EquivalentString[str,pressPage.FontDir[fontIndex].Family]
AND pfp.FontDir[i].Face = pressPage.FontDir[fontIndex].Face
AND pfp.FontDir[i].Size = pressPage.FontDir[fontIndex].PointSize
AND pfp.FontDir[i].Rotation = pressPage.FontDir[fontIndex].Rotation
THEN --SAME!!!!
BEGIN
SystemDefs.FreeHeapString[str];
RETURN[fontIndex,pressPage.FontDir[fontIndex].Widths];
END;
fontIndex ← fontIndex + 1;
ENDLOOP;

IF fontIndex = 16 THEN ERROR;--too many fonts

f ← AllocateHeapNode[SIZE[PressFont]];
f↑ ← [Family: str,Widths:,Face: LOOPHOLE[pfp.FontDir[i].Face],
PointSize: pfp.FontDir[i].Size,Rotation: pfp.FontDir[i].Rotation];
f.Widths ← AllocateSegment[256];

SELECT f.Rotation/60 FROM
90,270 => BEGIN bufx ← NIL;bufy ← LOOPHOLE[f.Widths];END;
ENDCASE => BEGIN bufx ← LOOPHOLE[f.Widths];bufy ← NIL;END;
IF NOT LookupFontName[s: pfp.fontWidthsStream,famstr: f.Family,
face: f.Face,siz: f.PointSize,rot: f.Rotation,
bufx:bufx,bufy:bufy,boundbox:NIL]
THEN {
IF PrintWidthError THEN {
errorString: STRING ← [100];
StringDefs.AppendString[to:errorString,
from:"LookupFontName failed: ("];
StringDefs.AppendString[to:errorString, from: f.Family];
StringDefs.AppendDecimal[s:errorString,n:f.PointSize];
StringDefs.AppendString[to:errorString,
from:"). Widths will be wrong if you Proceed"];
MiscDefs.CallDebugger[errorString];
};
MiscDefs.Zero[f.Widths,256];
};
pressPage.FontDir[fontIndex] ← f;
RETURN[fontIndex,f.Widths];
ENDLOOP;

IF n # 0 THEN --bogus first call in Entity
MiscDefs.CallDebugger["font not found"]; --can’t happen
RETURN[0,NIL];
END;

ProcessCommands: PROCEDURE[pfp: POINTER TO PressFilePointers,EL: POINTER TO PACKED ARRAY [0..0) OF ELCommand,trailer: POINTER TO EntityCommandTrailer,pressPage: POINTER TO PressPage,partDir: POINTER TO PartEntry,userProc: UNSPECIFIED ← 0] =
BEGIN
Proc: PROCEDURE [p: POINTER TO PressPage] ← userProc;
vDAs: POINTER TO ARRAY [0..0) OF vDA ← pfp.vDAs;
i: CARDINAL;
currentDLRecord: CARDINAL ← 177777B;
spaceX: CARDINAL ← 177777B;
spaceY: CARDINAL ← 177777B;
DLRecordStart: CARDINAL ← partDir.RecordStart+
LongDiv32[trailer.BeginByte[1],trailer.BeginByte[0],512]+1;
DLRecordOffset: CARDINAL ← trailer.BeginByte[1] MOD 512;
DL: PACKED ARRAY [0..512) OF [0..377B];
nELBytes: CARDINAL = 2*(trailer.EntityLen-SIZE[EntityCommandTrailer]);
micaX: CARDINAL ← trailer.Xe;
micaY: CARDINAL ← trailer.Ye;


currentFontIndex: CARDINAL;
currentWidth: POINTER TO ARRAY CHARACTER [0C..377C] OF INTEGER;
currentFontRotated: BOOLEAN;
currentHeight: CARDINAL;
currentSat,currentHue,currentBr: CARDINAL ← 0;
AlternativeOn: BOOLEAN ← FALSE;
lastLink: POINTER TO PressObject;

Width: PROCEDURE[c: CHARACTER] RETURNS[INTEGER] = INLINE {
w: INTEGER=currentWidth[c];
RETURN[IF w=missingWidth THEN 0 ELSE w];
};
DoCharImmediate: PROCEDURE =
BEGIN
ELOff: CARDINAL ← ELCommandOffset+i;
ELBase: CARDINAL ← ELCommandBase+ELOff/512;
ELByte: CARDINAL ← ELOff MOD 512;
ch: CHARACTER ← LOOPHOLE[EL[i]];
IF currentFontRotated THEN
BEGIN
IF ch = ’ AND spaceY # 177777B THEN micaY ← micaY + spaceY
ELSE micaY ← micaY + Width[ch];
END
ELSE
BEGIN
IF ch = ’ AND spaceX # 177777B THEN micaX ← micaX + spaceX
ELSE micaX ← micaX + Width[ch];
END;
AddPressObject[ELShowCharacters,1];
lastLink.diskPosition ← [VDA:vDAs[ELBase],beginByte: ELByte];
END;
DoChars: PROCEDURE[n: CARDINAL] =
BEGIN
ch: CHARACTER;
--note: only rotation=90 will work with this bad code
xoff: CARDINAL ← IF currentFontRotated THEN currentHeight ELSE 0;
yoff: CARDINAL ← IF currentFontRotated THEN 0 ELSE currentHeight;
AddPressObject[ELShowCharacters,n];
pressPage.leftX ← MIN[pressPage.leftX,micaX-xoff];
pressPage.bottomY ← MIN[pressPage.bottomY,micaY];
pressPage.topY ← MAX[pressPage.topY,micaY+yoff];
THROUGH [0..n) DO
ch ← Read[];
IF currentFontRotated THEN
BEGIN
IF ch = ’ AND spaceY # 177777B THEN micaY ← micaY + spaceY
ELSE micaY ← micaY + Width[ch];
END
ELSE
BEGIN
IF ch = ’ AND spaceX # 177777B THEN micaX ← micaX + spaceX
ELSE micaX ← micaX + Width[ch];
END;
ENDLOOP;
pressPage.rightX ← MAX[pressPage.rightX,micaX];
pressPage.topY ← MAX[pressPage.topY,micaY+yoff];
END;
Read: PROCEDURE RETURNS[rslt: UNSPECIFIED] =
BEGIN
rslt ← DL[DLRecordOffset];
Skip[1];
END;
AddPressObject: PROCEDURE[c: ELCommand,nDataBytes: CARDINAL] =
BEGIN
newObj: POINTER TO PressObject;
dot: BOOLEAN = c IN [ELShowDots..ELShowDotsOpaque];

--error check for space saving data structure kludge
IF (nDataBytes > 7777B) OR (currentFontIndex > 17B) THEN ERROR;
newObj ← AllocateHeapNode[SIZE[PressObject]+
(IF dot THEN SIZE[PressDotsData] ELSE 0)];
newObj↑ ← [link: NIL,micaX: micaX,micaY: micaY,command: c,
hue: currentHue,sat: currentSat,br: currentBr,spaceX: spaceX,spaceY: spaceY,
font: currentFontIndex,nDataBytes: nDataBytes,
diskPosition: [VDA:vDAs[currentDLRecord],beginByte: DLRecordOffset]];
IF pressPage.ObjectList = NIL THEN
BEGIN
pressPage.ObjectList ← newObj;
lastLink ← newObj;
END
ELSE
BEGIN
lastLink.link ← newObj;
lastLink ← newObj;
END;
END;
Skip: PROCEDURE[n: CARDINAL] =
BEGIN
DLRecordOffset ← DLRecordOffset+n;
IF DLRecordOffset >= 512 THEN
BEGIN
currentDLRecord ← currentDLRecord + DLRecordOffset/512;
DLRecordOffset ← DLRecordOffset MOD 512;
ReadPageFromVDA[@DL,vDAs[currentDLRecord]];
END;
END;

lastLink ← pressPage.ObjectList;
IF lastLink # NIL THEN
UNTIL lastLink.link = NIL DO lastLink ← lastLink.link;ENDLOOP;
[currentFontIndex,currentWidth] ← GetFont[pfp,trailer.FontSet*16,pressPage];
IF currentWidth=NIL THEN {
currentFontRotated ← FALSE;
currentHeight ← 0;
}
ELSE {
deg: CARDINAL ← pressPage.FontDir[currentFontIndex].Rotation/60;
currentFontRotated ← SELECT deg FROM
90,270 => TRUE,
ENDCASE => FALSE;
currentHeight ← pressPage.FontDir[currentFontIndex].PointSize*(2540/72);
};
IF currentDLRecord # DLRecordStart THEN
BEGIN
currentDLRecord ← DLRecordStart;
ReadPageFromVDA[@DL,vDAs[currentDLRecord]];
END;
FOR i IN [0..nELBytes) DO
SELECT EL[i] FROM
IN [ELShowCharactersShort..ELSkipCharactersShort)=>
DoChars[EL[i]+1-ELShowCharactersShort];
IN [ELSkipCharactersShort..ELShowCharactersAndSkip)=>
Skip[1+EL[i]-ELSkipCharactersShort];
IN [ELShowCharactersAndSkip..ELSetSpaceXShort)=>
BEGIN
DoChars[EL[i]+1-ELShowCharactersAndSkip];
Skip[1];
END;
IN [ELSetSpaceXShort..ELSetSpaceYShort)=>
BEGIN i←i+1;spaceX←(EL[i-1]-ELSetSpaceXShort)*256+EL[i];END;
IN [ELSetSpaceYShort..ELFont)=>
BEGIN i←i+2;spaceY←(EL[i-1]-ELSetSpaceYShort)*256+EL[i];END;
IN [ELFont..ELFont+16)=>
BEGIN
[currentFontIndex,currentWidth] ←
GetFont[pfp,trailer.FontSet*16+EL[i]-ELFont,pressPage];
currentFontRotated ←
SELECT pressPage.FontDir[currentFontIndex].Rotation/60 FROM
90,270 => TRUE,
ENDCASE => FALSE;
currentHeight ← pressPage.FontDir[currentFontIndex].PointSize*(2540/72);
END;
ELSkipControlBytesImmediate=> i←i+EL[i+1]+1;
ELAlternative=>
IF AlternativeOn THEN
BEGIN
last: BOOLEAN ← TRUE;
j: CARDINAL;
FOR j IN [1..10] DO
IF EL[j]#0 THEN BEGIN last←FALSE;EXIT;END;ENDLOOP;
IF last THEN AlternativeOn ← FALSE;
Skip[EL[i+9]*256+EL[i+10]];
i←i+10+EL[i+5]*256+EL[i+6];
END
ELSE
BEGIN
AlternativeOn ← TRUE;i←i+10;
END;
ELOnlyOnCopy=> MiscDefs.CallDebugger["ELOnlyOnCopy"];
ELSetX=> BEGIN i←i+2;micaX←trailer.Xe+EL[i-1]*256+EL[i];END;
ELSetY=> BEGIN i←i+2;micaY←trailer.Ye+EL[i-1]*256+EL[i];END;
ELShowCharacters=>
BEGIN
i←i+1;
DoChars[EL[i]];
END;
ELSkipCharacters=> BEGIN i←i+1;Skip[EL[i]];END;
ELSkipControlBytes=> BEGIN Skip[EL[i+1]*256+EL[i+2]];i←i+3;END;
ELShowCharacterImmediate=>
BEGIN i←i+1;DoCharImmediate[];END;
ELSetSpaceX=> BEGIN i←i+2;spaceX←EL[i-1]*256+EL[i];END;
ELSetSpaceY=> BEGIN i←i+2;spaceY←EL[i-1]*256+EL[i];END;
ELResetSpace=> spaceX←177777B;
ELSpace=> BEGIN micaX ← micaX+spaceX;micaY←micaY+spaceY;END;
ELSetBrightness=> BEGIN currentBr ← EL[i+1];i←i+1;END;
ELSetHue=> BEGIN currentHue ← EL[i+1];i←i+1;END;
ELSetSaturation=> BEGIN currentSat ← EL[i+1];i←i+1;END;
ELShowObject=>
BEGIN
nWords: CARDINAL ← EL[i+1]*256 + EL[i+2];
savedMicaX: CARDINAL ← micaX;
savedMicaY: CARDINAL ← micaY;
micaX ← trailer.Xe;micaY ← trailer.Ye;
AddPressObject[ELShowObject,nWords*2];
UNTIL nWords <= 0 DO
IF Read[] # 0 THEN ERROR;
SELECT Read[] FROM
DLMoveTo,DLDrawTo =>
BEGIN
x: CARDINAL ← micaX + Read[]*256 + Read[];
y: CARDINAL ← micaY + Read[]*256 + Read[];
pressPage.leftX ← MIN[pressPage.leftX,x];
pressPage.bottomY ← MIN[pressPage.bottomY,y];
pressPage.rightX ← MAX[pressPage.rightX,x];
pressPage.topY ← MAX[pressPage.topY,y];
nWords ← nWords-3;
END;
DLDrawCurve =>
BEGIN
Skip[12*2];
nWords ← nWords-13;
END;
ENDCASE => ERROR;
ENDLOOP;
micaX ← savedMicaX;micaY ← savedMicaY;
i←i+2;
END;
ELShowDots,ELShowDotsOpaque=> --EL[i] tells which
BEGIN
DotsData: POINTER TO PressDotsData;
nWords: CARDINAL ← EL[i+3]*256 + EL[i+4];
AddPressObject[EL[i],0]; --nDataBytes not used for dots
DotsData ← LOOPHOLE[lastLink+SIZE[PressObject]];

--double skip (Skip works on bytes) to handle larger files
Skip[nWords];
Skip[nWords];
THROUGH [1..EL[i+2]] DO
Skip[100000B];
Skip[100000B];
Skip[100000B];
Skip[100000B];
ENDLOOP;
i←i+4;

--find bounding box
GetPressDotsData[lastLink,DotsData];
pressPage.leftX ← MIN[pressPage.leftX,lastLink.micaX];
pressPage.bottomY ← MIN[pressPage.bottomY,lastLink.micaY];
pressPage.rightX ←
MAX[pressPage.rightX,lastLink.micaX+DotsData.micaWidth];
pressPage.topY ←
MAX[pressPage.topY,lastLink.micaY+DotsData.micaHeight];
END;
ELShowRectangle=>
BEGIN
width: CARDINAL ← EL[i+1]*256+EL[i+2];
height: CARDINAL ← EL[i+3]*256+EL[i+4];
AddPressObject[ELShowRectangle,0];
lastLink.spaceX ← width;
lastLink.spaceY ← height;
i←i+4;
pressPage.leftX ← MIN[pressPage.leftX,micaX];
pressPage.bottomY ← MIN[pressPage.bottomY,micaY];
pressPage.rightX ← MAX[pressPage.rightX,micaX+width];
pressPage.topY ← MAX[pressPage.topY,micaY+height];
END;
ELNop=> NULL;
ENDCASE=>NULL;
IF userProc # 0 THEN Proc[pressPage];
ENDLOOP; --for all EL commands

END;

END.