-- file VirtualMgrDefs.Mesa -- edited by Schroeder, January 13, 1980 7:22 PM. -- edited by Brotz, August 13, 1982 3:49 PM. -- edited by Horning, February 17, 1978 6:24 PM. -- edited by Kierr, February 3, 1978 4:15 PM. -- edited by Levin, January 16, 1981 11:27 AM. -- edited by Taft, May 9, 1983 4:30 PM DIRECTORY exD: FROM "ExceptionDefs" USING [Exception], VMDefs USING [FileHandle, Page, PageByteIndex, PageNumber]; vmD: DEFINITIONS = BEGIN -- Purpose. This division manages virtual structures for the message system in such a -- way that their virtualization is all but transparent to the several clients. Departments -- in this division include: the TOC Department, which maintains the table of contents -- of message files; the Message Department, which maintains messages as virtual -- strings; and the Editor Department, which supplies needed support in editing strings. -- TOC Department of the Virtual Storage Division manages the table of contents. The -- TOC is a virtual structure: it includes an index and a cache of demand paged -- buffers. The fact that the TOC is virtual is invisible to the client. An anticipated -- error condition is having a message file too large to fit into the virtual TOC structure, -- since there is a limit on the number of messages in a TOC. In this case, Laurel must -- fail in a soft mode: the user will be warned that his TOC contains only the initial -- part of the full TOC, and she will be expected to move some of the messages to -- another message file. TOCOverflow: ERROR; -- May be raised by ExtendTOC or LoadTOC. The resulting TOC is valid for a prefix of -- the corresponding mail file, but some messages at the end of the mail file will not be -- indexed in the TOC. CreateTOC: PROCEDURE RETURNS [toc: TOCHandle]; -- Allocates the TOC data structures and returns a handle to same. WaitForLock: PROCEDURE [toc: TOCHandle] RETURNS [key: CARDINAL]; -- Busy waits until it can return a non-zero key for toc. The key returned must be -- passed to any other virtual TOC procedures. LockTOC: PRIVATE PROCEDURE [toc: TOCHandle] RETURNS [key: CARDINAL]; -- Returns either 0, meaning that the toc is already locked, or some key # 0. A caller -- that receives a 0 must not call any other procedures requiring the TOC key. A non-0 -- key may be used by the caller in subsequent calls to VirtTOC procedures until the -- toc is unlocked by explicit call to UnlockTOC. UnlockTOC: PROCEDURE [toc: TOCHandle, key: CARDINAL]; -- Relinquishes the lock on this TOC handle. DestroyTOC: PROCEDURE [toc: TOCHandle, key: CARDINAL]; -- Deallocates all structures associated with a mail file TOC. The caller must not reuse the -- handle after calling this procedure. CleanupTOC: PROCEDURE [toc: TOCHandle, key: CARDINAL, option: CleanupTOCOption]; -- DMS should call this procedure prior to exiting, so that this department can have a -- chance to do any last minute housekeeping, such as restoring any dirty cache pages -- to the TOC file and closing the TOC file. CleanupTOC should also be called when -- changing from one message file to another. This procedure can be called even if -- there is no TOC file currently opened. -- Option = resetChanges causes all changed entries to be marked unchanged and all -- deleted entries to be removed. -- Option = dontResetChanges causes changed and deleted entries are left as they are. -- Option = delete causes the TOC file to be deleted. LoadTOC: 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. ExtendTOC: PROCEDURE [toc: TOCHandle, key: CARDINAL, fp: TOCFixedPartPtr, s: STRING]; -- The TOC data and string are incorporated in the TOC structure at the end. After this -- procedure is called, the information and string can be modified with -- PutTOC(FixedPart/String) and accessed with GetTOC(FixedPart/String). Care is taken -- to allocate a disk page for each new page of the TOC that is assigned. -- May raise TOCOverflow. SetTOCValidity: PROCEDURE [toc: TOCHandle, valid: BOOLEAN]; -- Flags the TOC as indicated by 'valid'. If, when LoadTOC is called, the TOC is -- invalid, LoadTOC will return an error code. GetTOCFixedPart: PROCEDURE [toc: TOCHandle, key: CARDINAL, index: TOCIndex, fp: TOCFixedPartPtr]; -- Obtains the index'th TOCEntry data portion and copies it into the structure pointed at -- by fP. GetTOCString: PROC [toc: TOCHandle, key: CARDINAL, index: TOCIndex, s: STRING]; -- Obtains the index'th TOCEntry string and copies as much as will fit into s. PutTOCFixedPart: PROCEDURE [toc: TOCHandle, key: CARDINAL, index: TOCIndex, fp: TOCFixedPartPtr, changed: BOOLEAN _ TRUE]; -- 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 "changed" and marks the -- TOC page as having been written. PutTOCString: PROC [toc: TOCHandle, key: CARDINAL, 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. FirstFreeTOCIndex: PROCEDURE [toc: TOCHandle, key: CARDINAL] RETURNS [index: 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. FirstChangedTOCIndex: PROCEDURE [toc: TOCHandle] RETURNS [index: 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. -- The Message Department of the Virtual Storage Division manages message strings, i.e. -- virtual messages. Note that the GetMessageChar procedure is designed to shield the -- client from the virtual structure of message storage. -- There are 2 kinds (i.e. variants) of virtual message objects: display and compose. The -- Editor Department deals with the latter, and this department deal with both. -- Procedures which require one or the other type so specify in their arguments' types. -- Procedures that can take either kind of virtual message object take -- VirtualMessagePtrs. MessageOverflow: ERROR; -- May be raised by any procedure that inserts into a ComposedMessage. The limit of -- any ComposedMessage is slightly less than 64K characters. AllocateDisplayMessageObject: PROCEDURE RETURNS [DisplayMessagePtr]; FreeVirtualMessageObject: PROCEDURE [vm: VirtualMessagePtr]; LoadDisplayMessage: PROCEDURE [toc: TOCHandle, key: CARDINAL, index: TOCIndex, msg: DisplayMessagePtr]; -- Initializes msg to be the messsage string pointed to by the index TOC entry. Any -- previous contents of msg are lost. FlushDisplayMessage: PROCEDURE [msg: DisplayMessagePtr, key: CARDINAL]; -- Notifies the virtual manager that a displayed message is no longer in use. CheckpointDisplayMessage: PROCEDURE [msg: DisplayMessagePtr, key: CARDINAL]; -- In cases where the mail file is to be written (as when appending to the file), this -- procedure updates the mail file to contain all changes in msg. msg is manipulated so -- that subsequent accesses to its contents will require initial reading from the mail file -- once again. GetMessageChar: PROCEDURE [vm: VirtualMessagePtr, index: CharIndex] RETURNS [CHARACTER]; -- Obtains the index'th character (starting at zero) from the virtual structure vs. -- Maintains a cache for quick access to the index'th character or its neighbors on the -- next call. PutMessageChar: PROCEDURE [vm: VirtualMessagePtr, index: CharIndex, char: CHARACTER]; -- The character at position index is overwritten with char. GetMessageSize: PROCEDURE [msg: VirtualMessagePtr] RETURNS [CharIndex] = INLINE {RETURN [msg.textLength]}; -- Returns the size of the message, which is equal to the first free CharIndex. ComposedMessage: PROC [vmp: VirtualMessagePtr] RETURNS [ComposedMessagePtr] = -- Narrows vmp to cmp. INLINE {WITH cm: vmp SELECT FROM CM => RETURN[@cm]; ENDCASE => ERROR}; DisplayMessage: PROC [vmp: VirtualMessagePtr] RETURNS [DisplayMessagePtr] = -- Narrows vmp to dmp. INLINE {WITH dm: vmp SELECT FROM DM => RETURN[@dm]; ENDCASE => ERROR}; -- The Editor Department of the Virtual Storage Division supports the editor used to edit -- messages and and provides virtual backing storage for any operations that have such -- requirements. It deals in terms of messages which are ComposedMessageObjects, a -- variant of VMOs. AllocateComposedMessageObject: PROCEDURE RETURNS [ComposedMessagePtr]; InitComposedMessage: PROCEDURE [cm: ComposedMessagePtr, s: STRING]; -- The composeMessage is initialized to contain the string. CleanupCMs: PROCEDURE; -- Truncates backing files for all CMs. ReplaceRangeInMessage: PROCEDURE [to, from: MessageRange]; -- The characters contained in the to range are overwritten with the characters contained -- in the from range. to and from must be in different VMOs. to's VMO must be a -- CM, and from's VMO can be a CM or a DM. InsertRangeInMessage: PROCEDURE [targetIndex: CharIndex, targetMessage: ComposedMessagePtr, from: MessageRange]; -- The characters contained in the from range are inserted in the target message just -- before the targetIndex character. targetMessage and from must be in different VMOs. -- The former must be a CM, and the latter can be a CM or a DM. -- May raise MessageOverflow. DeleteRangeInMessage: PROCEDURE [from: MessageRange]; -- The characters in the range [from.first .. from.end) are deleted from msg. InsertFileInMessage: PROCEDURE [targetIndex: CharIndex, targetMessage: ComposedMessagePtr, file: STRING]; -- Inserts the entire contents of the file in the message starting just before the targetIndex. -- May raise opD.FileOpError or MessageOverflow. PutRangeInFile: PROCEDURE [from: MessageRange, file: STRING, concurrenceNeeded: BOOLEAN, UserConcurs: PROCEDURE [exD.Exception] RETURNS [BOOLEAN]]; -- Overwrites the entire contents of the file with the characters from the message range. -- Pseudo CR's are converted to blanks. If file not empty and concurrenceNeeded, then -- UserConcurs is called and the put proceeds only if TRUE is returned. -- May raise opD.FileError. AppendMessageChar: PROCEDURE [cm: ComposedMessagePtr, char: CHARACTER]; -- The character, char, is appended to the end of the msg. -- May raise MessageOverflow. UnAppendMessageChar: PROCEDURE [cm: ComposedMessagePtr]; -- This routine is used to process a backspace. It deletes the last character in the msg. StartMessageInsertion: PROCEDURE [cm: ComposedMessagePtr, where: CharIndex]; -- Initializes a ComposedMessage for insertion just before the character "where". This -- procedure must be called before the other insertion procedures, and eventually -- followed by either StopMessageInsertion or AbandonMessageInsertion. InsertMessageChar: PROCEDURE [cm: ComposedMessagePtr, char: CHARACTER]; -- The character is appended to the current insertion. -- May raise MessageOverflow. UnInsertMessageChar: PROCEDURE [cm: ComposedMessagePtr]; -- This routine is used to process a backspace. It deletes the last character in an insertion, -- and is a nop if the insertion is empty. InsertSubstringInMessage: PROCEDURE [cm: ComposedMessagePtr, source: STRING, first: CARDINAL, charsToCopy: CARDINAL]; -- "source"["first" .. "first" + "charsToCopy") are inserted in "cm" at the current insertion -- point. "source".length and "source".maxlength are not referenced. -- May raise MessageOverflow. InsertStringInMessage: PROCEDURE [cm: ComposedMessagePtr, s: STRING] = INLINE {InsertSubstringInMessage[cm, s, 0, s.length]}; -- Inserts all of "s" at the current insertion point. -- May raise MessageOverflow. StopMessageInsertion: PROCEDURE [cm: ComposedMessagePtr]; -- The current insertion is terminated, and the inserted characters become part of the -- message. AbandonMessageInsertion: PROCEDURE [cm: ComposedMessagePtr]; -- The current insertion is discarded, and the inserted characters go away. -- Internal procedures common to several modules SearchTOCTable: PROCEDURE [toc: TOCHandle, index: TOCIndex] RETURNS [pn: PageNumber]; -- Maps a TOCIndex to a TOC file page number. FindTOCAddress: PROCEDURE [toc: TOCHandle, index: TOCIndex] RETURNS [hta: HardTOCAddress]; -- You'd better be careful, cache activity may cause the pointers returned to become -- dangling references. -- Leaves the toc page containing index in toc.buffer. TOCAddressOnPage: PROCEDURE [toc: TOCHandle, index: TOCIndex, page: VMDefs.Page, pn: PageNumber] RETURNS [TOCFixedPartPtr]; VoidCharCache: PROCEDURE [c: POINTER TO CharCache]; InvalidateCaches: PROCEDURE; -- Invalidates caches for all CM and DM objects and frees up the virtual memory -- buffers they are holding onto. MapCharIndexToPageByte: PROCEDURE [cm: ComposedMessagePtr, index: CharIndex] RETURNS [page: PageNumber, byte: PageByteIndex]; SetGetCacheForCMPage: PROCEDURE [cm: ComposedMessagePtr, pn: PageNumber, index: CharIndex, newPage: BOOLEAN, tryCompaction: BOOLEAN]; -- If option is "new" then insert a new logical page at number lpn and set g.first and -- g.free to index (the first character to be put in the page). If option is "old" then get -- the logical page with number lpn into the page cache and set the get cache to -- reference the contained characters. GetBuffer: PROCEDURE [vop: VirtualObjectPtr, pn: PageNumber, newPage: BOOLEAN]; -- Obtains a buffer for page number "pn" of "vop". If "pageState" = new, then a new -- page is created at this "pn" (it better be the last page). If "pageState" = old, then -- existing page "pn" is read from vop's file. GetCMBuffer: PROCEDURE [cm: ComposedMessagePtr, pn: PageNumber, index: CharIndex, newPage: BOOLEAN, tryCompaction: BOOLEAN] RETURNS [firstIndex: CharIndex, npn: PageNumber]; -- Obtains a buffer page that contains index. At the time of the call, "index" is the first -- character index on logical page "pn". Due to compaction, "index" may move to a -- different page and may not be the first index on that page any more. The actual -- page obtained is returned in "npn" and the first index on this page is returned in -- "firstIndex". -- If "newPage" is TRUE, then new logical page "pn" is obtained. Due to compaction, the -- actual page obtained may be different, and its number is likewise returned in "npn". -- Compaction will be tried only if "tryCompaction" is TRUE. -- Any compaction will be reflected in cm's charMap. MergeBufferWithNeighbors: PROCEDURE [cm: ComposedMessagePtr, pn: PageNumber, index: CharIndex] RETURNS [npn: PageNumber, firstIndex: CharIndex]; -- If possible, the logical page in cm.buffer and the logical pages immediately preceding -- and following this page are compacted. The resulting compacted page remains in -- cm.buffer, and the char map table is updated. "index" is the first CharIndex on some -- logical page "pn" at the time of the call to MergeBufferWithNeighbors. At the return -- of this procedure, "npn" is the logical page which contains "index", and "firstIndex" -- is the firstCharIndex on page "npn". MakeBufferEmpty: PROCEDURE [vop: VirtualObjectPtr]; -- Writes the buffer associated with "vop" if dirty. EnsureCMBackingFile: PROCEDURE [cm: ComposedMessagePtr]; -- Slides a backing file under the cm when needed. -- Data Structures and Types. CharIndex: TYPE = CARDINAL; PageNumber: TYPE = VMDefs.PageNumber; PageByteIndex: TYPE = VMDefs.PageByteIndex; TOCMinStringSize: CARDINAL = 12; --smallest "maxlength". TOCPageTableSize: CARDINAL = 64; -- app. 7-9 entries fit on a page TOCType: CARDINAL = 1; -- For TOCPageHeader.garbageDetector. VirtualObjectPtr: TYPE = POINTER TO VirtualObject; VirtualObject: TYPE = RECORD [file: VMDefs.FileHandle, buffer: VMDefs.Page, logicalPageNumber: PageNumber, -- for buffer. bufferState: BufferState, open: BOOLEAN, vOVar: SELECT VOType:* FROM TOC => [pageTable: POINTER TO TOCPageTable, filePageFF: PageNumber, -- Next avail page in TOC file. indexFF: TOCIndex, -- Next avail message index. firstChange: TOCIndex, -- 0 or 1st entry "changed". mailFile: VMDefs.FileHandle, -- from New/Virtualize-TOC. dmList: DMList, runArray: TOCRunArray, runs: CARDINAL, maxRuns: CARDINAL, key: CARDINAL, keyHolder: PROGRAM], VMO => [next: VirtualMessagePtr, textLength: CharIndex, -- in bytes, get: CharCache, -- For GetMessageChar look-ahead. formatStart: CharIndex, formatEnd: CharIndex, vMOVar: SELECT vmoType: VMOType FROM DM => -- DisplayMessage. [firstPage: PageNumber, firstByte: PageByteIndex, toc: TOCHandle, index: TOCIndex], CM => -- ComposedMessage. [inserting: BOOLEAN, --following for TRUE only insertionStart: CharIndex, insertionStop: CharIndex, charMap: POINTER TO CMOCharMapTable, filePageFF: PageNumber], ENDCASE], ENDCASE]; BufferState: TYPE = {empty, clean, dirty}; CharCache: TYPE = RECORD -- To access the char "i" of message "msg": -- "i" must be in [first .. free) -- Then use: msg.buffer[floor + i - first] [first, -- first char on page. free: CharIndex, -- first char off page. floor: VMDefs.PageByteIndex]; -- Space at beginning of buffer. TOC: TYPE = TOC VirtualObject; TOCHandle: TYPE = POINTER TO TOC; TOCIndex: TYPE = CARDINAL; -- Note: 0 not used. TOCRunRange: TYPE = RECORD [low, high: TOCIndex]; TOCRunArrayBlk: TYPE = ARRAY [0 .. 0) OF TOCRunRange; TOCRunArray: TYPE = POINTER TO TOCRunArrayBlk; TOCFixedPartPtr: TYPE = POINTER TO TOCFixedPart; TOCFixedPart: TYPE = RECORD [changed, deleted, seen, bogus: BOOLEAN, --this entry spans bad data-- mark: CHARACTER, firstPage: PageNumber, firstByte: PageByteIndex, bugTrap: [0 .. 127], --_bugTrapValue, Early warning device. offsetToHeader, textLength: CharIndex]; -- in bytes bugTrapValue: [0 .. 127] = 131B; -- for "quick fail". TOCPageHeaderBlk: TYPE = RECORD -- One of these at beginning of each toc file page. [numberOfEntries: CARDINAL, garbageDetector: CARDINAL]; -- gets TOCType TOCPageHeader: TYPE = POINTER TO TOCPageHeaderBlk; TOCPageTable: TYPE = ARRAY[0 .. TOCPageTableSize) OF TOCPageTableEntry; TOCPageTableEntry: TYPE = RECORD [firstTOCIndex: TOCIndex]; HardTOCAddress: TYPE = POINTER; -- to a TOC entry. VMOType: TYPE = {DM, CM}; DMListBlk: TYPE = RECORD [next: DMList, dm: DisplayMessagePtr]; DMList: TYPE = POINTER TO DMListBlk; CMOCharMapTableSize: CARDINAL = 128; -- Max pages/CMO file. CMOMaxCharPerPage: CARDINAL = 511; -- Waste 1 to save table space. VirtualMessagePtr: TYPE = POINTER TO VirtualMessageObject; VirtualMessageObject: TYPE = VMO VirtualObject; DisplayMessagePtr: TYPE = POINTER TO DisplayMessageObject; DisplayMessageObject: TYPE = DM VirtualMessageObject; ComposedMessagePtr: TYPE = POINTER TO ComposedMessageObject; ComposedMessageObject: TYPE = CM VirtualMessageObject; MessageRange: TYPE = RECORD [start: CharIndex, end: CharIndex, message: VirtualMessagePtr]; CMOCharMapTable: TYPE = ARRAY PageNumber[0 .. CMOCharMapTableSize) OF RECORD [count: CARDINAL[0 .. CMOMaxCharPerPage], -- Good chars/page. page: PageNumber[0 .. CMOCharMapTableSize)]; -- corresp fpn. GetMtPtrState: TYPE = {new, active, inactive}; CleanupTOCOption: TYPE = {resetChanges, dontResetChanges, delete}; LoadTOCOption: TYPE = {new, old}; END. -- of VirtualMgrDefs --z19932l2999(529)\f1