DIRECTORY Atom, BasicTime USING [GMT], Booting, Convert, FingerLog, FS USING[StreamOpen, Error], IO, Rope; FingerLogImpl: CEDAR MONITOR IMPORTS Atom, Booting, Convert, FS, IO EXPORTS FingerLog = BEGIN OPEN FingerLog; fingerLogName: Rope.ROPE = "///Temp/Finger.Log"; fingerStream: IO.STREAM; 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 ENTRY PROC[] ~ { IF fingerStream # NIL THEN fingerStream.Close[]; fingerStream _ FS.StreamOpen[fingerLogName, $write]; fingerStream.SetLength[0]; fingerStream.Close[]; fingerStream _ NIL }; Log: PUBLIC ENTRY 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[" "]]; fingerStream.Put[IO.rope[entry.machine], 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.machine]], 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 ENTRY PROC[] RETURNS[ stateLog: LIST OF LogEntry ] ~ { ENABLE FS.Error => GOTO Quit; IF fingerStream # NIL THEN fingerStream.Close[]; fingerStream _ 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[]; machine: Rope.ROPE = fingerStream.GetRopeLiteral[]; nextEntry _ NEW[ StateChange LogEntryObject _ [StateChange[event: IF what = $login THEN login ELSE logout, user: name, time: when, machine: machine ]] ] }; 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 => { machine: Rope.ROPE = fingerStream.GetRopeLiteral[]; name: Rope.ROPE = fingerStream.GetRopeLiteral[]; val: Rope.ROPE = fingerStream.GetRopeLiteral[]; nextEntry _ NEW[ MachinePropChange LogEntryObject _ [MachinePropChange[machine: machine, 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; fingerStream.Close[! IO.Error, FS.Error => CONTINUE]; fingerStream _ NIL EXITS Quit => {IF fingerStream # NIL THEN fingerStream.Close[! IO.Error, FS.Error => CONTINUE]; fingerStream _ NIL} }; CloseDown: Booting.CheckpointProc ~ { IF fingerStream # NIL THEN { fingerStream.Close[! IO.Error, FS.Error => CONTINUE]; fingerStream _ NIL }; }; Booting.RegisterProcs[c: CloseDown]; END. FingerLogImpl.mesa Last Edited by: Donahue, August 14, 1985 1:05:03 pm PDT Carl Hauser, October 19, 1986 12:56:48 pm PDT Spreitzer, August 11, 1985 5:11:26 pm PDT Gifford, July 26, 1985 12:02:15 pm PDT Ewan Tempero August 15, 1986 11:52:11 am PDT a stream always opened to the finger log file. Normally, the stream is opened for appending; when executing a ParseLog it is opened for reading and then closed Write the entry on the log file Ewan Tempero August 15, 1986 11:51:47 am PDT Put the log where is really belongs, in ///Temp. Κ˜codešœ™K™7K™-K™)K™&K™,—K˜šΟk ˜ K˜Kšœ œœ˜K˜K˜K˜ Kšœœ˜Kšœ˜Kšœ˜—K˜šœœ˜K˜Kšœ˜&K˜Kšœ ˜K˜š˜Kšœ ˜˜Kšœœ˜0šœœœ˜Kšœ ™ —J˜Jšœœ ˜5Jšœœ#˜;Jšœœ&˜AJšœœ#˜;Jšœœ ˜5Jšœœ&˜AJšœœ#˜;J˜šΟnœœ œ˜!Kšœœœ˜0Kšœœ#˜4Jšœ˜Jšœ˜Jšœœ˜—J˜šžœœ œœ˜8Jšœ™Kšœœœœ$˜Pšœœ˜ šœ˜Jšœœœ ˜9Jš œœœœœ œ ˜YJšœœœ ˜4Jšœœœ ˜4Jšœœœ˜:—šœ˜Jšœœœ ˜