-- RopeFromImpl.Mesa; written by Bill Paxton, February 1981
-- edited by Bill Paxton, July 11, 1983 10:56 am
-- edited by McGregor, July 2, 1982 1:21 pm
-- edited by Maxwell, January 5, 1983 12:08 pm
DIRECTORY
RopeFrom,
RopeEdit,
RopeEditingAlloc,
RopeReader,
Rope,
RopeInline,
RopeEditingBLT;
RopeFromImpl:
CEDAR PROGRAM
IMPORTS
RopeEditingBLT, RopeEditingAlloc, RopeReader, RopeInline, RopeFrom, RopeEdit
EXPORTS RopeFrom
SHARES Rope =
BEGIN
OPEN
RopeFrom, RopeInline;
CharsArray: TYPE = RopeReader.CharsArray;
Chars: TYPE = REF CharsArray;
charsPerArray: NAT = RopeReader.charsPerArray;
-- Editing Operations
FlatReplaceByChar:
PUBLIC
PROC [
base: ROPE, char: CHAR,
start: Offset ← 0, len, baseSize: Offset ← MaxLen,
tryAppend: BOOLEAN ← TRUE]
RETURNS [new: ROPE] = {
chars: Chars;
charsRope: ROPE;
initloc, loc, strt, sze, num, baseNum: NAT;
reader: RopeReader.Ref;
size: Offset;
Get:
PROC [count:
NAT] = {
IF count > 0
THEN {
IF RopeReader.GetChars[reader,chars,count,loc] # count THEN ERROR;
loc ← loc+count}};
IF baseSize=MaxLen THEN baseSize ← RopeInline.InlineSize[base];
IF baseSize=0 THEN RETURN [Character[char]];
IF start > baseSize THEN start ← baseSize;
IF len=MaxLen THEN len ← MIN[len,baseSize-start];
IF (sizeseSize+1-len) > charsPerArray
THEN
RETURN [
-- treat separately
FlatReplace[base,start,len,Character[char],size,baseSize,1]];
IF tryAppend
AND
(new ← TryAppendReplaceByChar[base,char,start,len,baseSize]) # NIL THEN
RETURN [new];
sze ← Short[size]; strt ← Short[start];
num ← Short[len]; baseNum ← Short[baseSize];
[chars, loc, charsRope] ← RopeEditingAlloc.AllocChars[sze];
initloc ← loc;
reader ← RopeReader.GetRopeReader[];
RopeReader.SetPosition[reader,base];
Get[strt];
chars[loc] ← char; loc ← loc+1;
IF num > 0 THEN RopeReader.SetIndex[reader,strt+num];
Get[baseNum-(strt+num)];
RopeReader.FreeRopeReader[reader];
IF loc-initloc # sze THEN ERROR;
RETURN [NEW[Tsubstr ← [node[substr[size,charsRope,initloc,1+RopeEdit.Depth[charsRope]]]]]]};
TryAppendReplaceByChar:
PUBLIC
PROC [
base: ROPE, char: CHAR,
start: Offset ← 0, len, baseSize: Offset ← MaxLen]
RETURNS [ROPE] = TRUSTED {
-- returns NIL if cannot do a flat replace
size: Offset;
IF baseSize=MaxLen THEN baseSize ← RopeInline.InlineSize[base];
IF baseSize=0 THEN RETURN [Character[char]];
IF start > baseSize THEN start ← baseSize;
IF len=MaxLen THEN len ← MIN[len,baseSize-start];
IF (sizeseSize+1-len) > charsPerArray THEN RETURN [NIL];
IF start=baseSize
THEN {
-- appending to end of rope
xstart: Offset;
chars: Chars;
sze: NAT ← Short[size];
strt: NAT ← Short[start];
num: NAT ← Short[len];
baseNum: NAT ← Short[baseSize];
WITH x:base SELECT FROM -- try to tack onto end of previous chars
node =>
WITH x:x
SELECT
FROM
substr =>
IF (xstart←x.start) < charsPerArray
THEN {
ok: BOOLEAN;
loc: NAT;
newbase: ROPE ← x.base;
xstrt: NAT ← Short[xstart];
[ok,chars] ← RopeEditingAlloc.TryAllocAdjacent[newbase,locseNum+xstrt,1];
IF ok
THEN {
-- got it
chars[loc] ← char;
RETURN [
NEW[Tsubstr ←
[node[substr[size,newbase,xstart,1+RopeEdit.Depth[newbase]]]]]]}};
ENDCASE; ENDCASE };
RETURN [NIL] };
FlatReplaceByString:
PUBLIC
PROC [
base: ROPE, string: REF READONLY TEXT,
stringStart: NAT ← 0, stringNum: NAT ← MaxNat,
start: Offset ← 0, len, baseSize: Offset ← MaxLen,
tryAppend: BOOLEAN ← TRUE]
RETURNS [new: ROPE] = {
chars: Chars;
charsRope: ROPE;
initloc, loc, strt, sze, num, baseNum: NAT;
reader: RopeReader.Ref;
size: Offset;
Get:
PROC [count:
NAT] = {
IF count > 0
THEN {
IF RopeReader.GetChars[reader,chars,count,loc] # count THEN ERROR;
loc ← loc+count}};
IF baseSize=MaxLen THEN baseSize ← RopeInline.InlineSize[base];
IF baseSize=0 THEN RETURN [String[string,stringStart,stringNum]];
IF start > baseSize THEN start ← baseSize;
IF len=MaxLen THEN len ← MIN[len,baseSize-start];
IF stringNum=MaxNat
THEN {
stringSize: NAT ← IF string=NIL THEN 0 ELSE string.length;
IF stringStart >= stringSize
THEN
RETURN [FlatDelete[base,start,len,baseSize]];
stringNum ← stringSize-stringStart };
IF (sizeseSize+stringNum-len) > charsPerArray
THEN
-- treat separately
RETURN [FlatReplace[base,start,len,String[string,stringStart,stringNum],
size,baseSize,stringNum]];
IF tryAppend
AND
(new ← TryAppendReplaceByString[base,string,stringStart,stringNum,start,len,baseSize]) # NIL
THEN RETURN [new];
IF size=0 THEN RETURN[NIL];
sze ← Short[size]; strt ← Short[start];
num ← Short[len]; baseNum ← Short[baseSize];
[chars, loc, charsRope] ← RopeEditingAlloc.AllocChars[sze];
initloc ← loc;
reader ← RopeReader.GetRopeReader[];
RopeReader.SetPosition[reader,base];
Get[strt];
RopeEditingBLT.StringToArrayBlt[nChars:stringNum, to:chars, toLoc:loc, from:string, fromLoc:stringStart];
loc ← loc+stringNum;
IF num > 0 THEN RopeReader.SetIndex[reader,strt+num];
Get[Short[baseSize]-(strt+num)];
RopeReader.FreeRopeReader[reader];
IF loc-initloc # sze THEN ERROR;
RETURN [NEW[Tsubstr ← [node[substr[size,charsRope,initloc,1+RopeEdit.Depth[charsRope]]]]]]};
TryAppendReplaceByString:
PUBLIC
PROC [
base: ROPE, string: REF READONLY TEXT,
stringStart: NAT ← 0, stringNum: NAT ← MaxNat,
start: Offset ← 0, len, baseSize: Offset ← MaxLen]
RETURNS [ROPE] = TRUSTED {
size: Offset;
sze, strt, num, baseNum, loc: NAT;
IF baseSize=MaxLen THEN baseSize ← RopeInline.InlineSize[base];
IF baseSize=0 THEN RETURN [String[string,stringStart,stringNum]];
IF start > baseSize THEN start ← baseSize;
IF len=MaxLen THEN len ← MIN[len,baseSize-start];
IF stringNum=MaxNat
THEN {
stringSize: NAT ← IF string=NIL THEN 0 ELSE string.length;
IF stringStart >= stringSize
THEN
RETURN [FlatDelete[base,start,len,baseSize]];
stringNum ← stringSize-stringStart };
IF (sizeseSize+stringNum-len) > charsPerArray THEN RETURN [NIL];
IF size=0 THEN RETURN[NIL];
sze ← Short[size]; strt ← Short[start];
num ← Short[len]; baseNum ← Short[baseSize];
IF start = baseSize
THEN {
-- appending string to end of rope
xstart: Offset;
chars: Chars;
WITH x:base SELECT FROM -- try to tack onto end of previous chars
node =>
WITH x:x
SELECT
FROM
substr =>
IF (xstart←x.start) < charsPerArray
THEN {
ok: BOOLEAN;
newbase: ROPE ← x.base;
[ok,chars] ← RopeEditingAlloc.TryAllocAdjacent[newbase,
locseNum+Short[xstart],stringNum];
IF ok
THEN {
-- got it
RopeEditingBLT.StringToArrayBlt[nChars:stringNum, to:chars, toLoc:loc,
from:string, fromLoc:stringStart];
RETURN [NEW[Tsubstr ← [node[substr[size,newbase,xstart,1+RopeEdit.Depth[newbase]]]]]]}};
ENDCASE; ENDCASE };
RETURN [NIL] };
String:
PUBLIC
PROC
[string: REF READONLY TEXT, start: NAT ← 0, len: NAT ← LAST[NAT]]
RETURNS [ROPE] = {
-- copies len characters from string starting at start
MakeRope:
PROC [string:
REF
READONLY
TEXT, start, len:
NAT]
RETURNS [ROPE] = {
chars: Chars;
loc: NAT;
base: ROPE;
IF len = 0 THEN RETURN [NIL];
IF len > charsPerArray
THEN {
-- split into balanced parts
half: NAT ← len/2;
front: ROPE ← MakeRope[string, start, half];
back: ROPE ← MakeRope[string, start+half, len-half];
RETURN [
NEW[Tconcat ← [node[concat[len,front,back,half,
1+MAX[RopeEdit.Depth[front],RopeEdit.Depth[back]]]]]]] };
[chars, loc, base] ← RopeEditingAlloc.AllocChars[len];
RopeEditingBLT.StringToArrayBlt[nChars:len, to:chars, toLoc:loc,
from:string, fromLoc:start];
RETURN [NEW[Tsubstr ← [node[substr[len,base,loc,1+RopeEdit.Depth[base]]]]]]};
IF string=NIL OR start >= string.length THEN RETURN [NIL];
len ← MIN[len,string.length-start];
RETURN [MakeRope[string,start,len]]};
Character:
PUBLIC
PROC [char:
CHARACTER]
RETURNS [
ROPE] = {
chars: Chars;
loc: NAT;
base: ROPE;
[chars, loc, base] ← RopeEditingAlloc.AllocChars[1];
chars[loc] ← char;
RETURN [NEW[Tsubstr ← [node[substr[1,base,loc,1+RopeEdit.Depth[base]]]]]]};
-- ***** Initialization
StartRopeFrom:
PUBLIC
PROC = {
};
END.