-- 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.