-- RopeReaderImpl.mesa -- written by Bill Paxton, January 1981 -- last edit by Bill Paxton, December 22, 1981 10:24 am DIRECTORY RopeReader, Rope, RopeInline; RopeReaderImpl: PROGRAM IMPORTS Rope, RopeInline EXPORTS RopeReader SHARES RopeReader, Rope = BEGIN OPEN RopeReader, RopeInline; ReadOffEnd: PUBLIC ERROR = CODE; ReadChar: PUBLIC PROC [reader: Ref, mode: Mode] RETURNS [char: CHAR] = { base: ROPE _ reader.rope; index, current: Offset _ reader.index+reader.current-reader.first; after: Offset _ InlineSize[base]; first: Offset _ 0; OffEnd: PROC RETURNS [CHAR] = { IF ~reader.charForEndOfRope THEN ERROR ReadOffEnd; RETURN [reader.endChar]}; SetReader: PROC = { reader.index _ SELECT mode FROM get => index+1, backwards => index-1, peek, peekbackwards => index, ENDCASE => ERROR; reader.current _ reader.first _ reader.after _ 0}; SetInfo: PROC [txtFlag: BOOLEAN] RETURNS [c: NAT] = { c _ Short[current]; reader.first _ Short[first]; reader.after _ Short[after]; reader.txtFlag _ txtFlag; SELECT mode FROM get => { reader.current _ c+1; reader.index _ index+first-c }; peekbackwards => { reader.current _ c+1; reader.index _ index+first-c-1 }; backwards => { reader.current _ c; reader.index _ index+first-c-1 }; peek => { reader.current _ c; reader.index _ index+first-c }; ENDCASE => ERROR }; SELECT mode FROM backwards, peekbackwards => IF current=0 THEN RETURN[OffEnd[]] ELSE current _ current-1; get, peek => NULL; ENDCASE => ERROR; IF current >= after THEN RETURN[OffEnd[]]; WHILE base # NIL DO WITH x:base SELECT FROM text => { reader.text _ @x; RETURN [x[SetInfo[TRUE]]] }; node => WITH x:x SELECT FROM object => IF current < x.size THEN WITH x.base SELECT FROM y: Chars => { reader.chars _ y; RETURN [y[SetInfo[FALSE]]] }; ENDCASE => { SetReader; RETURN [x.fetch[x.base, current]] }; substr => IF current < x.size THEN { offset: Offset; current _ current + (offset _ x.start); first _ first + offset; after _ after + offset; base _ x.base; LOOP }; concat => IF current < x.size THEN { xpos: Offset; IF current >= (xpos _ x.pos) THEN { current _ current - xpos; after _ after - xpos; first _ IF first <= xpos THEN 0 ELSE first - xpos; base _ x.rest; LOOP }; IF after > xpos THEN after _ xpos; base _ x.base; LOOP }; replace => IF current < x.size THEN { xstart: Offset _ x.start; newPos, oldPos: Offset; IF current < xstart THEN { IF after > xstart THEN after _ xstart; base _ 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; base _ x.replace; LOOP }; current _ current - newPos + (oldPos _ x.oldPos); after _ after - newPos + oldPos; first _ IF first >= newPos THEN first - newPos + oldPos ELSE oldPos; base _ x.base; LOOP }; ENDCASE => ERROR Rope.NoRope; ENDCASE => ERROR Rope.NoRope; EXIT; ENDLOOP; RETURN[OffEnd[]]}; -- ***** Initialization StartRopeReader: PUBLIC PROC = {}; END.