-- File: PressInit.mesa: Mesa version of PressInit
-- Last Edited: November 18, 1981 4:50 PM By: GWilliams
--Fixed PressInit to OR rather than AND the filesys and drive.
DIRECTORY
AltoRam USING [CantFindFile, FileLooksCrufty],
InlineDefs USING[BITOR, BITSHIFT, COPY],
IODefs USING[CR, NUL, SP, TAB, ReadChar, WriteChar, WriteString, WriteLine],
PressDefs USING [PageG, PageGLength, PressPassword, RamBoot, serverMode, SlotInit, uCodeLoaded],
SegmentDefs USING[DataSegmentHandle, DefaultBase, DeleteDataSegment, DeleteFileSegment, FileHandle, FileSegmentHandle, NewFile, NewFileSegment, FileNameError, NewDataSegment, OldFileOnly, SegmentAddress, SwapIn, SwapOut, Unlock],
StreamDefs USING[NewByteStream, Read, StreamHandle],
StringDefs USING[AppendChar, StringToDecimal, UpperCase],
SystemDefs USING [AllocateHeapNode],
TridentDefs USING[BadErrorRtn, dcReadD, ddMgrPtr, DefaultTfsCleanupRtn, DefaultTfsErrorRtn, fillInDA, FP, PAGE, TfsActOnPages, tfsdskPtr, TfsCloseDisk, TfsCreateDDmgr, TfsDestroyDDMgr, TfsInit, TfsOpenFile, VDA];
PressInit: PROGRAM
IMPORTS AltoRam, InlineDefs, IODefs, PressDefs, SegmentDefs, StreamDefs, StringDefs, SystemDefs, TridentDefs
EXPORTS PressDefs=
--SHARES
BEGIN OPEN AltoRam, InlineDefs, IODefs, PressDefs, SegmentDefs, StreamDefs, StringDefs, SystemDefs, TridentDefs;

-- Types
AqSwitches: TYPE=RECORD[
length: INTEGER,
options: ARRAY[1..5]OF CHARACTER,
num: INTEGER];
Switches: TYPE = POINTER TO AqSwitches;
PressError: TYPE = {noUcode, badUcode, noTrident, noBitsFile, tridentError, badBitFile, badStateFile};
-- Public Pack Variables EXPORTED to PressDefs
copies: PUBLIC INTEGER ← 1;
invertMode: PUBLIC BOOLEAN ← FALSE;
reprint: PUBLIC BOOLEAN ← FALSE;
numPages: PUBLIC CARDINAL;
fp: FP;
filePtr: PUBLIC POINTER TO FP; --
empty at first, load as first line of Init (compiler bug)

pageGarray: PUBLIC POINTER TO ARRAY OF PageG;

--EXPORTED to PressDefs
nPrinterColors, portrait, printerDevice, printerMode, ResolutionB, ResolutionS, SLOTScanLength, SLOTScanMarginAdjust, SLOTBitMarginAdjust, SLOTDouble, SLOTTimeOut, printerMaxBitsPerScan, ScanLengthInches: PUBLIC INTEGER;

--Private Pack Variables
debug: BOOLEAN ← FALSE;
h:
StreamDefs.StreamHandle;
putBackChar: CHARACTER ← NUL;

--Signals and Errors. None of these gets out of this module.
segmentNotIn: ERROR = CODE;
BadPressStateFile: ERROR = CODE;
CantOpenTrident: ERROR = CODE;
CantFindPressBits: ERROR = CODE;
TridentError: ERROR = CODE;
InconsistentBitsFile: ERROR = CODE;

--
Procs

--Main routine:
-- 1) Get commands (NO LONGER - - October 23, 1981 3:27 PM )
-- 2) Load state from Press.state off model 31 disk.
--
3) Load the ram
--
4) Init the Trident and find press.bits
--
5) exit to perform Press Main loop
Init: PUBLIC PROC[] RETURNS [disk: tfsdskPtr ← NIL, firstVDA: VDA ← LOOPHOLE[0, VDA], goAhead: BOOLEAN ← FALSE]=

BEGIN

filePtr ← @fp;
--Read Com.cm before calling this stuff
IF ~GetPressState[!BadPressStateFile => GOTO badStateFile] THEN RETURN [ , , ];

--
load microcode if not already in.
IF ~uCodeLoaded THEN
{RamBoot["MesaSlotMc.br"! CantFindFile => GOTO noUcode;
FileLooksCrufty =>GOTO badUcode];
uCodeLoaded ← TRUE;};
--init the Trident and find Press.bits
[disk, firstVDA] ← InitTrident[!
CantOpenTrident => GOTO noTrident;
CantFindPressBits => GOTO noBitsFile;
TridentError => GOTO tridentError;
InconsistentBitsFile => GOTO badBitFile];
goAhead ← TRUE;--made it here, continue.

