-- file VirtCom.mesa
-- edited by Kierr, February 8, 1978 11:32 AM.
-- edited by Schroeder, November 18, 1980 12:50 PM.
-- edited by Brotz, January 28, 1983 1:58 PM.
-- edited by Levin, November 19, 1980 10:15 AM.

DIRECTORY
exD: FROM "ExceptionDefs" USING [SysBug],
Inline USING [DIVMOD],
tfD: FROM "TempFileDefs" USING [AllocateTempFile],
vmD: FROM "VirtualMgrDefs" USING [CharCache, CharIndex, ComposedMessagePtr,
MapCharIndexToPageByte, PageNumber, SetGetCacheForCMPage, VirtualMessagePtr,
VirtualObjectPtr],
VMDefs USING [Mark, MarkStart, PageNumber, ReadPage, Release, RemapPage,
UsePage];

VirtCom: PROGRAM
IMPORTS exD, Inline, tfD, vmD, VMDefs
EXPORTS vmD =

BEGIN
OPEN vmD;


GetMessageChar: PUBLIC PROCEDURE [vm: VirtualMessagePtr, index: CharIndex]
RETURNS [CHARACTER] =
-- Obtains the index’th character (starting at zero) from the virtual structure vs.
BEGIN
page: PageNumber;
byte: CARDINAL;
IF index ~IN [vm.get.first .. vm.get.free) THEN
WITH msg: vm SELECT FROM
DM =>
BEGIN
IF index >= msg.textLength THEN exD.SysBug[];
[page, byte] ← Inline.DIVMOD[msg.firstByte + index, 512];
page ← page + msg.firstPage;
GetBuffer[vm, page, FALSE];
vm.get.first ← IF index > byte THEN index - byte ELSE 0;
vm.get.floor ← IF vm.get.first = 0 THEN byte - index ELSE 0;
vm.get.free ← MIN[index + 512 - byte, vm.textLength];
END;
CM =>
BEGIN
[page, byte] ← MapCharIndexToPageByte[@msg, index];
SetGetCacheForCMPage[@msg, page, index - byte, FALSE, TRUE];
END;
ENDCASE;
RETURN[vm.buffer.chars[index + vm.get.floor - vm.get.first]];
END; -- of GetMessageChar --


PutMessageChar: PUBLIC PROCEDURE
[vm: VirtualMessagePtr, index: CharIndex, char: CHARACTER] =
-- The character at position index is overwritten with char.
BEGIN
IF index ~IN [vm.get.first .. vm.get.free) THEN [] ← GetMessageChar[vm, index];
vm.buffer.chars[index + vm.get.floor- vm.get.first] ← char;
vm.bufferState ← dirty;
END; -- of PutMessageChar --


VoidCharCache: PUBLIC PROCEDURE [c: POINTER TO CharCache] =
BEGIN
easyToSpotValue: CharIndex = 177777B;
c.first ← c.free ← easyToSpotValue; -- first=free is what counts
END; -- of VoidCharCache --


GetBuffer: PUBLIC 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.
BEGIN
IF ~newPage AND vop.bufferState # empty AND vop.logicalPageNumber = pn
THEN RETURN;
IF vop.bufferState # empty THEN MakeBufferEmpty[vop];
vop.bufferState ← clean;
vop.logicalPageNumber ← pn;
vop.buffer ← IF newPage
THEN VMDefs.UsePage[[vop.file, pn]]
ELSE VMDefs.ReadPage[[vop.file, pn], 2];
END; -- of GetBuffer --


MakeBufferEmpty: PUBLIC PROCEDURE [vop: VirtualObjectPtr] =
-- Writes the buffer associated with "vop" if dirty.
BEGIN
SELECT vop.bufferState FROM
empty => RETURN;
dirty =>
WITH msg: vop SELECT FROM
VMO =>
WITH cm: msg SELECT FROM
CM => {EnsureCMBackingFile[@cm]; VMDefs.Mark[vop.buffer]};
ENDCASE => VMDefs.MarkStart[vop.buffer];
ENDCASE => VMDefs.MarkStart[vop.buffer];
ENDCASE;
VMDefs.Release[vop.buffer];
vop.bufferState ← empty;
END; -- of MakeBufferEmpty --


EnsureCMBackingFile: PUBLIC PROCEDURE [cm: ComposedMessagePtr] =
-- Slides a backing file under the cm when needed.
BEGIN
IF cm.file = NIL THEN
BEGIN
cm.file ← tfD.AllocateTempFile[];
IF cm.bufferState # empty THEN
BEGIN
IF cm.logicalPageNumber > 0 THEN exD.SysBug[];
VMDefs.RemapPage[cm.buffer, [cm.file, cm.logicalPageNumber]];
END;
END;
END; -- of EnsureCMBackingFile --


END. -- of VirtCom --