-- File: PressNetListener.mesa: Routines for getting for a file at a printing server.
-- GetBits is called by Press.mesa
-- Last Edited: April 16, 1982 2:36 PM By: GWilliams & Pier
-- Normalizing for Press Bands world.

DIRECTORY
AltoDefs USING [BytesPerWord, PageSize],
AltoRam USING [CantFindFile, FileLooksCrufty],
EFTPDefs USING [EFTPAbortReceiving, EFTPAlreadyReceiving, EFTPEndReceiving, EFTPFinishReceiving, EFTPGetBlock, EFTPNotReceiving, EFTPOpenForReceiving, EFTPTimeOut, EFTPTroubleReceiving],
IODefs USING[CR, SP, WriteChar, WriteDecimal, WriteOctal, WriteLine, WriteString],
InlineDefs USING [BITOR, BITSHIFT, LongCOPY],--LongCOPY[from, nwords, to]
MesaBands USING [BandDevice, ShowBands, ShowBandsInit],
MiscDefs USING[CallDebugger, Zero],
PressDefs USING [PageG, PressPassword, RamBoot, uCodeLoaded],
PressNetDefs USING [attributesCode, EndReason, imageCode, PageAttributes],
PressBandsDefs USING [CloseBandsFile, OpenPressBands, InitTfsBandsBuffer, ReleaseTfsBandsBuffer],
PupDefs USING [GetPupAddress, PupPackageDestroy, PupPackageMake],
PupStream USING [AppendPupAddress],
PupTypes USING[PupAddress, PupSocketID],
SegmentDefs USING[DataSegmentHandle, DefaultBase, DeleteDataSegment, NewDataSegment, SegmentAddress],
SlotDefs USING [longScans],
StreamDefs USING[AccessOptions, DiskHandle, FileNameError, NewByteStream, Read],
StringDefs USING [AppendChar, EquivalentString],
TridentDefs USING [BadErrorRtn, dcReadLD, dcWriteD, ddMgrPtr, DefaultTfsCleanupRtn, DefaultTfsErrorRtn, eofDA, fillInDA, FP, PAGE, TfsActOnPages, TfsCloseDisk, TfsCreateDDmgr, tfsdskPtr, TfsInit, TfsOpenFile, TFSwordsPerPage];

PressNetListener: PROGRAM
IMPORTS AltoRam, EFTPDefs, IODefs, InlineDefs, MesaBands, MiscDefs, PressDefs, PressBandsDefs, PupDefs, PupStream, SegmentDefs, StreamDefs, StringDefs, TridentDefs
EXPORTS PressBandsDefs, PressNetDefs =
BEGIN OPEN AltoDefs, AltoRam, EFTPDefs, IODefs, InlineDefs, MesaBands, MiscDefs, PressDefs, PressBandsDefs, PressNetDefs, PupDefs, PupStream, PupTypes, SegmentDefs, SlotDefs, StreamDefs, StringDefs, TridentDefs;
TerminationReason: TYPE = {errorTermination, fileDoneTermination, pageDoneTermination, nullTerminationReason};
--Press Stuff
bandWidth: CARDINAL ← 0;
FirstPage: TYPE = MACHINE DEPENDENT RECORD
[nPages: CARDINAL ← 1,
pageGSize: CARDINAL ← SIZE[PageG],
printerMode: CARDINAL,--3=portrait, 8=Landscape
password: CARDINAL ← PressPassword,
pageGs: ARRAY[0..80) OF PageG--enough to fit into a Trident Page
];
scanSeg: DataSegmentHandle ← NIL;
scanLength: CARDINAL;
wordAddrInTfsBuffer: CARDINAL;
scanInBand: CARDINAL;
--
net stuff
connectionOpen: BOOLEAN ← FALSE;
gotAJob: BOOLEAN ← FALSE;
hostAddress: PupAddress;
pupPtr: POINTER TO PupAddress ← @hostAddress;
senderAddress: PupAddress;
pupPkgExtant: BOOLEAN ← FALSE;
--Band Stuff
device: PUBLIC BandDevice ← end;