EXITS
noUcode => Scream[noUcode];
badUcode => Scream[badUcode];
noTrident => Scream[noTrident];
noBitsFile => Scream[noBitsFile];
tridentError => Scream[tridentError];
badBitFile => Scream[badBitFile];
badStateFile => Scream[badStateFile];
END;--Init

Scream
: PROC[error: PressError]=
{
SELECT error FROM
noUcode => WriteLine["Can’t find file MesaSlotMc.br."L];
badUcode => WriteLine["Microcode file ""MesaSlotMc.br"" is malformed."L];
noTrident => WriteLine["Can’t Init Trident, check it."L];
noBitsFile => WriteLine["Can’t find file ""Press.bits""."L];
tridentError => WriteLine["Sorry, Trident Hard Read Error."L];
badBitFile => WriteLine["Bits File is inconsistent."L];
badStateFile => WriteLine["Press.state is inconsistent."L];
ENDCASE;
WriteLine["Type any key to finish"];
[] ← ReadChar[];
};
--Scream


ReadCommandFile
: PUBLIC PROC[] RETURNS[okToProceed: BOOLEAN ← FALSE]=
--Raises no signals or errors
BEGIN
swIndex: INTEGER ← 1;
aqSwitches: AqSwitches←[0, [NUL, NUL, NUL, NUL, NUL], -1];
switches: Switches = @aqSwitches;
BEGIN

command: STRING ← [20];
switches.length ← 0;

IF serverMode THEN RETURN[TRUE];
ReadComInit[];-- open Com.cm etc.

UNTIL ReadCom[command, switches]--returns eof
DO
FOR swIndex IN [1..switches.length] DO
SELECT switches.options[swIndex] FROM
’N => invertMode ← TRUE;
’D => NULL;
ENDCASE => GOTO illegalComSwitch;
ENDLOOP;
IF debug THEN
{WriteString["Switches: "];
IF invertMode THEN WriteChar[’N] ELSE WriteString["None"]; WriteLine[""];
}; -- one line output per token
IF command[0] = ’R AND command[1] = ’E AND command[2] = ’P THEN
reprint ← TRUE;
IF command[0] = ’C AND command[1] = ’O AND command[2] = ’P THEN
copies ← switches.num;
IF command[0] = ’S AND command[1] = ’E AND command[2] = ’R THEN
serverMode ← TRUE;
IF copies < 1 THEN GOTO illegalCom;
ENDLOOP;

IF (~reprint AND ~ serverMode) THEN GOTO noCom;
h.destroy[h];--close file

okToProceed ← TRUE;
EXITS
illegalComSwitch => {WriteString["Illegal Switch: "];
WriteChar[switches.options[swIndex]];
WriteLine[""];
WriteLine["Type any key to finish"];
[]←ReadChar[]; h.destroy[h];};
illegalCom => {WriteLine["Illegal command Line"];
WriteLine["Type any key to finish"];
[]←ReadChar[]; h.destroy[h];};
noCom =>
{WriteLine["Reprint, Server & Copies are the only valid commands; /N the only switch"];
WriteLine["Type any character to finish"];
[]←ReadChar[]; h.destroy[h];};
END;
--for EXITS to be able to see switches

END;
--of ReadCommandFile

