-- file: Protection.Mesa
-- edited by McCreight, September 25, 1980 5:25 PM
-- edited by Brotz, September 28, 1982 11:44 AM

DIRECTORY
prA: FROM "ProtectionAbstractions" USING [],
prD: FROM "ProtectionDefs" USING [ProtectionBug],
Storage USING [Free, Node],
vmD: FROM "VirtualMgrDefs" USING [CharIndex, MessageRange];

Protection: PROGRAM
IMPORTS prD, Storage
EXPORTS prA, prD = PUBLIC
BEGIN

-- Implements protected fields for the editor by limiting selections
-- to unprotected fields.

-- Selection convention: a range is represented by a nonempty half open interval; a point is
-- represented by an empty half open interval; selection beyond the message end is
-- represented by the point [messageLength .. messageLength).

ProtectedFields: PUBLIC TYPE = RECORD -- in prA
[next: ProtectedFieldPtr,
start,
end: vmD.CharIndex];
ProtectedFieldPtr: TYPE = POINTER TO ProtectedFields;

ProtectionBug: SIGNAL = CODE;

FindUnprotectedSubrange: PROCEDURE [pfp: ProtectedFieldPtr,
rangePtr: POINTER TO vmD.MessageRange, fixStart: BOOLEAN ← TRUE] =
-- Restricts range to
-- lie within an unprotected field. fixStart=TRUE causes the restriction to
-- be limited to that unprotected field in which the range start lies; otherwise
-- the restriction is limited to that unprotected field in which the range end
-- lies.
BEGIN
fixed: vmD.CharIndex;
precProtField: ProtectedFieldPtr ← NIL;
fixed ← IF fixStart THEN rangePtr.start ELSE rangePtr.end;
WHILE pfp # NIL AND pfp.end <= fixed DO
precProtField ← pfp;
pfp ← pfp.next
ENDLOOP;
SELECT TRUE FROM
pfp # NIL AND ((fixStart AND pfp.start <= fixed) OR (~fixStart AND pfp.start < fixed)) =>
-- fixed IN [pfp.start .. pfp.end)
rangePtr.start ← rangePtr.end ← IF fixStart AND pfp.start > 0 THEN pfp.start ELSE pfp.end;
fixStart => IF pfp # NIL THEN rangePtr.end ← MIN[rangePtr.end, pfp.start];
ENDCASE =>
IF precProtField # NIL THEN
rangePtr.start ← MAX[rangePtr.start, precProtField.end];
END; -- of FindUnprotectedSubrange --


AdjustProtFields: PROCEDURE[pfpp: POINTER TO ProtectedFieldPtr,
actionIndex: vmD.CharIndex, deletedChars, insertedChars: CARDINAL] =
-- Adjusts the indexes of protected fields to reflect an editing
-- operation. Signals ProtectionBug if the editing operation overlapped
-- a protected field.
BEGIN
deltaChars: INTEGER;
pfp: ProtectedFieldPtr ← pfpp↑;
WHILE pfp#NIL AND pfp.end<=actionIndex DO
pfp ← pfp.next
ENDLOOP;
IF pfp=NIL THEN RETURN;
IF pfp.start<actionIndex+deletedChars THEN -- deletion runs into prot field
BEGIN
SIGNAL prD.ProtectionBug;
UnprotectAllFields[pfpp];
RETURN; -- if user Resumes
END;
deltaChars ← insertedChars-deletedChars;
FOR pfp ← pfp, pfp.next UNTIL pfp=NIL DO
pfp.start ← pfp.start+deltaChars;
pfp.end ← pfp.end+deltaChars;
ENDLOOP;
END; -- of AdjustProtFields --


ProtectNewField: PROCEDURE[pfpp: POINTER TO ProtectedFieldPtr,
range: vmD.MessageRange] =
-- Protects a new field. If this field overlaps with an existing protected
-- field, the existing field is stretched. If it overlaps with multiple existing
-- protected fields, they are merged.
BEGIN
t: ProtectedFieldPtr;
WHILE pfpp↑#NIL AND pfpp↑.end<range.start DO -- field ends before range starts
pfpp ← @pfpp↑.next
ENDLOOP;
IF pfpp↑=NIL OR range.end<=pfpp↑.start THEN
BEGIN
t ← Storage.Node[SIZE[ProtectedFields]];
t↑ ← ProtectedFields[next: pfpp↑, start: range.start, end: range.end];
pfpp↑ ← t;
END
ELSE BEGIN
p: ProtectedFieldPtr ← pfpp↑;
p.start ← MIN[p.start, range.start];
p.end ← MAX[p.end, range.end];
WHILE p.next#NIL AND p.next.start<range.end DO
-- range ends after second field begins, so merge
p.end ← MAX[range.end, p.next.end];
t ← p.next.next;
Storage.Free[p.next];
p.next ← t;
ENDLOOP;
END;
END; -- of ProtectNewField --


InitProtection: PROCEDURE[pfpp: POINTER TO ProtectedFieldPtr] =
-- Sets protected fields to empty.
{pfpp↑ ← NIL};


UnprotectAllFields: PROCEDURE[pfpp: POINTER TO ProtectedFieldPtr] =
-- Removes all protection and reclaims the storage for the
-- field protectors.
BEGIN
t: ProtectedFieldPtr;
UNTIL pfpp↑ = NIL DO
t ← pfpp↑.next; Storage.Free[pfpp↑];
pfpp↑ ← t;
ENDLOOP;
END; -- of UnprotectAllFields --


END. -- of Protection --