DIRECTORY AlpineCmds, AlpineFS USING [StreamOpen], FS USING [Error, ErrorDesc, ErrorFromStream], GVBasics USING [RName], IO, Log USING [ Problem, Report ], Names USING [ CurrentRName ], Nuthatch USING [NuthatchUserHandle, pd], NuthatchLog, Process USING [ EnableAborts ], Rope USING [Cat, ROPE], UserProfile USING [ Token ] ; NuthatchLogImpl: CEDAR MONITOR IMPORTS AlpineCmds, AlpineFS, FS, IO, Log, Names, Nuthatch, Process, Rope, UserProfile EXPORTS NuthatchLog = { Handle: TYPE = Nuthatch.NuthatchUserHandle; Error: PUBLIC ERROR[code: NuthatchLog.ErrorCode] = CODE; WriteLogEntry: PUBLIC ENTRY PROC [ logRope: Rope.ROPE, handle: Handle] = { DO ENABLE { UNWIND => { handle.inUse_FALSE; BROADCAST handle.doneUsing; }; IO.Error => IF HandleECError[handle, ec].retry THEN LOOP; FS.Error => IF HandleFSError[handle, error].retry THEN LOOP; }; WHILE handle.inUse DO WAIT handle.doneUsing; ENDLOOP; IF handle.logStream = NIL THEN { OpenLog[handle]; LOOP; }; handle.logStream.SetIndex[handle.logStream.GetLength[]]; handle.logStream.PutRope[logRope]; IF Nuthatch.pd.reportLogOut THEN Log.Report[Rope.Cat["Log <= ", logRope]]; handle.logStream.Flush[]; EXIT; ENDLOOP; }; HandleECError: INTERNAL PROC[handle: Handle, ec: IO.ErrorCode] RETURNS[retry: BOOL_FALSE] = { handle.inUse_FALSE; IF ec=StreamClosed THEN { handle.logStream_NIL; RETURN[TRUE]; }; RETURN[HandleFSError[handle, FS.ErrorFromStream[handle.logStream]]]; }; HandleFSError: INTERNAL PROC[handle: Handle, error: FS.ErrorDesc] RETURNS [retry: BOOL_FALSE] = { SELECT error.group FROM $environment => SELECT error.code FROM $transAborted => retry_TRUE; ENDCASE => Log.Problem[error.explanation, $System]; $lock, $user => Log.Problem[error.explanation, $System]; ENDCASE; handle.inUse_FALSE; IF ~retry THEN handle.logStream.Close[abort: TRUE!IO.Error=>CONTINUE]; handle.logStream _ NIL; }; SetLogIndex: PUBLIC ENTRY PROC [handle:Handle] = { DO ENABLE { UNWIND => { handle.inUse _ FALSE; BROADCAST handle.doneUsing; }; IO.Error => IF HandleECError[handle, ec].retry THEN LOOP; FS.Error => IF HandleFSError[handle, error].retry THEN LOOP; }; logReadPoint: INT; WHILE handle.inUse DO WAIT handle.doneUsing; ENDLOOP; handle.inUse _ TRUE; logReadPoint_handle.logReadPoint; IF logReadPoint=-1 THEN ERROR; IF handle.logStream = NIL THEN { OpenLog[handle]; handle.inUse _ FALSE; LOOP; }; IO.SetIndex[handle.logStream, logReadPoint]; EXIT; ENDLOOP; }; ReadLogEntry: PUBLIC ENTRY PROC [handle:Handle] RETURNS[logEntryRope: Rope.ROPE_NIL, endOfLog: BOOL_FALSE] = { ENABLE { UNWIND => { handle.inUse _ FALSE; BROADCAST handle.doneUsing; }; IO.EndOfStream => { endOfLog_TRUE; CONTINUE; }; IO.Error => IF HandleECError[handle, ec].retry THEN ERROR Error[aborted]; FS.Error => IF HandleFSError[handle, error] THEN ERROR Error[aborted]; }; IF ~handle.inUse THEN ERROR; IF handle.logStream = NIL THEN ERROR Error[aborted]; IF handle.logStream.EndOf[] THEN { endOfLog_TRUE; RETURN; }; []_IO.SkipWhitespace[handle.logStream]; -- Flush blanks logEntryRope_IO.GetLineRope[handle.logStream]; IF Nuthatch.pd.reportLogIn THEN Log.Report[Rope.Cat["Log => ", logEntryRope]]; }; UpdateLogIndex: PUBLIC ENTRY PROC [handle:Handle] = { ENABLE { UNWIND => { handle.inUse _ FALSE; BROADCAST handle.doneUsing; }; IO.Error => IF HandleECError[handle, ec].retry THEN ERROR Error[aborted]; FS.Error => IF HandleFSError[handle, error] THEN ERROR Error[aborted]; }; newReadPoint: INT; IF ~handle.inUse THEN ERROR; newReadPoint_IO.GetIndex[handle.logStream]; handle.logReadPoint _ newReadPoint; handle.inUse _ FALSE; BROADCAST handle.doneUsing; }; OpenLog: PROC [handle: Handle] = { logFilePrefix: Rope.ROPE = UserProfile.Token[ key: "NuthatchLogPrefix", default: "[Luther.Alpine]Strowger>"]; IF handle.userName=NIL THEN handle.userName _ Names.CurrentRName[]; handle.logFileName_ Rope.Cat[logFilePrefix, "Logs>", handle.userName]; TRUSTED { Process.EnableAborts[@handle.doneUsing]; }; handle.logStream _ AlpineFS.StreamOpen[ name: handle.logFileName, accessOptions: $append ]; }; InitializeLog: PUBLIC PROC [handle: Handle] = { }; Zap: PROC[files: Rope.ROPE_NIL, reallyZap: BOOL_FALSE] = { filePattern: Rope.ROPE _ Rope.Cat["[Luther.Alpine]", IF files#NIL THEN files ELSE "*"]; fileL: LIST OF REF _ AlpineCmds.List[filePattern]; FOR fl: LIST OF REF _ fileL, fl.rest WHILE fl#NIL DO fileName: Rope.ROPE _ NARROW[fl.first]; Log.Report[fileName]; IF reallyZap THEN [] _ AlpineCmds.Delete[Rope.Cat["[Luther.Alpine]", fileName]]; ENDLOOP; }; Get: PROC[file: Rope.ROPE] = { remoteFile: Rope.ROPE_Rope.Cat["[Luther.Alpine]", file]; AlpineCmds.Copy[to: file, from: remoteFile]; }; }. File: NuthatchLogImpl.mesa Last Edited by: Swinehart, October 14, 1985 4:03:08 pm PDT Do the flush, which commits the write to an Alpine file. Success=TRUE, in this instance, means that the original error should be rejected. Read the next entry in the user's Nuthatch log and return it as a rope. Read the next entry in the user's Nuthatch log and return it as a rope. This stuff has all been moved to OpenLog, which is called automatically when needed logFilePrefix: Rope.ROPE = UserProfile.Token[ key: "NuthatchLogPrefix", default: "[Luther.Alpine]Strowger>"]; IF handle.userName=NIL THEN handle.userName _ Names.CurrentRName[]; handle.logFileName_ Rope.Cat[logFilePrefix, "Logs>", handle.userName]; TRUSTED { Process.EnableAborts[@handle.doneUsing]; }; ÊŘJšœ™Jšœ:™:J˜šÏk ˜ J˜ Jšœ œ˜Jšœœ%˜-Jšœ œ ˜Jšœ˜Jšœœ˜Jšœœ˜Jšœ œ˜(J˜ Jšœœ˜Jšœœœ˜Jšœ œ ˜J˜J˜—šœœœ˜Jšœœœ3˜WJšœ˜—J˜Jšœœ˜+Jšœœœ œ˜8J˜š Ïn œœœœœ˜Jš˜šœ˜Jšœœ œ˜>Jšœ œ!œœ˜9Jšœ œ$œœ˜Jšœœœ˜Jšœ œ˜Jš œœœœœ˜@Jšœœ%˜DJ˜J˜—šž œœœœ ˜AJšœ œœ˜J™Qšœ ˜šœœ ˜&Jšœœ˜Jšœ,˜3—Jšœ8˜8Jšœ˜—Jšœ œ˜Jš œœœœœ˜FJšœœ˜J˜—J˜šž œœœœ˜2Jš˜šœ˜Jšœœ œ˜@Jšœ œ!œœ˜9Jšœ œ$œœ˜šœ˜Jšœœ œ˜@Jšœœœ˜/Jšœ œ!œœ˜IJšœ œœœ˜FJšœ˜—Jšœœœ˜Jšœœœœ˜4JšœH™HJšœœ œœ˜