-- file VirtualMgrDefs.Mesa
-- edited by Schroeder, January 13, 1980 7:22 PM.
-- edited by Brotz, August 14, 1980 4:00 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.

DIRECTORY
crD: FROM "CoreDefs",
exD: FROM "ExceptionDefs",
gsD: FROM "GlobalStorageDefs",
ovD: FROM "OverviewDefs";


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 to 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 vritual structure: it includes an index and a cache of demand paged buffers. The
-- fact that the TOC is virtual is invisable to the client. An anticipated error condition is
-- having a message file to large to fit into the virtual TOC structure, since there needs to
-- be a limit on the number of messages in a TOC. In this case, DMS must fail in a soft
-- mode: the user will be warned that his TOC contains only the initial part of the full
-- TOC, and he will be expected to move some of the messages to another message file.


CleanupTOC: PROCEDURE [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 clanged entries to be
-- marked unchanged and all deleted entries to be reoved. Option = dontResetChanges
-- causes changed and deleted entries are left as they are. Option = delete causes the TOC
-- file to be deleted.


VirtualizeTOC: PROCEDURE [user: crD.DMSUser, tOCFileName: crD.UFilename,
mailFileHandle: crD.UFileHandle, option: VirtualizeTOCOption]
RETURNS [firstUnSeen: TOCIndex, err: ovD.ErrorCode];
-- 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 than an empty TOC is created in the
-- file provided.


ExtendTOC: PROCEDURE [fP: TOCFixedPartPtr, s: STRING] RETURNS [ovD.ErrorCode];
-- The TOC data and string are encorporated in the TOC structure at the end. After this
-- procedure is called, the information and string can be modified with
-- PutTOC(Data/String) and accessed with GetTOC(Data/String). Care is taken to allocate a
-- disk page for each new page of the TOC that is assigned.


SetTOCValidity: PROCEDURE [valid: BOOLEAN];
-- Flags the TOC as indicated by ’valid’. If, when VirtualizeTOC is called, the TOC is
-- invalid, VirtualizeTOC will return an error code.


GetTOCFixedPart: PROCEDURE [index: TOCIndex, fP: TOCFixedPartPtr];
-- Obtains the index’th TOCEntry data portion and copies it into the structure pointed at by
-- fP.


GetTOCString: PROCEDURE [index: TOCIndex, s: STRING];
-- Obtains the index’th TOCEntry string and copies as much as will fit into s.


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.


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.


SetTOCBufferPoolSize: PROCEDURE [size: CARDINAL];
-- Adjusts the size of the TOC buffer pool. A minimum size of 2 is enforced.


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.


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.


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


AllocateDisplayMessageObject: PROCEDURE RETURNS [DisplayMessagePtr];


FreeVirtualMessageObject: PROCEDURE [vMPtr: VirtualMessagePtr];


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.


GetMessageChar: PROCEDURE [vs: VirtualMessagePtr, index: ovD.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.


SetBufferPoolSize: PROCEDURE[vop: VirtualObjectPtr, size: CARDINAL];


GetMessageSize: PROCEDURE [msg: VirtualMessagePtr] RETURNS [ovD.CharIndex] = INLINE
-- Returns the size of the message, which is equal to the first free CharIndex.
{RETURN [msg.textLength]};


MapVirtualToComposeMessage: PROCEDURE [vmp: VirtualMessagePtr]
RETURNS [cmp: ComposeMessagePtr];
-- Loopholes vmp to cmp.


-- 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 ComposeMessageObjects, a variant
-- of VMOs.


AllocateComposeMessageObject: PROCEDURE RETURNS [ComposeMessagePtr];


InitComposeMessage: PROCEDURE [cMPtr: ComposeMessagePtr, s: STRING];
-- The composeMessage is initialized to contain the string.


CleanupCMs: PROCEDURE;
-- Truncates backing files for all CMs.


PutMessageChar: PROCEDURE [cMPtr: ComposeMessagePtr, index: ovD.CharIndex,
char: CHARACTER];
-- The character a position index is overwritten with char.


ReplaceRangeInMessage: PROCEDURE [to, from: MessageRange]
RETURNS [erc: ovD.ErrorCode];
-- 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: ovD.CharIndex,
targetMessage: ComposeMessagePtr, from: MessageRange] RETURNS [erc: ovD.ErrorCode];
-- 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.


DeleteRangeInMessage: PROCEDURE [from: MessageRange];
-- The characters in the range [from.first .. from.end) are deleted from msg.


InsertFileInMessage: PROCEDURE[targetIndex: ovD.CharIndex,
targetMessage: ComposeMessagePtr, file: crD.UFilename, user: crD.DMSUser]
RETURNS [errorCode: ovD.ErrorCode, errorString: STRING];
-- Inserts the entire contents of the file in the message starting just before the targetIndex.
-- Errors encountered while opening or reading the file are returned.


PutRangeInFile: PROCEDURE[from: MessageRange, file: crD.UFilename, user: crD.DMSUser,
concurrenceNeeded: BOOLEAN,
UserConcurs: PROCEDURE [exD.Exception] RETURNS [BOOLEAN]]
RETURNS [errorCode: ovD.ErrorCode];
-- 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 cuncurrenceNeeded, then
-- UserConcurs is called and the put proceeds only if TRUE is returned. Errors encountered
-- while opening or reading the file are returned.


AppendMessageChar: PROCEDURE [cM: ComposeMessagePtr, char: CHARACTER]
RETURNS [erc: ovD.ErrorCode];
-- The character, char, is appended to the end of the msg.


UnAppendMessageChar: PROCEDURE [cM: ComposeMessagePtr];
-- This routine is used to process a rubout. It deletes the last character in the msg.


StartMessageInsertion: PROCEDURE [cM: ComposeMessagePtr, where: ovD.CharIndex];
-- Initializes a ComposeMessage 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: ComposeMessagePtr, char: CHARACTER]
RETURNS [erc: ovD.ErrorCode];
-- The character is appended to the current insertion.


