DIRECTORY NodeAddrs USING [AddrNotifyProc, Node, TextAddrsAction], NodeProps USING [GetProp, NullCopy, NullRead, NullWrite, PutProp, Register]; NodeAddrsImpl: CEDAR MONITOR IMPORTS NodeProps EXPORTS NodeAddrs = BEGIN OPEN NodeAddrs; Addrs: TYPE = REF AddrsBody; AddrsBody: TYPE = RECORD [addrs: Pair]; Pair: TYPE = REF PairBody; PairBody: TYPE = RECORD [ next: Pair, pinned: BOOL _ FALSE, -- if true, then don't modify location when edits take place addr: REF, movedTo: Node, -- NIL if hasn't been moved location: INT ]; TextAddrNotFound: PUBLIC ERROR = CODE; addrsProp: ATOM = $TiogaNodeAddrsProp; AddrsProp: PUBLIC PROC RETURNS [ATOM] = { RETURN [addrsProp]; }; FindPair: PROC [ref: Addrs, 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: Node] RETURNS [ref: Addrs] = INLINE { RETURN [NARROW[NodeProps.GetProp[n, addrsProp]]]; }; Put: PROC [n: Node, ref: Addrs] = INLINE { NodeProps.PutProp[n, addrsProp, ref]; }; PinTextAddr: PUBLIC PROC [n: Node, addr: REF] = { ref: Addrs _ Get[n]; p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN RETURN; p.pinned _ TRUE; }; UnpinTextAddr: PUBLIC PROC [n: Node, addr: REF] = { ref: Addrs _ Get[n]; p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN RETURN; p.pinned _ FALSE; }; UnpinAll: PUBLIC PROC [n: Node] = { ref: Addrs _ 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: Node, addr: REF, location: INT] = { ref: Addrs _ 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: Node, addr: REF, location: INT, pin: BOOL _ FALSE] = { ref: Addrs; p: Pair; IF (ref _ Get[n]) = NIL THEN Put[n, ref _ NEW[AddrsBody]]; IF (p _ FindPair[ref, addr])=NIL THEN ref.addrs _ p _ NEW[PairBody _ [ref.addrs, FALSE, addr, NIL, location]] ELSE p.location _ location; p.pinned _ pin; p.movedTo _ NIL; }; RemTextAddr: PUBLIC PROC [n: Node, addr: REF] = { ref: Addrs _ 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: Node, addr: REF] RETURNS [node: Node, location: INT] = { ref: Addrs _ 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: Node, addr: REF] RETURNS [found: BOOL, node: Node, location: INT] = { ref: Addrs _ 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: Node, action: TextAddrsAction] RETURNS [BOOL] = { ref: Addrs _ 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: Node, start, len, newlen: INT] = { replace: PROC [old: INT] RETURNS [INT] = { RETURN [AfterReplace[old, start, len, newlen]] }; end: INT _ start+len; ref: Addrs = 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: INT] RETURNS [newLoc: INT] = { newLoc _ SELECT initLoc FROM >= start+len => initLoc-len+newlen, >= start => start, ENDCASE => initLoc; }; StartNodeAddrs: PROC = { OPEN NodeProps; Register[addrsProp,NullRead,NullWrite,NullCopy] }; StartNodeAddrs[]; END. ŠNodeAddrsImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. written by Bill Paxton, March 1981 last edit by Bill Paxton, December 28, 1982 11:44 am Michael Plass, March 29, 1985 2:34:11 pm PST Doug Wyatt, September 8, 1986 2:14:39 pm PDT 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 Κ R˜codešœ™Kšœ Οmœ7™BKšœ#™#Kšœ4™4K™,K™,—K˜šΟk ˜ Kšœ žœ)˜8Kšœ žœ=˜L—K˜KšΠbl œžœž˜Kšžœ ˜Kšžœ ˜Kšœžœžœ ˜K˜Kšœžœžœ ˜Kšœ žœžœ˜'K˜Kšœžœžœ ˜šœ žœžœ˜Kšœ ˜ KšœžœžœΟc<˜RKšœžœ˜ Kšœ ˜*Kšœ ž˜ Kšœ˜—K˜Kšœžœžœžœ˜&K˜Kšœ žœ˜&K˜š Οn œžœžœžœžœ˜)Kšžœ ˜Kšœ˜K˜—š‘œžœžœžœ ˜9šžœžœž˜šžœžœžœž˜.Kšžœžœžœžœ˜*——Kšžœžœ˜ Kšœ˜K˜—š‘œžœ žœžœ˜3Kšžœžœ#˜1Kšœ˜K˜—š‘œžœžœ˜*K˜%K˜K˜—š‘ œžœžœžœ˜1Kšœ+™+K˜K˜Kšžœžœžœžœ˜-Kšœ žœ˜Kšœ˜K˜—š‘ œžœžœžœ˜3K˜K˜Kšžœžœžœžœ˜-Kšœ žœ˜Kšœ˜K˜—š‘œžœžœ˜#K˜šžœžœž˜šžœžœžœž˜.Kšœ žœ˜Kšžœ˜——Kšœ˜K˜—š ‘ œžœžœžœ žœ˜HKšœ˜K˜Kš žœžœžœžœžœžœ˜7Kšœ˜Kšœ ˜ Kšœ˜—K˜š‘ œžœžœžœ žœžœžœ˜TKšœ ™ Kšœ8™8K˜ K˜Kšžœžœžœžœ ˜:šžœžœž˜%Kšœžœžœžœ ˜G—Kšžœ˜Kšœ˜Kšœ žœ˜Kšœ˜K˜—š‘ œžœžœžœ˜1Kšœ™K˜K˜Kš žœžœžœžœžœžœ˜.Kšžœ žœ˜&šžœž˜K˜Kšžœžœžœžœ˜Kšžœ žœžœ˜1Kšžœ˜—Kš žœ žœžœ!žœ  ˜EKšœ˜K˜—š‘ œžœžœžœ˜-Kšžœžœ˜'KšœB™BK˜K˜Kšžœžœžœžœ˜=Kšžœ žœžœ0˜GKšžœžœ˜šœ˜K˜——š‘œžœžœžœ˜0Kšžœ žœžœ˜4K˜K˜Kš žœžœžœžœžœ˜;Kšžœ žœžœ:˜QKšžœžœžœ˜"Kšœ˜K˜—š‘ œžœžœ#˜Kšžœžœžœ˜Kšœžœžœ˜Kšžœ žœžœžœ˜Kšžœžœžœ˜=Kšžœžœžœ žœ˜.K˜š žœžœžœ&žœžœž˜DKšžœžœžœ˜6K˜ Kšžœ˜—K˜K˜—š‘œ˜Kšžœžœ ˜K˜š žœžœžœ!žœžœž˜?Kšœžœ˜—Kšœ ˜ šœ˜K˜——Kšœ1™1K˜š‘œžœžœ"žœ˜>Kšœ3™3Kšœ4™4KšœA™Aš œ žœžœžœžœ˜*Kšžœ+˜1—Kšœžœ ˜K˜K˜Kšžœžœžœžœ˜šžœžœžœž˜.Kš žœ žœ žœžœžœ˜)šžœ ž˜K˜-K˜Kšžœ˜—Kšžœ˜—šœ˜K˜——š‘ œžœžœžœ˜