DIRECTORY NodeProps, TextNode, NodeAddrs; NodeAddrsImpl: CEDAR MONITOR IMPORTS NodeProps, TextNode 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 [TextNode.pZone.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 _ TextNode.pZone.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] }; END.  -- NodeAddrsImpl.mesa -- written by Bill Paxton, March 1981 -- last edit by Bill Paxton, December 28, 1982 11:44 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šÏc™Jš&™&Jš7™7J˜JšÏk ˜ J˜ J˜ J˜ J˜šœž ˜Jšžœ˜Jšžœ ˜—Jšžœžœ ˜J˜Jšœžœžœžœ˜&J˜Jšœ žœ˜&J˜š Ïn œžœžœžœžœ˜)Jšžœ˜J˜—Jš Ÿœžœžœžœžœžœ ˜OJ˜šŸœžœžœžœ ˜<šžœžœž˜šžœžœžœž˜.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š;™;J˜J˜Jšžœžœžœ˜4šžœžœž˜%Jšœžœžœžœ ˜V—Jšžœ˜Jšœ žœ˜Jšœ žœ˜J˜—šŸ œžœžœžœ˜8Jš™J˜J˜Jš žœžœžœžœžœžœ˜.Jšžœ žœ˜&šž˜J˜Jšžœžœžœžœ˜Jšžœ žœžœ˜1Jšžœ˜—Jš žœ žœžœ!žœ œ˜HJ˜—šŸ œžœžœžœ˜4Jšžœ*˜1JšE™EJ˜J˜Jšžœžœžœžœ˜=Jšžœ žœžœ0˜Gšž œ˜J˜——šŸœžœžœžœ˜7Jšžœ žœ*˜AJ˜J˜Jš žœžœžœžœžœ˜;Jšžœ žœžœ:˜QJšž œžœ˜$J˜—šŸ œžœžœ*˜CJšžœžœ˜Jš;™;Jš.™.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š4™4J˜šŸœžœžœ4˜HJš6™6Jš7™7JšD™Dšœ žœžœ ˜0Jšžœ+˜1—J˜J˜J˜Jšžœžœžœžœ˜šžœžœžœž˜.Jš žœ žœ žœžœžœ˜)šžœ ž˜J˜-J˜Jšžœ˜—Jšžœ˜ J˜——šŸ œžœžœ&˜?Jšžœ˜šœ žœ ž˜J˜#J˜Jšžœ ˜J˜——Jš™J˜šŸœžœžœ˜Jšžœ ˜J˜2J˜—Jšžœ˜J˜—…—ú