<> <> <> <> <> <> <> <> <> <> <> DIRECTORY Commander USING [CommandProc, CommandProcHandle, CommandProcObject], CommanderRegistry USING [EnumerateProc, EnumPatternProc, LookupProc, LookupProp], 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], UnixEnviron USING [GetEnv]; CommanderImpl: CEDAR MONITOR IMPORTS List, ProcessProps, Prop, Rope, SymTab, UnixEnviron EXPORTS Commander, CommanderRegistry = BEGIN <> 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 ]; <> 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 ]]; <> 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 = { <> <> <> <> 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 = { <> <> 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[UnixEnviron.GetEnv["PWD"], "/"]]; }; PrependWorkingDir: PUBLIC PROC [key: ROPE] RETURNS [ROPE] = { <> RETURN [key]; }; <<>> <> <<>> <> <<>> 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; <> 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]; }; <<>> <> <<>> 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