-- RopeReaderImpl.mesa; written by Bill Paxton, January 1981
-- edited by McGregor, February 8, 1983 10:58 am
-- edited by Bill Paxton, December 22, 1981 10:24 am
-- edited by Maxwell, January 5, 1983 12:05 pm
DIRECTORY
RopeReader,
Rope,
RopeInline;
RopeReaderImpl: CEDAR 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[]];
TRUSTED {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[]]};
END.