-- JaMTajoImpl.mesa -- Last changed by Doug Wyatt, 24-Feb-82 18:13:55 DIRECTORY JaMBasic, JaMInternal, JaMOps, JaMTajo, JaMVM, JaMFnsDefs USING [PushInteger], StreamDefs, Ascii USING [CR], Directory USING [Error, Lookup], File USING [Capability], Heap USING [systemZone], Process USING [Abort, Detach, EnableAborts], Runtime USING [CallDebugger, ConfigError, GetBcdTime, IsBound, LoadConfig], Storage USING [String, FreeString], Time USING [Append, Unpack], TTY USING [PutString], PilotLoaderOps USING [VersionMismatch], Exec USING [AddCommand, commandLine, w], Tool, ToolWindow, FormSW, TTYSW, Put, UserInput, Window; JaMTajoImpl: MONITOR IMPORTS JaMOps, JaMVM, JaMFnsDefs, Directory, Heap, Process, Runtime, Storage, Time, TTY, PilotLoaderOps, Exec, Tool, ToolWindow, FormSW, TTYSW, Put, UserInput EXPORTS JaMTajo, StreamDefs = { OPEN TajoPut:Put, StreamDefs, JaMOps, JaMInternal, JaMBasic; Button: TYPE = JaMTajo.Button; zone: UNCOUNTED ZONE = Heap.systemZone; version: STRING ← "JaM of dd-mmm-yy hh:mm "; 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; dsObject: StreamObject ← [reset: DReset, get: DGet, putback: DPutback, put: DPut, endof: DEndof, destroy: DDestroy, data: NIL]; ds: StreamHandle ← @dsObject; GetDefaultDisplayStream: PUBLIC PROC RETURNS[StreamHandle] = { RETURN[ds] }; DReset: PROC[StreamHandle] = { }; DGet: PROC[StreamHandle] RETURNS[CHARACTER] = { RETURN[0C] }; DPutback: PROC[StreamHandle,CHARACTER] = { }; DPut: PROC[s: StreamHandle, c: CHARACTER] = { IF ttySW#NIL THEN TajoPut.Char[ttySW,c] }; DEndof: PROC[StreamHandle] RETURNS[BOOLEAN] = { RETURN[FALSE] }; DDestroy: PROC[StreamHandle] = { }; line: STRING ← NIL; lineIndex: CARDINAL ← 0; LReset: PROC[s: StreamHandle] = { lineIndex ← 0 }; LGet: PROC[s: StreamHandle] RETURNS[UNSPECIFIED] = { i: CARDINAL ← lineIndex; IF i<line.length THEN { lineIndex ← i + 1; RETURN[line[i]] } ELSE RETURN[0C] }; LPutback: PROC[s: StreamHandle, x: UNSPECIFIED] = { IF lineIndex>0 THEN lineIndex ← lineIndex - 1 }; LEndof: PROC[s: StreamHandle] RETURNS[BOOLEAN] = { RETURN[lineIndex>=line.length] }; LPut: PROC[s: StreamHandle, x: UNSPECIFIED] = { }; LDestroy: PROC[s: StreamHandle] = { }; lineObject: StreamObject ← [reset: LReset, get: LGet, putback: LPutback, endof: LEndof, put: LPut, destroy: LDestroy, data: NIL]; lineStream: StreamHandle ← @lineObject; jamStarted: BOOLEAN ← FALSE; JaMExecCommand: PROC = { OPEN Exec; IF jamStarted THEN { TTY.PutString[w,"JaM has already been started."L]; RETURN; }; jamStarted ← TRUE; -- Allocate line, and 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[]]; }; 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 }; fname: 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)>fname.maxlength THEN GOTO BadName ELSE StringText[string,fname]; file ← Directory.Lookup[fname ! Directory.Error => SELECT type FROM fileNotFound => IF extended THEN GOTO BadName ELSE { Append[fname,ext]; extended ← TRUE; RETRY }; ENDCASE => GOTO BadName]; prog ← Runtime.LoadConfig[file: file, offset: 1 ! Runtime.ConfigError => GOTO BadFile; PilotLoaderOps.VersionMismatch => { Push[frame.opstk,MakeString[name]]; -- push name of offending interface Push[frame.opstk,MakeString[fname]]; -- push name of file being loaded GOTO BadVersion}]; IF debug THEN { message: STRING ← [100]; Append[message,"JaM: Just loaded "]; Append[message,fname]; Runtime.CallDebugger[message]; }; IF Runtime.IsBound[prog] THEN START prog; EXITS BadFile => ERROR Error[badfile]; BadName => ERROR Error[badname]; BadVersion => ERROR Error[badversion,FALSE]; }; JPrint: PROC[frame: Frame] = { string: string Object ← PopString[frame.opstk]; Proc: PROC[c: CHARACTER] RETURNS[BOOLEAN] = { abort: BOOLEAN ← GetAbort[frame]; IF NOT abort THEN ds.put[ds,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; }; RunJaM: PROC = { WaitForSomethingToDo: ENTRY PROC = { WHILE state=idle DO WAIT somethingToDo ENDLOOP; }; NotifyReadyForMore: ENTRY PROC = { state ← idle; BROADCAST readyForInput; }; lineLoop: PROCESS ← NIL; StartJaM[vmname: "JaM.VM"L, maxPages: 2000]; myframe ← defaultFrame; quit ← FALSE; -- do start macro Execute[myframe,start !ABORTED => CONTINUE]; -- do command line IF line.length>0 THEN { objectToDo ← MakeStream[lineStream,X]; Execute[myframe,objectToDo !ABORTED => CONTINUE]; line.length ← 0; }; Process.Detach[lineLoop ← FORK LineLoop[]]; state ← idle; UNTIL quit DO WaitForSomethingToDo[]; Execute[myframe,objectToDo !ABORTED => CONTINUE]; NotifyReadyForMore[]; ENDLOOP; Process.Abort[lineLoop]; myframe ← NIL; StopJaM[]; Storage.FreeString[line]; IF tool# NIL THEN ToolWindow.Destroy[tool]; }; Do: ENTRY PROC[ob: Object] = { UNTIL state=idle DO WAIT readyForInput ENDLOOP; objectToDo ← ob; state ← busy; BROADCAST somethingToDo; UNTIL state=idle DO WAIT readyForInput ENDLOOP; }; LineLoop: PROC = { EndLine: PROC[c: CHARACTER] RETURNS[BOOLEAN] = { IF c=Ascii.CR THEN RETURN[LineComplete[line]] ELSE RETURN[FALSE] }; UNTIL quit OR ttySW=NIL 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]; lineIndex ← 0; Do[MakeStream[lineStream,X]]; ENDLOOP; }; 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; BROADCAST somethingToDo; }; -- Tajo stuff InitTool: PROC = { -- IF TajoCedarSwap.WhereAmI[] = cedar THEN RETURN; tool ← Tool.Create[ makeSWsProc: MakeSWs, initialState: active, clientTransition: ClientTransition, name: version, initialBox: [[500, 40], [464, 380]]]; 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 = 3; items ← AllocateItemDescriptor[nItems]; items[0] ← CommandItem[tag: "Interrupt"L, place: newLine, proc: InterruptButton]; items[1] ← CommandItem[tag: "CheckVM"L, place: nextPlace, proc: CheckVMButton]; items[2] ← 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]; }; CheckVMButton: FormSW.ProcType = { JaMVM.Check[]; }; -- Initialization version.length ← 7; Time.Append[version, Time.Unpack[Runtime.GetBcdTime[]]]; Install[InstallJaMPilot]; Process.EnableAborts[@somethingToDo]; InitTool[]; Exec.AddCommand["JaM"L,JaMExecCommand]; }. Wyatt 7-Nov-81 14:20:34 add CheckVM button ENABLE ABORTED for all of main loop in RunJaM Wyatt 19-Feb-82 10:57:40 better handling of VersionMismatch specify initialBox for Tool.Create Wyatt 24-Feb-82 18:13:12 no longer refers to TajoCedarSwap