ReadCom: PROC[com: STRING, sw: Switches] RETURNS[eof: BOOLEAN ← FALSE]=
--This routine is called repeatedly until it returns true.
--Raises no Errors or Signals
{c: CHARACTER ← NUL;
nm: STRING ← [10];
com.length ← 0;
nm.length ← 0;

sw↑ ← [0, [NUL, NUL, NUL, NUL, NUL], -1];
UNTIL h.endof[h] DO--get command
c ← GetChar[];
SELECT c FROM
CR, ’/ => EXIT;
SP, TAB => {IF com.length#0 THEN EXIT ELSE LOOP}; --elim leading spaces
IN [’a..’z] => AppendChar[com, UpperCase[c]];
IN [’A..’Z] => AppendChar[com,c];
ENDCASE;
ENDLOOP;

IF c = ’/ THEN--get 1 switch only
{UNTIL h.endof[h] DO
c← GetChar[];
SELECT c FROM
SP, TAB => LOOP;
CR => EXIT;
ENDCASE => {sw.length ← sw.length + 1;
sw.options[1] ← UpperCase[c]; EXIT};
ENDLOOP;
}
ELSE--look for a number
{UNTIL h.endof[h] DO
SELECT c FROM
CR => EXIT;
SP, TAB => {c←GetChar[]; LOOP};
IN [’0..’9] => AppendChar[nm, c];
ENDCASE => {putBackChar ← c; EXIT};--save other chars for later scan
c←GetChar[];
ENDLOOP;
};

IF nm.length # 0 THEN sw.num ← StringToDecimal[nm];
IF com.length =0 AND h.endof[h] THEN eof ← TRUE;
}
;--ReadCom

ReadComInit
: PROC[]=
{
h ← NewByteStream["Com.cm", Read];
};--ReadComInit

GetChar: PROC[]RETURNS[ch: CHARACTER]=
{
IF putBackChar # NUL
THEN {ch ← putBackChar; putBackChar ← NUL}
ELSE ch ← h.get[h];
};
--GetChar


InitTrident
: PROC[] RETURNS [disk: tfsdskPtr ← NIL, firstVda: VDA]=
--firstVda is not initialized at declaration line because this routine fills it in on successful return
--and error returns (as signals) => value is undefined.

--Errors: CantOpenTrident CantFindPressBits TridentError InconsistentBitsFile
BEGIN
DAs: DESCRIPTOR FOR ARRAY OF PAGE;
ddMgr: ddMgrPtr;
fileSys: CARDINAL ← 1; --ignore this and go to fileSys 0 on first try
nmChars: CARDINAL ← 2048;
pages: ARRAY[0..4] OF PAGE ← [fillInDA, fillInDA, fillInDA, fillInDA, fillInDA];
tridentBuffer: POINTER TO ARRAY [0..1024) OF WORD ← NIL;
tridentBufferSegment: DataSegmentHandle;
vda: CARDINAL ← 0;

disk.tfskd.ddMgr ←ddMgr ← TfsCreateDDmgr[];--assign disk part due to bug in TfsCreateDDmgr
disk ← TfsInit[TRUE,,ddMgr,];--initmode=TRUE, drive, ddMgr, freshDisk=FALSE
IF disk = NIL THEN {TfsDestroyDDMgr[ddMgr]; ERROR CantOpenTrident;}; --pretty bad if drive zero doesn’t work.
[, vda,] ← TfsOpenFile[disk, "Press.bits.", read, filePtr];
WHILE vda = 0 AND fileSys < 23 --check all filesystems on a T300
DO--drives 0-7 and 3 filesystems/drive
IF disk.tfskd.model = 80 THEN EXIT; --"not found" if not on 1st file system.

[]←TfsCloseDisk[disk, TRUE];--keep ddMgr around
disk ← TfsInit[TRUE, BITOR[BITSHIFT[(fileSys MOD 3), 8], (fileSys/3)], ddMgr, ];
fileSys←fileSys+1;
IF disk=NIL THEN LOOP;
[, vda,] ← TfsOpenFile[disk, "Press.bits.", read, filePtr];
ENDLOOP;--of WHILE vda = 0 DO

IF vda # 0 THEN
{
tridentBufferSegment ← NewDataSegment[DefaultBase, 4];--get 1K
tridentBuffer ← SegmentAddress[tridentBufferSegment];
DAs ← DESCRIPTOR[@pages[1], 4];
DAs[1] ← vda;
[] ← TfsActOnPages[disk, NIL, DAs, filePtr↑, 1, 1, dcReadD, @nmChars, dcReadD, tridentBuffer, DefaultTfsCleanupRtn, DefaultTfsErrorRtn, TRUE, 0!
BadErrorRtn =>
{DeleteDataSegment[tridentBufferSegment];
[] ← TfsCloseDisk[disk, FALSE! BadErrorRtn => ERROR TridentError];
ERROR TridentError;
};]; --end of call to TfsActOnPages
numPages ← tridentBuffer[0];--get number of pages to print from this Press.bits
printerMode ← (IF portrait # 0 THEN 3 ELSE 8);
IF tridentBuffer[1] # PageGLength THEN {DeleteDataSegment[tridentBufferSegment]; ERROR InconsistentBitsFile;};
IF LOOPHOLE[tridentBuffer[2], INTEGER] # printerMode THEN
{DeleteDataSegment[tridentBufferSegment]; ERROR InconsistentBitsFile;};
IF tridentBuffer[3] # PressPassword THEN {DeleteDataSegment[tridentBufferSegment]; ERROR InconsistentBitsFile;};
pageGarray ← AllocateHeapNode[PageGLength*numPages];
COPY[@tridentBuffer[4], PageGLength*numPages, pageGarray];

DeleteDataSegment[tridentBufferSegment];
RETURN [disk, LOOPHOLE[vda, VDA]];
}
ELSE --here if didn’t find either on T80 or T300
{[] ← TfsCloseDisk[disk, FALSE]; --with "don’tFree"=FALSE => destroy ddMgr
ERROR CantFindPressBits;
};
END; --
of InitTrident

--Format of Press.State holds state for all types of printing devices supported by press:
--
Word#Function
--0
Creation date time stamp
--1
# of default switches
--2-40
the switches
--41-<a zero
3-word tables:
--
word>word 0: address of static
--
word1: length of block (if zero, then block is 1 word log)
--
word2: value of static
--only words 0-40 are used by this program. BCPL Press uses the tables on initialization.

GetPressState: PROC[] RETURNS[flag: BOOLEAN ← TRUE]=--default to say all is ok
--load global variables that we’ll need
--
The global variables will appear in the following order (after the default list):
--
DoMeter, DoFileMeter, DoFaultMeter, UseMicroCode, DoEtherReport, SoftScan, nPrinterColors, PaperSpeedInches, printerDevice, ResolutionB, ResolutionS, printerForward, portrait, SLOTScanLength, SLOTScanMarginAdjust, SLOTBitMarginAdjust, SLOTDouble, SLOTTimeOut, VersatecMsSl, VersatecFF, blockBitsFile, printerMaxBitsPerScan, PaperDimensionB, PaperDimensionS, ScanLengthInches, ScreenModulus, ScreenMagnitude, ScreenAngle, len -this is a block > 0 - (for indexing files), tridentUsed, BESizes -another block >0-, OverlayTable -block >0-
--all the settings that concern us are single variables, and consist of a subset of the above list. Raises BadPressStateFile, segmentNotIn
{fH: FileHandle;
fileSeg: FileSegmentHandle;
inCoreAddress: POINTER TO ARRAY [0..256) OF CARDINAL;
curEntry: INTEGER;

fH ← NewFile["Press.State", Read, OldFileOnly!
FileNameError => {WriteString["File Press.State is required"];
GOTO abortRoutine;};];
fileSeg ← NewFileSegment[fH, 1, 2, ];--point to one page; default access
SwapIn[fileSeg];--get it into core
inCoreAddress ← LOOPHOLE[SegmentAddress[fileSeg]];--find out where it is
IF inCoreAddress = NIL THEN segmentNotIn;

--pick up index that points past last word of defaults

curEntry ← inCoreAddress[1] +1+ 7 * 3;--"7" for nPrinterColors, (3=length of each entry)+1 for loc of offset amt

--now load globals
nPrinterColors ← inCoreAddress[curEntry];
curEntry ← curEntry + 6;
printerDevice ← inCoreAddress[curEntry];
curEntry ← curEntry + 3;
ResolutionB ← inCoreAddress[curEntry];
curEntry ← curEntry + 3;
ResolutionS ← inCoreAddress[curEntry];
curEntry ← curEntry + 6;
portrait ← inCoreAddress[curEntry];
curEntry ← curEntry + 3;
SLOTScanLength ← inCoreAddress[curEntry];
curEntry ← curEntry + 3;
SLOTScanMarginAdjust ← inCoreAddress[curEntry];
curEntry ← curEntry + 3;
SLOTBitMarginAdjust ← inCoreAddress[curEntry];
curEntry ← curEntry + 3;
SLOTDouble ← inCoreAddress[curEntry];
curEntry ← curEntry + 3;
SLOTTimeOut ← inCoreAddress[curEntry];
curEntry ← curEntry + 12;
printerMaxBitsPerScan ← inCoreAddress[curEntry];
curEntry ← curEntry + 9;
ScanLengthInches ← inCoreAddress[curEntry];


Unlock[fileSeg];
SwapOut[fileSeg];
DeleteFileSegment[fileSeg];--calls ReleaseFile
IF nPrinterColors # LOOPHOLE[inCoreAddress[27+2]] OR--check for a little consistency
printerDevice # LOOPHOLE[inCoreAddress[5+2]] OR
~(printerDevice IN [1..9]) THEN BadPressStateFile;
EXITS
abortRoutine => RETURN[FALSE];--error!
};
--of GetPressState

PrintInit: PUBLIC PROC[] =
{
--
this routine would normally select on which device we’re running and init that device.
--However, just init the slot.
SlotInit[];
};
--PrintInit

END.
-- PressInit.mesa
LOG
Time: May 15, 1981 3:55 PMBy: Glen WilliamsAction: Created.
-- Last Edited: September 3, 1981 12:58 PM By: GWilliams
-- Last Edited: October 23, 1981 3:25 PM By: GWilliams
--changed ReadCommandFile to look for server switch, and make it public.
-- Last Edited: November 4, 1981 3:21 PM By: GWilliams
--dropped the WriteLine["Bit Flinger"]; changed # 11 to # PageGLength @InitTrident
-- Last Edited: November 18, 1981 10:17 AM By: GWilliams
--had given Press.bits. to tfsOpenfile, but then gave it Press.bits on a retry. Tfs blew up.