-- SExecImpl.mesa; Edited by McGregor on April 12, 1982 1:29 pm DIRECTORY CVExecutive USING [CommandProc], Inline USING [LowHalf], IOStream USING [Close, CreateFileStream, Error, GetBlock, GetLength, Handle, PutFR, time], LongString, -- ComSoft>Public> Menus USING [AppendMenuEntry, MenuProc], PilotLoadStateOps, -- Loader> PrincOps, -- Mesa>Public> Process USING [Detach], Rope USING [Compare, Concat, Fetch, Ref, Size, Substr, Text], RopeInline USING [NewText], Runtime USING [GetBcdTime], SExecOps, TypeScript USING [CharProc, Create, GetLine, PutChar, PutRope, TS], UserProfile USING [String], UserTerminal USING [BlinkDisplay], ViewerTools USING [GetSelectedViewer, GetSelectionContents, SetSelection]; SExecImpl: PROGRAM IMPORTS Inline, IOStream, Menus, Process, Rope, RopeInline, Runtime, SExecOps, TypeScript, UserProfile, UserTerminal, ViewerTools EXPORTS CVExecutive, SExecOps = BEGIN OPEN TypeScript; maxKeys: CARDINAL = 32; nKeys: CARDINAL _ 0; Command: TYPE = RECORD [ key: Rope.Ref, proc: CVExecutive.CommandProc, doc: Rope.Ref ]; commands: ARRAY [0..maxKeys) OF Command; AddCommand: PUBLIC PROC [key: Rope.Ref, proc: CVExecutive.CommandProc, doc: Rope.Ref] = BEGIN IF nKeys TRUE, ENDCASE => FALSE]; END; Break: PROC [c: CHARACTER] RETURNS [BOOLEAN] = INLINE BEGIN RETURN[SELECT c FROM ';, 15C => TRUE, ENDCASE => FALSE]; END; IF offset>=size THEN RETURN["", offset]; WHILE offset=size THEN EXIT; char _ Rope.Fetch[rope, offset]; IF Break[char] THEN BEGIN IF offset=start THEN RETURN[";", offset+1] ELSE EXIT; END; IF Blank[char] THEN EXIT; offset _ offset+1; ENDLOOP; RETURN[Rope.Substr[rope, start, IF thruEnd THEN size ELSE offset-start], offset]; END; currentParams: PUBLIC Rope.Ref; Line: PROC [line: Rope.Ref, ts: TS] = BEGIN OPEN Rope; cmd, token: Ref _ NIL; offset: LONG INTEGER _ 0; first: BOOLEAN _ TRUE; didSomething: BOOLEAN _ TRUE; IF Size[line] > 0 THEN BEGIN WHILE didSomething DO [line, didSomething] _ Expand[line]; ENDLOOP; DO [token, offset] _ GetToken[line, offset]; IF Size[token] = 0 THEN BEGIN IF Size[cmd]#0 THEN ProcessCommand[cmd, ts]; EXIT; END; IF Fetch[token, 0] = '; THEN BEGIN IF Size[cmd]#0 THEN ProcessCommand[cmd, ts]; cmd _ NIL; first _ TRUE; LOOP; END; IF first THEN first _ FALSE ELSE cmd _ Concat[cmd, " "]; cmd _ Concat[cmd, token]; ENDLOOP; END; PutChar[ts, '@]; END; Expand: PROC [line: Rope.Ref] RETURNS [newLine: Rope.Ref, didSomething: BOOLEAN] = BEGIN OPEN Rope; token: Ref _ NIL; offset: LONG INTEGER _ 0; first: BOOLEAN _ TRUE; didSomething _ FALSE; IF Size[line] > 0 THEN DO [token, offset] _ GetToken[line, offset]; IF Size[token] = 0 THEN RETURN; IF Fetch[token, 0] = '; THEN BEGIN first _ TRUE; newLine _ Concat[newLine, ";"]; LOOP; END; IF first THEN first _ FALSE ELSE newLine _ Concat[newLine, " "]; IF Fetch[token, 0] = '@ THEN BEGIN exp: Ref _ IF Size[token]<2 THEN "" ELSE RopeFromFile[Substr[token, 1, Size[token]-1], anExecTS]; IF exp = NIL THEN EXIT ELSE token _ exp; didSomething _ TRUE; END; newLine _ Concat[newLine, token]; ENDLOOP; END; RopeFromFile: PROC [file: Rope.Ref, ts: TypeScript.TS] RETURNS [contents: Rope.Ref] = BEGIN fh: IOStream.Handle; found: BOOLEAN _ TRUE; length: LONG INTEGER; text: Rope.Text; fh _ IOStream.CreateFileStream[file, read, oldOnly ! IOStream.Error => {found _ FALSE; CONTINUE}]; IF ~found THEN BEGIN found _ TRUE; fh _ IOStream.CreateFileStream[Rope.Concat[file, ".cm"], read, oldOnly ! IOStream.Error => {found _ FALSE; CONTINUE}]; END; IF ~found THEN BEGIN PutRope[ts, "Couldn't expand: "]; PutRope[ts, file]; PutChar[ts, 15C]; RETURN[NIL]; END; length _ IOStream.GetLength[fh]; IF length > 10000 THEN BEGIN PutRope[ts, "File expansion is too long: "]; PutRope[ts, file]; PutChar[ts, 15C]; IOStream.Close[fh]; RETURN[NIL]; END; text _ RopeInline.NewText[Inline.LowHalf[length]]; [] _ IOStream.GetBlock[fh, LOOPHOLE[text]]; IOStream.Close[fh]; RETURN[text]; END; ProcessCommand: PROC [cmd: Rope.Ref, ts: TypeScript.TS] = BEGIN OPEN Rope; token: Ref; length, parseOffset: LONG INTEGER _ 0; [token, parseOffset] _ GetToken[cmd]; length _ Size[token]; [currentParams, ----] _ GetToken[cmd, parseOffset, TRUE]; FOR n: CARDINAL IN [0..nKeys) DO IF Compare[token, Substr[commands[n].key, 0, MIN[length, Size[commands[n].key]]], FALSE]=0 THEN {commands[n].proc[ts, currentParams]; EXIT}; REPEAT FINISHED => IF length>4 AND Compare[Substr[token, length-4, 4],".bcd",FALSE]=0 THEN SExecOps.Run[ts, token] -- run as a program ELSE IF SExecOps.CheckForFile[Rope.Concat[token, ".bcd"]] THEN SExecOps.Run[ts, Rope.Concat[token, ".bcd"]] ELSE SExecOps.Old[ts, token]; -- create new viewer ENDLOOP; PutChar[ts, 15C]; END; Help: PUBLIC CVExecutive.CommandProc = BEGIN PutRope[ts, "This exec expects a command followed by a list of arguments. When you type something that isn't recognised as a command keyword, the executive will try to run it as a program, otherwise it will try to create a new viewer using the name as a backing file. Current commands registered: "]; FOR n: CARDINAL IN [0..nKeys) DO PutRope[ts, commands[n].key]; IF Rope.Size[commands[n].key] < 3 THEN PutChar[ts, ' ]; IF Rope.Size[commands[n].key] < 7 THEN PutChar[ts, ' ]; PutRope[ts, " -- "]; PutRope[ts, commands[n].doc]; IF nKeys-n>1 THEN PutChar[ts, 15C]; ENDLOOP; END; LineEval: PROC = BEGIN DO Line[GetLine[anExecTS], anExecTS]; ENDLOOP; END; CompileHack: Menus.MenuProc = BEGIN sel: Rope.Ref _ ViewerTools.GetSelectionContents[]; IF sel = NIL OR Rope.Size[sel] > 30 THEN {UserTerminal.BlinkDisplay[]; RETURN}; IF Rope.Size[sel] <= 1 THEN sel _ ViewerTools.GetSelectedViewer[].name; sel _ Rope.Concat["Compile ", sel]; sel _ Rope.Concat[sel, " "]; IF ViewerTools.GetSelectedViewer[] # anExecTS THEN ViewerTools.SetSelection[anExecTS, NIL]; anExecTS.class.notify[anExecTS, LIST[sel]]; END; UserName: PUBLIC Rope.Ref _ UserProfile.String["User"]; UserPassword: PUBLIC Rope.Ref _ NIL; version: Rope.Ref = IOStream.PutFR["SExec of %t", IOStream.time[Runtime.GetBcdTime[]]]; anExecTS: PUBLIC TS _ Create["SExec", TRUE]; Menus.AppendMenuEntry[menu: anExecTS.menu, name: "Compile", proc: CompileHack, copy: TRUE]; PutRope[anExecTS, version]; PutRope[anExecTS, "; Type '?' for help. @"]; Process.Detach[FORK LineEval]; END.