DIRECTORY NodeProps, TiogaNodeOps, NodeAddrs; NodeAddrsImpl: CEDAR MONITOR IMPORTS NodeProps EXPORTS NodeAddrs = BEGIN OPEN NodeAddrs; TextAddrNotFound: PUBLIC ERROR = CODE; addrsProp: ATOM = $TiogaNodeAddrsProp; AddrsProp: PUBLIC PROC RETURNS [ATOM] = { RETURN [addrsProp] }; Create: PROC RETURNS [RefAddrs] = INLINE { RETURN [NEW[Body]] }; FindPair: PROC [ref: RefAddrs, 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] }; Get: PROC [n: RefTextNode] RETURNS [ref: RefAddrs] = INLINE { RETURN [NARROW[NodeProps.GetProp[n, addrsProp]]] }; Put: PROC [n: RefTextNode, ref: RefAddrs] = INLINE { NodeProps.PutProp[n, addrsProp, ref] }; PinTextAddr: PUBLIC PROC [n: RefTextNode, addr: REF] = { ref: RefAddrs _ Get[n]; p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN RETURN; p.pinned _ TRUE }; UnpinTextAddr: PUBLIC PROC [n: RefTextNode, addr: REF] = { ref: RefAddrs _ Get[n]; p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN RETURN; p.pinned _ FALSE }; UnpinAll: PUBLIC PROC [n: RefTextNode] = { ref: RefAddrs _ Get[n]; IF ref#NIL THEN FOR p: Pair _ ref.addrs, p.next UNTIL p=NIL DO p.pinned _ FALSE; ENDLOOP }; MoveTextAddr: PUBLIC PROC [from, to: RefTextNode, addr: REF, location: Offset] = { ref: RefAddrs _ Get[from]; p: Pair; IF (p _ FindPair[ref, addr])=NIL OR to=NIL THEN RETURN; p.movedTo _ to; PutTextAddr[to, addr, location] }; PutTextAddr: PUBLIC PROC [n: RefTextNode, addr: REF, location: Offset] = { ref: RefAddrs; p: Pair; IF (ref _ Get[n]) = NIL THEN Put[n, ref _ Create[]]; IF (p _ FindPair[ref, addr])=NIL THEN ref.addrs _ p _ NEW[PairBody _ [ref.addrs, FALSE, addr, NIL, location]] ELSE p.location _ location; p.pinned _ FALSE; p.movedTo _ NIL }; RemTextAddr: PUBLIC PROC [n: RefTextNode, addr: REF] = { ref: RefAddrs _ Get[n]; p, prev: Pair; IF ref=NIL OR (p _ ref.addrs)=NIL THEN RETURN; IF p.addr=addr THEN ref.addrs _ p.next ELSE DO prev _ p; p _ p.next; IF p=NIL THEN EXIT; IF p.addr=addr THEN { prev.next _ p.next; EXIT }; ENDLOOP; IF ref.addrs=NIL THEN NodeProps.PutProp[n, addrsProp, NIL] --remove-- }; GetTextAddr: PUBLIC PROC [n: RefTextNode, addr: REF] RETURNS [node: RefTextNode, location: Offset] = { ref: RefAddrs _ Get[n]; p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN ERROR TextAddrNotFound; IF p.movedTo # NIL THEN [node, location] _ GetTextAddr[p.movedTo, addr] ELSE RETURN [n, p.location] }; TryGetTextAddr: PUBLIC PROC [n: RefTextNode, addr: REF] RETURNS [found: BOOLEAN, node: RefTextNode, location: Offset] = { ref: RefAddrs _ Get[n]; p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN RETURN [FALSE, n, 0]; IF p.movedTo # NIL THEN [found, node, location] _ TryGetTextAddr[p.movedTo, addr] ELSE RETURN [TRUE, n, p.location] }; MapTextAddrs: PUBLIC PROC [n: RefTextNode, action: TextAddrsAction] RETURNS [BOOLEAN] = { ref: RefAddrs _ Get[n]; IF ref#NIL THEN { p: Pair _ ref.addrs; UNTIL p=NIL DO next: Pair _ p.next; IF p.pinned OR p.movedTo # NIL THEN NULL ELSE IF action[p.addr, p.location] THEN RETURN [TRUE]; p _ next; ENDLOOP}; RETURN [FALSE] }; 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[] }; Replace: PUBLIC PROC [node: RefTextNode, start, len, newlen: Offset] = { replace: PROC [old: Offset] RETURNS [Offset] = { RETURN [AfterReplace[old, start, len, newlen]] }; end: Offset _ start+len; ref: RefAddrs = Get[node]; Notify[node, replace]; IF ref=NIL THEN RETURN; FOR p: Pair _ ref.addrs, p.next UNTIL p=NIL DO IF p.pinned OR p.movedTo # NIL THEN LOOP; 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}; StartNodeAddrs: PUBLIC PROC = { OPEN NodeProps; Register[addrsProp,NullRead,NullWrite,NullCopy] }; StartNodeAddrs[]; END. NodeAddrsImpl.mesa; written by Bill Paxton, March 1981 edited by McGregor, February 8, 1983 11:30 am edited by Bill Paxton, June 1, 1983 11:35 am don't modify location when edits take place assigns addr to location in node ok if addr was previously assigned elsewhere in the node removes the given addr generates ERROR TextAddrNotFound if the addr is not in the mapping apply the action to each addr&location pair for the node returns true if&when an action returns true skips pinned or moved addresses **** notify proc registration **** **** Editing Operations for persistent addrs **** 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 ***** Initialization ʘJšœ7™7Jšœ-™-Jšœ,™,J˜JšÏk ˜ J˜ J˜ J˜ J˜šœ ˜Jšœ ˜Jšœ ˜—Jšœœ ˜J˜Jšœœœœ˜&J˜Jšœ œ˜&J˜š Ïn œœœœœ˜)Jšœ˜J˜—Jš žœœœœœœ ˜@J˜šžœœœœ ˜<šœœ˜šœœœ˜.Jšœœœœ˜*——Jšœœ˜J˜—šžœœœœ˜=Jšœœ%˜3J˜—šžœœ#œ˜4J˜'J˜—šž œœœœ˜8Jšœ+™+J˜J˜Jšœœœœ˜-Jšœ œ˜J˜—šž œœœœ˜:J˜J˜Jšœœœœ˜-Jšœ œ˜J˜—šžœœœ˜*J˜šœœ˜šœœœ˜.Jšœ œœ˜——J˜—šž œœœœ˜RJšœ˜J˜Jš œœœœœœ˜7Jšœ˜Jšœ"˜"—J˜šž œœœœ˜KJšœ ™ Jšœ8™8J˜J˜Jšœœœ˜4šœœ˜%Jšœœœœ ˜G—Jšœ˜Jšœ œ˜Jšœ œ˜J˜—šž œœœœ˜8Jšœ™J˜J˜Jš œœœœœœ˜.Jšœ œ˜&š˜J˜Jšœœœœ˜Jšœ œœ˜1Jšœ˜—Jš œ œœ!œÏc œ˜HJ˜—šž œœœœ˜4Jšœ*˜1JšœB™BJ˜J˜Jšœœœœ˜=Jšœ œœ0˜Gš œ˜J˜——šžœœœœ˜7Jšœ œ*˜AJ˜J˜Jš œœœœœ˜;Jšœ œœ:˜QJš œœ˜$J˜—šž œœœ*˜CJšœœ˜Jšœ8™8Jšœ+™+J™J˜šœœœ˜J˜šœœ˜J˜Jš œ œ œœ˜(Jšœœœœ˜6J˜ Jšœ˜ ——Jšœœ˜J˜—Jšœ"™"J˜Jšœœœ˜J˜Jšœ œ˜Jšœ œ˜J˜Jšžœœœ˜/J˜šžœœœ˜šœ œ˜(Jšœ œ ˜%——J˜šž œœœœ˜;Jšœœœ˜Jšœ œ˜J˜J˜—šžœœœœ˜>Jšœœœ˜Jšœœœ˜Jšœ œœœ˜Jšœœœ˜=Jšœœœ œ˜.J˜š œœœ&œœ˜DJšœœœ˜6J˜ Jšœ˜—J˜J˜—šœ˜Jšœœ ˜J˜š œœœ!œœ˜?Jšœœ˜—šœ ˜ J˜——Jšœ1™1J˜šžœœœ4˜HJšœ3™3Jšœ4™4JšœA™Ašœ œœ ˜0Jšœ+˜1—J˜J˜J˜Jšœœœœ˜šœœœ˜.Jš œ œ œœœ˜)šœ ˜J˜-J˜Jšœ˜—Jšœ˜ J˜——šž œœœ&˜?Jšœ˜šœ œ ˜J˜#J˜Jšœ ˜J˜——Jšœ™J˜šžœœœ˜Jšœ ˜J˜2J˜—Jšœ˜J˜Jšœ˜J˜—…—ê