-- RopeReaderGetImpl.mesa -- written by Bill Paxton, January 1981 -- last edit by Bill Paxton, December 22, 1981 9:37 am DIRECTORY RopeReader, RopeEditingBLT, Rope, RopeInline; RopeReaderGetImpl: PROGRAM IMPORTS RopeReader, Rope, RopeInline, RopeEditingBLT EXPORTS RopeReader SHARES RopeReader, Rope = BEGIN OPEN RopeReader, RopeInline; GetText: PUBLIC PROC [reader: Ref, txt: Text, length: NAT ← LAST[NAT]] RETURNS [count: NAT] = { rope: ROPE; start: Offset; offset: NAT ← txt.length; [rope, start] ← Position[reader]; count ← Short[MIN[length, InlineSize[rope]-start, txt.max-offset]]; GTxt[rope, start, txt, offset, count]; SetPosition[reader, rope, start+count]; txt.length ← txt.length+count}; BackwardsGetText: PUBLIC PROC [reader: Ref, txt: Text, length: NAT ← LAST[NAT]] RETURNS [count: NAT] = { rope: ROPE; start: Offset; offset: NAT ← txt.length; [rope, start] ← Position[reader]; count ← Short[MIN[length, start, txt.max-offset]]; GTxt[rope, start ← start-count, txt, offset, count]; SetPosition[reader, rope, start]; txt.length ← txt.length+count}; GetString: PUBLIC PROC [reader: Ref, str: String, length: NAT ← LAST[NAT]] RETURNS [count: NAT] = { rope: ROPE; start: Offset; offset: NAT ← str.length; [rope, start] ← Position[reader]; count ← Short[MIN[length, InlineSize[rope]-start, str.maxLength-offset]]; GTxt[rope, start, str, offset, count]; SetPosition[reader, rope, start+count]; str.length ← str.length+count;}; BackwardsGetString: PUBLIC PROC [reader: Ref, str: String, length: NAT ← LAST[NAT]] RETURNS [count: NAT] = { rope: ROPE; start: Offset; offset: NAT ← str.length; [rope, start] ← Position[reader]; count ← Short[MIN[length, start, str.maxLength-offset]]; GTxt[rope, start ← start-count, str, offset, count]; SetPosition[reader, rope, start]; str.length ← str.length+count}; GetChars: PUBLIC PROC [ reader: Ref, chars: REF CharsArray, length: NAT ← LAST[NAT], offset: NAT ← 0] RETURNS [count: NAT] = { rope: ROPE; start: Offset; [rope, start] ← Position[reader]; count ← Short[MIN[length, InlineSize[rope]-start, charsPerArray-offset]]; GTxt[rope, start, chars, offset, count]; SetPosition[reader, rope, start+count]}; BackwardsGetChars: PUBLIC PROC [ reader: Ref, chars: REF CharsArray, length: NAT ← LAST[NAT], offset: NAT ← 0] RETURNS [count: NAT] = { rope: ROPE; start: Offset; [rope, start] ← Position[reader]; count ← Short[MIN[length, start, charsPerArray-offset]]; GTxt[rope, start ← start-count, chars, offset, count]; SetPosition[reader, rope, start]}; GTxt: PROC [base: ROPE, start: Offset, b: REF, offset, len: NAT] = { loc: NAT ← offset; WHILE len # 0 DO WITH x:base SELECT FROM text => { st: NAT ← Short[start]; rem: NAT ← Short[x.length]-st; IF rem > len THEN rem ← QShort[len]; WITH b SELECT FROM chars: REF CharsArray => RopeEditingBLT.TextToArrayBlt[to:chars, toLoc:loc, nChars:rem, from:@x, fromLoc:st]; txt: Text => RopeEditingBLT.TextToTextBlt[to:txt, toLoc:loc, nChars:rem, from:@x, fromLoc:st]; str: String => RopeEditingBLT.TextToStringBlt[to:str, toLoc:loc, nChars:rem, from:@x, fromLoc:st]; ENDCASE => ERROR; RETURN }; node => WITH x:x SELECT FROM object => WITH x.base SELECT FROM y: Chars => { st: NAT ← Short[start]; rem: NAT ← Short[x.size]-st; IF rem > len THEN rem ← QShort[len]; WITH b SELECT FROM chars: REF CharsArray => RopeEditingBLT.ArrayToArrayBlt[to:chars, toLoc:loc, nChars:rem, from:y, fromLoc:st]; txt: Text => RopeEditingBLT.ArrayToTextBlt[to:txt, toLoc:loc, nChars:rem, from:y, fromLoc:st]; str: String => RopeEditingBLT.ArrayToStringBlt[to:str, toLoc:loc, nChars:rem, from:y, fromLoc:st]; ENDCASE => ERROR; RETURN }; ENDCASE => { piecemap: Rope.PieceMapType ← x.pieceMap; data: REF ← x.base; fetch: Rope.FetchType ← x.fetch; rem: Offset ← NonNeg[x.size-start]; IF rem < len THEN { IF rem = 0 THEN EXIT ELSE len ← QShort[rem]}; IF piecemap # NIL THEN { action: PROC [r:ROPE, st: Offset, pl: Offset] RETURNS [BOOLEAN] = { ln: NAT ← Short[pl]; GTxt[r, st, b, loc, ln]; loc ← loc + ln; RETURN [FALSE]}; [] ← piecemap[data, start, len, action]} ELSE WITH b SELECT FROM txt: Text => FOR i: Offset IN [start..start+len) DO txt[loc] ← fetch[data,i]; loc ← loc+1; ENDLOOP; chars: REF CharsArray => FOR i: Offset IN [start..start+len) DO chars[loc] ← fetch[data,i]; loc ← loc+1; ENDLOOP; str: String => FOR i: Offset IN [start..start+len) DO str[loc] ← fetch[data,i]; loc ← loc+1; ENDLOOP; ENDCASE => ERROR; EXIT}; substr => { rem: Offset ← NonNeg[x.size-start]; IF rem < len THEN { IF rem = 0 THEN EXIT ELSE len ← QShort[rem]}; start ← start + x.start; base ← x.base; LOOP}; concat => { xpos: Offset ← x.pos; rem: Offset ← NonNeg[x.size-start]; IF rem < len THEN { IF rem = 0 THEN EXIT ELSE len ← QShort[rem]}; IF start+len <= xpos THEN {base ← x.base; LOOP}; IF start < xpos THEN { subLen: NAT ← Short[xpos-start]; GTxt[x.base, start, b, loc, subLen]; start ← 0; len ← len - subLen; loc ← loc + subLen} ELSE start ← start - xpos; base ← x.rest; LOOP }; replace => { xstart: Offset ← x.start; xnew: Offset ← x.newPos; rem: Offset ← NonNeg[x.size-start]; IF rem < len THEN {IF rem = 0 THEN EXIT ELSE len ← QShort[rem]}; IF start < xstart THEN {subLen: NAT; IF xstart-start >= len THEN {base ← x.base; LOOP}; subLen ← Short[xstart-start]; GTxt[x.base, start, b, loc, subLen]; start ← xstart; len ← len - subLen; loc ← loc + subLen}; IF start < xnew THEN {subLen: NAT; st: Offset ← start - xstart; IF xnew-start >= len THEN {start ← st; base ← x.replace; LOOP}; subLen ← Short[xnew-start]; GTxt[x.replace, st, b, loc, subLen]; start ← xnew; len ← len - subLen; loc ← loc + subLen}; start ← start - xnew + x.oldPos; base ← x.base; LOOP}; ENDCASE => { IF base # NIL THEN ERROR Rope.NoRope; IF len = 0 THEN EXIT ELSE ERROR}; ENDCASE => { IF base # NIL THEN ERROR Rope.NoRope; IF len = 0 THEN EXIT ELSE ERROR}; ENDLOOP}; -- ***** Initialization StartRopeReaderGet: PUBLIC PROC = {}; END.