DIRECTORY NodeAddrs, NodeProps; NodeAddrsImpl: CEDAR MONITOR IMPORTS NodeProps EXPORTS NodeAddrs = BEGIN OPEN NodeAddrs; TextAddrNotFound: PUBLIC ERROR = CODE; addrsProp: ATOM = $TiogaNodeAddrsProp; AddrsProp: PUBLIC PROC RETURNS [ATOM] = { RETURN [addrsProp] }; 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: Node] RETURNS [ref: RefAddrs] = INLINE { RETURN [NARROW[NodeProps.GetProp[n, addrsProp]]] }; Put: PROC [n: Node, ref: RefAddrs] = INLINE { NodeProps.PutProp[n, addrsProp, ref] }; PinTextAddr: PUBLIC PROC [n: Node, addr: REF] = { ref: RefAddrs _ Get[n]; p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN RETURN; p.pinned _ TRUE }; UnpinTextAddr: PUBLIC PROC [n: Node, addr: REF] = { ref: RefAddrs _ Get[n]; p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN RETURN; p.pinned _ FALSE }; UnpinAll: PUBLIC PROC [n: Node] = { 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: Node, addr: REF, location: INT] = { 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: Node, addr: REF, location: INT] = { ref: RefAddrs; p: Pair; IF (ref _ Get[n]) = NIL THEN Put[n, ref _ NEW[Body]]; 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: Node, 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: Node, addr: REF] RETURNS [node: Node, location: INT] = { 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: Node, addr: REF] RETURNS [found: BOOL, node: Node, location: INT] = { 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: Node, action: TextAddrsAction] RETURNS [BOOL] = { 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: Node, start, len, newlen: INT] = { replace: PROC [old: INT] RETURNS [INT] = { RETURN [AfterReplace[old, start, len, newlen]] }; end: INT _ 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: 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 Σ 1985, 1986, 1988 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, February 17, 1988 11:43:44 am PST 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 Κ:˜codešœ™KšœH™HKšœ#™#Kšœ4™4K™,K™-—K˜šΟk ˜ K˜ K˜ —K˜KšΠbl œœ˜Kšœ ˜Kšœ ˜Kšœœœ ˜K˜Kšœœœœ˜&K˜Kšœ œ˜&K˜š Οn œœœœœ˜)Kšœ˜K˜—šŸœœœœ ˜<šœœ˜šœœœ˜.Kšœœœœ˜*——Kšœœ˜K˜—šŸœœ œœ˜6Kšœœ%˜3K˜—šŸœœœ˜-K˜'K˜—šŸ œœœœ˜1Kšœ+™+K˜K˜Kšœœœœ˜-Kšœ œ˜K˜—šŸ œœœœ˜3K˜K˜Kšœœœœ˜-Kšœ œ˜K˜—šŸœœœ˜#K˜šœœ˜šœœœ˜.Kšœ œœ˜——K˜—š Ÿ œœœœ œ˜HKšœ˜K˜Kš œœœœœœ˜7Kšœ˜Kšœ"˜"—K˜š Ÿ œœœœ œ˜AKšœ ™ Kšœ8™8K˜K˜Kšœœœœ˜5šœœ˜%Kšœœœœ ˜G—Kšœ˜Kšœ œ˜Kšœ œ˜K˜—šŸ œœœœ˜1Kšœ™K˜K˜Kš œœœœœœ˜.Kšœ œ˜&šœ˜K˜Kšœœœœ˜Kšœ œœ˜1Kšœ˜—Kš œ œœ!œΟc œ˜HK˜—šŸ œœœœ˜-Kšœœ˜'KšœB™BK˜K˜Kšœœœœ˜=Kšœ œœ0˜Gšœœ˜K˜——šŸœœœœ˜0Kšœ œœ˜4K˜K˜Kš œœœœœ˜;Kšœ œœ:˜QKšœœœ˜$K˜—šŸ œœœ#˜Kšœœœ˜Kšœœœ˜Kšœ œœœ˜Kšœœœ˜=Kšœœœ œ˜.K˜š œœœ&œœ˜DKšœœœ˜6K˜ 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˜——šŸ œœœœ˜