-- RopeFromImpl.Mesa
-- written by Bill Paxton, February 1981
-- last edit by Bill Paxton, July 2, 1982 1:21 pm
Last Edited by: Maxwell, January 5, 1983 12:08 pm
DIRECTORY
RopeFrom,
RopeEdit,
RopeEditingAlloc,
RopeReader,
Rope,
RopeInline,
SafeStorage,
Space,
RopeEditingBLT;
RopeFromImpl: CEDAR PROGRAM
IMPORTS
RopeEditingBLT, RopeEditingAlloc, RopeReader, RopeInline,
SafeStorage, RopeFrom, RopeEdit
EXPORTS RopeFrom
SHARES Rope =
BEGIN
OPEN
RopeFrom, RopeInline;
CharsArray: TYPE = RopeReader.CharsArray;
Chars: TYPE = REF CharsArray;
charsPerArray: NAT = RopeReader.charsPerArray;
qZone: PUBLIC ZONE ← SafeStorage.NewZone[quantized];
pZone: PUBLIC ZONE ← SafeStorage.NewZone[prefixed];
-- Editing Operations
FlatReplaceByChar: PUBLIC PROC [
base: ROPE, char: CHAR,
start: Offset ← 0, len, baseSize: Offset ← MaxLen,
tryAppend: BOOLEANTRUE]
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 (size�seSize+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 [qZone.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 (size�seSize+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,loc�seNum+xstrt,1];
IF ok THEN { -- got it
chars[loc] ← char;
RETURN [qZone.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: BOOLEANTRUE]
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: NATIF string=NIL THEN 0 ELSE string.length;
IF stringStart >= stringSize THEN
RETURN [FlatDelete[base,start,len,baseSize]];
stringNum ← stringSize-stringStart };
IF (size�seSize+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 [qZone.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: NATIF string=NIL THEN 0 ELSE string.length;
IF stringStart >= stringSize THEN
RETURN [FlatDelete[base,start,len,baseSize]];
stringNum ← stringSize-stringStart };
IF (size�seSize+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,
loc�seNum+Short[xstart],stringNum];
IF ok THEN { -- got it
RopeEditingBLT.StringToArrayBlt[nChars:stringNum, to:chars, toLoc:loc,
from:string, fromLoc:stringStart];
RETURN [qZone.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: NATLAST[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 [qZone.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 [qZone.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 [qZone.NEW[Tsubstr ← [node[substr[1,base,loc,1+RopeEdit.Depth[base]]]]]]};
-- ***** Initialization
StartRopeFrom: PUBLIC PROC = {
};
END.