<<-- EditAddrsImpl.Mesa>> <<-- written by Paxton. March 1981>> <<-- last written by Paxton. October 18, 1982 11:14 am>> <<-- **** Persistent addressing ****>> DIRECTORY EditAddrs, NodeAddrs, NodeProps, TextNode; EditAddrsImpl: MONITOR IMPORTS npI:NodeProps, TextNode, NodeAddrs EXPORTS EditAddrs = BEGIN OPEN EditAddrs; Create: PUBLIC PROC RETURNS [Ref] = { RETURN [TextNode.pZone.NEW[Body]] }; FindPair: PROC [ref: Ref, 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] }; PutAddr: PUBLIC PROC [ref: Ref, addr: REF, location: Offset] = { <<-- assigns addr to location in ref>> <<-- ok if addr was previously assigned elsewhere>> p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN ref.addrs _ TextNode.pZone.NEW[PairBody _ [ref.addrs, addr, location]] ELSE p.location _ location }; RemAddr: PUBLIC PROC [ref: Ref, addr: REF] = { <<-- removes the given addr>> p, prev: Pair; IF ref=NIL OR (p _ ref.addrs)=NIL THEN RETURN; IF p.addr=addr THEN { ref.addrs _ p.next; RETURN }; DO prev _ p; p _ p.next; IF p=NIL THEN RETURN; IF p.addr=addr THEN { prev.next _ p.next; RETURN }; ENDLOOP }; GetAddr: PUBLIC PROC [ref: Ref, addr: REF] RETURNS [location: Offset] = { <<-- generates ERROR AddrNotFound if the addr is not in the mapping>> p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN ERROR AddrNotFound; RETURN [p.location] }; TryGetAddr: PUBLIC PROC [ref: Ref, addr: REF] RETURNS [found: BOOLEAN, location: Offset] = { p: Pair; IF (p _ FindPair[ref, addr])=NIL THEN RETURN [FALSE, 0]; RETURN [TRUE, p.location] }; AddrNotFound: PUBLIC ERROR = CODE; MapAddrs: PUBLIC PROC [ref: Ref, action: MapAddrsAction] RETURNS [BOOLEAN] = { <<-- apply the action to each addr&location pair for the ref>> <<-- returns true if&when an action returns true>> IF ref#NIL THEN { p: Pair _ ref.addrs; UNTIL p=NIL DO next: Pair _ p.next; IF action[p.addr, p.location] THEN RETURN [TRUE]; p _ next; ENDLOOP}; RETURN [FALSE] }; <<-- **** notify proc registration ****>> 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[] }; <<-- **** Editing Operations for persistent addrs ****>> GetAddrs: PROC [n: RefTextNode] RETURNS [Ref] = { RETURN [IF n.props = NIL THEN NIL ELSE NARROW[npI.GetProp[n,addrsProp]]] }; addrsProp: ATOM _ NodeAddrs.AddrsProp[]; Replace: PUBLIC PROC [node: RefTextNode, start, len, newlen: Offset] = { <<-- 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>> replace: PROC [old: Offset] RETURNS [Offset] = { RETURN [AfterReplace[old, start, len, newlen]] }; end: Offset _ start+len; ref: Ref = GetAddrs[node]; Notify[node, replace]; IF ref=NIL THEN RETURN; FOR p: Pair _ ref.addrs, p.next UNTIL p=NIL DO 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}; Start: PUBLIC PROC = { }; END.