-- file VirtSS.Mesa -- edited by Schroeder, January 18, 1981 3:08 PM. -- edited by Brotz, November 30, 1981 10:18 PM DIRECTORY Core USING [Close, Delete, Open], exD: FROM "ExceptionDefs" USING [SysBug], Process USING [Yield], Storage USING [Free, Node], tfD: FROM "TempFileDefs" USING [FreeTempFile], vmD: FROM "VirtualMgrDefs" USING [bugTrapValue, CleanupTOCOption, CMOCharMapTable, ComposedMessageObject, ComposedMessagePtr, DisplayMessageObject, DisplayMessagePtr, DMList, DMListBlk, ExtendTOC, FindTOCAddress, GetBuffer, LoadTOCOption, MakeBufferEmpty, PageNumber, TOC, TOCAddressOnPage, TOCFixedPart, TOCFixedPartPtr, TOCHandle, TOCIndex, TOCPageHeader, TOCPageTable, TOCPageTableSize, TOCType, VirtualMessagePtr, VirtualObject], VMDefs USING [FileHandle, GetFileLength, PageNumber, Position, Release, SetFileLength]; VirtSS: PROGRAM IMPORTS Core, exD, Process, Storage, tfD, vmD, VMDefs EXPORTS vmD = BEGIN OPEN vmD; -- Data Structures and Types. vMORoot: VirtualMessagePtr _ NIL; tOCBufferPoolSize: CARDINAL = 3; dMBufferPoolSize: CARDINAL = 3; cMBufferPoolSize: CARDINAL = 3; -- This is VirtSS, Start/Stop routines. See also VirtTOC. TOCOverflow: PUBLIC ERROR = CODE; CreateTOC: PUBLIC PROCEDURE RETURNS [toc: TOCHandle] = BEGIN toc _ Storage.Node[SIZE[TOC]]; toc^ _ VirtualObject [file: NIL, buffer: NIL, logicalPageNumber: 0, bufferState: empty, open: FALSE, vOVar: TOC [pageTable: Storage.Node[SIZE[TOCPageTable]], filePageFF: 0, -- Next avail page in TOC file. indexFF: 1, -- Next avail message index. firstChange: 0, -- No changes yet. mailFile: NIL, dmList: Storage.Node[SIZE[DMListBlk]], runArray: NIL, runs: 0, maxRuns: 0, key: 0, keyHolder: NIL]]; toc.dmList^ _ DMListBlk[next: NIL, dm: NIL]; END; -- of CreateTOC -- DestroyTOC: PUBLIC PROCEDURE [toc: TOCHandle, key: CARDINAL] = BEGIN dml, nextDml: DMList; IF key = 0 OR key # toc.key THEN exD.SysBug[]; Storage.Free[toc.pageTable]; IF toc.runArray # NIL THEN Storage.Free[toc.runArray]; IF toc.bufferState # empty THEN VMDefs.Release[toc.buffer]; FOR dml _ toc.dmList, nextDml UNTIL dml = NIL DO nextDml _ dml.next; IF dml.dm # NIL THEN exD.SysBug[]; Storage.Free[dml]; ENDLOOP; Storage.Free[toc]; END; -- of DestroyTOC -- LoadTOC: PUBLIC PROCEDURE [toc: TOCHandle, key: CARDINAL, TOCFileName: STRING, mailFileHandle: VMDefs.FileHandle, option: LoadTOCOption] RETURNS [firstUnSeen: TOCIndex] = -- Initializes the TOC virtual structure from the indicated file. If the file doesn't contain -- a recognizable TOC then an empty TOC is created in the file. Before calling this -- procedure, the client is expected to have called CleanupTOC if another TOC -- previously was in use. firstUnSeen returns the index of the first unseen entry found -- in the TOC, or 0 if no unseen entries are found. If option=new then an empty TOC -- is created in the file provided. -- May raise TOCOverflow if the mail file contains more messages than can be held in -- the TOC. BEGIN pn: PageNumber; position: VMDefs.Position; pageHeader: TOCPageHeader; index: TOCIndex; fp: TOCFixedPartPtr; zerothFP: TOCFixedPart _ [FALSE, FALSE, FALSE, FALSE, '~, 0, 0, bugTrapValue, 0, 0]; BEGIN -- for EXITS DoSomeYields: PROCEDURE = {THROUGH [1 .. 3] DO Process.Yield[]; ENDLOOP}; IF toc.open OR key = 0 OR key # toc.key THEN exD.SysBug[]; toc.file _ Core.Open[TOCFileName, update]; DoSomeYields[]; toc.open _ TRUE; --now a call to CleanupTOC[dontResetChanges or delete] will work. position _ VMDefs.GetFileLength[toc.file]; pn _ firstUnSeen _ toc.indexFF _ toc.firstChange _ 0; toc.filePageFF _ position.page; --now a call to CleanupTOC[resetChanges] will work. toc.mailFile _ mailFileHandle; IF option = new OR position.page ~IN (0 .. TOCPageTableSize] OR position.byte # 0 THEN GOTO truncateTOC; FOR pn IN [0 .. position.page) DO DoSomeYields[]; GetBuffer[toc, pn, FALSE]; pageHeader _ LOOPHOLE[toc.buffer]; IF pageHeader.numberOfEntries = 0 OR pageHeader.garbageDetector # TOCType THEN {MakeBufferEmpty[toc]; GOTO truncateTOC}; toc.pageTable[pn].firstTOCIndex _ toc.indexFF; -- 1st entry on page. toc.indexFF _ toc.indexFF + pageHeader.numberOfEntries; FOR index IN [toc.pageTable[pn] .. toc.indexFF) WHILE toc.firstChange = 0 OR firstUnSeen = 0 DO fp _ TOCAddressOnPage[toc, index, toc.buffer, pn]; IF fp.changed AND toc.firstChange = 0 THEN toc.firstChange _ index; IF ~fp.seen AND firstUnSeen = 0 THEN firstUnSeen _ index; ENDLOOP; ENDLOOP; EXITS truncateTOC => BEGIN IF position.page # pn THEN VMDefs.SetFileLength[toc.file, [pn, 0]]; toc.filePageFF _ pn; IF pn = 0 THEN ExtendTOC[toc, key, @zerothFP, "dummy"L]; END; END; -- for EXITS END; -- of LoadTOC -- CleanupTOC: PUBLIC PROCEDURE [toc: TOCHandle, key: CARDINAL, option: CleanupTOCOption] = BEGIN pageHeader: TOCPageHeader; lastPage: PageNumber; IF key = 0 OR key # toc.key THEN exD.SysBug[]; IF toc.open THEN BEGIN toc.open _ FALSE; IF option = delete THEN GOTO deleteTOC; IF option = resetChanges AND toc.firstChange # 0 THEN BEGIN [] _ FindTOCAddress[toc, toc.firstChange]; lastPage _ toc.logicalPageNumber; pageHeader _ LOOPHOLE[toc.buffer]; pageHeader.numberOfEntries _ toc.firstChange - toc.pageTable[lastPage]; toc.bufferState _ dirty; IF pageHeader.numberOfEntries = 0 THEN lastPage _ lastPage - 1; END ELSE lastPage _ toc.filePageFF - 1; MakeBufferEmpty[toc]; IF option = resetChanges AND lastPage + 1 < toc.filePageFF THEN VMDefs.SetFileLength[toc.file, [lastPage + 1, 0]]; Core.Close[toc.file]; EXITS deleteTOC => BEGIN IF toc.bufferState # empty THEN VMDefs.Release[toc.buffer]; toc.bufferState _ empty; Core.Delete[toc.file]; END; END; -- of IF toc.open. toc.mailFile _ NIL; END; -- of CleanupTOC -- SetTOCValidity: PUBLIC PROCEDURE [toc: TOCHandle, valid: BOOLEAN] = BEGIN pageHeader: TOCPageHeader; GetBuffer[toc, 0, FALSE]; pageHeader _ LOOPHOLE[toc.buffer]; pageHeader.garbageDetector _ TOCType + (IF valid THEN 0 ELSE 1); toc.bufferState _ dirty; MakeBufferEmpty[toc]; END; -- of SetTOCValidity -- AllocateDisplayMessageObject: PUBLIC PROCEDURE RETURNS [dm: DisplayMessagePtr] = BEGIN dm _ Storage.Node[SIZE[DisplayMessageObject]]; dm^ _ VirtualObject [file: NIL, buffer: NIL, logicalPageNumber: 0, bufferState: empty, open: FALSE, vOVar: VMO[next: vMORoot, textLength: 0, get: , formatStart: 0, formatEnd: 0, vMOVar: DM[firstPage: 0, firstByte: 0, toc: NIL, index: 0]]]; vMORoot _ dm; -- Splice new one into the list. END; -- of AllocateDisplayMessageObject -- FreeVirtualMessageObject: PUBLIC PROCEDURE [vm: VirtualMessagePtr] = -- DM or CM. BEGIN p, back: VirtualMessagePtr; IF (p _ vMORoot) = vm THEN vMORoot _ vm.next -- Was at head. ELSE BEGIN UNTIL p = NIL DO back _ p; p _ p.next; IF p = vm THEN EXIT; REPEAT FINISHED => exD.SysBug[]; ENDLOOP; back.next _ vm.next; --Splice it out. END; IF vm.bufferState # empty THEN VMDefs.Release[vm.buffer]; WITH msg: vm SELECT FROM DM => IF msg.open THEN exD.SysBug[]; CM => {Storage.Free[msg.charMap]; IF msg.file # NIL THEN tfD.FreeTempFile[msg.file]}; ENDCASE => exD.SysBug[]; Storage.Free[vm] END; -- of FreeVirtualMessageObject -- CleanupCMs: PUBLIC PROCEDURE = -- Truncates all backing files. BEGIN vm: VirtualMessagePtr; FOR vm _ vMORoot, vm.next UNTIL vm = NIL DO WITH msg: vm SELECT FROM DM => NULL; CM => BEGIN IF msg.bufferState # empty THEN VMDefs.Release[msg.buffer]; msg.bufferState _ empty; IF msg.file # NIL THEN tfD.FreeTempFile[msg.file]; msg.open _ FALSE; END; ENDCASE => exD.SysBug[]; ENDLOOP; END; -- of CleanupCMs. AllocateComposedMessageObject: PUBLIC PROCEDURE RETURNS [cm: ComposedMessagePtr] = BEGIN cm _ Storage.Node[SIZE[ComposedMessageObject]]; cm^ _ VirtualObject [file: NIL, buffer: NIL, logicalPageNumber: 0, bufferState: empty, open: FALSE, vOVar: VMO[next: vMORoot, textLength: , get: , formatStart: 0, formatEnd: 0, vMOVar: CM[inserting: FALSE, insertionStart: , insertionStop: , charMap: Storage.Node[SIZE[CMOCharMapTable]], filePageFF: 0]]]; vMORoot _ cm; -- Splice new one into the list. END; -- of AllocateComposedMessageObject -- END. -- of VirtSS.(635)\f1