UnInsertMessageChar: PROCEDURE [cM: ComposeMessagePtr];
-- This routine is used to process a rubout. It deletes the last character in an insertion, and
-- is a nop if the insertion is empty.


InsertSubstringInMessage: PROCEDURE [cM: ComposeMessagePtr, source: STRING,
first: CARDINAL, charsToCopy: CARDINAL] RETURNS [erc: ovD.ErrorCode];
-- source[first .. first+charsToCopy) are inserted in the cM at the current insertion point.
-- source.length and surce.maxlength are not referenced.


StopMessageInsertion: PROCEDURE [cM: ComposeMessagePtr];
-- The current insertion is terminated, and the inserted characters become part of the
-- message.


AbandonMessageInsertion: PROCEDURE [cM: ComposeMessagePtr];
-- The current insertion is discarded, and the inserted characters go away.


-- Internal procedures common to several modules


GetTOCPtr: PRIVATE PROCEDURE RETURNS [POINTER TO TOC];
-- Used to communicate between the departments of this division. Needed when broken into
-- more than one file.


MakeBufferPoolHeadUnused: PRIVATE PROCEDURE [vop: VirtualObjectPtr]
RETURNS [compacted: BOOLEAN, rpn: PageNumber];
-- Finds or makes an unused mte and relinks it to head of lru list. Compacted is returned
-- FALSE unless the vop designates a CM and finding an unused Mte has caused
-- compaction in the CM’s buffer pool. When compacted is returned TRUE, the rpn
-- returns the number of the CM page removed by the compaction.


FindTOCAddress: PRIVATE PROCEDURE [index: TOCIndex]
RETURNS [p: HardTOCAddress, mtPtr: MemoryTableEntryPtr];
-- You’d better be careful, cache activity may cause the pointers returned to become
-- dangling references.


GetTOCAddressOnPage: PRIVATE PROCEDURE [index: TOCIndex,
mtPtr: MemoryTableEntryPtr] RETURNS [TOCFixedPartPtr];


GetMtPtr: PRIVATE PROCEDURE [vop: VirtualObjectPtr, pn: PageNumber,
pageState: GetMtPtrState] RETURNS [mtPtr: MemoryTableEntryPtr, npn: PageNumber];


VoidCharCache: PRIVATE PROCEDURE [c: POINTER TO CharCache];


MapCharIndexToPageByte: PRIVATE PROCEDURE [cm: ComposeMessagePtr,
index: ovD.CharIndex] RETURNS [PageNumber, CARDINAL];


SetGetCacheForCMPage: PRIVATE PROCEDURE [option: SetCacheOption,
cm: ComposeMessagePtr, lpn: PageNumber, index: ovD.CharIndex]
RETURNS [erc: ovD.ErrorCode];
-- 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.


TryToCompactBufferPool: PRIVATE PROCEDURE [cmp: ComposeMessagePtr]
RETURNS [BOOLEAN, PageNumber];


WritePageToFile: PRIVATE PROCEDURE [vop: VirtualObjectPtr,
mtPtr: MemoryTableEntryPtr];
-- Writes the file page associated with the designated Mte. Will open a temporary backing
-- file for the object if vop↑.file = NIL.


ReadPageFromFile: PRIVATE PROCEDURE [vop: VirtualObjectPtr,
mtPtr: MemoryTableEntryPtr];
-- Reads the file page associated with the designated Mte.


BombIfIOError: PRIVATE PROCEDURE [erc: ovD.ErrorCode];
-- Call SysBug if erc isn’t "ok".



-- Data Structures and Types.


CheatersSTRING: PRIVATE TYPE = RECORD [length, maxlength: INTEGER];
-- Copied from AllocateHeapString. MAY CHANGE. BEWARE.

PageNumber: PRIVATE TYPE = crD.PageNumber;

