DIRECTORY Convert USING [IntFromRope], File USING [SystemVolume], FileBackdoor USING [IsDebugger], FS USING [Error, ExpandName, GetName, OpenFileFromStream, StreamOpen], IO USING [Backup, BreakProc, Close, CR, EndOfStream, Error, GetChar, GetIndex, GetRopeLiteral, GetTokenRope, int, PeekChar, PutF, PutFR, rope, SP, STREAM, TAB, time], MachineProfile, MachineProfileBackdoor USING [GuestProcsRec], PupDefs USING [GetMyName], Rope USING [Cat, Concat, Equal, ROPE, Run, SkipTo], RuntimeError USING [UNCAUGHT], UserProfile USING [ProfileChanged, ProfileChangeReason, ProfileChangedProc], ViewerEvents USING [EventProc, RegisterEventProc]; MachineProfileImpl: CEDAR MONITOR IMPORTS Convert, File, FileBackdoor, FS, IO, PupDefs, Rope, RuntimeError, UserProfile, ViewerEvents EXPORTS MachineProfile, MachineProfileBackdoor = BEGIN ProfileList: TYPE = LIST OF ProfileEntry; ProfileEntry: TYPE = REF ProfileRecord; ProfileRecord: TYPE = RECORD[key: ROPE, tokens: LIST OF ROPE, position: INT]; ROPE: TYPE = Rope.ROPE; ProfileChangedItem: TYPE = RECORD [ proc: UserProfile.ProfileChangedProc, clientData: REF ANY ]; IsGuestProcess: PROC [] RETURNS [isGuest: BOOL] _ FalseProc; GuestProcs: REF MachineProfileBackdoor.GuestProcsRec _ NEW[MachineProfileBackdoor.GuestProcsRec _ [FalseProc]] ; Boolean: PUBLIC PROC [key: ROPE, default: BOOL _ FALSE] RETURNS [value: BOOL] = { entry: ProfileEntry; val: ROPE; IF IsGuestProcess[] THEN RETURN GuestProcs.Boolean[key, default]; entry _ Lookup[key]; val _ GetRope[entry]; IF val = NIL THEN RETURN[default]; IF val.Equal["TRUE", FALSE] THEN RETURN[TRUE]; IF val.Equal["FALSE", FALSE] THEN RETURN[FALSE]; Report[entry, val.Concat[" is not a Boolean"]]; RETURN[default]; }; Number: PUBLIC PROC [key: ROPE, default: INT] RETURNS [value: INT] = { entry: ProfileEntry; val: ROPE; IF IsGuestProcess[] THEN RETURN GuestProcs.Number[key, default]; entry _ Lookup[key]; val _ GetRope[entry]; IF val = NIL THEN RETURN[default]; value _ Convert.IntFromRope[val ! RuntimeError.UNCAUGHT => { value _ default; Report[entry, val.Concat[" is not an INT"]]; CONTINUE; } ]; }; Token: PUBLIC PROC [key: ROPE, default: ROPE] RETURNS [value: ROPE] = { entry: ProfileEntry; val: ROPE; IF IsGuestProcess[] THEN RETURN GuestProcs.Token[key, default]; entry _ Lookup[key]; val _ GetRope[entry]; IF val = NIL THEN RETURN[default]; value _ val; }; ListOfTokens: PUBLIC PROC [key: ROPE, default: LIST OF ROPE] RETURNS [value: LIST OF ROPE] = { entry: ProfileEntry; IF IsGuestProcess[] THEN RETURN GuestProcs.ListOfTokens[key, default]; entry _ Lookup[key]; IF entry = NIL THEN RETURN[default] ELSE RETURN[entry.tokens]; }; Line: PUBLIC PROC [key: ROPE, default: ROPE] RETURNS [value: ROPE] = { entry: ProfileEntry; IF IsGuestProcess[] THEN RETURN GuestProcs.Line[key, default]; entry _ Lookup[key]; IF entry = NIL THEN RETURN[default]; FOR l: LIST OF ROPE _ entry.tokens, l.rest UNTIL l = NIL DO IF value = NIL THEN value _ l.first ELSE value _ value.Cat[" ", l.first]; ENDLOOP; }; Lookup: ENTRY PROC [key: ROPE] RETURNS [ProfileEntry] = { ENABLE UNWIND => NULL; RETURN[LookupInternal[key]] }; LookupInternal: INTERNAL PROC [key: ROPE] RETURNS [ProfileEntry] = { IF FileBackdoor.IsDebugger[File.SystemVolume[]] THEN { s2: ROPE = Rope.Concat["Debugger.", key]; FOR l: ProfileList _ profileList, l.rest UNTIL l = NIL DO IF Rope.Equal[s1: l.first.key, s2: s2, case: FALSE] THEN RETURN[l.first]; ENDLOOP; }; FOR l: ProfileList _ profileList, l.rest UNTIL l = NIL DO IF Rope.Equal[s1: l.first.key, s2: key, case: FALSE] THEN RETURN[l.first]; ENDLOOP; RETURN[NIL]; }; GetRope: PROC [entry: ProfileEntry] RETURNS [value: ROPE] = INLINE { IF entry = NIL OR entry.tokens = NIL THEN RETURN[NIL]; value _ entry.tokens.first; IF entry.tokens.rest # NIL THEN Report[entry, "extra material on line"]; }; GetProfileName: PUBLIC PROC RETURNS [ROPE] = { IF IsGuestProcess[] THEN RETURN GuestProcs.GetProfileName[] ELSE RETURN[profileName]; }; profileList: ProfileList _ NIL; profileName: ROPE _ NIL; ParseProfile: ENTRY PROC [startNewErrorLog: BOOL _ FALSE] = { ENABLE UNWIND => NULL; ParseProfileInternal[startNewErrorLog]; }; ParseProfileInternal: INTERNAL PROC [startNewErrorLog: BOOL _ FALSE] = { name: ROPE; stream: IO.STREAM _ NIL; IF startNewErrorLog THEN errorLog _ NIL; profileList _ NIL; profileName _ NIL; name _ PupDefs.GetMyName[]; profileName _ Rope.Cat["///", name, ".profile"]; stream _ FS.StreamOpen[fileName: profileName ! FS.Error => IF error.group # bug THEN CONTINUE ]; IF stream = NIL THEN { profileName _ "///Machine.profile"; stream _ FS.StreamOpen[fileName: profileName ! FS.Error => IF error.group # bug THEN CONTINUE ]; }; IF stream # NIL THEN { ENABLE { RuntimeError.UNCAUGHT => GOTO Out; UNWIND => IO.Close[stream]; }; stream _ FS.StreamOpen[fileName: profileName, accessOptions: $read]; DO SkipWhite: PROC [flushLines: BOOL _ FALSE] RETURNS [c: CHAR] = { DO ENABLE IO.Error, IO.EndOfStream => GO TO stop; c _ stream.PeekChar[]; SELECT c FROM '\n => IF NOT flushLines THEN RETURN; <= 40C => {}; '- => {-- could be a comment [] _ stream.GetChar[]; IF stream.PeekChar[] # '- THEN { stream.Backup[c]; RETURN [c]; }; DO c _ stream.GetChar[]; SELECT c FROM '\n => { stream.Backup[c]; IF flushLines THEN EXIT; RETURN; }; '- => IF stream.PeekChar[] = '- THEN EXIT; ENDCASE; ENDLOOP; }; ENDCASE => RETURN; [] _ stream.GetChar[]; ENDLOOP; EXITS stop => {c _ 0C}; }; LocalToken: PROC [flushLines: BOOL _ FALSE] = { stop: CHAR _ SkipWhite[flushLines]; position _ stream.GetIndex[]; token _ NIL; SELECT stop FROM 0C, '\n => RETURN; '" => token _ stream.GetRopeLiteral[]; ENDCASE => token _ stream.GetTokenRope[tokenProc].token; }; tokenProc: IO.BreakProc = { RETURN[SELECT char FROM IO.SP, IO.TAB, ', => sepr, IO.CR, ': => break, ENDCASE => other ]; }; token: ROPE _ NIL; tokens, tail: LIST OF ROPE _ NIL; position: INT; key: ROPE _ NIL; LocalToken[TRUE]; IF (key _ token) = NIL THEN EXIT; SELECT SkipWhite[] FROM ': => [] _ stream.GetChar[]; -- flush the ': ENDCASE => { DO IF stream.GetChar[ ! IO.EndOfStream => EXIT] = '\n THEN EXIT; ENDLOOP; ReportInternal[msg: IO.PutFR["missing : at [%d]", IO.int[position]]]; LOOP; }; DO list: LIST OF ROPE _ NIL; LocalToken[]; IF token = NIL THEN EXIT; list _ LIST[token]; IF tail = NIL THEN {tail _ tokens _ list} ELSE {tail.rest _ list; tail _ list}; ENDLOOP; IF LookupInternal[key] # NIL THEN ReportInternal[ entry: LookupInternal[key], msg: IO.PutFR["%g also appears at [%d]", IO.rope[key], IO.int[position]] ]; profileList _ CONS[NEW[ProfileRecord _ [key, tokens, position]], profileList]; ENDLOOP; EXITS Out => NULL; }; IF stream # NIL THEN stream.Close[]; }; Report: ENTRY PROC [entry: ProfileEntry _ NIL, msg: ROPE] = { ENABLE UNWIND => NULL; ReportInternal[entry, msg]; }; ReportInternal: INTERNAL PROC [entry: ProfileEntry _ NIL, msg: ROPE] = { ENABLE RuntimeError.UNCAUGHT => CONTINUE; IF errorLog = NIL THEN { errorLog _ FS.StreamOpen[fileName: "///MachineProfile.log", accessOptions: $create]; errorLog.PutF["Processing %g at %t", IO.rope[profileName], IO.time[]]; }; errorLog.PutF["\n\n%g", IO.rope[msg]]; IF entry # NIL THEN errorLog.PutF[", at %g [%d]", IO.rope[entry.key], IO.int[entry.position]]; }; GetErrorLog: PUBLIC ENTRY PROC RETURNS [fileName: ROPE _ NIL] = { ENABLE UNWIND => {errorLog _ NIL; NULL}; IF errorLog # NIL THEN { fileName _ FS.GetName[FS.OpenFileFromStream[errorLog]].fullFName; errorLog.Close[]; errorLog _ NIL; }; }; errorLog: IO.STREAM _ NIL; RegisterGuestProcs: PUBLIC PROC [newProcs: REF MachineProfileBackdoor.GuestProcsRec] = { GuestProcs _ newProcs; IsGuestProcess _ newProcs.IsGuestProcess; }; FalseProc: PROC RETURNS [isGuest: BOOL] = { isGuest _ FALSE; }; NoticeProfileChanges: ViewerEvents.EventProc = { IF viewer # NIL THEN { ENABLE FS.Error => GOTO GiveUp; name1: ROPE _ FS.ExpandName[viewer.file].fullFName; bang1: INT _ Rope.SkipTo[name1, 0, "!"]; name2: ROPE _ FS.ExpandName[GetProfileName[]].fullFName; bang2: INT _ Rope.SkipTo[name2, 0, "!"]; IF bang1 # 0 AND bang1 = bang2 AND Rope.Run[name1, 0, name2, 0, FALSE] = bang1 THEN UserProfile.ProfileChanged[edit]; EXITS GiveUp => NULL; }; }; Init: PROC ~ { [] _ ViewerEvents.RegisterEventProc[NoticeProfileChanges, save, $Text, FALSE]; ParseProfile[]; }; Init[]; END. RMachineProfileImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Copied from UserProfileImpl.mesa... Teitelman on January 13, 1983 1:52 pm Levin, October 6, 1983 12:03 pm Russ Atkinson, April 11, 1985 10:31:43 am PST Paul Rovner on December 12, 1983 8:45 pm Bob Hagmann May 22, 1985 4:50:10 pm PDT Russ Atkinson (RRA) May 20, 1985 5:16:59 pm PDT Eric Nickell, June 13, 1985 9:24:48 pm PDT Booting USING [switches], Types Variables Accessing profile Building profileList IF Booting.switches[p] THEN RETURN; -- return default values for the profile it is not a comment the end of a comment is either a '\n or a double - Only flush the \n if it was requested key was NOT followed by ':, so flush to the end of line and report the error Reporting errors Exported to MachineProfileBackdoor default IsGuestProcess (not really exported) NO initialization, since InstallerImpl has that responsibility! [viewer: ViewerClasses.Viewer, event: ViewerEvent, before: BOOL] RETURNS[abort: BOOL _ FALSE] The profile is the same (except for version info), so notify about a change Κ_– "Cedar" style˜codešΟc™Kšœ Οmœ7™B™#Kš œ™%K™K™-Kšœ™(K™'K™/—K™*—K˜šΟk ˜ KšœŸœ ™KšœŸœ˜KšœŸœ˜Kšœ Ÿœ˜ KšŸœŸœ>˜FKš ŸœŸœŸœiŸœŸœŸœ˜¦K˜KšœŸœ˜-KšœŸœ ˜KšœŸœŸœ˜3Kšœ ŸœŸœ˜Kšœ Ÿœ;˜LKšœ Ÿœ ˜2K˜—K˜šΟbœŸœŸ˜!KšŸœŸœŸœ:˜eKšŸœ(˜/KšœŸ˜—K™šœ™K™Kšœ ŸœŸœŸœ˜)KšœŸœŸœ˜'KšœŸœŸœŸœ ŸœŸœŸœ Ÿœ˜MKšŸœŸœŸœ˜K˜šœŸœŸœ˜#Kšœ%˜%Kšœ ŸœŸ˜Kšœ˜——K™™ JšΠbnœŸœŸœ Ÿœ˜K˜K˜—š’œŸœŸœŸœ ŸœŸœ Ÿœ˜FK˜KšŸœŸœŸœ˜>K˜KšŸœ ŸœŸœŸœ ˜$š ŸœŸœŸœŸœŸœŸœŸ˜;KšŸœ ŸœŸœŸ˜(K˜ KšŸœ˜—K˜K˜—š ’œŸœŸœŸœŸœ˜9KšŸœŸœŸœ˜KšŸœ˜Kšœ˜K˜—š ’œŸœŸœŸœŸœ˜DšŸœ.Ÿœ˜6KšœŸœ!˜)šŸœ&ŸœŸœŸ˜9KšŸœ+ŸœŸœŸœ ˜IKšŸœ˜—K˜—šŸœ&ŸœŸœŸ˜9KšŸœ,ŸœŸœŸœ ˜JKšŸœ˜—KšŸœŸœ˜ K˜K˜—š ’œŸœŸœ ŸœŸœ˜DKšŸœ ŸœŸœŸœŸœŸœŸœ˜6K˜KšŸœŸœŸœ)˜HK˜K˜—š ’œŸœŸœŸœŸœ˜.KšŸœŸœŸœ˜;KšœŸœŸœ˜Kšœ˜——K™™K˜KšœŸœ˜Kšœ ŸœŸœ˜š ’ œŸœŸœŸœŸœ˜>KšŸœŸœŸœ˜Kšœ'˜'K˜K˜—š ’œŸœŸœŸœŸœ˜IKšœŸœ˜ KšœŸœŸœŸœ˜KšŸœŸœ Ÿœ˜(KšœŸœ˜KšœŸœ˜KšŸœŸœŸœ(™LKšœ˜Kšœ0˜0šœ Ÿœ!˜,KšœŸœ ŸœŸœŸ˜0Kšœ˜—šŸœ ŸœŸœ˜Kšœ#˜#šœ Ÿœ!˜,KšœŸœ ŸœŸœŸ˜0Kšœ˜—K˜—šŸœ ŸœŸœ˜šŸœ˜Kšœ ŸœŸœ˜"KšŸœŸœ˜K˜—Kšœ Ÿœ9˜DšŸ˜š ’ œŸœŸœŸœŸœŸœ˜@šŸ˜Kš ŸœŸœŸœŸœŸœ˜.Kšœ˜šŸœŸ˜ Kš œŸœŸœ ŸœŸœ˜%Kšœ ˜ šœ˜Kšœ˜šŸœŸœ˜ Kšœ™Kšœ˜KšŸœ˜ K˜—šŸ˜Kšœ2™2Kšœ˜šŸœŸ˜ šœ˜Kšœ%™%Kšœ˜KšŸœ ŸœŸœ˜KšŸœ˜Kšœ˜—KšœŸœŸœŸœ˜*KšŸœ˜—KšŸœ˜—K˜—KšŸœŸœ˜—Kšœ˜KšŸœ˜—KšŸœ˜K˜—š’ œŸœŸœŸœ˜/KšœŸœ˜#Kšœ˜KšœŸœ˜ šŸœŸ˜Kšœ Ÿœ˜Kšœ&˜&KšŸœ1˜8—K˜—šœ Ÿœ˜šŸœŸœŸ˜KšŸœŸœŸœŸœ ˜KšŸœŸœ˜KšŸœ ˜K˜—Kšœ˜—KšœŸœŸœ˜Kš œŸœŸœŸœŸœ˜!Kšœ Ÿœ˜KšœŸœŸœ˜Kšœ Ÿœ˜KšŸœŸœŸœŸœ˜!šŸœ Ÿ˜Kšœ˜-šŸœ˜ KšœL™LšŸ˜Kš ŸœŸœŸœŸœŸœ˜=KšŸœ˜—KšœŸœŸœ˜EKšŸœ˜Kšœ˜——šŸ˜Kš œŸœŸœŸœŸœ˜Kšœ ˜ KšŸœ ŸœŸœŸœ˜KšœŸœ˜šŸœŸ˜ KšŸœ˜KšŸœ!˜%—KšŸœ˜—šŸœŸœŸ˜!šœ˜Kšœ˜KšœŸœ"Ÿœ Ÿœ˜HKšœ˜——KšœŸœŸœ8˜NKšŸœ˜—šŸ˜KšœŸœ˜ —K˜—KšŸœ ŸœŸœ˜$Kšœ˜——K™™K˜š ’œŸœŸœŸœŸœ˜=KšŸœŸœŸœ˜Kšœ˜Kšœ˜—K˜š ’œŸœŸœŸœŸœ˜HKšŸœŸœŸœ˜)šŸœ ŸœŸœ˜Kšœ ŸœG˜TKšœ%ŸœŸœ ˜FK˜—KšœŸœ ˜'šŸœ ŸœŸ˜KšœŸœŸœ˜K—Kšœ˜—K˜š’ œŸœŸœŸœŸœ ŸœŸœ˜AKšŸœŸœŸœŸœ˜(šŸœ ŸœŸœ˜Kšœ Ÿœ Ÿœ)˜AKšœ˜Kšœ Ÿœ˜Kšœ˜—K˜—K˜Kšœ ŸœŸœŸœ˜—K™šœ"™"J˜š’œŸœŸœ Ÿœ*˜XIcode2šœ˜Lšœ)˜)L˜L˜Lšœ,™,—š’ œŸœŸœ Ÿœ˜,Lšœ Ÿœ˜L˜L˜——Kšœ?™?šœ0˜0Kš œ;ŸœŸœŸœŸœ™]šŸœ ŸœŸœ˜KšŸœŸœ Ÿœ˜KšœŸœŸœ#˜3KšœŸœ˜(KšœŸœŸœ(˜8KšœŸœ˜(š Ÿœ ŸœŸœŸœ Ÿ˜SKšœK™KKšœ!˜!—KšŸœ Ÿœ˜K˜—Kšœ˜K˜—š’œŸœ˜KšœGŸœ˜NKšœ˜K˜K˜—K˜K˜KšŸœ˜K™K™—…— B2σ