-- file: Protection.Mesa
-- edited by McCreight, September 25, 1980 5:25 PM
-- edited by Brotz, December 1, 1980 11:22 AM
DIRECTORY
ovD: FROM "OverviewDefs",
prA: FROM "ProtectionAbstractions",
prD: FROM "ProtectionDefs",
Storage,
vmD: FROM "VirtualMgrDefs";
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: ovD.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: ovD.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 pfp.start <= fixed => -- fixed IN [pfp.start .. pfp.end)
{rangePtr.start ← rangePtr.end ← IF fixStart 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: ovD.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.
BEGIN pfpp↑ ← NIL END; -- of InitProtection --
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 --