DIRECTORY Atom, BasicTime USING [GMT], Convert, FingerLog, FS USING[StreamOpen, Error], IO, Rope; FingerOpsImpl: CEDAR PROGRAM IMPORTS Atom, Convert, FS, IO EXPORTS FingerLog = BEGIN OPEN FingerLog; fingerLogName: Rope.ROPE = "///Finger.Log"; fingerStream: IO.STREAM; -- a stream always opened to the finger log file stateChangeAtom: ATOM = Atom.MakeAtom["StateChange"]; userPropChangeAtom: ATOM = Atom.MakeAtom["UserPropChange"]; machinePropChangeAtom: ATOM = Atom.MakeAtom["MachinePropChange"]; addMachinePropAtom: ATOM = Atom.MakeAtom["AddMachineProp"]; addUserPropAtom: ATOM = Atom.MakeAtom["AddUserProp"]; deleteMachinePropAtom: ATOM = Atom.MakeAtom["DeleteMachineProp"]; deleteUserPropAtom: ATOM = Atom.MakeAtom["DeleteUserProp"]; FlushLog: PUBLIC PROC[] ~ { fingerStream.SetLength[0]; fingerStream.Flush[] }; Log: PUBLIC PROC[ logEntry: LogEntry ] = TRUSTED { IF fingerStream = NIL THEN fingerStream _ FS.StreamOpen[fingerLogName, $append]; WITH entry: logEntry SELECT FROM StateChange => { fingerStream.Put[IO.atom[stateChangeAtom], IO.rope[" "]]; fingerStream.Put[IO.atom[IF entry.event = login THEN $login ELSE $logout], IO.rope[" "]]; fingerStream.Put[IO.rope[entry.user], IO.rope[" "]]; fingerStream.Put[IO.time[entry.time], IO.rope["\n"]] }; UserPropChange => { fingerStream.Put[IO.atom[userPropChangeAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.user]], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.val]], IO.rope[" "]]; fingerStream.Put[IO.time[entry.time], IO.rope["\n"]] }; MachinePropChange => { fingerStream.Put[IO.atom[machinePropChangeAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.val]], IO.rope["\n"]] }; AddMachineProp => { fingerStream.Put[IO.atom[addMachinePropAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.int[entry.version], IO.rope["\n"]] }; AddUserProp => { fingerStream.Put[IO.atom[addUserPropAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.int[entry.version], IO.rope["\n"]] }; DeleteUserProp => { fingerStream.Put[IO.atom[deleteUserPropAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.int[entry.version], IO.rope["\n"]] }; DeleteMachineProp => { fingerStream.Put[IO.atom[deleteMachinePropAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.int[entry.version], IO.rope["\n"]]}; ENDCASE; fingerStream.Flush[] }; ParseLog: PUBLIC PROC[] RETURNS[ stateLog: LIST OF LogEntry ] ~ { ENABLE FS.Error => CONTINUE; fingerStream: IO.STREAM = FS.StreamOpen[fingerLogName, $read]; BEGIN ENABLE IO.EndOfStream, IO.Error => CONTINUE; op: ATOM; nextEntry: LogEntry; WHILE TRUE DO op _ fingerStream.GetAtom[]; SELECT op FROM stateChangeAtom => { what: ATOM = fingerStream.GetAtom[]; name: Rope.ROPE = fingerStream.GetRopeLiteral[]; when: BasicTime.GMT = fingerStream.GetTime[]; nextEntry _ NEW[ StateChange LogEntryObject _ [StateChange[event: IF what = $login THEN login ELSE logout, user: name, time: when ]] ] }; userPropChangeAtom => { user: Rope.ROPE = fingerStream.GetRopeLiteral[]; name: Rope.ROPE = fingerStream.GetRopeLiteral[]; val: Rope.ROPE = fingerStream.GetRopeLiteral[]; time: BasicTime.GMT = fingerStream.GetTime[]; nextEntry _ NEW[ UserPropChange LogEntryObject _ [UserPropChange[user: user, name: name, val: val, time: time ]] ] }; machinePropChangeAtom => { name: Rope.ROPE = fingerStream.GetRopeLiteral[]; val: Rope.ROPE = fingerStream.GetRopeLiteral[]; nextEntry _ NEW[ MachinePropChange LogEntryObject _ [MachinePropChange[name: name, val: val]] ] }; addMachinePropAtom => { name: Rope.ROPE = fingerStream.GetRopeLiteral[]; version: INT = fingerStream.GetInt[]; nextEntry _ NEW[ AddMachineProp LogEntryObject _ [AddMachineProp[name: name, version: version]] ] }; addUserPropAtom => { name: Rope.ROPE = fingerStream.GetRopeLiteral[]; version: INT = fingerStream.GetInt[]; nextEntry _ NEW[ AddUserProp LogEntryObject _ [AddUserProp[name: name, version: version]] ] }; deleteUserPropAtom => { name: Rope.ROPE = fingerStream.GetRopeLiteral[]; version: INT = fingerStream.GetInt[]; nextEntry _ NEW[ DeleteUserProp LogEntryObject _ [DeleteUserProp[name: name, version: version]] ] }; deleteMachinePropAtom => { name: Rope.ROPE = fingerStream.GetRopeLiteral[]; version: INT = fingerStream.GetInt[]; nextEntry _ NEW[ DeleteMachineProp LogEntryObject _ [DeleteMachineProp[name: name, version: version]] ] }; ENDCASE; IF stateLog = NIL THEN stateLog _ LIST[nextEntry] ELSE { log: LIST OF LogEntry _ stateLog; WHILE log.rest # NIL DO log _ log.rest ENDLOOP; log.rest _ LIST[nextEntry] } ENDLOOP END; IF fingerStream # NIL THEN fingerStream.Close[! IO.Error, FS.Error => CONTINUE] }; END. ’FingerLogImpl.mesa Last Edited by: Donahue, April 23, 1985 2:37:25 pm PST Write the entry on the log file and also on the internal log list Κ‹˜codešœ™K™6—K˜šΟk ˜ K˜Kšœ œœ˜K˜K˜ Kšœœ˜Kšœ˜Kšœ˜—K˜šœœ˜K˜Kšœ˜K˜Kšœ ˜K˜š˜Kšœ ˜˜Kšœœ˜+KšœœœΟc0˜JJ˜Jšœœ ˜5Jšœœ#˜;Jšœœ&˜AJšœœ#˜;Jšœœ ˜5Jšœœ&˜AJšœœ#˜;J˜JšΟnœœœ9˜NJ˜šŸœœœœ˜2JšœA™AKšœœœœ$˜Pšœœ˜ šœ˜Jšœœœ ˜9Jš œœœœœ œ ˜YJšœœœ ˜4Jšœœœ˜7—šœ˜Jšœœœ ˜š˜Jšœœœ œ˜,Kšœœ˜ K˜šœœ˜ Kšœ˜šœ˜šœ˜Kšœœ˜$Kšœ œ!˜0Kšœœ˜-Kš œ œ3œœœ'˜‰—˜Kšœ œ!˜0Kšœ œ!˜0Kšœ œ!˜/Kšœœ˜-Kšœ œf˜u—˜Kšœ œ!˜0Kšœ œ!˜/Kšœ œS˜b—˜Kšœ œ!˜0Kšœ œ˜%Kšœ œU˜d—˜Kšœ œ!˜0Kšœ œ˜%Kšœ œO˜^—˜Kšœ œ!˜0Kšœ œ˜%Kšœ œU˜d—˜Kšœ œ!˜0Kšœ œ˜%Kšœ œ[˜j——Kšœ˜Kšœ œœ œ ˜1šœ˜Kšœœœ˜!Kšœ œœœ˜/Kšœ œ ˜K˜—Kš˜—Kšœ˜—Kš œœœœœ œ˜OJ˜——J˜—Kšœ˜—J˜—…—¦Γ