<> <> <> <> <> <> DIRECTORY RopeFrom, RopeEdit, RopeEditingAlloc, RopeReader, Rope, RopePrivate, SafeStorage, RopeEditingBLT; RopeFromImpl: CEDAR PROGRAM IMPORTS Rope, RopeEditingBLT, RopeEditingAlloc, RopeReader, RopePrivate, SafeStorage, RopeFrom, RopeEdit EXPORTS RopeFrom SHARES Rope = BEGIN OPEN RopeFrom, RopePrivate; CharsArray: TYPE = RopeReader.CharsArray; Chars: TYPE = REF CharsArray; charsPerArray: NAT = RopeReader.charsPerArray; qZone: PUBLIC ZONE _ SafeStorage.GetSystemZone[]; pZone: PUBLIC ZONE _ SafeStorage.GetSystemZone[]; <<-- 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 _ Rope.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_baseSize+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 _ Rope.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_baseSize+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_baseNum+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: 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 _ Rope.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 (size_baseSize+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 _ Rope.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 (size_baseSize+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_baseNum+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: 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 [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.