DIRECTORY Char, CharOps, NodeReader, Rope, Rosary, TextEdit, TextFind, TextLooks, TextNode, Tioga, TiogaFind; TiogaFindImpl: CEDAR PROGRAM IMPORTS Char, CharOps, NodeReader, Rope, Rosary, TextEdit, TextFind, TextLooks, TextNode EXPORTS TiogaFind ~ BEGIN ROPE: TYPE ~ Rope.ROPE; ROSARY: TYPE ~ Rosary.ROSARY; Node: TYPE ~ Tioga.Node; Location: TYPE ~ Tioga.Location; Looks: TYPE ~ Tioga.Looks; Event: TYPE ~ Tioga.Event; Direction: TYPE ~ TextFind.Direction; -- {forward, backward} refFalse: REF BOOL ~ NEW[BOOL ¬ FALSE]; LiteralSearch: PUBLIC PROC [direction: Direction, loc1, loc2: Location, target: Node ¬ NIL, targetStart: INT ¬ 0, targetLen: INT ¬ INT.LAST, case: BOOL ¬ TRUE, match: Match ¬ any, interrupt: REF BOOL ¬ NIL] RETURNS [node: Node ¬ NIL, matchStart, matchEnd: INT ¬ 0] ~ { targetReader: NodeReader.Ref ~ NodeReader.New[target]; targetSize: INT ~ NodeReader.Size[targetReader]; scratchReader: NodeReader.Ref ~ NodeReader.New[]; map: TextFind.CharMap ~ TextFind.CharMapFromCase[case]; found: BOOL ¬ FALSE; IF interrupt=NIL THEN interrupt ¬ refFalse; targetStart ¬ MIN[MAX[0, targetStart], targetSize]; targetLen ¬ MIN[MAX[0, targetLen], targetSize-targetStart]; FOR node ¬ (SELECT direction FROM forward => loc1.node, backward => loc2.node, ENDCASE => ERROR), (SELECT direction FROM forward => IF node=loc2.node THEN NIL ELSE TextNode.StepForward[node], backward => IF node=loc1.node THEN NIL ELSE TextNode.StepBackward[node], ENDCASE => ERROR) UNTIL node=NIL OR interrupt­ DO objectReader: NodeReader.Ref ~ NodeReader.New[node, scratchReader]; objectSize: INT ~ NodeReader.Size[objectReader]; i0: INT ~ IF node=loc1.node THEN loc1.where ELSE 0; i1: INT ~ IF node=loc2.node THEN loc2.where ELSE objectSize; targetHash: PROC [i: INT] RETURNS [BYTE] ~ { RETURN[ORD[map[VAL[NodeReader.FetchCharCode[targetReader, i]]]]]; }; objectHash: PROC [i: INT] RETURNS [BYTE] ~ { RETURN[ORD[map[VAL[NodeReader.FetchCharCode[objectReader, i]]]]]; }; matchProc: PROC [objectStart, targetStart, len: INT] RETURNS [BOOL] ~ { IF NodeReader.Run[objectReader, objectStart, targetReader, targetStart, case, len]0 AND CharOps.XAlphaNumeric[NodeReader.FetchChar[objectReader, matchStart-1]] THEN RETURN[FALSE]; IF match=word AND matchEnd loc1.node, backward => loc2.node, ENDCASE => ERROR), (SELECT direction FROM forward => IF node=loc2.node THEN NIL ELSE TextNode.StepForward[node], backward => IF node=loc1.node THEN NIL ELSE TextNode.StepBackward[node], ENDCASE => ERROR) UNTIL node=NIL OR interrupt­ DO reader: NodeReader.Ref ~ NodeReader.New[node, scratchReader]; size: INT ~ NodeReader.Size[reader]; IF (checkComment AND TextEdit.GetComment[node]#comment) THEN LOOP; IF (checkFormat AND TextEdit.GetFormat[node]#format) THEN LOOP; IF (checkStyle AND styleProc[node]#style) THEN LOOP; IF target=NIL THEN { matchStart ¬ 0; matchEnd ¬ size; EXIT } ELSE { i0: INT ~ IF node=loc1.node THEN loc1.where ELSE 0; i1: INT ~ IF node=loc2.node THEN loc2.where ELSE size; matchString: TextFind.MatchStringProc ~ { WITH text SELECT FROM text: Node => { IF Rope.Run[s1: node.rope, pos1: index, s2: text.rope, pos2: start, len: len, case: case] { IF Rope.Run[s1: node.rope, pos1: index, s2: rope, pos2: start, len: len, case: case] ERROR; }; matchProps: TextFind.MatchStringProc ~ { WITH text SELECT FROM text: Node => { IF (text.runs#NIL OR (looksExact AND node.runs#NIL)) AND RosaryRun[r1: node.runs, pos1: index, r2: text.runs, pos2: start, len: len, match: IF looksExact THEN NIL ELSE LooksSubset] { IF (looksExact AND node.runs#NIL) AND RosaryRun[r1: node.runs, pos1: index, r2: NIL, pos2: start, len: len, match: NIL] ERROR; }; matchType: TextFind.MatchTypeProc ~ { char: Char.XCHAR ~ NodeReader.FetchChar[reader, index]; RETURN[SELECT type FROM any => TRUE, alpha => CharOps.XAlphaNumeric[char], nonalpha => NOT CharOps.XAlphaNumeric[char], blank => CharOps.XBlank[char], nonblank => NOT CharOps.XBlank[char], ENDCASE => ERROR]; }; matchBound: TextFind.MatchBoundProc ~ { RETURN[SELECT bound FROM start => SELECT match FROM any => TRUE, word, def => NOT(index>0 AND matchType[index-1, alpha]), all => index=0, ENDCASE => FALSE, end => SELECT match FROM any => TRUE, word => NOT(index (index index=size, ENDCASE => FALSE, ENDCASE => FALSE]; }; substr: TextFind.SubstrProc ~ { RETURN[NodeSubstr[node, start, len]] }; [found: found, selStart: matchStart, selEnd: matchEnd, subs: subs] ¬ TextFind.Search[ direction: direction, target: target, size: size, start: i0, len: i1-i0, substr: substr, matchString: matchString, matchType: matchType, matchProps: (IF checkLooks THEN matchProps ELSE NIL), matchBound: matchBound, interrupt: interrupt]; IF found THEN EXIT; }; ENDLOOP; NodeReader.Free[scratchReader]; IF NOT found THEN RETURN[NIL]; }; Replace: PUBLIC PROC [dest: Node, destStart: INT ¬ 0, destLen: INT ¬ INT.LAST, source: Node, sourceStart: INT ¬ 0, sourceLen: INT ¬ INT.LAST, pattern: BOOL ¬ FALSE, subs: Subs ¬ NIL, event: Event ¬ NIL] RETURNS [resultStart, resultLen: INT ¬ 0] ~ { reader: NodeReader.Ref ~ NodeReader.New[source]; fetch: TextFind.FetchProc ~ { RETURN[NodeReader.FetchChar[reader, index]] }; put: PROC [source: Node, start, len: INT] RETURNS [repStart, repLen: INT] ~ { [repStart, repLen] ¬ TextEdit.ReplaceText[destRoot: NIL, sourceRoot: NIL, dest: dest, destStart: destStart, destLen: destLen, source: source, sourceStart: start, sourceLen: len, event: event]; destStart ¬ repStart+repLen; destLen ¬ 0; resultLen ¬ resultLen+repLen; }; replace: TextFind.ReplaceProc ~ { [] ¬ put[source, start, len] }; substitute: TextFind.SubstituteProc ~ { WITH text SELECT FROM text: Node => { repStart, repLen: INT; [repStart, repLen] ¬ put[text, start, len]; IF nameLen>0 THEN { looks: Looks ~ TextEdit.FetchLooks[source, nameStart]; TextEdit.ChangeLooks[root: NIL, text: dest, remove: Tioga.allLooks, add: looks, start: repStart, len: repLen, event: event]; }; }; ENDCASE; }; TextFind.Replace[replace: replace, substitute: substitute, size: TextEdit.Size[source], start: sourceStart, len: sourceLen, fetch: fetch, pattern: pattern, subs: subs]; IF destLen>0 THEN [] ¬ put[NIL, 0, 0]; resultStart ¬ destStart-resultLen; NodeReader.Free[reader]; }; Apply: PUBLIC PROC [proc: TiogaFind.ApplyProc, loc1, loc2: Location, target: Target ¬ NIL, case: BOOL ¬ TRUE, match: Match ¬ any, checkLooks: BOOL ¬ FALSE, looksExact: BOOL ¬ FALSE, checkComment: BOOL ¬ FALSE, comment: BOOL ¬ FALSE, checkFormat: BOOL ¬ FALSE, format: ATOM ¬ NIL, checkStyle: BOOL ¬ FALSE, style: ATOM ¬ NIL, styleProc: PROC [Node] RETURNS [ATOM] ¬ NIL, interrupt: REF BOOL ¬ NIL] RETURNS [count: INT ¬ 0] ~ { node: Node ¬ loc1.node; where: INT ¬ loc1.where; matchStart, matchEnd, from, delta: INT ¬ 0; subs: Subs ¬ NIL; continue, bumpCount: BOOL ¬ FALSE; UNTIL node=NIL DO IF node=loc2.node AND where>=loc2.where THEN EXIT; [node: node, matchStart: matchStart, matchEnd: matchEnd, subs: subs] ¬ Search[ direction: forward, loc1: [node, where], loc2: loc2, target: target, case: case, match: match, checkLooks: checkLooks, looksExact: looksExact, checkComment: checkComment, comment: comment, checkFormat: checkFormat, format: format, checkStyle: checkStyle, style: style, styleProc: styleProc, interrupt: interrupt]; IF node=NIL THEN RETURN; [continue: continue, bumpCount: bumpCount, from: from, delta: delta] ¬ proc[node: node, matchStart: matchStart, matchEnd: matchEnd, subs: subs]; IF bumpCount THEN count ¬ count+1; IF NOT continue THEN EXIT; IF node=loc2.node THEN loc2.where ¬ loc2.where+delta; IF target#NIL THEN { where ¬ from } ELSE { node ¬ TextNode.StepForward[node]; where ¬ 0 }; ENDLOOP; }; END. ~ TiogaFindImpl.mesa Copyright Σ 1985, 1986, 1992 by Xerox Corporation. All rights reserved. Doug Wyatt, March 19, 1992 4:45 pm PST NodeAction: TYPE ~ PROC [node: Node, i0, i1: INT] RETURNS [quit: BOOL ¬ FALSE]; MapNodes: PUBLIC PROC [direction: Direction, loc1, loc2: Location, action: MapAction, interrupt: REF BOOL ¬ NIL] RETURNS [BOOL ¬ FALSE] ~ { SELECT direction FROM forward => { FOR node: Node _ loc1.node, TextNode.StepForward[node] UNTIL node=NIL DO i0: INT ~ IF node=loc1.node THEN loc1.where ELSE 0; i1: INT ~ IF node=loc2.node THEN loc2.where ELSE TextEdit.Size[node]; IF action[node, i0, i1] THEN RETURN[TRUE]; IF node=loc2.node OR interrupt­ THEN EXIT; ENDLOOP; }; backward => { FOR node: Node _ loc2.node, TextNode.StepBackward[node] UNTIL node=NIL DO i0: INT ~ IF node=loc1.node THEN loc1.where ELSE 0; i1: INT ~ IF node=loc2.node THEN loc2.where ELSE TextEdit.Size[node]; IF action[node, i0, i1] THEN RETURN[TRUE]; IF node=loc1.node OR interrupt­ THEN EXIT; ENDLOOP; }; ENDCASE => ERROR; }; LiteralSearch: PUBLIC PROC [direction: Direction, loc1, loc2: Location, target: Target ¬ NIL, case, word, def, looks: BOOL ¬ FALSE, interrupt: REF BOOL ¬ NIL] RETURNS [node: Node ¬ NIL, matchStart, matchEnd: INT ¬ 0] ~ { scratchReader: NodeReader.Ref ~ NodeReader.New[]; map: TextFind.CharMap ~ TextFind.CharMapFromCase[case]; found: BOOL ¬ FALSE; IF interrupt=NIL THEN interrupt ¬ refFalse; reader: NodeReader.Ref ~ NodeReader.New[node, scratchReader]; size: INT ~ NodeReader.Size[reader]; i0: INT ~ IF node=loc1.node THEN loc1.where ELSE 0; i1: INT ~ IF node=loc2.node THEN loc2.where ELSE size; hash1: PROC [i: INT] RETURNS [BYTE] ~ { RETURN[ORD[map[Rope.Fetch[rope1, i]]]] }; hash2: PROC [i: INT] RETURNS [BYTE] ~ { RETURN[ORD[map[Rope.Fetch[rope2, i]]]] }; equal: PROC [index1, index2, len: INT] RETURNS [BOOL] ~ { IF Rope.Run[s1: rope1, pos1: index1, s2: rope2, pos2: index2, case: case, len: len]#len THEN RETURN[FALSE]; IF sets1#NIL OR sets2#NIL THEN { IF NOT RosaryEqual[sets1, sets2, index1, index2, len] THEN RETURN[FALSE]; }; IF looks AND (runs1#NIL OR runs2#NIL) THEN { IF NOT RosaryEqual[runs1, runs2, index1, index2, len] THEN RETURN[FALSE]; }; IF word THEN { alpha2: PROC [i: INT] RETURNS [BOOL] ~ { RETURN[(sets2=NIL OR Rosary.Fetch[sets2, i]=NIL) AND CharOps.AlphaNumeric[Rope.Fetch[rope2, i]]]; }; IF index2>start2 AND alpha2[index2-1] THEN RETURN[FALSE]; IF (index2+len)<(start2+len2) AND alpha2[index2+len] THEN RETURN[FALSE]; }; RETURN[TRUE]; }; [found: found, matchStart: matchStart, matchEnd: matchEnd, selStart: selStart, selEnd: selEnd, subs: subs] ¬ TextFind.Search[ direction: direction, target: target, size: size, start: i0, len: i1-i0, matchString: matchString, matchType: matchType, matchProps: matchProps, substr: substr, word: word, interrupt: interrupt]; IF found THEN EXIT; IF interrupt­ THEN EXIT; ENDLOOP; NodeReader.Free[scratchReader]; IF NOT found THEN RETURN[NIL]; }; Κj–(cedarcode) style•NewlineDelimiter ™codešœ™Kšœ Οeœ=™HK™&—K˜šΟk ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜K˜ —K˜KšΟn œžœž˜KšžœQ˜XKšžœ ˜Kšœž˜K˜Kšžœžœžœ˜Kšžœžœ žœ˜Kšœžœ˜Kšœ žœ˜ Kšœžœ˜šœžœ˜K™—šœ žœΟc˜ŸœžœžœDžœžœžœ"žœžœžœžœžœžœ žœžœžœžœ žœžœžœžœ žœžœ žœžœžœžœ žœžœžœžœ žœ ˜©Jšœ˜Jšœžœ˜Kšœ#žœ˜+Kšœ žœ˜Kšœžœžœ˜"šžœžœž˜Kšžœžœžœžœ˜2Kšœˆ˜ˆKšžœžœžœžœ˜Kšœ‘˜‘Kšžœ žœ˜"Kšžœžœ žœžœ˜Kšžœžœ˜5Kšžœžœžœ˜#Kšžœ2˜6Kšžœ˜—K˜K˜—Kšžœ˜—…—,^IF