<<-- RopeFromEditImpl.Mesa>> <<-- written by Bill Paxton, February 1981>> <<-- last edit by Bill Paxton, August 11, 1982 10:32 am>> <> DIRECTORY RopeFrom, RopeEdit, RopeEditingAlloc, RopeReader, Rope, RopeInline, File; RopeFromEditImpl: CEDAR MONITOR IMPORTS RopeInline, RopeFrom, RopeEdit, RopeEditingAlloc, RopeReader, Rope EXPORTS RopeFrom SHARES Rope = BEGIN OPEN RopeFrom, RopeInline; CharsArray: TYPE = RopeReader.CharsArray; Chars: TYPE = REF CharsArray; charsPerArray: NAT = RopeReader.charsPerArray; <<-- Editing Operations>> FlatSubstr: PUBLIC PROC [rope: ROPE, start: Offset _ 0, len: Offset _ MaxLen] RETURNS [ROPE] = TRUSTED { chars: Chars; loc, num: NAT; base: ROPE; substr: BOOLEAN _ FALSE; size: Offset _ RopeInline.InlineSize[rope]; reader: RopeReader.Ref; IF len=MaxLen THEN { IF start >= size THEN RETURN [NIL]; len _ MIN[len,size-start] }; IF len=0 OR rope=NIL THEN RETURN [NIL]; IF len > charsPerArray THEN { -- split into balanced parts front, back: ROPE; half: Offset _ len/2; half _ ((half+charsPerArray-1)/charsPerArray)*charsPerArray; -- round up front _ FlatSubstr[rope, start, half]; back _ FlatSubstr[rope, start+half, len-half]; RETURN [qZone.NEW[Tconcat _ [node[concat[len,front,back,half, 1+MAX[RopeEdit.Depth[front],RopeEdit.Depth[back]]]]]]] }; WITH x:rope SELECT FROM node => WITH x:x SELECT FROM substr => substr _ TRUE; object => IF x.size=charsPerArray THEN WITH x.base SELECT FROM z: Chars => -- don't need to move the characters IF len=charsPerArray AND start=0 THEN RETURN [rope] ELSE RETURN [qZone.NEW[Tsubstr _ [node[substr[len,rope,start,1+RopeEdit.Depth[rope]]]]]]; ENDCASE; ENDCASE; ENDCASE; [chars,loc,base] _ RopeEditingAlloc.AllocChars[num _ Short[len]]; reader _ RopeReader.GetRopeReader[]; RopeReader.SetPosition[reader, rope, start]; IF RopeReader.GetChars[reader, chars, num, loc] # num THEN ERROR; RopeReader.FreeRopeReader[reader]; IF substr AND start=0 AND len=size THEN -- just flattening an existing substr WITH x:rope SELECT FROM node => WITH x:x SELECT FROM substr => { x.base _ base; x.start _ loc; RETURN [@x] }; ENDCASE; ENDCASE; RETURN [qZone.NEW[Tsubstr _ [node[substr[len,base,loc,1+RopeEdit.Depth[base]]]]]]}; FlatConcat: PUBLIC PROC [base, rest: ROPE, baseSize, restSize: Offset _ MaxLen, tryAppend: BOOLEAN _ TRUE] RETURNS [new: ROPE] = { chars: Chars; loc, baseNum, restNum: NAT; reader: RopeReader.Ref; charsRope: ROPE; size: Offset; IF baseSize=MaxLen THEN baseSize _ RopeInline.InlineSize[base]; IF restSize=MaxLen THEN restSize _ RopeInline.InlineSize[rest]; IF (size _ baseSize+restSize) > charsPerArray THEN -- treat separately RETURN [qZone.NEW[Tconcat _ [node[concat[size,base,rest,baseSize, 1+MAX[RopeEdit.Depth[base],RopeEdit.Depth[rest]]]]]]]; IF size=0 THEN RETURN[NIL]; IF tryAppend AND (new _ TryAppendConcat[base, rest, baseSize, restSize]) # NIL THEN RETURN; baseNum _ Short[baseSize]; restNum _ Short[restSize]; [chars, loc, charsRope] _ RopeEditingAlloc.AllocChars[Short[size]]; reader _ RopeReader.GetRopeReader[]; RopeReader.SetPosition[reader, base]; IF RopeReader.GetChars[reader, chars, baseNum, loc] # baseNum THEN ERROR; RopeReader.SetPosition[reader, rest]; IF RopeReader.GetChars[reader, chars, restNum, loc+baseNum] # restNum THEN ERROR; RopeReader.FreeRopeReader[reader]; RETURN [qZone.NEW[Tsubstr _ [node[substr[size,charsRope,loc,1+RopeEdit.Depth[charsRope]]]]]]}; TryAppendConcat: PUBLIC PROC [base, rest: ROPE, baseSize, restSize: Offset _ MaxLen] RETURNS [ROPE] = TRUSTED { chars: Chars; size: Offset; IF baseSize=MaxLen THEN baseSize _ RopeInline.InlineSize[base]; IF restSize=MaxLen THEN restSize _ RopeInline.InlineSize[rest]; IF (size _ baseSize+restSize) > charsPerArray THEN -- treat separately RETURN [qZone.NEW[Tconcat _ [node[concat[size,base,rest,baseSize, 1+MAX[RopeEdit.Depth[base],RopeEdit.Depth[rest]]]]]]]; IF size=0 THEN RETURN[NIL]; IF base#NIL AND rest#NIL THEN WITH--1-- x:base SELECT FROM node => WITH--2-- x:x SELECT FROM substr => WITH--3-- z:x.base SELECT FROM node => WITH--4-- z:z SELECT FROM object => IF z.size=charsPerArray THEN WITH--5-- z.base SELECT FROM w: Chars => { -- base is a substr of a charsarray WITH--6-- y:rest SELECT FROM node => WITH--7-- y:y SELECT FROM substr => IF x.base=y.base AND x.start+x.size=y.start THEN WITH--8-- z:x.base SELECT FROM node => WITH--9-- z:z SELECT FROM object => IF z.size=charsPerArray THEN WITH--10-- z.base SELECT FROM w: Chars => -- don't need to move the characters RETURN [qZone.NEW[Tsubstr _ [node[substr[x.size+y.size,x.base,x.start, 1+RopeEdit.Depth[x.base]]]]]]; ENDCASE; ENDCASE; ENDCASE; ENDCASE; ENDCASE; --6..10-- { -- try to allocate room adjacent to base ok: BOOLEAN; loc: NAT; newbase: ROPE _ x.base; xstart: Offset _ x.start; count: NAT _ Short[restSize]; baseNum: NAT _ Short[baseSize]; [ok,chars] _ RopeEditingAlloc.TryAllocAdjacent[newbase, loc_baseNum+Short[xstart],count]; IF ok THEN { -- transfer the chars reader: RopeReader.Ref _ RopeReader.GetRopeReader[]; RopeReader.SetPosition[reader,rest]; IF RopeReader.GetChars[reader,chars,count,loc] # count THEN ERROR; RopeReader.FreeRopeReader[reader]; RETURN [qZone.NEW[Tsubstr _ [node[substr[size,newbase,xstart,1+RopeEdit.Depth[newbase]]]]]] }}}; ENDCASE; ENDCASE; ENDCASE; ENDCASE; ENDCASE; --1..5-- RETURN [NIL] }; FlatReplace: PUBLIC PROC [ base: ROPE, start: Offset _ 0, len: Offset _ MaxLen, replace: ROPE _ NIL, size, baseSize, repSize: Offset _ MaxLen] RETURNS [ROPE] = { chars: Chars; charsRope: ROPE; initloc, loc, tailsize, sze: NAT; reader: RopeReader.Ref; oldpos: Offset; Get: PROC [r: ROPE, begin: Offset, count: NAT] = { IF count > 0 THEN { RopeReader.SetPosition[reader,r,begin]; IF RopeReader.GetChars[reader,chars,count,loc] # count THEN ERROR; loc _ loc+count}}; IF baseSize=MaxLen THEN baseSize _ RopeInline.InlineSize[base]; IF start >= baseSize THEN RETURN [FlatConcat[base,replace,baseSize,repSize]]; IF len=MaxLen THEN len _ MIN[len,baseSize-start]; IF repSize=MaxLen THEN repSize _ RopeInline.InlineSize[replace]; IF size=MaxLen THEN size _ baseSize-len+repSize; IF size=0 THEN RETURN [NIL]; IF size > charsPerArray THEN -- treat separately RETURN [Rope.Replace[base, start, len, replace]]; tailsize _ Short[baseSize-(oldpos_len+start)]; [chars,loc,charsRope] _ RopeEditingAlloc.AllocChars[sze_Short[size]]; initloc _ loc; reader _ RopeReader.GetRopeReader[]; Get[base,0,Short[start]]; Get[replace,0,Short[repSize]]; Get[base,oldpos,tailsize]; RopeReader.FreeRopeReader[reader]; IF loc-initloc#sze THEN ERROR; RETURN [qZone.NEW[Tsubstr _ [node[substr[size,charsRope,initloc,1+RopeEdit.Depth[charsRope]]]]]]}; FlatCopy: PUBLIC PROC [ dest: ROPE, destLoc: Offset _ 0, source: ROPE, start: Offset _ 0, len: Offset _ MaxLen, destSize: Offset _ MaxLen] RETURNS [ROPE] = { chars: Chars; charsRope: ROPE; size: Offset; initloc, loc, dst, sze: NAT; reader: RopeReader.Ref; Get: PROC [base: ROPE, begin, count: NAT] = { IF count > 0 THEN { RopeReader.SetPosition[reader,base,begin]; IF RopeReader.GetChars[reader,chars,count,loc] # count THEN ERROR; loc _ loc+count}}; IF len=MaxLen THEN { sourceSize: Offset _ RopeInline.InlineSize[source]; IF start >= sourceSize THEN RETURN [dest]; len _ MIN[len,sourceSize-start] }; IF destSize=MaxLen THEN destSize _ RopeInline.InlineSize[dest]; IF destLoc > destSize THEN destLoc _ destSize; IF (size_destSize+len) > charsPerArray THEN -- treat separately RETURN [FlatInsert[dest,destLoc,FlatSubstr[source,start,len],destSize,len]]; IF size=0 THEN RETURN[NIL]; [chars, loc, charsRope] _ RopeEditingAlloc.AllocChars[sze _ Short[size]]; initloc _ loc; reader _ RopeReader.GetRopeReader[]; Get[dest,0,dst_Short[destLoc]]; Get[source,Short[start],Short[len]]; Get[dest,dst,Short[destSize]-dst]; RopeReader.FreeRopeReader[reader]; IF loc-initloc # sze THEN ERROR; RETURN [qZone.NEW[Tsubstr _ [node[substr[size,charsRope,initloc,1+RopeEdit.Depth[charsRope]]]]]]}; <<-- ***** Initialization>> StartRopeFromEdit: PUBLIC PROC = { }; END.