-- NubControl.Mesa Edited by Sandman on Apr 3, 1979 3:19 PM
-- Edited for XMesa by Levin on April 16, 1979 6:11 PM
DIRECTORY
AltoFileDefs: FROM "altofiledefs" USING [CFA, FA, NullFP],
BcdOps: FROM "BcdOps" USING [BcdBase],
ControlDefs: FROM "controldefs" USING [
GFT, GlobalFrameHandle, NullGlobalFrame],
CoreSwapDefs: FROM "coreswapdefs" USING [CAbort, CantSwap],
DisplayDefs: FROM "displaydefs" USING [DisplayControl],
ImageDefs: FROM "imagedefs" USING [
AddFileRequest, FileRequest, ImageTime, MakeImage, StopMesa],
IODefs: FROM "iodefs" USING [
CR, DEL, LineOverflow, NewLine, NUL, ReadChar, ReadID, ReadNumber,
Rubout, SP, WriteChar, WriteOctal, WriteString],
LoaderOps: FROM "LoaderOps" USING [
FileNotFound, Load, New, VersionMismatch],
MiscDefs: FROM "miscdefs" USING [CallDebugger],
ProcessDefs: FROM "processdefs" USING [Aborted],
SegmentDefs: FROM "segmentdefs" USING [
LockFile, Read, ReleaseFile, UnlockFile],
StreamDefs: FROM "streamdefs" USING [
CreateByteStream, GetFA, JumpToFA, KeyStreams, Read, StreamHandle],
StringDefs: FROM "stringdefs" USING [
AppendChar, AppendString, EquivalentString, InvalidNumber,
StringBoundsFault],
TimeDefs: FROM "timedefs" USING [AppendDayTime, DefaultTime, UnpackDT];
NubControl: PROGRAM
IMPORTS CoreSwapDefs, DisplayDefs, ImageDefs, IODefs, LoaderOps,
MiscDefs, ProcessDefs, SegmentDefs, StreamDefs, StringDefs, TimeDefs
EXPORTS MiscDefs =
BEGIN
-- System Signals are converted to these to prevent NubCommand
-- from catching user generated signals
Delete: SIGNAL = CODE; -- nee Rubout
StringTooLong: ERROR = CODE; -- nee LineOverflow
BadFile: ERROR [badname: STRING] = CODE; -- nee FileNameError
BadVersion: SIGNAL [badname: STRING] = CODE; -- nee VersionMismatch
BadNumber: ERROR = CODE; -- nee InvalidNumber
GlobalFrameHandle: TYPE = ControlDefs.GlobalFrameHandle;
NullGlobalFrame: GlobalFrameHandle = ControlDefs.NullGlobalFrame;
useCommandLine, skipImage: BOOLEAN ← TRUE;
module: STRING ← [40];
defaultframe: GlobalFrameHandle ← NullGlobalFrame;
DoCommand: PROCEDURE =
BEGIN OPEN ControlDefs;
p: PROCESS;
f: GlobalFrameHandle;
IF skipImage THEN SkipImage[];
f ← IF useCommandLine THEN LoadSystem[] ELSE Command[];
IF f # NullGlobalFrame THEN
BEGIN
p ← FORK StartModule[LOOPHOLE[f]];
JOIN p;
END;
RETURN
END;
StartModule: PROCEDURE [f: PROGRAM] =
BEGIN
BEGIN
ENABLE ProcessDefs.Aborted, CoreSwapDefs.CAbort => CONTINUE;
IF ~LOOPHOLE[f, GlobalFrameHandle].started THEN START f ELSE RESTART f;
END;
RETURN
END;
Command: PROCEDURE RETURNS [GlobalFrameHandle] =
BEGIN OPEN IODefs;
nCommand: STRING = "New"L;
sCommand: STRING = "Start"L;
dCommand: STRING = "Debug"L;
qCommand: STRING = "Quit"L;
mCommand: STRING = "MakeImage"L;
c: CHARACTER;
f: GlobalFrameHandle;
DO
WriteEOL[]; WriteChar['>];
SELECT c←ReadChar[] FROM
'N,'n =>
BEGIN
WriteString[nCommand];
LoadModule[];
END;
'S,'s =>
BEGIN
WriteString[sCommand];
f ← getgframe[];
WriteEOL[];
RETURN[f];
END;
'D,'d =>
BEGIN
WriteString[dCommand];
confirm[];
MiscDefs.CallDebugger["You called?"L];
END;
'M,'m =>
BEGIN
WriteString[mCommand];
ImageDefs.MakeImage[getfilename[".image"L]];
END;
'Q,'q =>
BEGIN
WriteString[qCommand];
confirm[];
ImageDefs.StopMesa[];
END;
CR,SP => NULL;
ENDCASE =>
BEGIN
WriteChar[c];
WriteString[" Commands are:"L];
WriteChar[' ]; WriteString[nCommand];
WriteChar[' ]; WriteString[sCommand];
WriteChar[' ]; WriteString[dCommand];
WriteChar[' ]; WriteString[mCommand];
WriteChar[' ]; WriteString[qCommand];
END;
ENDLOOP;
END;
LoadModule: PROCEDURE =
BEGIN
name: STRING ← [40];
ext: STRING ← [10];
switches: STRING ← [10];
i: CARDINAL ← 0;
g: GlobalFrameHandle;
fn: STRING = " Filename: "L;
get: PROCEDURE RETURNS [c: CHARACTER] =
BEGIN
IF i = module.length THEN RETURN[IODefs.NUL];
c ← module[i];
i ← i + 1;
RETURN[c]
END;
IODefs.WriteString[fn];
IODefs.ReadID[module ! IODefs.Rubout => ERROR Delete;
IODefs.LineOverflow => ERROR StringTooLong];
GetToken[get, name, ext, switches];
IF ext.length = 0 THEN ext ← "bcd";
StringDefs.AppendChar[name, '.];
StringDefs.AppendString[name, ext];
InitSwitches[];
ProcessSwitches[switches];
g ← LoadNew[name, framelinks];
IF g # NullGlobalFrame THEN defaultframe ← g;
RETURN
END;
LoadNew: PROCEDURE [name: STRING, framelinks: BOOLEAN]
RETURNS [g: GlobalFrameHandle] =
BEGIN OPEN LoaderOps;
s: STRING = " -- "L;
bcd: BcdOps.BcdBase;
bcd ← Load[name ! BadFile, UNWIND => NULL; ANY => ERROR BadFile[name]];
g ← New[bcd, framelinks, FALSE
! BadFile, BadVersion, UNWIND => NULL;
VersionMismatch => BEGIN SIGNAL BadVersion[name]; RESUME END;
FileNotFound => ERROR BadFile[name];
ANY => ERROR BadFile[name]];
IODefs.WriteString[s];
IODefs.WriteOctal[g];
WriteEOL[];
RETURN
END;
getgframe: PROCEDURE RETURNS [f: GlobalFrameHandle] =
BEGIN OPEN ControlDefs, IODefs;
gf: STRING = " Global frame: "L;
ngf: STRING = " not a global frame!"L;
WriteString[gf];
f ← ReadNumber[defaultframe,8
! LineOverflow => ERROR StringTooLong;
Rubout => ERROR Delete;
StringDefs.InvalidNumber => ERROR BadNumber];
IF GFT[f.gfi].frame # f THEN
BEGIN WriteString[ngf]; SIGNAL CoreSwapDefs.CAbort END;
defaultframe ← f;
RETURN
END;
getfilename: PROCEDURE [defaultextension: STRING] RETURNS [STRING] =
BEGIN OPEN IODefs;
fn: STRING = " Filename: "L;
WriteString[fn];
ReadID[module ! Rubout => ERROR Delete;
LineOverflow => ERROR StringTooLong];
defaultext[module, defaultextension];
RETURN[module]
END;
defaultext: PROCEDURE [idstring: STRING, ext: STRING] =
BEGIN
i: CARDINAL;
FOR i IN [0..idstring.length) DO
IF idstring[i] = '. THEN EXIT;
REPEAT FINISHED =>
FOR i IN [0..ext.length) DO
StringDefs.AppendChar[idstring, ext[i]
! StringDefs.StringBoundsFault => ERROR StringTooLong];
ENDLOOP;
ENDLOOP;
END;
confirm: PROCEDURE =
BEGIN OPEN IODefs;
c: STRING = " [Confirm] "L;
WriteString[c];
DO
SELECT ReadChar[] FROM
CR => EXIT;
DEL => ERROR Delete;
ENDCASE => WriteChar['?];
ENDLOOP;
WriteChar[CR];
RETURN
END;
WriteEOL: PROCEDURE =
BEGIN OPEN IODefs;
IF ~NewLine[] THEN WriteChar[CR];
RETURN
END;
comcmRequest: short ImageDefs.FileRequest ← [
body: short[fill:, name: "Com.Cm."],
file: NIL,
access: SegmentDefs.Read,
link: ];
Done: SIGNAL = CODE;
debug, start, command, framelinks: BOOLEAN;
ProcessSwitches: PROCEDURE [s: STRING] =
BEGIN
i: CARDINAL;
inverse: BOOLEAN ← FALSE;
FOR i IN [0..s.length) DO
SELECT s[i] FROM
'c, 'C => BEGIN inverse ← FALSE; command ← TRUE END;
'd, 'D => BEGIN inverse ← FALSE; debug ← TRUE END;
's, 'S => IF inverse THEN inverse ← start ← FALSE ELSE start ← TRUE;
'l, 'L => BEGIN inverse ← FALSE; framelinks ← FALSE END;
'- => inverse ← TRUE;
ENDCASE => inverse ← FALSE;
ENDLOOP;
END;
InitSwitches: PROCEDURE =
BEGIN command ← debug ← FALSE; framelinks ← start ← TRUE; END;
GetToken: PROCEDURE [
get: PROCEDURE RETURNS [CHARACTER], token, ext, switches: STRING] =
BEGIN OPEN IODefs;
s: STRING;
c: CHARACTER;
token.length ← ext.length ← switches.length ← 0;
s ← token;
WHILE (c ← get[]) # NUL DO
SELECT c FROM
SP, CR =>
IF token.length # 0 OR ext.length # 0 OR switches.length # 0 THEN RETURN;
'. => s ← ext;
'/ => s ← switches;
ENDCASE => StringDefs.AppendChar[s, c
! StringDefs.StringBoundsFault => ERROR StringTooLong];
ENDLOOP;
RETURN
END;
cfa: AltoFileDefs.CFA;
CommandLineCFA: PUBLIC PROCEDURE RETURNS [POINTER TO AltoFileDefs.CFA] =
BEGIN
RETURN[@cfa]
END;
CleanUpCommandLine: PROCEDURE =
BEGIN
SegmentDefs.UnlockFile[comcmRequest.file];
SegmentDefs.ReleaseFile[comcmRequest.file];
comcmRequest.file ← NIL;
useCommandLine ← FALSE;
RETURN
END;
LoadSystem: PROCEDURE RETURNS [user: GlobalFrameHandle] =
BEGIN
BEGIN
ENABLE UNWIND => CleanUpCommandLine[];
InitSwitches[];
user ← LoadUser[@cfa.fa ! Done => GOTO done];
IF user # NullGlobalFrame THEN defaultframe ← user;
IF debug THEN MiscDefs.CallDebugger["You called?"L];
IF ~start THEN user ← NullGlobalFrame;
EXITS
done =>
BEGIN user ← NullGlobalFrame; CleanUpCommandLine[] END;
END;
RETURN
END;
LoadUser: PROCEDURE [fa: POINTER TO AltoFileDefs.FA]
RETURNS [user: GlobalFrameHandle] =
BEGIN OPEN IODefs, StreamDefs;
com: StreamHandle;
name: STRING ← [40];
ext: STRING ← [10];
switches: STRING ← [10];
get: PROCEDURE RETURNS [c: CHARACTER] =
BEGIN
IF com.endof[com] THEN RETURN[NUL];
RETURN[com.get[com]];
END;
com ← CreateByteStream[comcmRequest.file, Read];
user ← NullGlobalFrame;
BEGIN
StreamDefs.JumpToFA[com, fa ! ANY => GO TO finished];
GetToken[get, name, ext, switches];
IF name.length = 0 AND switches.length = 0 THEN GO TO finished;
StreamDefs.GetFA[com, fa];
com.destroy[com];
ProcessSwitches[switches];
IF name.length # 0 AND ~command THEN
BEGIN
IF ext.length = 0 THEN ext ← "bcd"L;
WriteEOL[]; WriteChar['>];
WriteString[name];
StringDefs.AppendChar[name, '.];
StringDefs.AppendString[name, ext];
user ← LoadNew[name, framelinks];
END;
IF command THEN ProcessSwitches[name];
EXITS
finished => BEGIN com.destroy[com ! ANY => CONTINUE]; SIGNAL Done; END;
END;
RETURN
END;
SkipImage: PROCEDURE =
BEGIN OPEN IODefs, StreamDefs;
com: StreamHandle;
name: STRING ← [40];
ext: STRING ← [10];
switches: STRING ← [10];
get: PROCEDURE RETURNS [c: CHARACTER] =
BEGIN
IF com.endof[com] THEN RETURN[NUL];
RETURN[com.get[com]];
END;
skipImage ← FALSE;
IF comcmRequest.file = NIL THEN
BEGIN
cfa.fp ← AltoFileDefs.NullFP;
useCommandLine ← FALSE;
RETURN
END;
cfa.fp ← comcmRequest.file.fp;
SegmentDefs.LockFile[comcmRequest.file];
InitSwitches[];
com ← CreateByteStream[comcmRequest.file, Read];
StreamDefs.GetFA[com, @cfa.fa];
GetToken[get, name, ext, switches];
IF StringDefs.EquivalentString[ext, "image"L] THEN
StreamDefs.GetFA[com, @cfa.fa];
com.destroy[com];
ProcessSwitches[switches];
IF debug THEN MiscDefs.CallDebugger["You called?"L];
END;
WriteHerald: PROCEDURE =
BEGIN OPEN TimeDefs;
h: STRING = "Alto/Mesa 5.0 [XM] of "L;
time: STRING ← [18];
AppendDayTime[time, UnpackDT[ImageDefs.ImageTime[]]];
time.length ← time.length - 3;
IODefs.WriteString[h]; IODefs.WriteString[time];
time.length ← 0;
AppendDayTime[time, UnpackDT[DefaultTime]];
time.length ← time.length - 3;
WriteEOL[]; IODefs.WriteString[time];
END;
ErrorName: TYPE = {XXX, file, number, toolong, nodebug, aborted, diffver};
WriteError: PROCEDURE [error: ErrorName] =
BEGIN
IODefs.WriteString[SELECT error FROM
file => "!File: "L,
number => "!Number"L,
toolong => "!String too long"L,
nodebug =>
"External Debugger not installed, type DEL to abort "L,
aborted => "...Aborted..."L,
diffver => " referenced in different versions"L,
ENDCASE => " XXX"L]
END;
-- Main body
START StreamDefs.KeyStreams; -- Start keyboard process
ImageDefs.AddFileRequest[@comcmRequest];
START DisplayDefs.DisplayControl;
STOP;
RESTART DisplayDefs.DisplayControl;
WriteHerald[];
DO OPEN IODefs; -- forever
DoCommand[
! Delete => BEGIN WriteError[XXX]; CONTINUE END;
CoreSwapDefs.CAbort => CONTINUE;
BadFile --[badname: STRING]-- =>
BEGIN
WriteEOL[];
WriteError[file];
WriteString[badname];
CONTINUE
END;
BadNumber =>
BEGIN WriteEOL[]; WriteError[number]; CONTINUE END;
StringTooLong =>
BEGIN WriteEOL[]; WriteError[toolong]; CONTINUE END;
CoreSwapDefs.CantSwap =>
BEGIN
WriteEOL[];
WriteError[nodebug];
UNTIL ReadChar[]=DEL DO WriteChar['?] ENDLOOP;
WriteError[aborted];
CONTINUE
END;
BadVersion --[badname: STRING]-- =>
BEGIN
WriteEOL[];
WriteError[file];
WriteString[badname];
WriteError[diffver];
RESUME
END;
UNWIND =>CONTINUE
];
ENDLOOP;
END..