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