-- file VirtTOC.Mesa -- Edited by Schroeder, October 17, 1979 3:38 PM. -- Edited by Brotz, August 5, 1980 5:42 PM. -- Edited by Levin, February 25, 1981 10:37 AM. DIRECTORY crD: FROM "CoreDefs", exD: FROM "ExceptionDefs", gsD: FROM "GlobalStorageDefs", InlineDefs: FROM "InlineDefs", ovD: FROM "OverviewDefs", StringDefs: FROM "StringDefs", SystemDefs: FROM "SystemDefs", vmD: FROM "VirtualMgrDefs"; VirtTOC: PROGRAM IMPORTS crD, exD, InlineDefs, StringDefs, vmD EXPORTS vmD SHARES vmD = PUBLIC BEGIN OPEN vmD; -- Data Structures and Types. tOCp: POINTER TO TOC_GetTOCPtr[]; -- The TOC Department is implemented here and in VirtSS.mesa. ExtendTOC: PROCEDURE [fP: TOCFixedPartPtr, s: STRING] RETURNS [ovD.ErrorCode] = -- The TOC data and string are encorporated in the TOC structure at the end (with -- fP.changed_FALSE). After this procedure is called, the information and string can be -- modified with PutTOC(Data/String) and accessed with GetTOC(Data/String). BEGIN numWords,remainingWordsOnPage: CARDINAL; errorCode: ovD.ErrorCode _ ovD.ok; sLen: CARDINAL = s.length; sMaxLen: CARDINAL = MAX[sLen,tOCMinStringSize]; sWords: CARDINAL = StringDefs.WordsForString[sMaxLen]; mtPtr: MemoryTableEntryPtr; hPtr: HardTOCAddress; numWords _ SIZE[TOCFixedPart] + sWords; IF numWords > 256 - SIZE[TOCPageHdr] THEN exD.SysBug[]; IF tOCp^.indexFF=0 THEN remainingWordsOnPage _ 0 ELSE BEGIN [mtPtr,] _ GetMtPtr[tOCp, tOCp^.filePageFF-1, active]; IF mtPtr.state=unused THEN exD.SysBug[]; hPtr _ LOOPHOLE[mtPtr.address+SIZE[TOCPageHdr]]; THROUGH [tOCp^.pageTableHeader^[mtPtr^.logicalPageNumber]..tOCp^.indexFF) DO hPtr _ WordsInTOCEntry[hPtr] + hPtr; ENDLOOP; remainingWordsOnPage _ 256 - InlineDefs.BITAND[255, LOOPHOLE[hPtr, CARDINAL]]; IF remainingWordsOnPage=256 THEN remainingWordsOnPage _ 0; END; IF numWords > remainingWordsOnPage THEN BEGIN -- Get a new page. IF tOCp^.filePageFF>=tOCPageTableSize THEN RETURN [ovD.tOCOverflow]; [mtPtr,] _ GetMtPtr[tOCp, tOCp^.filePageFF, new]; hPtr _ mtPtr.address+SIZE[TOCPageHdr]; mtPtr^.address^.numberOfEntries _ 0; mtPtr^.address^.garbageDetector _ tOCType; -- for VirtualizeTOC. --make sure there's a place on the disk for the new page errorCode _ crD.WritePages[mtPtr^.address, 512, mtPtr^.filePageNumber, tOCp^.file]; SELECT errorCode FROM ovD.ok => NULL; ovD.diskFull => BEGIN --undo the extension, report disk full mtPtr.state _ unused; RETURN [ovD.diskFull] END; ENDCASE => BombIfIOError[errorCode]; tOCp^.pageTableHeader[tOCp^.filePageFF].firstTOCIndex _ tOCp^.indexFF; tOCp^.filePageFF _ tOCp^.filePageFF+1; END; -- We have gotten and inited a new page. tOCp^.indexFF_tOCp^.indexFF+1; mtPtr.address^.numberOfEntries _ mtPtr.address^.numberOfEntries+1; mtPtr.state _ dirty; fP^.changed _ FALSE; PutTOCFixedPartInMemory[fP, hPtr]; PutTOCStringInMemory[s, sWords, sLen, sMaxLen, hPtr + SIZE[TOCFixedPart]]; RETURN[ovD.ok]; END; -- of ExtendTOC. GetTOCFixedPart: PROCEDURE [index: TOCIndex, fP: TOCFixedPartPtr] = -- Obtains the index'th TOCEntry data portion and copies it into the structure pointed at by -- fP. BEGIN hPtr: HardTOCAddress; [hPtr, ] _ FindTOCAddress[index]; fP^ _ LOOPHOLE[hPtr, TOCFixedPartPtr]^; END; -- of GetTOCFixedPart. GetTOCString: PROCEDURE [index: TOCIndex, s: STRING] = -- Obtains the index'th TOCEntry string and copies as much as will fit into s. BEGIN x: CARDINAL = SIZE[CheatersSTRING]; hPtr: HardTOCAddress; s2: STRING; size: CARDINAL; [hPtr,]_FindTOCAddress[index]; s2_LOOPHOLE[hPtr+SIZE[TOCFixedPart],STRING]; size_MIN[s.maxlength, s2.length]; InlineDefs.COPY[s2+x, StringDefs.WordsForString[size]-x, s+x]; s.length_size; END; -- of GetTOCString. PutTOCFixedPart: PROCEDURE [index: TOCIndex, toc: TOCFixedPartPtr] = -- Obtains the index'th TOCEntry and copies portions of the data structure pointed to by toc -- into it. Also sets the changed flag of that TOCEntry to TRUE and marks the TOC page -- as having been written. BEGIN hPtr: HardTOCAddress; mtPtr: MemoryTableEntryPtr; [hPtr, mtPtr]_FindTOCAddress[index]; PutTOCFixedPartInMemory[toc, hPtr]; MarkChange[index, hPtr, mtPtr]; END; -- of PutTOCFixedPart. PutTOCString: PROCEDURE [index: TOCIndex, s: STRING] = -- Obtains the index'th TOCEntry and copies as much of s as will fit into the string portion -- of this entry. Marks the TOC page as having been written. BEGIN hPtr: HardTOCAddress; mtPtr: MemoryTableEntryPtr; old: STRING; sMaxLen,sLen: CARDINAL; [hPtr, mtPtr ]_ FindTOCAddress[index]; old _ LOOPHOLE[hPtr+ SIZE[TOCFixedPart], STRING]; sMaxLen _ old.maxlength; sLen _ MIN[s.length, sMaxLen]; PutTOCStringInMemory[s, StringDefs.WordsForString[sMaxLen], sLen, sMaxLen, old]; MarkChange[index, hPtr, mtPtr]; END; -- of PutTOCString. MarkChange: PRIVATE PROCEDURE [index: TOCIndex, hPtr: HardTOCAddress, mtPtr: MemoryTableEntryPtr] = -- House-keep changed records. BEGIN LOOPHOLE[hPtr, TOCFixedPartPtr]^.changed _ TRUE; tOCp^.firstChange _ IF tOCp^.firstChange=0 THEN index ELSE MIN[tOCp^.firstChange, index]; mtPtr.state_dirty; END; -- of MarkChange. GetFirstFreeTOCIndex: PROCEDURE RETURNS [TOCIndex] = -- This procedure returns the TOC Index value of the next entry available after the current -- TOC, which is equal to the number of entries in the TOC and one greater than the real -- last TOC Index. If the toc is not open then zero is returned. BEGIN RETURN[IF ~tOCp^.open THEN 0 ELSE tOCp^.indexFF]; END; -- of GetFirstFreeTOCIndex. GetFirstChangedTOCIndex: PROCEDURE RETURNS [TOCIndex] = -- Returns the TOC Index value of the 1st (i.e. the numerically lowest) TOC entry which -- has been changed via PutTOCFixedPart. This is the first TOC entry which has the -- "changed" BOOLEAN as true. ExtendTOC does not normally set this true (as does -- PutTOCFixedPart), but will respect that setting if the user does so. If no TOC entries -- have changed=TRUE, then the first free (ref. GetFirstFreeTOCIndex) index is returned. -- Non-recoverable errors: "No TOC open". BEGIN IF ~tOCp^.open THEN exD.SysBug []; RETURN[IF tOCp^.firstChange=0 THEN tOCp^.indexFF ELSE tOCp^.firstChange]; END; -- of GetFirstChangedTOCIndex. PutTOCFixedPartInMemory: PRIVATE PROCEDURE [fP: TOCFixedPartPtr, hPtr: HardTOCAddress] = -- Internal proc to stash FixedPart into memory. BEGIN fP.bugTrap_bugTrapValue; InlineDefs.COPY[fP, SIZE[TOCFixedPart], hPtr]; END; -- of PutTOCFixedPartInMemory. PutTOCStringInMemory: PRIVATE PROCEDURE [s: STRING, sWords, sLen, sMaxLen: CARDINAL, hPtr: HardTOCAddress] = -- Internal proc to stash String into memory. (This is made complicated by my avoiding -- knowing the structure of a STRING, which may change!) BEGIN InlineDefs.COPY[s,sWords,hPtr]; SmashStringSizes[LOOPHOLE[hPtr, STRING], sLen, sMaxLen]; END; -- of PutTOCFixedPartInMemory. SmashStringSizes: PRIVATE PROCEDURE [s: STRING, sLen,sMaxLen: CARDINAL] = -- BEWARE** Depends upon STRING format. ** -- Sets s.maxlength & s.length. BEGIN p: POINTER TO CheatersSTRING_LOOPHOLE[s]; p.length_sLen; p.maxlength_sMaxLen; END; -- of SmashStringSizes. GetTOCAddressOnPage: PROCEDURE [index: TOCIndex, mtPtr: MemoryTableEntryPtr] RETURNS [TOCFixedPartPtr] = BEGIN p: TOCFixedPartPtr_LOOPHOLE[mtPtr.address+SIZE[TOCPageHdr]]; first: TOCIndex = tOCp^.pageTableHeader^[mtPtr^.logicalPageNumber]; i: CARDINAL; IF mtPtr.state=unused THEN exD.SysBug[]; FOR i IN [first..index) DO p_WordsInTOCEntry[p]+p; ENDLOOP; IF p.bugTrap#bugTrapValue THEN exD.SysBug []; RETURN[p]; END; -- of GetTOCAddressOnPage. SearchTOCTable: PRIVATE PROCEDURE [index: TOCIndex] RETURNS [page: PageNumber] = -- Maps a TOCIndex to a TOC file page number. BEGIN IF index>=tOCp^.indexFF THEN exD.SysBug []; FOR page IN [1..tOCp^.filePageFF) DO IF tOCp^.pageTableHeader^[page]>index THEN EXIT; REPEAT FINISHED => page_tOCp^.filePageFF; ENDLOOP; page _ page - 1; END; -- of SearchTOCTable. WordsInTOCEntry: PROCEDURE [hPtr: HardTOCAddress] RETURNS [CARDINAL] = INLINE BEGIN fWords: CARDINAL = SIZE[TOCFixedPart]; RETURN[fWords+(LOOPHOLE[hPtr+fWords, STRING].maxlength+1)/2+2]; END; -- of WordsInTOCEntry. FindTOCAddress: PROCEDURE [index: TOCIndex] RETURNS [p: HardTOCAddress, mtPtr: MemoryTableEntryPtr] = -- You'd better be careful, cache activity may cause the pointers returned to become -- dangling references. BEGIN page: PageNumber=SearchTOCTable[index]; -- index is on "page". [mtPtr,]_GetMtPtr[tOCp, page, active]; -- Maintains page buffers. RETURN [GetTOCAddressOnPage[index,mtPtr],mtPtr]; END; --of FindTOCAddress. VirtualizeMessage: PROCEDURE [index: TOCIndex, msg: DisplayMessagePtr] RETURNS [ovD.ErrorCode] = -- Calls ClearMessage[msg] and then initializes msg to be the messsage string pointed to by -- the index TOC entry. Any previous contents of msg are lost. BEGIN hPtr: HardTOCAddress; mtPtr: MemoryTableEntryPtr; tOCPtr: POINTER TO TOC = GetTOCPtr[]; fP: TOCFixedPartPtr; -- What a waste, fighting the type checker. IF ~tOCPtr^.open THEN exD.SysBug[]; [hPtr,mtPtr]_FindTOCAddress[index]; -- "SysBugs" errors. fP_LOOPHOLE[hPtr]; -- Sigh. There must be a better way! FOR mtPtr_msg^.memoryHeader, mtPtr.next UNTIL mtPtr=NIL DO mtPtr.state_unused; ENDLOOP; VoidCharCache[@msg.get]; msg^.file_tOCPtr^.mailFile; msg^.open_TRUE; msg^.firstPage_fP.firstPage; msg^.firstByte_fP.firstByte+fP.offsetToHeader; msg^.textLength_fP.textLength; -- in bytes, -- Note: I'm supposed to check that the last character of the stamp is a , but that's a real -- pain to do. RETURN [ovD.ok]; END; --of VirtualizeMessage. END. -- of VirtTOCz20461(529)\f1