DIRECTORY RunReader, TextLooks, TextLooksSupport; 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: TextLooks.Offset] = { base: Base; offset: TextLooks.Offset; 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: TextLooks.Offset, looks: TextLooks.Looks] = { runs: TextLooks.Runs _ reader.runs; index, current: TextLooks.Offset _ GetIndex[reader]; after: TextLooks.Offset _ TextLooks.Size[runs]; first: TextLooks.Offset _ 0; remove, add: TextLooks.Looks _ TextLooks.noLooks; SetIndx: PROC [index: TextLooks.Offset] = { 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: TextLooks.Offset _ after-first; firstRun, lastRun, afterRun, curRun: NAT; -- indexes into runs startRuns, afterRuns, startCur: TextLooks.Offset; [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: TextLooks.Offset; 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: TextLooks.Offset; 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: TextLooks.Offset _ x.start; newPos, oldPos: TextLooks.Offset; 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: TextLooks.Offset _ x.start; xend: TextLooks.Offset; 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: TextLooks.Offset; 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: TextLooks.Offset; 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: TextLooks.Offset, rdr1, rdr2: Ref] RETURNS [BOOL] = { NoLooks: PROC [r: TextLooks.Runs, start, len: TextLooks.Offset, rdr: Ref] RETURNS [BOOL] = { looks: TextLooks.Looks; runLen: TextLooks.Offset; size: TextLooks.Offset _ 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: TextLooks.Offset; 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[TextLooks.Offset] 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: TextLooks.Offset; [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. FRunReaderImpl.mesa Copyright c 1985 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, March 3, 1985 5:51:37 pm PST 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 Ê º˜šœ™Jšœ Ïmœ1™J˜/J˜)J˜—JšŸ œžœžœ˜4šŸ œžœ˜J˜)Jšœ0žœ˜KJ˜—šŸœžœžœžœ˜HJšžœ2˜8J˜—šŸ œžœ˜J˜šžœž˜J˜0J˜J˜8J˜)Jšžœž˜—J˜—Jš žœžœžœžœžœžœ˜7šžœžœÏc(˜9J˜Jšžœ žœžœ žœ˜J˜1J˜Cšžœžœ ˜3Jšœ žœ$˜5J˜—Jšžœ žœ ž˜šœ žœžœ˜AJšžœ !˜&Jšžœ,ž˜2Jšœ ˜1šžœ 6˜=Jšžœžœ ˜:J˜(J˜—Jšžœ8˜<šžœž˜˜J˜šžœžœ˜J˜1J˜0J˜—Jšžœ(˜,J˜—˜ J˜J˜J˜—˜J˜J˜$J˜—˜J˜J˜J˜—Jšžœžœ˜—Jšžœ$˜*J˜—šžœžœ ˜;J˜(J˜—šžœ  ˜'Jšœ%™%šžœ-žœ˜5Jšœ1™1šžœž˜J˜J˜J˜$J˜—˜ J˜J˜J˜—˜J˜šžœžœ˜J˜-J˜$J˜—Jšžœ(˜,J˜—˜J˜J˜J˜—Jšžœžœ˜Jšžœ#˜)J˜—J˜J˜—J˜AJšœ žœ žœžœ˜5šžœž˜˜J˜ J˜-J˜0J˜—˜ J˜ šžœžœ˜J˜+J˜0J˜—Jšžœ"˜&J˜—šœ +˜:J˜J˜+J˜2J˜—˜J˜šžœžœ˜%J˜-J˜2J˜—Jšžœ"˜&J˜—Jšžœžœ˜—Jšžœ!˜'J˜—šœžœ$žœžœ˜DJ˜J˜'J˜0Jšœžœ˜J˜—šœžœ$žœžœ˜DJ˜šžœžœ˜#J˜0Jšœžœžœžœ˜3Jšœžœ˜J˜—Jšžœžœ˜"Jšœžœ˜J˜—šœžœ$žœžœ˜DJ˜#J˜!šžœžœ˜Jšžœžœ˜&Jšœžœ˜J˜—šžœžœ˜'J˜Jšœžœ˜$Jšœžœžœžœ˜4Jšœžœ˜J˜—J˜1J˜ Jšœžœžœžœ˜DJšœžœ˜J˜—šœžœ$˜*J˜#J˜šžœžœ˜Jšœžœ žœ˜0J˜—šžœ!žœ˜)Jšœžœžœ˜5J˜LJšžœžœžœ˜DJšœžœ˜J˜—Jšœžœžœ˜.J˜—Jšžœž˜J˜—Jšžœ˜Jšžœ˜—Jšžœ ˜J˜—J˜šŸ œžœ˜ J˜šžœžœž˜:J˜J˜Jšœ3žœ˜9Jšžœžœžœ˜J˜J˜Jšžœ˜—J˜—J˜šŸœžœ˜&J˜#šžœžœž˜:J˜J˜Jšœ<žœ˜BJšžœžœžœ˜J˜J˜Jšžœ˜—J˜—J˜š Ÿœžœžœ+žœžœ˜OJšœF™FJšžœžœžœ˜8J˜—J˜JšŸ œžœžœQ˜gšžœžœ˜JšœF™FJšœ?™?šŸœžœ=žœžœ˜\J˜J˜J˜+Jš œžœžœžœžœ˜7J˜J˜Jš žœžœžœžœžœ˜AJšžœžœ˜J˜—J˜Jšžœžœžœžœ˜šžœžœžœ˜Jš žœžœžœžœžœ˜Jšžœ"˜(J˜—Jšžœžœžœžœ"˜7J˜J˜Jšžœžœžœžœ%žœžœžœ˜aJš žœžœžœžœžœ˜.Jš žœžœžœžœžœ˜/J˜J˜šžœ +˜.J˜ J˜#J˜$J˜$Jšžœžœžœžœ˜'Jšžœžœžœžœžœžœžœ˜FJšžœžœžœžœ˜)J˜Jšžœ˜—Jšžœžœ˜J˜—J˜Jšœ™Jšœ  ˜5š Ÿ œžœžœžœžœ˜9Jšžœžœžœ˜Jšžœ žœžœžœ˜9Jš žœžœ žœžœžœ˜>Jš žœžœ žœžœžœ˜>Jšžœ˜J˜—J˜šŸ œžœžœžœ˜2Jšžœžœžœ˜Jšœžœ˜Jš žœžœžœžœžœ˜Gšžœ žœžœ˜&Jšžœžœ žœžœ˜+Jšžœžœ žœžœ˜,—J˜—J˜Jšžœ˜——…—/ò@ò