-- 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[]]; }.