--Tfs stuff
bandDiskBuffer: POINTER;
ddMgr: PUBLIC ddMgrPtr ← NIL;
disk: tfsdskPtr ← NIL;
bufferWordLen: CARDINAL = TFSwordsPerPage;
bufferByteLen: CARDINAL = BytesPerWord*bufferWordLen;
pagesLength: CARDINAL = 4;
firstVda: CARDINAL ← 0;--allways holds page 1 of the file
fp: FP;--fp gets filled in by TfsOpenFile
filePtr: POINTER TO FP ← @fp;
tfsSeg: DataSegmentHandle ← NIL;
tfsBuff: POINTER TO ARRAY[0..TFSwordsPerPage) OF CARDINAL;
pages: ARRAY[0..pagesLength] OF PAGE;
dAsLength: CARDINAL;
dAsBase: POINTER;--this is modified after ea call on TfsActOnPages.
pageNum: CARDINAL;

--Debugging Switches
fileLengthReport: BOOLEAN ← TRUE;--print out length of received file in pages
dasMonitor: BOOLEAN ← FALSE;--for debugging tfs file handler.
debuggerIfTfsError: PUBLIC BOOLEAN ← TRUE;
checkTermination: PUBLIC BOOLEAN ← TRUE;

--Signals & Errors
CommErr: TYPE = {alreadyHaveJob, nullComErr, endReceiving, noisyChannel, protocolError, illegalEnd, notReceiving, alreadyReceiving};
errorComm: ERROR[e: CommErr, wordsTransferred: CARDINAL ← 0, s: STRING ← NIL] = CODE;
errorTfs: PUBLIC ERROR[e: EndReason] = CODE;

GetBits: PUBLIC PROC[] RETURNS[okToProceed: BOOLEAN ← FALSE]=
--Raises no signals or errors
BEGIN

pa: PageAttributes;
endReason: EndReason ← illegalReason;
iii: CARDINAL ← 0;--used in data fetching loop
inCoreAddress: POINTER TO ARRAY OF WORD;
tooMuchData: BOOLEAN ← FALSE;--set when sender sends too much data
receivedFile: BOOLEAN ← FALSE;
scanLineLength: CARDINAL;--copy of scanLength
wordsInBuff: CARDINAL;

BEGIN
IF ~FirstPageCheck[] THEN RETURN[FALSE];

WHILE ~receivedFile
DO
OpenPressBits[filePtr! errorTfs => {SELECT e FROM noTrident => WriteLine["Trident not up"L];
cantFindFile => WriteLine["Can’t find Press.bits"L];
ENDCASE; GOTO getOut}--no state to clean up--];

pa ← GetAJob[! errorComm => IF e = alreadyReceiving THEN {PupPackageDestroy[]; GOTO getOut}];
bandWidth ← (IF pa.bitWc > longScans THEN 8 ELSE 16);
InitTfsBuffer[];
inCoreAddress ← InitScanBuffer[pa];--get enough space for a scan line; must call after InitTfsBuffer
scanLineLength ← scanLength;--scan Length is valid now.
BEGIN ENABLE BEGIN
errorComm =>
{SELECT e FROM
noisyChannel => {WriteLine["Noisy Channel, aborting transfer"L];
EFTPAbortReceiving["Channel too noisy, aborting transfer"L!
EFTPNotReceiving => CONTINUE]};
endReceiving => WriteLine["Transfer aborted, not enough data received"L];
ENDCASE;
GOTO incompleteXFer};
errorTfs => SELECT e FROM tridentError, hitEOF, dANotFilled => {endReason ← e; GOTO done}; ENDCASE;
END;--of catch series

FOR iii IN [0..pa.lastScan-pa.firstScan]
DO
wordsInBuff ← GetBuffer[inCoreAddress, 1];--check header word
IF inCoreAddress[0] # imageCode THEN
{WriteLine["Buffer doesn’t contain image data"L]; GOTO incompleteXFer};

wordsInBuff ← GetBuffer[inCoreAddress, scanLineLength];--get scan line
IF wordsInBuff = 0 THEN {endReason ← emptyBuffReason; GOTO done};--blow up
StoreScanLine[inCoreAddress];--buffers data and writes to disk.
ENDLOOP;

EXITS
incompleteXFer =>
{IF checkTermination THEN
CallDebugger["File transfer trouble"];
CloseServerConnection[];
disk←TfsCloseDisk[disk, FALSE];--delete the ddMgr too
ddMgr ← NIL;
ReleaseScanBuffer[TRUE, inCoreAddress, pa];
ReleaseTfsBuffer[];
LOOP};--restart @ WHILE ~ receivedFile
END;

