-- TJaMImpl.mesa
-- Last changed by Bill Paxton, 20-Oct-81 14:21:56
DIRECTORY
JaMBasic,
JaMInternal,
JaMOps,
Ascii USING [CR],
Directory USING [Error, Lookup],
File USING [Capability],
Heap USING [systemZone],
Process USING [Detach],
Runtime USING [CallDebugger, ConfigError, IsBound, LoadConfig],
Storage USING [String, FreeString],
StreamDefs;
TJaMImpl: MONITOR
IMPORTS JaMOps, Directory, Heap, Process, Runtime, Storage, TTY, Exec
EXPORTS TJaM = {
OPEN StreamDefs, JaMOps, JaMInternal, JaMBasic;
zone: UNCOUNTED ZONE = Heap.systemZone;
prompt,start,badfile,badname,badversion: name Object;
version: STRING ← "Tioga JaM of 16-Oct-81";
line: STRING ← NIL;
index: CARDINAL ← 0;
running: BOOLEAN ← FALSE; -- this is the monitor data
quit: BOOLEAN ← FALSE;
Quit: PROC[frame: Frame] = {
quit ← TRUE;
Stop[frame];
};
-- ***** BCD procs
LoadBCD: PROC[frame: Frame] = { BCDLoader[frame,FALSE] };
-- Expects opstk: (bcdFileName)
-- Loads and STARTS the configuration in bcdFileName
DebugBCD: PROC[frame: Frame] = { BCDLoader[frame,TRUE] };
-- Expects opstk: (bcdFileName)
-- Like LoadBCD, but invokes the debugger before STARTing
BCDLoader: PROC[frame: Frame, debug: BOOLEAN] = {
Append: PROC[s,t: STRING] = {
FOR i: CARDINAL IN[0..t.length) WHILE s.length<s.maxlength DO
s[s.length] ← t[i]; s.length ← s.length + 1 ENDLOOP };
name: STRING ← [80];
ext: STRING ← ".bcd"L;
extended: BOOLEAN ← FALSE;
file: File.Capability;
prog: PROGRAM ← NIL;
string: string Object ← PopString[frame.opstk];
IF (string.length+ext.length)>name.maxlength THEN GOTO BadName
ELSE StringText[string,name];
file ← Directory.Lookup[name !
Directory.Error => SELECT type FROM
fileNotFound => IF extended THEN GOTO BadName
ELSE { Append[name,ext]; extended ← TRUE; RETRY };
ENDCASE => GOTO BadName];
prog ← Runtime.LoadConfig[file: file, offset: 1 !
Runtime.ConfigError => SELECT type FROM
versionMismatch => GOTO BadVersion;
ENDCASE => GOTO BadFile];
IF debug THEN {
message: STRING ← [100];
Append[message,"JaM: Just loaded "];
Append[message,name];
Runtime.CallDebugger[message];
};
IF Runtime.IsBound[prog] THEN START prog;
EXITS
BadFile => ERROR Error[badfile];
BadName => ERROR Error[badname];
BadVersion => ERROR Error[badversion];
};
-- ***** I/O procs
JPrint: PROC[frame: Frame] = {
string: string Object ← PopString[frame.opstk];
Put: PROC[c: CHARACTER] RETURNS[BOOLEAN] = {
abort: BOOLEAN ← TTY.UserAbort[];
IF abort THEN { TTY.ResetUserAbort[]; SetAbort[frame,TRUE] }
ELSE TTY.PutChar[tty,c];
RETURN[abort] };
StringForAll[string,Put];
};
-- ***** Initialization
InstallJaMPilot: PROC[why: InstallReason, frame: Frame] = { SELECT why FROM
register => {
found: BOOLEAN;
badfile ← MakeName[".badfile"L];
badname ← MakeName[".badname"L];
badversion ← MakeName[".badversion"L];
prompt ← MakeName[".prompt"L];
start ← MakeName[".start"L];
RegisterExplicit[frame,".print"L,JPrint];
RegisterExplicit[frame,".quit"L,Quit];
RegisterExplicit[frame,".loadbcd"L,LoadBCD];
RegisterExplicit[frame,".debugbcd"L,DebugBCD];
Def[frame,prompt,MakeString["(*).print"L,X]];
Def[frame,MakeName[".version"L],MakeString[version]];
Def[frame, undefname, MakeString["(Undefined name - .undefname: ).print
( ).cvis .print"L,X]];
[found,] ← TryToLoad[frame,start];
IF NOT found THEN Def[frame,start,MakeString[".version .print (
).print"L,X]];
};
ENDCASE;
};
LineReset: PROC[s: StreamHandle] = { index ← 0 };
LineGet: PROC[s: StreamHandle] RETURNS[UNSPECIFIED] = {
i: CARDINAL ← index;
IF i<line.length THEN { index ← i + 1; RETURN[line[i]] }
ELSE RETURN[0C];
};
LinePutback: PROC[s: StreamHandle, x: UNSPECIFIED] = {
IF index>0 THEN index ← index - 1;
};
LineEndof: PROC[s: StreamHandle] RETURNS[BOOLEAN] = {
RETURN[index>=line.length];
};
NoopPut: PROC[s: StreamHandle, x: UNSPECIFIED] = { };
NoopDestroy: PROC[s: StreamHandle] = { };
EndLine: PROC[c: CHARACTER] RETURNS[BOOLEAN] = {
IF c=Ascii.CR THEN RETURN[LineComplete[line]] ELSE RETURN[FALSE] };
DoJaM: ENTRY PROC = {
ENABLE UNWIND => NULL;
IF running THEN TTY.PutString[Exec.w,"JaM is already running."L]
ELSE { OPEN Exec;
TTY.PutString[w,"Starting "]; TTY.PutString[w,version]; TTY.PutString[w,"..."L];
-- Grab the rest of the command line now, before it goes away
line ← Storage.String[MAX[200,commandLine.s.length-commandLine.i]];
WHILE commandLine.i<commandLine.s.length DO
line[line.length] ← commandLine.s[commandLine.i];
line.length ← line.length + 1; commandLine.i ← commandLine.i + 1;
ENDLOOP;
Process.Detach[FORK RunJaM[]];
running ← TRUE;
};
};
RunJaM: PROC = {
frame: Frame;
s: StreamHandle ← zone.NEW[StreamObject ← [
reset: LineReset, get: LineGet, putback: LinePutback, endof: LineEndof,
put: NoopPut, destroy: NoopDestroy, data: NIL]];
stream: stream Object;
tty ← TTY.Create["JaM.log"L];
StartJaM[];
frame ← defaultFrame;
{ ENABLE ABORTED => CONTINUE;
-- do start macro
Execute[frame,start];
-- do command line
s.reset[s]; stream ← MakeStream[s];
stream.tag ← X; Execute[frame,stream];
-- The Main Loop
quit ← FALSE;
UNTIL quit DO
Execute[frame,prompt];
[] ← TTY.GetEditedString[tty,line,EndLine,TRUE !
TTY.LineOverflow => IF s=line THEN {
new: STRING ← Storage.String[s.maxlength+s.maxlength/2];
FOR i: CARDINAL IN[0..s.length) DO new[i] ← s[i] ENDLOOP;
new.length ← s.length; line ← new; Storage.FreeString[s];
RESUME[new] };
TTY.Rubout => { TTY.PutLine[tty," XXX"L]; LOOP }];
TTY.PutCR[tty];
s.reset[s]; stream ← MakeStream[s];
stream.tag ← X; Execute[frame,stream];
ENDLOOP;
};
StopJaM[];
TTY.Destroy[tty];
Storage.FreeString[line];
running ← FALSE;
};
-- Initialization
Install[InstallJaMPilot];
}.