-- JaMTajoImpl.mesa
-- Last changed by Doug Wyatt, 23-Oct-81 10:42:23
DIRECTORY
JaMBasic,
JaMInternal,
JaMOps,
JaMTajo,
JaMVM,
JaMFnsDefs USING [PushInteger],
Ascii USING [CR],
Directory USING [Error, Lookup],
File USING [Capability],
Heap USING [systemZone],
Process USING [Abort, Detach, EnableAborts],
Runtime USING [CallDebugger, ConfigError, IsBound, LoadConfig],
Storage USING [String, FreeString],
StreamDefs,
PilotLoaderOps USING [VersionMismatch],
Tool,
ToolWindow,
TajoCedarSwap USING [WhereAmI],
FormSW,
TTYSW,
Put,
UserInput,
Window;
JaMTajoImpl: MONITOR
IMPORTS
JaMOps, JaMVM, JaMFnsDefs,
Directory, Heap, Process, Runtime, Storage,
PilotLoaderOps, TajoCedarSwap,
Tool, ToolWindow, FormSW, TTYSW, Put, UserInput
EXPORTS
JaMTajo
= {
OPEN TajoPut:Put, StreamDefs, JaMOps, JaMInternal, JaMBasic;
Button: TYPE = JaMTajo.Button;
zone: UNCOUNTED ZONE = Heap.systemZone;
version: STRING ← "JaM of 22-Oct-81";
prompt,start,badfile,badname,badversion: name Object;
buttonName: ARRAY Button OF name Object;
myframe: Frame ← NIL;
State: TYPE = {idle, busy};
state: State ← idle;
readyForInput: CONDITION;
somethingToDo: CONDITION;
objectToDo: Object; -- the object to be executed
tool: Window.Handle ← NIL;
formSW,ttySW: Window.Handle ← NIL;
quit: BOOLEAN ← FALSE;
Quit: PROC[frame: Frame] = {
quit ← TRUE; Stop[frame];
};
CallDebugger: PROC[frame: Frame] = {
Runtime.CallDebugger["JaM executed .calldebugger"L];
};
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;
-- The following awful crock brought to you by the purveyors of CedarLoaderCore...
PilotLoaderOps.VersionMismatch => GOTO BadVersion];
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];
};
JPrint: PROC[frame: Frame] = {
string: string Object ← PopString[frame.opstk];
Proc: PROC[c: CHARACTER] RETURNS[BOOLEAN] = {
abort: BOOLEAN ← GetAbort[frame];
IF NOT abort THEN TajoPut.Char[ttySW,c];
RETURN[abort] };
IF tool=NIL THEN RETURN; -- running on cedar side
StringForAll[string,Proc];
};
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];
buttonName[rd] ← MakeName[".reddown"L];
buttonName[ru] ← MakeName[".redup"L];
buttonName[yd] ← MakeName[".yellowdown"L];
buttonName[yu] ← MakeName[".yellowup"L];
buttonName[bd] ← MakeName[".bluedown"L];
buttonName[bu] ← MakeName[".blueup"L];
RegisterExplicit[frame,".print"L,JPrint];
RegisterExplicit[frame,".loadbcd"L,LoadBCD];
RegisterExplicit[frame,".debugbcd"L,DebugBCD];
RegisterExplicit[frame,".calldebugger"L,CallDebugger];
RegisterExplicit[frame,".quit"L,Quit];
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;
};
--DoJaM: PROC = {
-- 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[]];
-- };
RunJaM: PROC = {
WaitForSomethingToDo: ENTRY PROC = {
WHILE state=idle DO WAIT somethingToDo ENDLOOP;
};
NotifyReadyForMore: ENTRY PROC = {
state ← idle; NOTIFY readyForInput;
};
lineLoop: PROCESS ← NIL;
StartJaM["JaM.VM"L];
myframe ← defaultFrame;
quit ← FALSE;
-- do start macro
Execute[myframe,start];
-- do command line
-- s.reset[s]; stream ← MakeStream[s];
-- stream.tag ← X; Execute[myframe,stream];
Process.Detach[lineLoop ← FORK LineLoop[]];
state ← idle;
UNTIL quit DO
WaitForSomethingToDo[!ABORTED => { quit ← TRUE; EXIT }];
Execute[myframe,objectToDo];
NotifyReadyForMore[];
ENDLOOP;
Process.Abort[lineLoop];
myframe ← NIL;
StopJaM[];
IF tool# NIL THEN ToolWindow.Destroy[tool];
};
Do: ENTRY PROC[ob: Object] = {
UNTIL state=idle DO WAIT readyForInput ENDLOOP;
objectToDo ← ob; state ← busy; NOTIFY somethingToDo;
UNTIL state=idle DO WAIT readyForInput ENDLOOP;
};
LineLoop: PROC = {
line: STRING ← Storage.String[200];
index: CARDINAL ← 0;
Reset: PROC[s: StreamHandle] = { index ← 0 };
Get: PROC[s: StreamHandle] RETURNS[UNSPECIFIED] = {
i: CARDINAL ← index;
IF i<line.length THEN { index ← i + 1; RETURN[line[i]] }
ELSE RETURN[0C] };
Putback: PROC[s: StreamHandle, x: UNSPECIFIED] = {
IF index>0 THEN index ← index - 1 };
Endof: PROC[s: StreamHandle] RETURNS[BOOLEAN] = {
RETURN[index>=line.length] };
Put: PROC[s: StreamHandle, x: UNSPECIFIED] = { };
Destroy: PROC[s: StreamHandle] = { };
sobject: StreamObject ← [reset: Reset, get: Get, putback: Putback,
endof: Endof, put: Put, destroy: Destroy, data: NIL];
stream: StreamHandle ← @sobject;
EndLine: PROC[c: CHARACTER] RETURNS[BOOLEAN] = {
IF c=Ascii.CR THEN RETURN[LineComplete[line]] ELSE RETURN[FALSE] };
IF ttySW=NIL THEN RETURN;
UNTIL quit DO
Do[prompt];
[] ← TTYSW.GetEditedString[ttySW,line,EndLine,TRUE !
TTYSW.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] };
TTYSW.Rubout => { TajoPut.Line[ttySW," XXX"L]; line.length ← 0; CONTINUE };
ANY => EXIT];
IF quit THEN EXIT;
TajoPut.CR[ttySW]; index ← 0;
Do[MakeStream[stream,X]];
ENDLOOP;
Storage.FreeString[line];
};
MouseProc: TYPE = JaMTajo.MouseProc;
mouseProc: MouseProc ← DefaultMouseProc;
DefaultMouseProc: PROC[x,y: INTEGER] = {
JaMFnsDefs.PushInteger[x];
JaMFnsDefs.PushInteger[y];
};
SetMouseProc: PUBLIC PROC[new: MouseProc] RETURNS[MouseProc] = {
old: MouseProc ← mouseProc;
mouseProc ← new; RETURN[old];
};
DoButton: PUBLIC ENTRY PROC[button: Button, x,y: INTEGER] = {
IF state#idle THEN RETURN; -- ignore buttons if not idle
mouseProc[x,y]; -- push transformed coordinates
objectToDo ← buttonName[button];
state ← busy; NOTIFY somethingToDo;
};
-- Tajo stuff
InitTool: PROC = {
IF TajoCedarSwap.WhereAmI[] = cedar THEN RETURN;
tool ← Tool.Create[
makeSWsProc: MakeSWs, initialState: active,
clientTransition: ClientTransition, name: version];
ToolWindow.SetTinyName[tool,"JaM"L];
};
AcceptTypeInFrom: PUBLIC PROC[w: Window.Handle] = {
IF ttySW=NIL THEN RETURN;
UserInput.CreateIndirectStringInOut[from: w, to: ttySW];
UserInput.SetKeyPNR[w, keyboard, UserInput.TypeInPNR];
UserInput.SetCursorPNR[w, UserInput.TypeInCursorPNR];
};
ClientTransition: ToolWindow.TransitionProcType = {
IF old=active AND new#active THEN JaMVM.Check[];
};
logName: STRING ← [20];
MakeSWs: Tool.MakeSWsProc = {
Tool.UnusedLogName[unused: logName, root: "JaM.log"L];
formSW ← Tool.MakeFormSW[window: window, formProc: MakeForm];
ttySW ← Tool.MakeTTYSW[window: window, name: logName];
};
MakeForm: FormSW.ClientItemsProcType = { OPEN FormSW;
nItems: CARDINAL = 2;
items ← AllocateItemDescriptor[nItems];
items[0] ← CommandItem[tag: "Interrupt"L,
place: newLine, proc: InterruptButton];
items[1] ← StringItem[tag: "Logged on"L,
place: nextPlace, string: @logName, readOnly: TRUE];
RETURN[items: items, freeDesc: TRUE];
};
InterruptButton: FormSW.ProcType = {
IF myframe#NIL THEN SetAbort[myframe,TRUE];
};
-- Initialization
Install[InstallJaMPilot];
Process.EnableAborts[@somethingToDo];
InitTool[];
Process.Detach[FORK RunJaM[]];
}.