--now loop asking for data, waiting for an EFTPEndReceiving
BEGIN ENABLE errorComm => IF e = endReceiving THEN GOTO closeConn;
DO wordsInBuff ← GetBuffer[inCoreAddress, scanLineLength]; tooMuchData ← TRUE;
ENDLOOP;
EXITS
closeConn => NULL;
END;

CloseServerConnection[];--turn off net driver
ReleaseScanBuffer[FALSE, inCoreAddress, pa];--write out blank scan lines if last band is not full & free storage
WritePageGPage[pa!--get out if error
errorTfs => IF (e = tridentError)
THEN {WriteLine["Transfer Complete, but"L]; endReason ← tridentError; GOTO done}];
ReleaseTfsBuffer[];
disk←TfsCloseDisk[disk, FALSE];
ddMgr ← NIL;
receivedFile ← TRUE;
ENDLOOP;
okToProceed ← TRUE;

EXITS
getOut=> NULL;
done=>
{
ReleaseScanBuffer[FALSE, inCoreAddress, pa];--write out blank scan lines if last band is not full & free storage
ReleaseTfsBuffer[];
CloseServerConnection[];--turn off net if on.
SELECT endReason FROM
emptyBuffReason=>WriteLine["Empty Page: error!"L];
illegalReason =>WriteLine["illegal End."L];
tridentError =>{WriteLine["Trident error"L];
EFTPAbortReceiving["Trident error"L];};
hitEOF => {WriteLine["Ran into EOF on write"L];
EFTPAbortReceiving["Trident ran into EOF on file write"L];};
dANotFilled =>{WriteLine["Trident software trouble -- bad DA multiple times"L];
EFTPAbortReceiving["Trident software trouble -- bad DA"L];};
ENDCASE;

SELECT endReason FROM
tridentError => NULL;
emptyBuffReason, hitEOF, dANotFilled => {IF disk # NIL THEN disk ← TfsCloseDisk[disk, FALSE]; ddMgr ← NIL};
ENDCASE;
};
END;
IF checkTermination THEN
IF ~okToProceed THEN CallDebugger["Exiting with error from GetBits"L];
END;
--of GetBits
GetBitsFromBands: PUBLIC PROC[] RETURNS[okToProceed: BOOLEAN ← FALSE]=
--Raises no signals or errors
BEGIN

pa: PageAttributes;
endReason: EndReason ← illegalReason;
iii: CARDINAL ← 0;--used in data fetching loop
inCoreAddress: POINTER TO ARRAY OF WORD;
tooMuchData: BOOLEAN ← FALSE;--set when sender sends too much data
receivedFile: BOOLEAN ← FALSE;
pTypeH: DiskHandle ← NIL;
pName: STRING ← [5];

BEGIN
--this routine destroys the
ddMgr if it fails

device ← end;
pTypeH ← NewByteStream["PrinterType"L, Read!
FileNameError => {WriteLine["Can’t find file PrinterType"L];
GOTO getOut;}];
FOR ii: CARDINAL IN [0..5) DO
AppendChar[pName, pTypeH.get[pTypeH]]; ENDLOOP;
pTypeH.destroy[pTypeH];
IF EquivalentString[pName, "Horne"L] THEN device ← hornet;
IF EquivalentString[pName, "Plate"L] THEN device ← platemaker;
IF EquivalentString[pName, "Retic"L] THEN device ← reticlemaker;
IF device = end THEN {WriteLine["Device mismatch"L]; GOTO getOut;};

OpenPressBits[filePtr! errorTfs => {SELECT e FROM noTrident => WriteLine["Trident not up"L];
cantFindFile => WriteLine["Can’t find Press.bits"L];
ENDCASE; GOTO getOut --no state to clean up--}];

OpenPressBands[! errorTfs => {SELECT e FROM noTrident => WriteLine["Trident not up"L];
cantFindFile =>
{WriteLine["Can’t find RETBAND"L];
disk ← TfsCloseDisk[disk, FALSE]; --get rid of Bits file disk object
ddMgr ← NIL}; --and the community ddMgr
ENDCASE; GOTO getOut}];

bandDiskBuffer ← InitTfsBandsBuffer[];--init the input buffer for Press.Bands
pa ← MesaBands.ShowBandsInit[device];
bandWidth ← (IF pa.bitWc > longScans THEN 8 ELSE 16);
InitTfsBuffer[];--init the output buffer to Press.bits
inCoreAddress ← InitScanBuffer[pa];--get enough space for a scan line; must call after InitTfsBuffer
MesaBands.ShowBands[];

ReleaseScanBuffer[FALSE, inCoreAddress, pa];--write out blank scan lines if last band is not full & free storage

WritePageGPage[pa!--get out if error
errorTfs => IF (e = tridentError)
THEN {WriteLine["Transfer Complete, but"L]; endReason ← tridentError; GOTO done}];
ReleaseTfsBuffer[];
ReleaseTfsBandsBuffer[];
CloseBandsFile[];--must call this before TfsCloseDisk[,FALSE] as it needs a disk descriptor
disk←TfsCloseDisk[disk, FALSE];
ddMgr ← NIL;
okToProceed ← TRUE;

EXITS
getOut=> NULL;
done=>
{
ReleaseScanBuffer[FALSE, inCoreAddress, pa];--write out blank scan lines if last band is not full & free storage
ReleaseTfsBandsBuffer[];
ReleaseTfsBuffer[];
SELECT endReason FROM
emptyBuffReason=>WriteLine["Empty Page: error!"L];
illegalReason =>WriteLine["illegal End."L];
tridentError =>WriteLine["Trident error"L];
hitEOF => WriteLine["Ran into EOF on write"L];
dANotFilled =>WriteLine["Trident software trouble -- bad DA multiple times"L];
ENDCASE;

SELECT endReason FROM
tridentError => NULL;
emptyBuffReason, hitEOF, dANotFilled => { CloseBandsFile[]; disk ← TfsCloseDisk[disk, FALSE]; ddMgr ← NIL};
ENDCASE;
};
END;
IF checkTermination THEN
IF ~okToProceed THEN CallDebugger["Exiting with error from GetBits"L];
END;
--of GetBitsFromBands
GetAJob: PROC[] RETURNS [pa: PageAttributes]=
{
typedMessage: BOOLEAN ← FALSE;
getAJobEndReason: EndReason ← illegalReason;
code: CARDINAL;
wordsReturned: CARDINAL;
pupAddressString: STRING ← [30];

IF gotAJob THEN ERROR errorComm [alreadyHaveJob, , ];
WHILE ~gotAJob DO
IF ~connectionOpen THEN
{IF ~pupPkgExtant THEN
{PupPackageMake[];
pupPkgExtant ← TRUE;
GetPupAddress[pupPtr, "ME"];
--don’t use the normal socket for debugging!
pupPtr.socket ← PupSocketID[1, 25B];--[0, 20B] is the normal printer socket
};

senderAddress ← EFTPOpenForReceiving[pupPtr↑!
EFTPTimeOut =>
{IF ~typedMessage
THEN {WriteLine["Listening for print request."]; typedMessage ← TRUE;};
RESUME};
EFTPAlreadyReceiving =>
{WriteLine["Connection Already Open!"L];
ERROR errorComm[alreadyReceiving, 0, NIL]};
];
connectionOpen ← TRUE;
};

WriteString["Connection open to "L];
AppendPupAddress[pupAddressString, senderAddress];
WriteLine[pupAddressString];
typedMessage ← FALSE;

[wordsReturned] ← GetBuffer[@code, 1!
errorComm =>
SELECT e FROM
noisyChannel, protocolError, endReceiving =>
{EFTPFinishReceiving[!
EFTPNotReceiving => CONTINUE];
connectionOpen ← FALSE; LOOP;};
ENDCASE
];--get code to see if it is a Page Attributes code

IF code # attributesCode THEN
{EFTPAbortReceiving["I Expect Page Attributes first"];
WriteLine["Connection Refused, protocol error."L];
typedMessage ← connectionOpen ← FALSE; LOOP};--get rid of this customer & type init message

wordsReturned ← GetBuffer[@pa, SIZE[PageAttributes]!
errorComm =>
SELECT e FROM
noisyChannel, protocolError, endReceiving => LOOP;
ENDCASE
];

gotAJob ← TRUE;
ENDLOOP;
};
--GetAJob

FirstPageCheck
: PROC [] RETURNS[goAhead: BOOLEAN ← TRUE]=
{
IF SIZE[FirstPage] > TFSwordsPerPage THEN
{WriteLine["First page description exceeds Trident Page Length"];
RETURN[FALSE]};
};
--FirstPageCheck
GetBuffer: PROC[buffer: POINTER, len: CARDINAL] RETURNS [wordsInBufCt: CARDINAL ← 0]=
--copy from net Stream to buffer len amount of words
BEGIN
blockByteLen, bytesToGet: CARDINAL ← 0;
bufferEnd: POINTER ← buffer + len;--actually is first word past buffer
bufferPos: POINTER ← buffer;
getABuffEndReason: EndReason ← illegalReason;

BEGIN

UNTIL bufferPos = bufferEnd
DO
bytesToGet ← (bufferEnd - bufferPos) + (bufferEnd - bufferPos);--remember, bufferEnd is one past end of buffer
blockByteLen ← 0;
blockByteLen ← EFTPGetBlock[bufferPos, bytesToGet!
EFTPNotReceiving => {getABuffEndReason ← errorNotReceiving; GOTO done;};
EFTPEndReceiving => {getABuffEndReason ← doneReason; GOTO done;};
EFTPTroubleReceiving => {getABuffEndReason ← errorTroubleReceiving; GOTO done;};
EFTPTimeOut => RETRY];

bufferPos ← bufferPos + blockByteLen/2;
wordsInBufCt ← wordsInBufCt + BITSHIFT[blockByteLen, -1];--divide by bytes/word
ENDLOOP;

EXITS
done=>
{--CloseServerConnection[]; - - this is done at the catch phrase higher up.
wordsInBufCt ← wordsInBufCt + blockByteLen;

SELECT getABuffEndReason FROM
doneReason =>ERROR errorComm[endReceiving, wordsInBufCt, NIL];--not necessarily an error
errorTroubleReceiving =>ERROR errorComm[noisyChannel, wordsInBufCt, NIL];
errorNotReceiving =>ERROR errorComm[notReceiving, 0, NIL];
illegalReason =>ERROR errorComm[illegalEnd, wordsInBufCt, NIL];
ENDCASE;
};
END;
END;
--of GetBuffer

StoreScanLine: PUBLIC PROC [p: LONG POINTER]=
--Put scan line into Press.bits. Breaks scan line up if it overflows a Trident Page. Also pads the band out to 1K boundary.
--Now, if we overflow the Tfsbuffer, we automatically write out the full page and add remainder of scan to newly emptied buffer. If that was the last scan line of the buffer, we write out the partial page regardless whether we just flushed the full buffer since we’re padding the trident page at the end of a band. Hence the test for scanInBand at end.
{
wordsLeft: CARDINAL;
xLength: CARDINAL ← scanLength;
from: LONG POINTER ← p;

DO
wordsLeft ← (TFSwordsPerPage-wordAddrInTfsBuffer);
LongCOPY[from, MIN[wordsLeft, xLength], tfsBuff + wordAddrInTfsBuffer];

IF wordsLeft < xLength--wordsLeft can be zero
THEN --did not fit into buffer
{WriteTfsPage[];
from ← from+wordsLeft;
xLength ← xLength-wordsLeft;
wordAddrInTfsBuffer ← 0;
}
ELSE -- buffer had room for all the words
{wordAddrInTfsBuffer ← wordAddrInTfsBuffer + xLength;
--can = TFSwordsPerPage
EXIT;};
ENDLOOP;

IF (scanInBand ← scanInBand + 1) = bandWidth THEN
{WriteTfsPage[];
--reset wordAddrInTfsBuffer to 0 to avoid an empty page next go around
wordAddrInTfsBuffer ← 0;
scanInBand ← 0;
};
};
--StoreScanLine
WriteTfsPage: PROC[]=
{
endReason: EndReason ← illegalReason;
loopCtr: CARDINAL;--this detects infinite loops in GetBits
maxTries: CARDINAL = 3;
nmChars: CARDINAL ← BytesPerWord*TFSwordsPerPage;

dAs: DESCRIPTOR FOR ARRAY OF PAGE ← DESCRIPTOR[dAsBase, dAsLength];
BEGIN
IF (dAs[pageNum] ← dAs[pageNum+1]) = eofDA
THEN{endReason ← hitEOF; GOTO done;};--by now the vda of the next page to write is in

IF (dAs[pageNum] = fillInDA)
THEN--the vda is not valid
IF debuggerIfTfsError
THEN CallDebugger["disk address is fillInDA"L]
ELSE{endReason ← dANotFilled; GOTO done};

dAs[pageNum+1] ← fillInDA;--reset the to-be-pagenum+1 vda
dAsLength ← dAsLength + 1;--extend range of descriptor from new base
dAsBase ← dAsBase - 1;--must reset base because the low-level disk routines write pageNum onto
pageNum ← pageNum + 1;-- the disk label; and the vda is accessed from dAs using pageNum!
dAs ← DESCRIPTOR[dAsBase, dAsLength];
--TypeOutStatus[dAs, pageNum, charsInPage, TRUE];----the TRUE means "before ActOnPages"
[]← TfsActOnPages[disk, NIL, dAs, filePtr↑, pageNum, pageNum, dcWriteD, @nmChars, dcWriteD, tfsBuff, DefaultTfsCleanupRtn, DefaultTfsErrorRtn, TRUE, 0!
BadErrorRtn => {endReason ← tridentError; GOTO done;};];
--TypeOutStatus[dAs, pageNum, charsInPage, FALSE];----the FALSE means "after ActOnPages"

loopCtr ← 0;
UNTIL dAs[pageNum+1] # fillInDA
DO--the Default TfsCleanupRtn didn’t fill in the next DA, try again, but don’t write data this time
IF (loopCtr ← loopCtr + 1) > maxTries
THEN
IF debuggerIfTfsError
THENCallDebugger["disk address is fillInDA after some retries"L]
ELSE{endReason ← dANotFilled; GOTO done};
IF dAs[pageNum+1] = eofDA THEN EXIT;
[]←TfsActOnPages[disk, NIL, dAs, filePtr↑, pageNum, pageNum, dcReadLD, @nmChars, dcReadLD, tfsBuff, DefaultTfsCleanupRtn, DefaultTfsErrorRtn, TRUE, 0!
BadErrorRtn => {endReason ← dANotFilled; GOTO done;};];
ENDLOOP;
EXITS
done=>
SELECT endReason FROM
illegalReason =>WriteLine["illegal End."L];
tridentError, hitEOF, dANotFilled =>errorTfs[endReason];
ENDCASE;
END;
};--WriteTfsPage

InitTrident: PUBLIC PROC[ddMgrPt: ddMgrPtr ← NIL, iDisk: tfsdskPtr] RETURNS [disk: tfsdskPtr]=
BEGIN

--
load microcode
IF ~uCodeLoaded THEN
{RamBoot["MesaSlotMc.br"! CantFindFile => GOTO noUcode;
FileLooksCrufty =>GOTO badUcode];
uCodeLoaded ← TRUE;};
IF iDisk # NIL THEN disk ← TfsCloseDisk[iDisk, TRUE];
disk ← TfsInit[TRUE,, ddMgrPt,];--initmode=TRUE, drive, ddMgr, freshDisk=FALSE

EXITS
noUcode => WriteLine["Can’t find file MesaSlotMc.br."L];
badUcode => WriteLine["Microcode file ""MesaSlotMc.br"" is malformed."L];
END;--
of InitTrident

InitTfsBuffer
: PROC[]=
{
IF tfsSeg # NIL THEN DeleteDataSegment[tfsSeg];
tfsSeg ← NewDataSegment[DefaultBase, (TFSwordsPerPage + PageSize-1)/PageSize];
tfsBuff ← SegmentAddress[tfsSeg];
pages ← [fillInDA, fillInDA, fillInDA, fillInDA, fillInDA];
dAsLength ← pagesLength;--this varies with the bits file writing
--in next line, we are assuming that Press.bits is contiguous!!!!
pages[2] ← firstVda + 1;--this will be accessed as dAs[pageNum+1] to set up dAs[pageNum]
dAsBase ← @pages[0];
pageNum ← 1;--this gets incremented before using
};
--InitTfsBuffer

GetTfsBandsBuffer:
PUBLIC PROC[] RETURNS[POINTER]=
{
RETURN[bandDiskBuffer]};--GetTfsBandsBuffer

ReleaseTfsBuffer: PROC[]=
{
DeleteDataSegment[tfsSeg];
tfsSeg ← NIL;
}
;--ReleaseTfsBuffer

InitScanBuffer
: PROC[pa: PageAttributes] RETURNS [coreAddress: POINTER]=
{
padding: CARDINAL;

IF scanSeg # NIL THEN DeleteDataSegment[scanSeg];
scanSeg ← NewDataSegment[DefaultBase, (pa.bitWc + PageSize-1)/PageSize];
coreAddress ← SegmentAddress[scanSeg];

scanInBand ← wordAddrInTfsBuffer ← 0;--init the scan line # we’re on
scanLength ← pa.bitWc;

--will never need more than bandWidth scans
IF (padding ← pa.firstScan MOD bandWidth) > 0 THEN
{Zero[coreAddress, pa.bitWc];
FOR i: CARDINAL IN [0..padding)
DO StoreScanLine[coreAddress]; ENDLOOP;
};

};
--InitScanBuffer

ReleaseScanBuffer
: PROC[aborting: BOOLEAN ← FALSE, address: POINTER, pa: PageAttributes]=
--Pads the first and last bands with blank scan lines if, for instance, firstScan is not = to a (multiple of bandWidth + 1)
BEGIN
padding: CARDINAL;

IF ~aborting THEN
{padding ← pa.lastScan MOD bandWidth;
IF padding # bandWidth-1 THEN
{Zero[address, pa.bitWc];
FOR i: CARDINAL IN [1..bandWidth-padding)--output bandWidth-padding-1 lines
DOStoreScanLine[address];
ENDLOOP};};

DeleteDataSegment[scanSeg];
scanSeg ← NIL;
END
;--ReleaseScanBuffer


WritePageGPage: PROC[pa: PageAttributes]=
--can raise errorTfs[tridentError]
{pageBuf: ARRAY[0..TFSwordsPerPage) OF WORD; --Plug in PageG info and write this buffer to disk
firstPage: POINTER TO FirstPage ← LOOPHOLE[@pageBuf[0]];
nmChars: CARDINAL ← BytesPerWord*TFSwordsPerPage;

dAs: DESCRIPTOR FOR ARRAY OF PAGE ← DESCRIPTOR[@pages[1], dAsLength];
dAs[1] ← firstVda;

Zero [@pageBuf[0], TFSwordsPerPage];

firstPage.nPages ← 1;
firstPage.pageGSize ← SIZE[PageG];
firstPage.printerMode ← (IF pa.scanDirection = portrait THEN 3 ELSE 8);
firstPage.password ← PressPassword;
firstPage.pageGs[0].FirstBand ← pa.firstScan/bandWidth;
firstPage.pageGs[0].LastBand ← pa.lastScan/bandWidth;
firstPage.pageGs[0].BitMargin ← pa.margin;
firstPage.pageGs[0].BitWc ← pa.bitWc;
firstPage.pageGs[0].BitPage ← 1;--i.e., first page after the firstPge
firstPage.pageGs[0].PageNumber ← 1;--i.e., from first page of Press file
firstPage.pageGs[0].BandWidth ← bandWidth;--so outputter can do right thing

[]← TfsActOnPages[disk, NIL, dAs, filePtr↑, 1, 1, dcWriteD, @nmChars, dcWriteD, @pageBuf[0], DefaultTfsCleanupRtn, DefaultTfsErrorRtn, TRUE, 0!
BadErrorRtn => GOTO done];

EXITS
done => errorTfs[tridentError];

};
--WritePageGPage


OpenPressBits: PROC[filePtr: POINTER TO FP]=
--This routine deletes the global ddMgr if it can’t find Press.bits on the Trident. It also deletes the disk object.
--Thus, this routine must be called before calling OpenPressBands, as that routine assumes this routine has already succeeded.
BEGIN
fileSys: CARDINAL ← 1;--TP0:sys 1


IF ddMgr = NIL THEN ddMgr ← TfsCreateDDmgr[];
disk ← InitTrident[ddMgr, disk];--loads disk object

IF disk = NIL THEN ERROR errorTfs[noTrident];

[, firstVda,] ← TfsOpenFile[disk, "Press.bits.", read, filePtr];--must fool Open with read. Only other option is create.
IF firstVda=0 AND disk.tfskd.model = 80 THEN --"not found" if not on 1st file system.
GOTO errorXit;


WHILE firstVda = 0 AND fileSys < 23 --check all filesystems on a T300
DO--drives 0-7 and 3 filesystems/drive
IF disk # NIL THEN
disk←LOOPHOLE[TfsCloseDisk[disk, TRUE]];--keep ddMgr, and make disk NIL
disk ← TfsInit[TRUE, BITOR[BITSHIFT[(fileSys MOD 3), 8], (fileSys/3)], ddMgr,];
fileSys ← fileSys + 1;
IF disk = NIL THEN LOOP;
[, firstVda, ] ← TfsOpenFile[disk, "Press.bits.", read, filePtr];
ENDLOOP;

IF firstVda = 0 THEN
GOTO errorXit;--not anywhere on T300

EXITS
errorXit =>
{IF disk # NIL THEN disk ← TfsCloseDisk[disk, FALSE];
ddMgr ← NIL;
ERROR errorTfs[cantFindFile]};
END;
--OpenPressBits

CloseServerConnection: PROC[]=
{
IF ~gotAJob THEN GOTO done;

EFTPFinishReceiving[!
EFTPNotReceiving => CONTINUE];--acknowledge to sender.
PupPackageDestroy[];
gotAJob ← pupPkgExtant ← connectionOpen ← FALSE;

EXITS
done => NULL;
};
--CloseServerConnection

TypeOutStatus
: PROC[dAs: DESCRIPTOR FOR ARRAY OF PAGE, pageNum, charsInPage: CARDINAL, beforeActOnPages: BOOLEAN ← TRUE]=
{--for debugging
i: CARDINAL;--debugging variable

IF ~dasMonitor THEN RETURN;
IF beforeActOnPages
THEN WriteLine["Before ActOnPages"L]
ELSE WriteLine["After ActOnPages"L];
WriteString["page number: "L];
WriteDecimal[pageNum]; WriteChar[CR];
IF beforeActOnPages
THEN {WriteString["Before ActOnPages -- chars received from GetAPage: "L];
WriteDecimal[charsInPage]; WriteChar[CR];};

WriteLine["dAs[0]..dAs[dAsLength] (length changes with page#)"];
FOR i IN [0..dAsLength) DO
WriteOctal[dAs[i]]; WriteChar[SP]; WriteChar [SP]; ENDLOOP;
WriteChar[CR]; WriteChar[CR];
};--
TypeOutStatus


--initialization (for debugging only)
--filePtr ← @fp; Use this if Mesa doesn’t allow startup assignment

END.
-- ReticlePressNetListener.mesa
-- Last Edited: October 27, 1981 4:35 PM By: GWilliams
-- added code to try for the next vda again if not filled by TfsActOnPages the first -- Last Edited: October 27, 1981 3:12 PM By: GWilliams
-- added debuggerIfTfsError
-- Last Edited: October 26, 1981 2:38 PM By: GWilliams
-- added check that filled-in DA is valid at GetBits & added EFTPFinishReceiving.
-- Last Edited: October 26, 1981 10:54 AM By: GWilliams
--added fileLengthReport
-- Last Edited: October 27, 1981 5:17 PM By: GWilliams
-- put check at end of GetBits to stop if not continuing
-- Last Edited: November 24, 1981 3:04 PM By: GWilliams
-- In middle of revamping to accept bits on a scan line basis rather than read a whole Press.bits file.
-- Last Edited: December 2, 1981 11:16 AM By: GWilliams
-- Back again - - took time out to help Starkweather & to write Performance appraisal.
-- Last Edited: December 8, 1981 6:03 PM By: GWilliams
-- Back again - - Press.fonts broke, now debugging.
-- Last Edited: December 9, 1981 4:38 PM By: GWilliams
-- Fixing OpenPressBits for when can’t find Press.bits on T300.
-- Last Edited: December 10, 1981 4:24 PM By: GWilliams
-- In InitTfsBuffer, was loading vda of 2nd page of bits file with firstVda.
-- Last Edited: December 21, 1981 3:49 PM By: GWilliams
-- Changed CloseServerConnection to not do EFTPFinishReceiving on closing.
-- Last Edited: December 21, 1981 5:04 PM By: GWilliams
-- Changed GetBits to ask for more data than needed in order to wait for sender disconnect.
-- Last Edited: December 31, 1981 3:17 PM By: GWilliams
-- Changed ordering of call on InitTfsBuffer and InitScanBuffer.
-- GetBits is called by Press.mesa
-- Last Edited: February 8, 1982 11:22 AM By: GWilliams
-- WritePageGPage now gets printerMode from pageAttributes record sent from client.
-- Last Edited: March 5, 1982 3:48 PM By: GWilliams
-- Added Press Bands code to read Cedar bands file entries and explode into press.bits.
-- Last Edited: March 8, 1982 1:59 PM By: GWilliams
-- Refining Bands code: clean up bits file disk object if fail in openning band sfile.
--March 19, 1982 converted to reticle maker version by Pier
--fixed bug in StoreScanLine, 4/1/82
-- Last Edited: April 2, 1982 1:39 PM By: Pier
-- created Reticle Band version.
-- Last Edited: April 14, 1982 2:00 PM By: GWilliams
-- Added possibility of cutting the bandWidth in interests of core.
-- Last Edited: April 15, 1982 3:18 PM By: GWilliams
-- Record bandwidth in PageG now.