-- 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 --