DIRECTORY RunReader USING [Base, Body, noLooks, ReaderProc, Ref], TextLooks USING [allLooks, Looks, noLooks, Runs, RunsBody, Size], TextLooksSupport USING [BaseRun, FindBaseRuns, MergeChanges, ModifyLooks]; RunReaderImpl: CEDAR MONITOR IMPORTS TextLooks, TextLooksSupport EXPORTS RunReader SHARES TextLooks = BEGIN OPEN RunReader; Create: PUBLIC PROC RETURNS [Ref] = { RETURN [NEW[Body]] }; SetPosition: PUBLIC PROC [reader: Ref, runs: TextLooks.Runs, index: INT _ 0] = { IF runs # GetRuns[reader] OR index # GetIndex[reader] THEN reader^ _ [0, 0, 0, NIL, FALSE, TextLooks.noLooks, TextLooks.noLooks, runs, index]; }; SetIndex: PUBLIC PROC [reader: Ref, index: INT _ 0] = { IF index # GetIndex[reader] THEN { runs: TextLooks.Runs _ GetRuns[reader]; reader^ _ [0, 0, 0, NIL, FALSE, TextLooks.noLooks, TextLooks.noLooks, runs, index] } }; BackupIndex: PUBLIC PROC [reader: Ref, amount: INT] = { SetIndex[reader, GetIndex[reader]-amount] }; BumpIndex: PUBLIC PROC [reader: Ref, amount: INT] = { SetIndex[reader, GetIndex[reader]+amount] }; Position: PUBLIC PROC [reader: Ref] RETURNS [runs: TextLooks.Runs, index: INT] = { RETURN [GetRuns[reader], GetIndex[reader]] }; GetRuns: PUBLIC PROC [reader: Ref] RETURNS [runs: TextLooks.Runs] = { RETURN [reader.runs] }; Get: PUBLIC ReaderProc = { current: NAT; base: Base; IF (current_reader.current) >= reader.after THEN { [count, looks] _ ReadRun[reader, get]; RETURN }; reader.current _ current+1; base _ reader.base; count _ IF current=0 THEN base[0].after ELSE base[current].after-base[current-1].after; looks _ base[current].looks; IF reader.changeLooks THEN looks _ TextLooksSupport.ModifyLooks[looks, reader.remove, reader.add] }; Backwards: PUBLIC ReaderProc = { current: NAT; base: Base; IF (current_reader.current) <= reader.first THEN { [count, looks] _ ReadRun[reader, backwards]; RETURN }; base _ reader.base; count _ IF (reader.current _ current _ current-1)=0 THEN base[0].after ELSE base[current].after-base[current-1].after; looks _ base[current].looks; IF reader.changeLooks THEN looks _ TextLooksSupport.ModifyLooks[looks, reader.remove, reader.add] }; Peek: PUBLIC ReaderProc = { current: NAT; base: Base; IF (current_reader.current) >= reader.after THEN { [count, looks] _ ReadRun[reader, peek]; RETURN }; base _ reader.base; count _ IF current=0 THEN base[0].after ELSE base[current].after-base[current-1].after; looks _ base[current].looks; IF reader.changeLooks THEN looks _ TextLooksSupport.ModifyLooks[looks, reader.remove, reader.add] }; PeekBackwards: PUBLIC ReaderProc = { current: NAT; base: Base; IF (current_reader.current) <= reader.first THEN { [count, looks] _ ReadRun[reader, backwards]; RETURN }; base _ reader.base; count _ IF (current _ current-1)=0 THEN base[0].after ELSE base[current].after-base[current-1].after; looks _ base[current].looks; IF reader.changeLooks THEN looks _ TextLooksSupport.ModifyLooks[looks, reader.remove, reader.add] }; GetIndex: PUBLIC PROC [reader: Ref] RETURNS [index: INT] = { base: Base; offset: INT; IF reader.after = reader.current THEN RETURN [reader.index]; base _ reader.base; offset _ IF reader.current=0 THEN base[reader.after-1].after ELSE base[reader.after-1].after-base[reader.current-1].after; RETURN [reader.index - offset] }; NoMoreRuns: PUBLIC ERROR = CODE; Mode: TYPE = {get, backwards, peek, peekbackwards}; ReadRun: PROC [reader: Ref, mode: Mode] RETURNS [count: INT, looks: TextLooks.Looks] = { runs: TextLooks.Runs _ reader.runs; index, current: INT _ GetIndex[reader]; after: INT _ TextLooks.Size[runs]; first: INT _ 0; remove, add: TextLooks.Looks _ TextLooks.noLooks; SetIndx: PROC [index: INT] = { reader.index _ index }; SetBaseInfo: PROC [current, first, after: NAT, base: Base] = { reader.current _ current; reader.first _ first; reader.after _ after; reader.base _ base }; ClearBaseInfo: PROC = { SetBaseInfo[0, 0, 0, NIL] }; SetLooksInfo: PROC = { reader.remove _ remove; reader.add _ add; reader.changeLooks _ remove # TextLooks.noLooks OR add # TextLooks.noLooks }; Modify: PUBLIC PROC [lks: TextLooks.Looks] RETURNS [TextLooks.Looks] = { RETURN [TextLooksSupport.ModifyLooks[lks, remove, add]] }; SingleRun: PROC = { ClearBaseInfo; SELECT mode FROM get => SetIndx[index + (count _ after-current)]; peek => count _ after-current; backwards => SetIndx[index - (count _ current-first+1)]; peekbackwards => count _ current-first+1; ENDCASE => ERROR }; IF runs=NIL THEN RETURN [LAST[NAT], TextLooks.noLooks]; SELECT mode FROM -- adjust current depending on direction backwards, peekbackwards => IF current=0 THEN ERROR NoMoreRuns ELSE current _ current-1; get, peek => NULL; ENDCASE => ERROR; IF current >= after THEN ERROR NoMoreRuns; WHILE runs # NIL DO TRUSTED {WITH runs SELECT FROM x: REF TextLooks.RunsBody.base => { len: INT _ after-first; firstRun, lastRun, afterRun, curRun: NAT; -- indexes into runs startRuns, afterRuns, startCur: INT; [firstRun, lastRun] _ TextLooksSupport.FindBaseRuns[x, first, len]; IF firstRun=lastRun THEN { -- treat as special case SingleRun; RETURN [count, Modify[x[firstRun].looks]] }; IF (firstRun=0 AND first=0) OR (firstRun>0 AND x[firstRun-1].after=first) THEN startRuns _ first ELSE -- only included part of firstRun IF current >= (startRuns _ x[firstRun].after) THEN firstRun _ firstRun+1 -- current not in first run ELSE { -- current is in the first run. must special case it. IF x[lastRun].after=after THEN { -- include all of lastRun afterRuns _ after; afterRun _ lastRun+1 } ELSE { afterRuns _ x[lastRun-1].after; afterRun _ lastRun }; SELECT mode FROM get => { count _ startRuns-current; IF afterRun > firstRun THEN { SetBaseInfo[firstRun+1, firstRun+1, afterRun, x]; SetIndx[index+afterRuns-current]; SetLooksInfo; } ELSE { ClearBaseInfo; SetIndx[index+count] } }; peek => { count _ startRuns-current; ClearBaseInfo; SetIndx[index] }; backwards => { count _ current-first+1; ClearBaseInfo; SetIndx[index-count] }; peekbackwards => { count _ current-first+1; ClearBaseInfo; SetIndx[index] }; ENDCASE => ERROR; RETURN [count, Modify[x[firstRun].looks]] }; IF x[lastRun].after=after THEN { -- included all of lastRun afterRuns _ after; afterRun _ lastRun+1 } ELSE { -- only included part of lastRun IF current >= (afterRuns _ x[lastRun-1].after) THEN { SELECT mode FROM get => { count _ after-current; ClearBaseInfo; SetIndx[index+count] }; peek => { count _ after-current; ClearBaseInfo; SetIndx[index] }; backwards => { count _ current-afterRuns+1; IF lastRun > firstRun THEN { SetBaseInfo[lastRun-1, firstRun, lastRun, x]; SetIndx[index-count]; SetLooksInfo; } ELSE { ClearBaseInfo; SetIndx[index-count] } }; peekbackwards => { count _ current-afterRuns+1; ClearBaseInfo; SetIndx[index] }; ENDCASE => ERROR; RETURN [count, Modify[x[lastRun].looks]] }; afterRun _ lastRun }; curRun _ TextLooksSupport.BaseRun[x, current, firstRun, lastRun]; startCur _ IF curRun=0 THEN 0 ELSE x[curRun-1].after; SELECT mode FROM get => { count _ x[curRun].after-current; SetBaseInfo[curRun+1, firstRun, afterRun, x]; SetIndx[index+afterRuns-current]; SetLooksInfo; }; peek => { count _ x[curRun].after-current; IF current = startCur THEN { SetBaseInfo[curRun, firstRun, afterRun, x]; SetIndx[index+afterRuns-current]; SetLooksInfo; } ELSE { ClearBaseInfo; SetIndx[index] } }; backwards => { -- recall that current has been decremented count _ current-startCur+1; SetBaseInfo[curRun, firstRun, afterRun, x]; SetIndx[index+afterRuns-current-1]; SetLooksInfo; }; peekbackwards => { count _ current-startCur+1; IF current = x[curRun].after-1 THEN { SetBaseInfo[curRun+1, firstRun, afterRun, x]; SetIndx[index+afterRuns-current-1]; SetLooksInfo; } ELSE { ClearBaseInfo; SetIndx[index] } }; ENDCASE => ERROR; RETURN [count, Modify[x[curRun].looks]] }; x: REF TextLooks.RunsBody.node.substr => IF current < x.size THEN { offset: INT; current _ current + (offset _ x.start); first _ first + offset; after _ after + offset; runs _ x.base; LOOP }; x: REF TextLooks.RunsBody.node.concat => IF current < x.size THEN { xpos: INT; IF current >= (xpos _ x.pos) THEN { current _ current - xpos; after _ after - xpos; first _ IF first <= xpos THEN 0 ELSE first - xpos; runs _ x.rest; LOOP }; IF after > xpos THEN after _ xpos; runs _ x.base; LOOP }; x: REF TextLooks.RunsBody.node.replace => IF current < x.size THEN { xstart: INT _ x.start; newPos, oldPos: INT; IF current < xstart THEN { IF after > xstart THEN after _ xstart; runs _ x.base; LOOP }; IF current < (newPos _ x.newPos) THEN { current _ current - xstart; after _ MIN[after, newPos] - xstart; first _ IF first <= xstart THEN 0 ELSE first-xstart; runs _ x.replace; LOOP }; current _ current - newPos + (oldPos _ x.oldPos); after _ after - newPos + oldPos; first _ IF first >= newPos THEN first - newPos + oldPos ELSE oldPos; runs _ x.base; LOOP }; x: REF TextLooks.RunsBody.node.change => { xstart: INT _ x.start; xend: INT; IF current < xstart THEN { after _ MIN[after, xstart]; runs _ x.base; LOOP }; IF current < (xend _ xstart+x.len) THEN { after _ MIN[after, xend]; first _ MAX[first, xstart]; [remove, add] _ TextLooksSupport.MergeChanges[x.remove, x.add, remove, add]; IF remove=TextLooks.allLooks THEN { SingleRun; RETURN[count, add] }; runs _ x.base; LOOP }; first _ MAX[first, xend]; runs _ x.base; LOOP }; ENDCASE => ERROR }; EXIT; ENDLOOP; ERROR NoMoreRuns }; MergedGet: PUBLIC ReaderProc = { [count, looks] _ Get[reader]; WHILE reader.current=reader.after OR reader.changeLooks DO nxtCount: INT; nxtLooks: TextLooks.Looks; [nxtCount, nxtLooks] _ Peek[reader ! NoMoreRuns => EXIT]; IF nxtLooks#looks THEN RETURN; count _ count+nxtCount; [, ] _ Get[reader]; ENDLOOP }; MergedBackwards: PUBLIC ReaderProc = { [count, looks] _ Backwards[reader]; WHILE reader.current=reader.first OR reader.changeLooks DO nxtCount: INT; nxtLooks: TextLooks.Looks; [nxtCount, nxtLooks] _ PeekBackwards[reader ! NoMoreRuns => EXIT]; IF nxtLooks#looks THEN RETURN; count _ count+nxtCount; [, ] _ Backwards[reader]; ENDLOOP }; Equal: PUBLIC PROC [r1, r2: TextLooks.Runs, rdr1, rdr2: Ref] RETURNS [BOOL] = { RETURN [EqSubstrs[r1, r2, 0, 0, LAST[INT], rdr1, rdr2]] }; EqSubstrs: PUBLIC PROC [r1, r2: TextLooks.Runs, start1, start2, len: INT, rdr1, rdr2: Ref] RETURNS [BOOL] = { NoLooks: PROC [r: TextLooks.Runs, start, len: INT, rdr: Ref] RETURNS [BOOL] = { looks: TextLooks.Looks; runLen: INT; size: INT _ TextLooks.Size[r]; len _ IF start > size THEN 0 ELSE MIN[len, size-start]; SetPosition[rdr, r, start]; [runLen, looks] _ Get[rdr]; IF looks # TextLooks.noLooks OR runLen < len THEN RETURN [FALSE]; RETURN [TRUE] }; size1, size2: INT; IF len=0 THEN RETURN[TRUE]; IF r1=NIL THEN { IF r2=NIL THEN RETURN [TRUE]; RETURN [NoLooks[r2, start2, len, rdr2]] }; IF r2=NIL THEN RETURN [NoLooks[r1, start1, len, rdr1]]; size1 _ TextLooks.Size[r1]; size2 _ TextLooks.Size[r2]; IF len=LAST[INT] THEN { IF (len _ size1-start1) # size2-start2 THEN RETURN [FALSE] } ELSE IF start1+len > size1 THEN RETURN [FALSE] ELSE IF start2+len > size2 THEN RETURN [FALSE]; SetPosition[rdr1, r1, start1]; SetPosition[rdr2, r2, start2]; DO -- check the runs in the specified sections looks1, looks2: TextLooks.Looks; runLen1, runLen2: INT; [runLen1, looks1] _ MergedGet[rdr1]; [runLen2, looks2] _ MergedGet[rdr2]; IF looks1 # looks2 THEN RETURN [FALSE]; IF runLen1 >= len THEN { IF runLen2 < len THEN RETURN [FALSE]; EXIT }; IF runLen2 # runLen1 THEN RETURN [FALSE]; len _ len-runLen1; ENDLOOP; RETURN [TRUE] }; runrdr1, runrdr2, runrdr3: Ref; -- shared run readers GetRunReader: PUBLIC ENTRY PROC RETURNS [reader: Ref] = { ENABLE UNWIND => NULL; IF runrdr3 # NIL THEN { reader _ runrdr3; runrdr3 _ NIL } ELSE IF runrdr2 # NIL THEN { reader _ runrdr2; runrdr2 _ NIL } ELSE IF runrdr1 # NIL THEN { reader _ runrdr1; runrdr1 _ NIL } ELSE reader _ Create[] }; FreeRunReader: PUBLIC ENTRY PROC [reader: Ref] = { ENABLE UNWIND => NULL; SetPosition[reader, NIL]; IF runrdr3 = reader OR runrdr2 = reader OR runrdr1 = reader THEN ERROR; IF runrdr3 = NIL THEN runrdr3 _ reader ELSE IF runrdr2 = NIL THEN runrdr2 _ reader ELSE IF runrdr1 = NIL THEN runrdr1 _ reader; }; END. NRunReaderImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. written by Bill Paxton, March 1981 last edit by Bill Paxton, October 18, 1982 11:32 am Last Edited by: Maxwell, January 5, 1983 1:08 pm Michael Plass, March 29, 1985 5:00:19 pm PST Doug Wyatt, August 28, 1986 6:07:38 pm PDT returns the current position of the reader get run, then increment reader location decrement reader location, then get run get run without incrementing reader location like Backwards, but doesn't change position know lastRun>0 since lastRun>firstRun current is in the lastRun. must special case it. uses readers rdr1 and rdr2 to read runs r1 and r2 to test for equality uses readers rdr1 and rdr2 to read runs r1 and r2 to test for equality returns TRUE if r1 is same as len looks of r2 starting at start ***** Shared readers Κt˜codešœ™Kšœ Οmœ7™BKšœ#™#Kšœ3™3Kšœ0™0Kšœ,™,Kšœ*™*K™—šΟk ˜ Kšœ žœ(˜7Kšœ žœ2˜AKšœžœ4˜J—K˜KšΟn œžœž˜Kšžœ˜#Kšžœ ˜Kšžœ ˜šœžœžœ ˜K˜—š Ÿœžœžœžœ žœžœ ˜;K˜—šŸ œžœžœ,žœ ˜PKšžœžœž˜:Kšœžœžœ5˜SK˜—K˜šŸœžœžœžœ ˜7šžœžœ˜"K˜'Kšœžœžœ4˜RK˜—K˜—K˜šŸ œžœžœžœ˜7K˜*K˜—K˜šŸ œžœžœžœ˜5K˜*K˜—K˜KšŸœžœžœ˜#šžœžœ˜.Kšœ*™*Kšžœ%˜+K˜—K˜KšŸœžœžœ˜"Kšžœžœ˜:K˜šŸœžœ˜Kšœ'™'Kšœ žœ˜ K˜ Kšžœ*ž˜0Kšœ)žœ˜2K˜K˜Kšœžœ žœž˜,K˜*K˜Kšžœž˜K˜GK˜—K˜šŸ œžœ˜ Kšœ'™'Kšœ žœ˜ K˜ Kšžœ*ž˜0Kšœ/žœ˜8K˜Kšœžœ*žœž˜KK˜*K˜Kšžœž˜K˜GK˜—K˜šŸœžœ˜Kšœ,™,Kšœ žœ˜ K˜ Kšžœ*ž˜0Kšœ*žœ˜3K˜Kšœžœ žœž˜,K˜*K˜Kšžœž˜K˜GK˜—K˜šŸ œžœ˜$Kšœ+™+Kšœ žœ˜ K˜ Kšžœ*ž˜0Kšœ/žœ˜8K˜Kšœžœžœž˜:K˜*K˜Kšžœž˜K˜GK˜—K˜š Ÿœžœžœžœ žœ˜K˜/K˜)K˜—KšŸ œžœžœ˜4šŸ œžœ˜K˜)Kšœ0žœ˜KK˜—šŸœžœžœžœ˜HKšžœ2˜8K˜—šŸ œžœ˜K˜šžœž˜K˜0K˜K˜8K˜)Kšžœž˜—K˜—Kš žœžœžœžœžœžœ˜7šžœžœΟc(˜9K˜Kšžœ žœžœ žœ˜Kšœ žœ˜$K˜Cšžœžœ ˜3Kšœ žœ$˜5K˜—Kšžœ žœ ž˜šœ žœžœ˜AKšžœ !˜&Kšžœ,ž˜2Kšœ ˜1šžœ 6˜=Kšžœžœ ˜:K˜(K˜—Kšžœ8˜<šžœž˜˜K˜šžœžœ˜K˜1K˜0K˜—Kšžœ(˜,K˜—˜ K˜K˜K˜—˜K˜K˜$K˜—˜K˜K˜K˜—Kšžœžœ˜—Kšžœ$˜*K˜—šžœžœ ˜;K˜(K˜—šžœ  ˜'Kšœ%™%šžœ-žœ˜5Kšœ1™1šžœž˜K˜K˜K˜$K˜—˜ K˜K˜K˜—˜K˜šžœžœ˜K˜-K˜$K˜—Kšžœ(˜,K˜—˜K˜K˜K˜—Kšžœžœ˜Kšžœ#˜)K˜—K˜K˜—K˜AKšœ žœ žœžœ˜5šžœž˜˜K˜ K˜-K˜0K˜—˜ K˜ šžœžœ˜K˜+K˜0K˜—Kšžœ"˜&K˜—šœ +˜:K˜K˜+K˜2K˜—˜K˜šžœžœ˜%K˜-K˜2K˜—Kšžœ"˜&K˜—Kšžœžœ˜—Kšžœ!˜'K˜—šœžœ$žœžœ˜DKšœžœ˜ K˜'K˜0Kšœžœ˜K˜—šœžœ$žœžœ˜DKšœžœ˜ šžœžœ˜#K˜0Kšœžœžœžœ˜3Kšœžœ˜K˜—Kšžœžœ˜"Kšœžœ˜K˜—šœžœ$žœžœ˜DKšœžœ ˜Kšœžœ˜šžœžœ˜Kšžœžœ˜&Kšœžœ˜K˜—šžœžœ˜'K˜Kšœžœ˜$Kšœžœžœžœ˜4Kšœžœ˜K˜—K˜1K˜ Kšœžœžœžœ˜DKšœžœ˜K˜—šœžœ$˜*Kšœžœ ˜Kšœžœ˜ šžœžœ˜Kšœžœ žœ˜0K˜—šžœ!žœ˜)Kšœžœžœ˜5K˜LKšžœžœžœ˜DKšœžœ˜K˜—Kšœžœžœ˜.K˜—Kšžœž˜K˜—Kšžœ˜Kšžœ˜—Kšžœ ˜K˜—K˜šŸ œžœ˜ K˜šžœžœž˜:Kšœ žœ˜K˜Kšœ3žœ˜9Kšžœžœžœ˜K˜K˜Kšžœ˜—K˜—K˜šŸœžœ˜&K˜#šžœžœž˜:Kšœ žœ˜K˜Kšœ<žœ˜BKšžœžœžœ˜K˜K˜Kšžœ˜—K˜—K˜š Ÿœžœžœ+žœžœ˜OKšœF™FKšžœžœžœ˜8K˜—K˜KšŸ œžœžœ/žœ˜Zšžœžœ˜KšœF™FKšœ?™?š Ÿœžœ!žœ žœžœ˜OK˜Kšœžœ˜ Kšœžœ˜Kš œžœžœžœžœ˜7K˜K˜Kš žœžœžœžœžœ˜AKšžœžœ˜K˜—Kšœžœ˜Kšžœžœžœžœ˜šžœžœžœ˜Kš žœžœžœžœžœ˜Kšžœ"˜(K˜—Kšžœžœžœžœ"˜7K˜K˜Kšžœžœžœžœžœ%žœžœžœ˜TKš žœžœžœžœžœ˜.Kš žœžœžœžœžœ˜/K˜K˜šžœ +˜.K˜ Kšœžœ˜K˜$K˜$Kšžœžœžœžœ˜'Kšžœžœžœžœžœžœžœ˜FKšžœžœžœžœ˜)K˜Kšžœ˜—Kšžœžœ˜K˜—K˜Kšœ™Kšœ  ˜5š Ÿ œžœžœžœžœ˜9Kšžœžœžœ˜Kšžœ žœžœžœ˜9Kš žœžœ žœžœžœ˜>Kš žœžœ žœžœžœ˜>Kšžœ˜K˜—K˜šŸ œžœžœžœ˜2Kšžœžœžœ˜Kšœžœ˜Kš žœžœžœžœžœ˜Gšžœ žœžœ˜&Kšžœžœ žœžœ˜+Kšžœžœ žœžœ˜,—K˜—K˜Kšžœ˜—…—/VA