CommandToolImpl.mesa
Larry Stewart, April 21, 1983 4:57 pm
Russ Atkinson, April 20, 1983 8:25 pm
Paul Rovner, June 2, 1983 2:44 pm
DIRECTORY
Buttons USING [ButtonProc, Create],
Commander,
CommandTool,
ConvertUnsafe USING [AppendRope, ToRope],
Directory USING [Error, GetProps, Lookup],
IO,
File USING [Capability],
List USING [AList, DotCons],
Loader USING [Error, Start, Instantiate],
PrincOps USING [ControlModule],
Process USING [Priority, GetPriority, SetPriority, priorityNormal],
ProcessProps USING [AddPropList],
ReadEvalPrint USING [ClientProc, CreateViewerEvaluator, Handle, IsACR, MainLoop],
Rope USING [Compare, Concat, Find, Length, Match, ROPE, Substr],
UECP USING [Argv, Parse];
CommandToolImpl:
CEDAR
MONITOR
IMPORTS
Buttons, Commander, ConvertUnsafe, Directory, IO, List, Loader, Process, ProcessProps, ReadEvalPrint, Rope, UECP
EXPORTS CommandTool
= BEGIN
promptKey: ROPE = "prompt";
initPrompt: ROPE = "%% ";
defaultPrompt: ROPE = "%% ";
Useful Types
ProcCellRef: TYPE = REF Commander.ProcCell;
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
EachCommand:
PUBLIC ReadEvalPrint.ClientProc = {
cmd: Commander.Handle;
propertyList: List.AList ← NIL;
cStream: STREAM;
err: STREAM ← NIL;
WITH h.clientData
SELECT
FROM
cth: Commander.Handle => {
propertyList ← cth.propertyList;
err ← cth.err;
};
ENDCASE;
IF propertyList =
NIL
THEN
propertyList ← Commander.PutProperty[key: promptKey, val: h.prompt, aList: propertyList];
IF err = NIL THEN err ← h.out;
cmd ←
NEW[Commander.CommandObject ← [
in: h.in,
out: h.out,
err: err,
propertyList: propertyList
]];
cStream ← IO.RIS[rope: command, oldStream: cStream];
cmd.command ← cStream.GetToken[];
IF cmd.command.Length[] = 0 THEN RETURN;
cmd.commandLine ← Rope.Substr[
base: command,
start: Rope.Find[s1: command, s2: cmd.command] + cmd.command.Length[]];
ExecuteCommand[cmd];
h.in.ResetUserAbort[];
WITH Commander.GetProperty[key: promptKey, aList: propertyList]
SELECT
FROM
rope: ROPE => h.prompt ← rope;
ENDCASE => h.prompt ← defaultPrompt;
};
CallList:
PROC [property:
REF
ANY, cmd: Commander.Handle] = {
WITH Commander.GetProperty[key: property, aList: cmd.propertyList]
SELECT
FROM
list:
LIST
OF
REF
ANY =>
FOR l:
LIST
OF
REF
ANY ← list, l.rest
WHILE l #
NIL
DO
WITH l.first
SELECT
FROM
cpc: ProcCellRef => cpc.proc[cmd];
ENDCASE;
ENDLOOP;
ENDCASE;
};
DoCommand:
PUBLIC
PROC [command:
ROPE, commandLine, in:
ROPE ←
NIL]
RETURNS [out, err:
ROPE] = {
outS: STREAM;
errS: STREAM;
cmd: Commander.Handle;
outS ← IO.ROS[];
errS ← IO.ROS[];
cmd ←
NEW[Commander.CommandObject ← [
in: IO.RIS[in],
out: outS,
err: errS,
commandLine: commandLine,
command: command,
propertyList: Commander.PutProperty[$Junk, $Junk, NIL]
]];
ExecuteCommand[cmd];
RETURN[out: outS.GetOutputStreamRope[], err: errS.GetOutputStreamRope[]];
};
ExecuteCommand:
PUBLIC
PROC [command: Commander.Handle] = {
innerExecute:
PROC = {
commandProc: Commander.CommandProc;
CallList[property: $PreLookup, cmd: command !
ABORTED => {
command.err.PutRope[". . . Aborted\n" ! ANY => CONTINUE];
CONTINUE;
};
UNWIND => {
command.err.PutRope[". . . Unwound\n" ! ANY => CONTINUE];
CONTINUE;
};
];
commandProc ← Commander.Lookup[command.command].proc;
IF commandProc =
NIL
THEN {
-- try for unique prefix (i.e. allow abbreviations, patterns)
lst: LIST OF ROPE ← NIL;
p:
PROC[name:
ROPE, proc: Commander.CommandProc, doc:
ROPE]
RETURNS[stop: BOOL ← FALSE] = {
IF Rope.Match[
pattern: Rope.Concat[command.command, "*"],
object: name,
case: FALSE
]
THEN lst ← CONS[name, lst];
};
[] ← Commander.Enumerate[p];
IF lst =
NIL THEN {
command.err.PutF[". . . %g: command not found\n", IO.rope[command.command]];
RETURN;
};
IF lst.rest #
NIL
THEN {
-- ambiguous prefix
command.err.PutF[". . . %g: command ambiguous ( ", IO.rope[command.command]];
FOR x:
LIST
OF
ROPE ← lst, x.rest
UNTIL x =
NIL
DO
command.err.PutRope[x.first];
command.err.PutRope[" "];
ENDLOOP;
command.err.PutRope[")\n"];
RETURN;
}
ELSE
{
command.command ← lst.first;
commandProc ← Commander.Lookup[lst.first].proc -- this will succeed
};
};
IF commandProc = NIL THEN ERROR;
{
ENABLE {
ABORTED => {
command.err.PutRope[". . . Aborted\n" ! ANY => CONTINUE];
CONTINUE;
};
UNWIND => {
command.err.PutRope[". . . Unwound\n" ! ANY => CONTINUE];
CONTINUE;
};
};
CallList[property: $Before, cmd: command];
commandProc[cmd: command];
CallList[property: $After, cmd: command];
};
};
ProcessProps.AddPropList[
LIST[List.DotCons[key: $CommanderHandle, val: command]],
innerExecute];
};
Create:
PUBLIC
PROC = {
cmd: Commander.Handle ← NEW[Commander.CommandObject];
readEvalPrint: ReadEvalPrint.Handle;
oldPriority: Process.Priority ← Process.GetPriority[];
TRUSTED{Process.SetPriority[Process.priorityNormal]};
readEvalPrint ← ReadEvalPrint.CreateViewerEvaluator[
clientProc: EachCommand,
prompt: initPrompt,
info: [name: "Commander", column: right, iconic: FALSE],
edited: TRUE,
deliverWhen: ReadEvalPrint.IsACR,
clientData: cmd];
very first propery makes the list NON-NIL
cmd.propertyList ← Commander.PutProperty[
key: promptKey, val: defaultPrompt, aList: cmd.propertyList];
subsequent properties will never change the first cell
cmd.propertyList ← Commander.PutProperty[
key: $ReadEvalPrintHandle, val: readEvalPrint, aList: cmd.propertyList];
ReadEvalPrint.MainLoop[readEvalPrint, TRUE];
TRUSTED{Process.SetPriority[oldPriority]};
};
CreateCommanderButtonProc: Buttons.ButtonProc = {
Create[];
};
CreateCommander: Commander.CommandProc = {
Create[];
};
Run: Commander.CommandProc =
TRUSTED {
argv: UECP.Argv ← UECP.Parse[cmd.commandLine];
bcdName: ROPE;
stringBCDName: LONG STRING ← [50];
error: ROPE ← NIL;
name: ROPE;
f: File.Capability;
length: INT;
unboundImports: BOOL ← FALSE;
cm: PrincOps.ControlModule;
IF argv.argc # 2
THEN {
cmd.out.PutRope["Usage: Run bcdFileName\n"];
RETURN;
};
bcdName ← argv[1];
length ← Rope.Length[bcdName];
IF length < 5 OR Rope.Compare[Rope.Substr[bcdName, length - 4, 4], ".bcd", FALSE] # equal THEN bcdName ← Rope.Concat[bcdName, ".bcd"];
length ← Rope.Length[bcdName];
IF length > 50
THEN {
cmd.out.PutF["Run %g: name too long\n", IO.rope[bcdName]];
RETURN;
};
TRUSTED {
ENABLE {
Loader.Error => {
SELECT type
FROM
invalidBcd => error ← "Invalid Bcd";
fileNotFound => error ← "File Not Found";
versionMismatch => error ← "Version Mismatch";
loadStateFull => error ← "LoadState Full";
insufficientVM => error ← "Insufficient VM";
ENDCASE => ERROR;
CONTINUE;
};
Directory.Error => {
SELECT type
FROM
invalidFileName => error ← "Illegal file name";
fileNotFound => error ← "Couldn't find a runnable file named";
ENDCASE => error ← "Directory.Lookup failed on";
CONTINUE;
};
};
ConvertUnsafe.AppendRope[to: stringBCDName, from: bcdName];
f ← Directory.Lookup[stringBCDName];
IF error=
NIL
THEN {
[cm, unboundImports] ← Loader.Instantiate[file: f, offset: 1 !
ABORTED => {
error ← "Execution Aborted in";
CONTINUE;
}];
IF unboundImports THEN cmd.out.PutRope["There are unbound imports.\n"];
};
IF error=NIL THEN Loader.Start[cm];
IF error=NIL THEN [] ← Directory.GetProps[f, stringBCDName];
IF error=NIL THEN name ← ConvertUnsafe.ToRope[stringBCDName];
};
cmd.out.PutF["%g: %g\n", IO.rope[IF error = NIL THEN "Loaded and ran" ELSE error], IO.rope[IF error = NIL THEN name ELSE bcdName]];
};
Init:
PROC = {
[] ← Buttons.Create[info: [name: "Cmd"], proc: CreateCommanderButtonProc, fork: FALSE, documentation: "Create a Commander viewer"];
Commander.Register[key: "Commander", proc: CreateCommander, doc: "Create a new Commander Tool"];
Commander.Register[key: "Run", proc: Run, doc: "Run xxx.bcd - Load and Start a .bcd"];
};
main program for Commander
Init[];
END.
March 27, 1983 3:27 pm, Stewart, Created from ChatImpl
April 20, 1983 8:26 pm, Russ Atkinson, added Process Props stuff