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: 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 _ 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: 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: BOOL, 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 [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: 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: PROC = { OPEN NodeProps; Register[addrsProp,NullRead,NullWrite,NullCopy] }; StartNodeAddrs[]; END. €NodeAddrsImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. written by Bill Paxton, March 1981 last edit by Bill Paxton, December 28, 1982 11:44 am Doug Wyatt, March 3, 1985 5:42:02 pm PST Michael Plass, March 29, 1985 2:34:11 pm 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šœ Οmœ1™K˜K˜Kš žœžœžœžœžœ˜;Kšžœ žœžœ:˜QKšžœžœžœ˜$K˜—š  œžœžœ*˜CKšžœžœ˜Kšœ8™8Kšœ+™+K™K˜šžœžœžœ˜K˜šžœžœž˜K˜Kš žœ žœ žœžœž˜(Kš žœžœžœžœžœ˜6K˜ Kšžœ˜ ——Kšžœžœ˜K˜—Kšœ"™"K˜Kšœžœžœ˜K˜Kšœ ž œ˜Kšœ žœ˜K˜Kš œžœžœ˜/K˜š œžœžœ˜šžœ žœ˜(Kšœž œ ˜%——K˜š  œžœžœžœ˜;Kšžœžœžœ˜Kšœ žœ˜K˜K˜—š œžœžœžœ˜>Kšžœžœžœ˜Kšœžœžœ˜Kšžœ žœžœžœ˜Kšžœžœžœ˜=Kšžœžœžœ žœ˜.K˜š žœžœžœ&žœžœž˜DKšžœžœžœ˜6K˜ Kšžœ˜—K˜K˜—šœ˜Kšžœžœ ˜K˜š žœžœžœ!žœžœž˜?Kšœžœ˜—šœ ˜ K˜——Kšœ1™1K˜š œžœžœ4˜HKšœ3™3Kšœ4™4KšœA™Ašœ žœžœ ˜0Kšžœ+˜1—K˜K˜K˜Kšžœžœžœžœ˜šžœžœžœž˜.Kš žœ žœ žœžœžœ˜)šžœ ž˜K˜-K˜Kšžœ˜—Kšžœ˜ K˜——š  œžœžœ&˜?Kšžœ˜šœ žœ ž˜K˜#K˜Kšžœ ˜K˜——Kšœ™K˜š œžœ˜Kšžœ ˜K˜/K˜—Kšœ˜K˜Kšžœ˜K˜—…—Œ