-- EditAddrsImpl.Mesa
-- written by Paxton. March 1981
-- last written by Paxton. October 18, 1982 11:14 am
-- **** Persistent addressing ****
DIRECTORY
EditAddrs,
NodeAddrs,
NodeProps,
TextNode;
EditAddrsImpl: MONITOR
IMPORTS npI:NodeProps, TextNode, NodeAddrs
EXPORTS EditAddrs =
BEGIN OPEN EditAddrs;
Create: PUBLIC PROC RETURNS [Ref] = { RETURN [TextNode.pZone.NEW[Body]] };
FindPair: PROC [ref: Ref, addr: REF] RETURNS [Pair] = {
IF ref#NIL THEN
FOR p: Pair ← ref.addrs, p.next UNTIL p=NIL DO
IF p.addr = addr THEN RETURN [p]; ENDLOOP;
RETURN [NIL] };
PutAddr: PUBLIC PROC [ref: Ref, addr: REF, location: Offset] = {
-- assigns addr to location in ref
-- ok if addr was previously assigned elsewhere
p: Pair;
IF (p ← FindPair[ref, addr])=NIL THEN
ref.addrs ← TextNode.pZone.NEW[PairBody ← [ref.addrs, addr, location]]
ELSE p.location ← location };
RemAddr: PUBLIC PROC [ref: Ref, addr: REF] = {
-- removes the given addr
p, prev: Pair;
IF ref=NIL OR (p ← ref.addrs)=NIL THEN RETURN;
IF p.addr=addr THEN { ref.addrs ← p.next; RETURN };
DO
prev ← p; p ← p.next;
IF p=NIL THEN RETURN;
IF p.addr=addr THEN { prev.next ← p.next; RETURN };
ENDLOOP };
GetAddr: PUBLIC PROC [ref: Ref, addr: REF] RETURNS [location: Offset] = {
-- generates ERROR AddrNotFound if the addr is not in the mapping
p: Pair;
IF (p ← FindPair[ref, addr])=NIL THEN ERROR AddrNotFound;
RETURN [p.location] };
TryGetAddr: PUBLIC PROC [ref: Ref, addr: REF]
RETURNS [found: BOOLEAN, location: Offset] = {
p: Pair;
IF (p ← FindPair[ref, addr])=NIL THEN RETURN [FALSE, 0];
RETURN [TRUE, p.location] };
AddrNotFound: PUBLIC ERROR = CODE;
MapAddrs: PUBLIC PROC [ref: Ref, action: MapAddrsAction]
RETURNS [BOOLEAN] = {
-- apply the action to each addr&location pair for the ref
-- returns true if&when an action returns true
IF ref#NIL THEN {
p: Pair ← ref.addrs;
UNTIL p=NIL DO
next: Pair ← p.next;
IF action[p.addr, p.location] THEN RETURN [TRUE];
p ← next;
ENDLOOP};
RETURN [FALSE] };
-- **** notify proc registration ****
notify: LIST OF AddrNotifyProc;
unlocked: CONDITION;
lockCount: INTEGER ← 0;
Lock: ENTRY PROC = { lockCount ← lockCount+1 };
Unlock: ENTRY PROC = {
IF (lockCount ← lockCount-1) <= 0 THEN {
lockCount ← 0; BROADCAST unlocked }};
AddNotifyProc: PUBLIC ENTRY PROC [proc: AddrNotifyProc] = {
ENABLE UNWIND => NULL;
notify ← CONS[proc, notify];
};
RemoveNotifyProc: PUBLIC ENTRY PROC [proc: AddrNotifyProc] = {
ENABLE UNWIND => NULL;
prev: LIST OF AddrNotifyProc;
IF notify = NIL THEN RETURN;
IF notify.first = proc THEN { notify ← notify.rest; RETURN };
WHILE lockCount > 0 DO WAIT unlocked; ENDLOOP;
prev ← notify;
FOR l: LIST OF AddrNotifyProc ← notify.rest, l.rest UNTIL l = NIL DO
IF l.first = proc THEN { prev.rest ← l.rest; RETURN };
prev ← l;
ENDLOOP;
};
Notify: AddrNotifyProc = {
ENABLE UNWIND => Unlock[];
Lock[];
FOR l: LIST OF AddrNotifyProc ← notify, l.rest UNTIL l = NIL DO
l.first[node, new]; ENDLOOP;
Unlock[] };
-- **** Editing Operations for persistent addrs ****
GetAddrs: PROC [n: RefTextNode] RETURNS [Ref] = {
RETURN [IF n.props = NIL THEN NIL ELSE NARROW[npI.GetProp[n,addrsProp]]] };
addrsProp: ATOM ← NodeAddrs.AddrsProp[];
Replace: PUBLIC PROC [node: RefTextNode, start, len, newlen: Offset] = {
-- replace chars in [start..start+len) by newlen chars
-- addrs that are in the replaced section move to start
-- add (newlen-len) to locations that are after the replaced section
replace: PROC [old: Offset] RETURNS [Offset] = {
RETURN [AfterReplace[old, start, len, newlen]] };
end: Offset ← start+len;
ref: Ref = GetAddrs[node];
Notify[node, replace];
IF ref=NIL THEN RETURN;
FOR p: Pair ← ref.addrs, p.next UNTIL p=NIL DO
SELECT p.location FROM
>= end => p.location ← p.location-len+newlen;
>= start => p.location ← start;
ENDCASE;
ENDLOOP };
AfterReplace: PUBLIC PROC [initLoc, start, len, newlen: Offset]
RETURNS [newLoc: Offset] = {
newLoc ← SELECT initLoc FROM
>= start+len => initLoc-len+newlen,
>= start => start,
ENDCASE => initLoc};
Start: PUBLIC PROC = {
};
END.