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] = { 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 ςCommanderImpl.mesa Copyright Σ 1985, 1986, 1987, 1989, 1991 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 Types Data Procedures 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. 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. Should deimplement this one. Useful procedures for property lists This procedure is much like List.Assoc, except it works more sensibly for ROPEs handle it differently if key is a ROPE This procedure is much like List.PutAssoc, except it works more sensibly(?) for ROPEs handle it differently if key is a ROPE and already present on the list Κ ά–(cedarcode) style•NewlineDelimiter ˜codešœ™Kšœ ΟeœI™TKšœ'™'K™1K™-K™.K™$K™'K™,K™(K™$—K˜šΟk ˜ Kšœ žœ5˜DKšœžœ:˜QKšœžœ˜$Kšœ žœ˜!Kšœžœ˜Kšœžœžœ.˜>Kšœžœ<˜HKšœ žœ ˜K˜—šΟn œžœž˜Kšžœ4˜;Kšžœž˜,—head™Kšžœžœžœ˜Kšœ žœ˜Kšœ žœ ˜0Kšœ žœ ˜0Kšœžœ#˜6Kšœžœ%˜:šœ žœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜——™Kšœ<žœ˜Cšœžœ žœ ˜&Kšœžœžœ!˜KKšœžœžœ'˜WKšœžœžœ+˜_Kšœž˜Kšœ˜——™ šŸœžœžœžœžœ$žœžœžœžœžœžœ˜ˆšžœž˜ Kšžœ5˜9šžœ˜šœ˜Kšœ˜šœžœ˜$KšœM˜M——Kšœ˜——K˜—K˜š Ÿœžœžœ žœ+žœ0˜‹Kšœžœ˜Kšœžœ žœ ˜"š Ÿœžœžœžœžœ˜%šžœ ˜Kšžœžœžœ˜#Kšžœžœžœ˜$—Kšœ˜—šžœS˜UKšœW˜WKšžœ žœžœ˜Kšžœ˜—K˜K˜—šŸœžœžœ˜#Kšžœžœžœ˜Kšœ(žœ˜,šžœ-žœžœž˜@šžœžœž˜šœžœ˜K˜Kšœ/˜/Kšžœžœžœžœ žœžœžœžœžœ˜GK˜—Kšžœ˜—Kšžœ˜—Kšžœ ˜K˜K˜—šŸœ˜ šžœ0žœž˜?Kšœ)žœ ˜;Kšžœžœ˜—Kšžœžœ˜ K˜K˜—šŸ œžœžœ˜)K™ŒK™kK™aK™=Kšžœžœžœ˜šžœ0žœžœž˜Cšžœžœž˜šœžœ˜Kšœ˜Kšœ˜K˜—Kšžœ˜—Kšžœ˜—K˜K˜—šŸœ˜&Kšœ žœ˜Kšœ+˜+šŸ œ˜'Kšœžœ#˜9Kšœ˜Kšžœ4˜:K˜—šžœžœ8žœ˜DKšœ žœ˜Kšœžœ˜K˜—Kšžœ)˜/K˜—K˜šŸœžœžœ˜2K™ŒK™kKšžœžœžœ˜šžœ2žœžœž˜Ešžœžœž˜šœžœ˜K˜Kšœ˜K˜—Kšžœ˜—Kšžœ˜—K˜K˜—šŸœ˜*Kšœ žœ˜Kšœ+˜+šŸ œ˜'Kš žœžœ1žœžœžœžœ˜QKšœžœ#˜9Kšœ˜Kšžœ4˜:K˜—šžœžœ8žœ˜DKšœ žœ˜Kšœžœ˜K˜—Kšžœ)˜/K˜K˜—šŸœžœ!˜0šžœ8žœžœž˜Lšžœžœž˜šœžœ˜Kšœ˜Kšœ˜Kš žœžœžœžœΟc/˜IK˜—Kšžœ˜—Kšžœ˜—Kšœ˜K˜—Kšœ žœ˜"šŸœžœžœžœ˜ Kšœžœžœ˜Kšœ2˜2šžœ+žœž˜:Kšœžœ˜Kšžœ˜—Kšžœžœ˜3Kšžœ˜ K˜K˜K˜—šŸœžœžœ žœ˜2Kšžœ.˜4K˜K˜—š Ÿœž œžœžœžœ˜=K™Kšžœ˜ K˜—K™K™$K™K™OK™šŸ œžœžœž œžœžœžœžœžœ˜`Kšžœžœžœ˜Kšœ žœ˜Kšœ)˜)Kšžœžœžœžœ˜K™&šžœžœž˜Kšœžœ˜Kšœžœžœ"˜-Kšžœ˜—šžœ žœžœ˜šžœžœžœž˜2šžœ žœž˜Kš œžœžœ&žœžœžœ˜RKš œžœžœžœ8žœžœžœ˜hKšžœ˜—Kšžœ˜—K˜—Kšžœžœ˜ K˜—K™K™UK™šŸ œžœžœž œžœžœžœžœžœ˜lK™GKšžœžœžœ˜šžœžœžœžœ˜Kšœ žœžœ˜šžœžœžœž˜2šžœžœžœžœ˜#š žœžœžœ žœžœ˜LKšœ˜Kšžœ˜K˜—K˜—Kšžœ˜—K˜—Kšžœ2˜8K˜K˜——Kšžœ˜Kšœžœ˜,Kšœžœ˜/Kšœžœ˜7Kšœžœ*˜EK˜—…—”)b