tOCMinStringSize: CARDINAL = 12; --smallest "maxlength".

tOCPageTableSize: CARDINAL = 64; -- app. 7-9 entries fit on a page

tOCType: CARDINAL = 1; -- For TOCPageHdr.garbageDetector.

VirtualObjectPtr: PRIVATE TYPE = POINTER TO VirtualObject;

VirtualObject: PRIVATE TYPE = RECORD
[file: crD.UFileHandle,
memoryHeader: MemoryTableEntryPtr,
open: BOOLEAN,
vOVar: SELECT VOType:* FROM
TOC =>
[pageTableHeader: 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: crD.UFileHandle], -- from New/Virtualize-TOC.
VMO =>
[next: VirtualMessagePtr,
textLength: ovD.CharIndex, -- in bytes,
get: CharCache, -- For GetMessageChar look-ahead.
vMOVar: SELECT VMOType:* FROM
DM => -- DisplayMessage.
[firstPage: PageNumber,
firstByte: [0 .. 511]],
CM => -- ComposeMessage.
[inserting: BOOLEAN, --following for TRUE only
insertionStart: ovD.CharIndex,
insertionStop: ovD.CharIndex,
charMap: POINTER TO CMOCharMapTable,
filePageFF: PageNumber],
ENDCASE],
ENDCASE];

MemoryTableEntry: PRIVATE TYPE = RECORD
[state: {clean, dirty, unused},
next: MemoryTableEntryPtr,
filePageNumber, -- (= lpn, except for Composemsg.)
logicalPageNumber: PageNumber,
address: POINTER TO TOCPageHdr];

MemoryTableEntryPtr: PRIVATE TYPE = POINTER TO MemoryTableEntry;

CharCache: TYPE = RECORD
-- To access the iTH char of a message:
-- (1) it must be in [first..free)
-- (2) "page" must be mapped into "mtPtr"
-- Then use: string[iTH+offset]
[first, -- first char on "page".
free: ovD.CharIndex, -- first char off "page".
string: STRING, -- Set up to "page" via "mtPtr".
floor: CARDINAL[0 .. 512), -- Space a beg of (1st) page.
mtPtr: MemoryTableEntryPtr];

TOC: PRIVATE TYPE = TOC VirtualObject;

TOCIndex: TYPE = CARDINAL; -- Note: 0 not used.

TOCFixedPartPtr: TYPE = POINTER TO TOCFixedPart;

TOCFixedPart: TYPE = RECORD
[changed,
deleted,
seen,
bogus: BOOLEAN, --this entry spans bad data--
mark: CHARACTER,
firstPage: PageNumber,
firstByte: [0 .. 511],
bugTrap: [0 .. 127], --←bugTrapValue, Early warning device.
offsetToHeader,
textLength: ovD.CharIndex]; -- in bytes

bugTrapValue: [0 .. 127] = 131B; -- for "quick fail".

TOCPageHdr: PRIVATE TYPE = RECORD -- One of these at beg of each file page.
[numberOfEntries: CARDINAL,
garbageDetector: CARDINAL]; -- gets tOCType--

TOCPageTable: PRIVATE TYPE = ARRAY[0 .. tOCPageTableSize) OF TOCPageTableEntry;

TOCPageTableEntry: PRIVATE TYPE = PRIVATE RECORD [firstTOCIndex: TOCIndex];

HardTOCAddress: PRIVATE TYPE = POINTER; -- to a TOC entry.

cMOCharMapTableSize: CARDINAL = 128; -- Max pages/CMO file.

cMOMaxCharPerPage: CARDINAL = 511; -- Waste 1 to save table space.

VirtualMessagePtr: TYPE = POINTER TO VirtualMessageObject;
VirtualMessageObject: PRIVATE TYPE = VMO VirtualObject;
DisplayMessagePtr: TYPE = POINTER TO DisplayMessageObject;
DisplayMessageObject: PRIVATE TYPE = DM VirtualMessageObject;
ComposeMessagePtr: TYPE = POINTER TO ComposeMessageObject;
ComposeMessageObject: PRIVATE TYPE = CM VirtualMessageObject;

MessageRange: TYPE = RECORD
[start,
end: ovD.CharIndex,
message: VirtualMessagePtr];

CMOCharMapTable: PRIVATE TYPE = ARRAY PageNumber[0 .. cMOCharMapTableSize) OF
RECORD
[count: CARDINAL[0 .. cMOMaxCharPerPage], -- Good chars/page.
page: PageNumber[0 .. cMOCharMapTableSize)]; -- corresp fpn.

GetMtPtrState: PRIVATE TYPE = {new, active, inactive};

SetCacheOption: PRIVATE TYPE = {new, old};

CleanupTOCOption: TYPE = {resetChanges, dontResetChanges, delete};

VirtualizeTOCOption: TYPE = {new, old};

END. -- of VirtualMgrDefs --