CommanderImpl.mesa
Copyright Ó 1985, 1986, 1987, 1989, 1991, 1993 by Xerox Corporation. All rights reserved.
Larry Stewart, January 14, 1984 3:40 pm
Russ Atkinson (RRA) March 6, 1985 12:50:20 pm PST
Doug Wyatt, September 18, 1987 2:42:17 pm PDT
Carl Hauser, December 12, 1988 10:40:02 am PST
JKF November 21, 1988 5:36:08 pm PST
Foote, November 21, 1988 6:00:05 pm PST
Michael Plass, February 21, 1991 2:03 am PST
Swinehar, December 10, 1990 11:32 am PST
Willie-s, August 9, 1991 2:15 pm PDT
Christian Jacobi, February 17, 1993 4:00 pm PST
DIRECTORY
Commander USING [CommandProc, CommandProcHandle, CommandProcObject],
CommanderRegistry USING [EnumerateProc, EnumPatternProc, LookupProc, LookupProp],
EnvironmentVariables USING [Get],
List USING [AList, Assoc, PutAssoc],
ProcessProps USING [GetPropList],
Prop USING [PropList, Put],
Rope USING [ROPE, Concat, Equal, FromRefText, IsEmpty, Match],
SymTab USING [Create, Delete, EachPairAction, Fetch, Pairs, Ref, Store];
CommanderImpl: CEDAR MONITOR
IMPORTS EnvironmentVariables, List, ProcessProps, Prop, Rope, SymTab
EXPORTS Commander, CommanderRegistry = BEGIN
Types
ROPE: TYPE = Rope.ROPE;
PropList: TYPE = Prop.PropList;
LookupProc: TYPE ~ CommanderRegistry.LookupProc;
LookupProp: TYPE ~ CommanderRegistry.LookupProp;
EnumerateProc: TYPE ~ CommanderRegistry.EnumerateProc;
EnumPatternProc: TYPE ~ CommanderRegistry.EnumPatternProc;
HooksRep: TYPE ~ RECORD [
lookupProcs: PropList,
enumerateProcs: PropList,
enumPatternProcs: PropList,
lookupPropProcs: PropList
];
Data
commandRegistry: SymTab.Ref ¬ SymTab.Create[mod: 101, case: FALSE];
hooks: REF HooksRep ¬ NEW[HooksRep ¬ [
lookupProcs: Prop.Put[NIL, $StdLookup, NEW[LookupProc ¬ LookupInRegistry]],
enumerateProcs: Prop.Put[NIL, $StdEnumerate, NEW[EnumerateProc ¬ EnumerateInRegistry]],
enumPatternProcs: Prop.Put[NIL, $StdEnumPattern, NEW[EnumPatternProc ¬ EnumPatternInRegistry]],
lookupPropProcs: NIL
]];
Procedures
Register: PUBLIC ENTRY PROC [key: ROPE, proc: Commander.CommandProc, doc: ROPE, clientData: REF ANY ¬ NIL, interpreted: BOOL ¬ TRUE] = {
IF proc = NIL
THEN { [] ¬ SymTab.Delete[x: commandRegistry, key: key] }
ELSE {
[] ¬ SymTab.Store[
x: commandRegistry, key: key,
val: NEW[Commander.CommandProcObject
¬ [proc: proc, doc: doc, clientData: clientData, interpreted: interpreted]]];
};
};
ChangeRegistry: PUBLIC PROC [change: PROC[oldLk, oldEn, oldEnP, oldLkPrp: PropList] RETURNS [newLk, newEn, newEnP, newLkPrp: PropList]] ~ {
old: REF HooksRep ¬ hooks;
new: REF HooksRep ¬ NEW[HooksRep];
Update: ENTRY PROC RETURNS [BOOL] = {
IF old = hooks
THEN { hooks ¬ new; RETURN [TRUE] }
ELSE { old ¬ hooks; RETURN [FALSE] }
};
DO [new.lookupProcs, new.enumerateProcs, new.enumPatternProcs, new.lookupPropProcs] ¬
change[old.lookupProcs, old.enumerateProcs, old.enumPatternProcs, old.lookupPropProcs];
IF Update[] THEN EXIT;
ENDLOOP;
};
Lookup: PUBLIC ENTRY LookupProc = {
ENABLE UNWIND => NULL;
procData: Commander.CommandProcHandle ¬ NIL;
FOR lPs: PropList ¬ hooks.lookupProcs, lPs.rest WHILE lPs#NIL DO
WITH lPs.first.val SELECT FROM
val: REF LookupProc => {
proc: LookupProc ¬ val­;
pData: Commander.CommandProcHandle ¬ proc[key];
IF pData#NIL THEN IF procData=NIL THEN procData¬pData ELSE RETURN[NIL];
};
ENDCASE;
ENDLOOP;
RETURN[procData];
};
LookupInRegistry: LookupProc = {
WITH SymTab.Fetch[x: commandRegistry, key: key].val SELECT FROM
procData: Commander.CommandProcHandle => RETURN [procData];
ENDCASE => NULL;
RETURN [NIL];
};
Enumerate: PUBLIC ENTRY EnumerateProc = {
Return results are never used; next interface party, take them out. Also, no current
callers return stop:TRUE, so needn't worry about that.
Also, procData argument to the matchData is never looked at, so no need to supply non-NIL value at present.
Consider leaving this one alone, restricted only to commandRegistry -- because of Alias commands.
I don't want to list all Aka commands as aliases -- too many.
ENABLE UNWIND => NULL;
FOR ePs: PropList ¬ hooks.enumerateProcs, ePs.rest WHILE ePs#NIL DO
WITH ePs.first.val SELECT FROM
val: REF EnumerateProc => {
proc: EnumerateProc ¬ val­;
[] ¬ proc[matchProc];
};
ENDCASE;
ENDLOOP;
};
EnumerateInRegistry: EnumerateProc = {
outerKey: ROPE;
outerProcData: Commander.CommandProcHandle;
EachPairProc: SymTab.EachPairAction = {
outerProcData ¬ NARROW[val, Commander.CommandProcHandle];
outerKey ¬ key;
RETURN[matchProc[key: outerKey, procData: outerProcData]];
};
IF NOT SymTab.Pairs[x: commandRegistry, action: EachPairProc] THEN {
outerKey ¬ NIL;
outerProcData ¬ NIL;
};
RETURN[key: outerKey, procData: outerProcData];
};
EnumeratePattern: PUBLIC ENTRY EnumPatternProc = {
Return results are never used; next interface party, take them out. Also, no current
callers return stop:TRUE, so needn't worry about that.
Also, procData argument to the matchData is never looked at, so no need to supply non-NIL value at present.
ENABLE UNWIND => NULL;
FOR ePs: PropList ¬ hooks.enumPatternProcs, ePs.rest WHILE ePs#NIL DO
WITH ePs.first.val SELECT FROM
val: REF EnumPatternProc => {
proc: EnumPatternProc ¬ val­;
[] ¬ proc[pattern, matchProc];
};
ENDCASE;
ENDLOOP;
};
EnumPatternInRegistry: EnumPatternProc = {
outerKey: ROPE;
outerProcData: Commander.CommandProcHandle;
EachPairProc: SymTab.EachPairAction = {
IF NOT Rope.Match[pattern: pattern, object: key, case: FALSE] THEN RETURN[FALSE];
outerProcData ¬ NARROW[val, Commander.CommandProcHandle];
outerKey ¬ key;
RETURN[matchProc[key: outerKey, procData: outerProcData]];
};
IF NOT SymTab.Pairs[x: commandRegistry, action: EachPairProc] THEN {
outerKey ¬ NIL;
outerProcData ¬ NIL;
};
RETURN[key: outerKey, procData: outerProcData];
};
GetProp: PUBLIC CommanderRegistry.LookupProp ~ {
FOR lpPs: Prop.PropList ¬ hooks.lookupPropProcs, lpPs.rest WHILE lpPs#NIL DO
WITH lpPs.first.val SELECT FROM
refP: REF LookupProp => {
proc: LookupProp ¬ refP­;
value ¬ proc[cmd, key];
IF value#NIL THEN RETURN; -- Accept first answer for properties, for now.
};
ENDCASE;
ENDLOOP;
};
wDirKey: ATOM ~ $WorkingDirectory;
GetWDir: PROC RETURNS [ROPE] = {
wDir: ROPE ¬ NIL;
propList: List.AList ~ ProcessProps.GetPropList[];
WITH List.Assoc[key: wDirKey, aList: propList] SELECT FROM
rope: ROPE => wDir ¬ rope;
ENDCASE;
IF Rope.IsEmpty[wDir] THEN wDir ¬ GetDefaultWDir[];
RETURN[wDir];
};
GetDefaultWDir: PROC RETURNS [wdir: Rope.ROPE] ~ {
RETURN[Rope.Concat[EnvironmentVariables.Get["PWD"], "/"]];
};
PrependWorkingDir: PUBLIC PROC [key: ROPE] RETURNS [ROPE] = {
Should deimplement this one.
RETURN [key];
};
Useful procedures for property lists
This procedure is much like List.Assoc, except it works more sensibly for ROPEs
GetProperty: PUBLIC ENTRY PROCEDURE [key: REF ANY, aList: List.AList] RETURNS [val: REF ANY] = {
ENABLE UNWIND => NULL;
ropeKey: ROPE;
val ¬ List.Assoc[key: key, aList: aList];
IF val # NIL THEN RETURN;
handle it differently if key is a ROPE
WITH key SELECT FROM
r: ROPE => ropeKey ¬ r;
t: REF TEXT => ropeKey ¬ Rope.FromRefText[t];
ENDCASE;
IF ropeKey # NIL THEN {
FOR l: List.AList ¬ aList, l.rest WHILE l # NIL DO
WITH l.first.key SELECT FROM
r: ROPE => IF Rope.Equal[s1: ropeKey, s2: r, case: TRUE] THEN RETURN[l.first.val];
t: REF TEXT => IF Rope.Equal[s1: ropeKey, s2: Rope.FromRefText[t], case: TRUE] THEN RETURN[l.first.val];
ENDCASE;
ENDLOOP;
};
RETURN[NIL];
};
This procedure is much like List.PutAssoc, except it works more sensibly(?) for ROPEs
PutProperty: PUBLIC ENTRY PROCEDURE [key: REF ANY, val: REF ANY, aList: List.AList] RETURNS [List.AList] = {
handle it differently if key is a ROPE and already present on the list
ENABLE UNWIND => NULL;
IF ISTYPE[key, ROPE] THEN {
ropeKey: ROPE ¬ NARROW[key];
FOR l: List.AList ¬ aList, l.rest WHILE l # NIL DO
IF ISTYPE[l.first.key, ROPE] THEN {
IF Rope.Equal[s1: ropeKey, s2: NARROW[l.first.key, ROPE], case: TRUE] THEN {
l.first.val ¬ val;
RETURN[aList];
};
};
ENDLOOP;
};
RETURN[List.PutAssoc[key: key, val: val, aList: aList]];
};
END.
March 28, 1983 12:26 pm, L. Stewart, created
September 9, 1983 11:04 am, L. Stewart, Cedar 5
November 3, 1983 2:10 pm, L. Stewart, add CommandExtras
January 14, 1984 3:40 pm, L. Stewart, Register uses working directory