-- 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, -- <APilot>ComSoft>Public>
Menus USING [AppendMenuEntry, MenuProc],
PilotLoadStateOps, -- <CedarLang>Loader>
PrincOps, -- <APilot>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<maxKeys THEN BEGIN
commands[nKeys] ← [key, proc, doc];
nKeys ← nKeys+1;
END
ELSE ERROR; -- too many commands!
END;
GetToken: PUBLIC PROCEDURE [rope: Rope.Ref, offset: LONG INTEGER ← 0, thruEnd: BOOLEAN ← FALSE]
RETURNS [token: Rope.Ref, newOffset: LONG INTEGER] = BEGIN
size: LONG INTEGER = Rope.Size[rope];
start: LONG INTEGER;
char: CHARACTER;
Blank: PROC [c: CHARACTER] RETURNS [BOOLEAN] = INLINE BEGIN
RETURN[SELECT c FROM
40C, 11C, 15C, 33C, 0C => 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 AND Blank[Rope.Fetch[rope, offset]] DO
offset ← offset+1;
ENDLOOP;
start ← offset;
DO IF 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.