-- File: Slosher.mesa, Last Edit: HGM December 20, 1980 4:09 PM DIRECTORY Inline USING [LowHalf, LongDivMod], Process USING [Yield], Storage USING [Node], System USING [GetClockPulses], File USING [Capability], George USING [ CountFreeDiskPages, CreateInputStream, CreateOutputStream, Destroy, DiskFull, GetCreateDate, GetLength, GetWords, Handle, PutByte, PutWords, SetCreateDate, SetIndex], Slosh USING [RecvStatus, Why]; Slosher: MONITOR IMPORTS Inline, Process, Storage, System, George EXPORTS Slosh = BEGIN OPEN Slosh; RejectThisTrash: PUBLIC ERROR [text: STRING] = CODE; first: Proc ← NIL; Proc: TYPE = POINTER TO ProcObject; ProcObject: TYPE = RECORD [ next: Proc, proc: PROCEDURE [Why, STRING, File.Capability]]; AddProcs: PUBLIC ENTRY PROCEDURE [ proc: PROCEDURE [Why, STRING, File.Capability]] = BEGIN temp: Proc ← Storage.Node[SIZE[ProcObject]]; temp↑ ← [first, proc]; first ← temp; END; Check: PUBLIC PROCEDURE [fn: STRING, temp: File.Capability] = BEGIN RunTheList[check, fn, temp]; END; Release: PUBLIC PROCEDURE [fn: STRING, file: File.Capability] = BEGIN RunTheList[release, fn, file]; END; Arrived: PUBLIC PROCEDURE [fn: STRING, file: File.Capability] = BEGIN RunTheList[arrived, fn, file]; END; Failed: PUBLIC PROCEDURE [fn: STRING, file: File.Capability] = BEGIN RunTheList[failed, fn, file]; END; RunTheList: PROCEDURE [why: Why, fn: STRING, file: File.Capability] = BEGIN proc: Proc; FOR proc ← first, proc.next UNTIL proc = NIL DO proc.proc[why, fn, file]; ENDLOOP; END; RetransmissionInterval: PUBLIC PROCEDURE RETURNS [seconds: CARDINAL] = BEGIN mumble: LONG CARDINAL = System.GetClockPulses[]; -- Alto Pulses are short RETURN[Inline.LowHalf[mumble] MOD 5*60]; -- 5 min END; CopyFile: PUBLIC PROCEDURE [to, from: File.Capability] RETURNS [result: RecvStatus] = BEGIN n: CARDINAL ← 0; pagesLeft: CARDINAL; sourceLength, destLength: LONG CARDINAL; sourcePages, destPages: CARDINAL; sourceBytes, destBytes: CARDINAL; source, dest: George.Handle; buffer: PACKED ARRAY [0..512) OF [0..377B]; source ← George.CreateInputStream[from]; dest ← George.CreateOutputStream[to]; George.SetCreateDate[dest, George.GetCreateDate[source]]; BEGIN pagesLeft ← George.CountFreeDiskPages[]; destLength ← George.GetLength[dest]; George.SetIndex[dest, 0]; sourceLength ← George.GetLength[source]; George.SetIndex[source, 0]; [sourcePages, sourceBytes] ← Inline.LongDivMod[sourceLength, 512]; [destPages, destBytes] ← Inline.LongDivMod[destLength, 512]; IF (destPages + pagesLeft) < (sourcePages + 10) THEN GOTO WontFit; THROUGH [0..sourcePages) DO [] ← George.GetWords[source, @buffer, 256]; Process.Yield[]; George.PutWords[dest, @buffer, 256 ! George.DiskFull[] => GOTO FileFull]; Process.Yield[]; ENDLOOP; [] ← George.GetWords[source, @buffer, 256]; George.PutWords[ dest, @buffer, sourceBytes/2 ! George.DiskFull[] => GOTO FileFull]; IF (sourceBytes MOD 2) # 0 THEN George.PutByte[dest, buffer[sourceBytes - 1]]; result ← statusStoreOk; EXITS WontFit => result ← statusDiskFull; FileFull => result ← statusFileClobbered; END; George.Destroy[source]; George.Destroy[dest]; END; END.