DIRECTORY RopeEdit, RopeIO, RopeEditingAlloc, Rope, RopeFrom, RopeReader, RopeInline, CIFS, File, IO, FileIO; RopeEditImpl: CEDAR PROGRAM IMPORTS RopeEdit, RopeReader, RopeInline, RopeFrom, Rope, CIFS, IO, FileIO, RopeEditingAlloc EXPORTS RopeEdit, RopeIO SHARES Rope = BEGIN OPEN RopeEdit, RopeInline; FlatMax: Offset = 30; -- if shorter, copy to flat rope Depth: PUBLIC PROC [rope: ROPE] RETURNS [depth: INTEGER] = TRUSTED { IF rope=NIL THEN RETURN [0]; WITH x:rope SELECT FROM text => depth _ 0; node => WITH x:x SELECT FROM substr => depth _ x.depth; concat => depth _ x.depth; replace => depth _ x.depth; object => depth _ 0; ENDCASE => ERROR Rope.NoRope; ENDCASE => ERROR Rope.NoRope }; Substr: PUBLIC PROC [base: ROPE, start: Offset _ 0, len: Offset _ MaxLen] RETURNS [ROPE] = TRUSTED { IF start < 0 THEN ERROR; DO IF base=NIL OR len<=0 THEN RETURN[NIL]; WITH x:base SELECT FROM text => { rem: Offset; IF (rem _ NonNeg[x.length-start]) <= len THEN IF start = 0 THEN RETURN [base] ELSE len _ rem}; node => WITH x:x SELECT FROM substr => { rem: Offset; IF (rem _ NonNeg[x.size-start]) <= len THEN IF start = 0 THEN RETURN [base] ELSE len _ rem; start _ start + x.start; base _ x.base; LOOP}; concat => { xpos, rem: Offset; IF (rem _ NonNeg[x.size-start]) <= len THEN IF start = 0 THEN RETURN [base] ELSE len _ rem; IF start >= (xpos _ x.pos) THEN { start _ start - xpos; base _ x.rest; LOOP}; IF xpos >= start+len THEN {base _ x.base; LOOP}}; replace => { xstart, xnew, rem: Offset; IF (rem _ NonNeg[x.size-start]) <= len THEN IF start = 0 THEN RETURN [base] ELSE len _ rem; IF start >= (xnew _ x.newPos) THEN { start _ start - xnew + x.oldPos; base _ x.base; LOOP}; IF (rem _ start+len) <= (xstart _ x.start) THEN { base _ x.base; LOOP}; IF start >= xstart AND rem <= xnew THEN { start _ start - xstart; base _ x.replace; LOOP}}; object => { rem: Offset; IF (rem _ x.size-start) <= len THEN IF start = 0 THEN RETURN [base] ELSE len _ rem}; ENDCASE => ERROR Rope.NoRope; ENDCASE => ERROR Rope.NoRope; EXIT; ENDLOOP; RETURN [ IF len <= FlatMax THEN RopeFrom.FlatSubstr[base,start,len] ELSE RopeFrom.qZone.NEW[Tsubstr _ [node[substr[len,base,start,Depth[base]+1]]]]] }; Concat: PUBLIC PROC [base, rest: ROPE, baseLen, restLen: Offset _ MaxLen] RETURNS [new: ROPE] = TRUSTED { size: Offset; IF baseLen=MaxLen THEN baseLen _ RopeInline.InlineSize[base]; IF restLen=MaxLen THEN restLen _ RopeInline.InlineSize[rest]; IF restLen <= FlatMax AND (new _ RopeFrom.TryAppendConcat[base,rest,baseLen,restLen]) # NIL THEN RETURN [new]; IF (size _ baseLen+restLen) <= FlatMax THEN RETURN [RopeFrom.FlatConcat[base,rest,baseLen,restLen,FALSE]]; IF rest=NIL THEN RETURN [base]; IF base=NIL THEN RETURN [rest]; IF baseLen < FlatMax THEN WITH x:rest SELECT FROM node => WITH x:x SELECT FROM concat => -- try ((base & rest.base) & rest.rest) IF x.pos <= FlatMax AND (new _ RopeFrom.TryAppendConcat[base, x.base, baseLen, x.pos]) # NIL THEN RETURN [RopeFrom.qZone.NEW[Tconcat _ [node[concat[size, new, x.rest, baseLen+x.pos, 1+MAX[Depth[new],Depth[x.rest]]]]]]] ELSE IF baseLen+x.pos <= FlatMax THEN { new _ RopeFrom.FlatConcat[base, x.base, baseLen, x.pos, FALSE]; RETURN [RopeFrom.qZone.NEW[Tconcat _ [node[concat[size, new, x.rest, baseLen+x.pos, 1+MAX[Depth[new],Depth[x.rest]]]]]]] }; ENDCASE; ENDCASE; IF restLen <= FlatMax THEN WITH x:base SELECT FROM node => WITH x:x SELECT FROM concat => -- try (base.base & (base.rest & rest)) IF (new _ RopeFrom.TryAppendConcat[x.rest, rest, x.size-x.pos, restLen]) # NIL THEN RETURN [RopeFrom.qZone.NEW[Tconcat _ [node[concat[size,x.base,new,x.pos, 1+MAX[Depth[new],Depth[x.base]]]]]]] ELSE IF restLen+x.size-x.pos <= FlatMax THEN { new _ RopeFrom.FlatConcat[x.rest, rest, x.size-x.pos, restLen, FALSE]; RETURN [RopeFrom.qZone.NEW[Tconcat _ [node[concat[size,x.base,new,x.pos, 1+MAX[Depth[new],Depth[x.base]]]]]]]}; ENDCASE; ENDCASE; RETURN [RopeFrom.qZone.NEW[Tconcat _ [node[concat[size,base,rest,baseLen, 1+MAX[Depth[base],Depth[rest]]]]]]] }; Copy: PUBLIC PROC [ dest: ROPE, destLoc: Offset _ 0, source: ROPE, start: Offset _ 0, len: Offset _ MaxLen, destSize: Offset _ MaxLen] RETURNS [ROPE] = { size: Offset; 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) <= FlatMax THEN RETURN [ RopeFrom.FlatCopy[dest,destLoc,source,start,len,destSize]]; RETURN [Insert[dest,destLoc,Substr[source,start,len],destSize,len]]}; SemiFlatten: PUBLIC PROC [base: ROPE] RETURNS [flattened: ROPE] = { lastStart, lastLen: Offset; lastPiece: ROPE; list: LIST OF ROPE; listLen: INT _ 0; loc: Offset _ 0; -- where we are in reading base end: Offset _ 0; -- everything up to here has been flattened and put on list Flush: PROC = { size: INT _ loc-end; newChunk: ROPE; IF size=0 THEN RETURN; newChunk _ IF size=lastLen THEN Substr[base,end,size] -- will find the last piece, so won't allocate ELSE RopeFrom.FlatSubstr[base,end,size]; list _ RopeFrom.qZone.CONS[newChunk,list]; listLen _ listLen+1; end _ loc }; Map: SAFE PROC [base: ROPE, start: INT, len: INT] RETURNS [quit: BOOL _ FALSE] = TRUSTED { next: INT; IF (next _ loc+len)-end > 300 THEN Flush; -- flatten the pieces ahead of this one loc _ next; lastPiece _ base; lastStart _ start; lastLen _ len; RETURN [FALSE] }; Nth: PROC [n: INT] RETURNS [ROPE] = INLINE { IF n NOT IN [0..listLen) THEN ERROR; FOR l: LIST OF ROPE _ list, l.rest DO IF (n _ n+1)=listLen THEN RETURN [l.first]; ENDLOOP }; Balance: PROC [first, num: INT] RETURNS [ROPE] = { -- concat num ropes starting at first half: INT; IF num=1 THEN RETURN [Nth[first]]; half _ num/2; RETURN [Concat[Balance[first,half],Balance[first+half,num-half]]]; }; [] _ Rope.PieceMap[base: base, action: Map]; IF loc # Size[base] THEN ERROR; Flush[]; IF listLen = 0 THEN RETURN [NIL]; flattened _ Balance[0,listLen]; -- concat the ropes on the list }; RopeStats: PUBLIC PROC [base: ROPE, start: Offset _ 0, len: Offset _ MaxLen] RETURNS [size, pieces, depth: Offset] = TRUSTED { rem, altDepth, subDepth, subPieces: Offset; size _ RopeInline.InlineSize[base]; rem _ NonNeg[size - NonNeg[start]]; altDepth _ 0; IF len > rem THEN len _ rem; pieces _ depth _ 0; WHILE len > 0 DO x: ROPE _ base; WITH x: x SELECT FROM text => RETURN [size,pieces+1,MAX[depth,altDepth]]; node => { depth _ depth+1; WITH x: x SELECT FROM substr => {base _ x.base; start _ start + x.start; LOOP}; concat => {subLen: Offset _ x.pos - start; IF subLen > 0 THEN {IF len <= subLen THEN {base _ x.base; LOOP}; [,subPieces,subDepth] _ RopeStats[x.base, start, subLen]; pieces _ pieces+subPieces; altDepth _ MAX[altDepth,depth+subDepth]; len _ len - subLen; start _ 0} ELSE start _ -subLen; base _ x.rest; LOOP}; replace => {xstart: Offset _ x.start; len1: Offset _ xstart - start; base _ x.base; IF len1 > 0 THEN {-- a piece in first section of rope IF len1 >= len THEN LOOP; -- only in first section [,subPieces,subDepth] _ RopeStats[base, start, len1]; pieces _ pieces+subPieces; altDepth _ MAX[altDepth,depth+subDepth]; start _ xstart; len _ len - len1; len1 _ 0}; {xpos: Offset _ x.newPos; len2: Offset _ xpos - start; IF len2 <= 0 THEN {-- no piece in middle section start _ x.oldPos - len2; LOOP}; base _ x.replace; start _ -len1; IF len2 >= len THEN LOOP; -- only in middle section [,subPieces,subDepth] _ RopeStats[base, start, len2]; pieces _ pieces+subPieces; altDepth _ MAX[altDepth,depth+subDepth]; base _ x.base; start _ x.oldPos; len _ len - len2; }}; object => RETURN [size,pieces+1,MAX[depth,altDepth]]; ENDCASE => ERROR Rope.NoRope }; ENDCASE => ERROR Rope.NoRope; ENDLOOP; RETURN [0,0,0]; }; PutRope: PUBLIC PROC [stream: IO.Handle, rope: ROPE] = { reader: RopeReader.Ref _ RopeReader.GetRopeReader[]; size: Offset _ RopeInline.InlineSize[rope]; cnt: NAT; blockSize: NAT = 512; block: REF TEXT _ RopeEditingAlloc.GetBlock[]; RopeReader.SetPosition[reader,rope]; block.length _ 0; UNTIL size=0 DO IF block.length >= blockSize THEN { -- buffer is full IO.PutBlock[stream,block]; block.length _ 0 }; cnt _ RopeReader.GetString[reader:reader, str:block]; size _ size-cnt; ENDLOOP; IF block.length > 0 THEN IO.PutBlock[stream,block]; RopeEditingAlloc.FreeBlock[block]; RopeReader.FreeRopeReader[reader] }; GetRope: PUBLIC PROC [stream: IO.Handle, len: Offset _ MaxLen] RETURNS [ROPE] = { RETURN [RopeFrom.Stream[stream,len]] }; ToFile: PUBLIC PROC [fileName, rope: ROPE, start: Offset _ 0] = { WriteFile[FileIO.Open[fileName,overwrite], rope, start] }; ToFileC: PUBLIC PROC [capability: File.Capability, rope: ROPE, start: Offset _ 0] = { WriteFile[FileIO.StreamFromCapability[capability,overwrite], rope, start] }; WriteFile: PROC [stream: IO.Handle, rope: ROPE, start: Offset] = { IO.SetLength[stream,start]; IO.SetIndex[stream,start]; PutRope[stream,rope]; IO.Close[stream] }; FromFile: PUBLIC PROC [fileName: ROPE, start: Offset _ 0, len: Offset _ MaxLen] RETURNS [rope: ROPE] = { fh: CIFS.OpenFile = CIFS.Open[fileName, CIFS.read]; rope _ RopeFrom.File[CIFS.GetFC[fh], start, len, FALSE, MaxLen, FALSE]; CIFS.Close[fh] }; FromFileC: PUBLIC PROC [capability: File.Capability, start: Offset _ 0, len: Offset _ MaxLen] RETURNS [ROPE] = { RETURN [RopeFrom.File[capability, start, len, FALSE, MaxLen, FALSE]] }; charPropertyTable: PUBLIC REF READONLY CharPropertyTable; LegalCharacters: TYPE = CHAR[0C..177C]; Start: PUBLIC PROC = { cpt: REF CharPropertyTable _ NEW[CharPropertyTable]; ch: CHAR; i: CARDINAL; punctuationString: STRING = "!@#$%~&*()-`=+[{]};:'"",.<>/?\\|_^"L; charPropertyTable _ cpt; FOR ch IN CHAR DO cpt[ch] _ illegal; ENDLOOP; FOR ch IN LegalCharacters DO cpt[ch] _ alphaNumeric; ENDLOOP; cpt[TAB] _ white; cpt[SP] _ white; cpt[CR] _ white; cpt[140C] _ punctuation; TRUSTED { FOR i IN [0 .. punctuationString.length) DO cpt[punctuationString[i]] _ punctuation; ENDLOOP}; }; END. \-- RopeEditImpl.mesa; written by Bill Paxton, February 1981 -- edited by Paxton, October 29, 1982 8:45 am Last Edited by: Maxwell, January 5, 1983 11:57 am -- Edit -- three pieces to consider (first, middle, last) -- a piece in middle section of replace node -- **** IO Operations **** -- **** Filing Operations **** -- ***** Initialization Ê â˜JšÏc;™;Jš-™-J™1JšÏk ˜ J˜ J˜J˜J˜J˜ J˜ J˜ Jšžœ˜J˜Jšžœ˜J˜J˜šœž ˜šžœ3žœ˜?Jšžœ˜—Jšžœ˜Jšžœ˜ —Jšž˜Jšžœ˜J˜Jšœ ˜6J˜šÏnœžœžœžœžœ žœžœ˜DJšžœžœžœžœ˜Jšžœžœž˜J˜šœžœžœž˜J˜J˜J˜J˜Jšžœžœ ˜—Jšžœžœ˜J˜—Jš™J˜šŸœžœž˜Jšœžœ*˜5Jšžœžœžœ˜Jšžœ žœžœ˜šžœžœžœžœžœžœžœ˜+Jšžœžœž˜˜ J˜ šžœ'ž˜-Jšžœ žœžœžœ ˜0——šœžœžœž˜˜ J˜ šžœ%ž˜+Jšžœ žœžœžœ ˜/—Jšœ(žœ˜.—˜ J˜šžœ%ž˜+Jšžœ žœžœžœ ˜/—šžœžœ˜!Jšœ%žœ˜+—Jšžœžœžœ˜1—˜ J˜šžœ%ž˜+Jšžœ žœžœžœ ˜/—šžœžœ˜$Jšœ0žœ˜6—šžœ)žœ˜1Jšœžœ˜—šžœžœ žœ˜)Jšœ*žœ˜1——˜ J˜ šžœž˜#Jšžœ žœžœžœ ˜0——Jšžœžœ ˜—Jšžœžœ ˜Jšžœ˜Jšžœ˜—šžœ˜Jšžœžœ$˜:Jšžœžœ<˜SJ˜——šŸœžœžœžœ$˜IJšžœžœžœ˜ J˜ Jšžœžœ'˜=Jšžœžœ'˜=šžœž˜šœ>ž˜AJšžœžœ˜——šžœ%ž˜+Jšžœ0žœ˜>—Jšžœžœžœžœ˜Jšžœžœžœžœ˜š žœžœžœžœž˜1šœžœžœž˜šœ '˜1šžœž˜JšœAž˜Dšžœžœžœ ˜)˜.Jšœžœ˜$———šžœžœžœ˜'Jšœ8žœ˜?šžœžœ˜7J˜Jšœžœ"˜'———Jšžœ˜—Jšžœ˜—š žœžœžœžœž˜2šœžœžœž˜šœ '˜1šžœIž˜Nšžœžœžœ ˜)˜#Jšœžœ˜$———šžœžœ!žœ˜.Jšœ?žœ˜Fšžœžœ.˜HJšœžœ!˜&———Jšžœ˜—Jšžœ˜—šžœžœ/˜IJšœžœ!˜&J˜——šŸœžœžœ˜Jšœžœ˜ Jšœžœ*˜6J˜Jšžœžœ˜J˜ šžœ žœ˜J˜3Jšžœžœžœ˜*Jšœžœ˜"—Jšžœžœ(˜?Jšžœžœ˜.šžœ žœžœ˜/J˜;—Jšžœ?˜EJ˜—š Ÿ œžœžœžœžœ žœ˜CJšœ˜Jšœ žœ˜Jšœžœžœžœ˜Jšœ žœ˜Jšœ˜0Jšœ;˜LšŸœžœ˜Jšœžœ ˜Jšœ žœ˜Jšžœžœžœ˜šœ ˜ Jšžœžœ.˜YJšžœ$˜(—Jšœžœ˜*J˜J˜ —šŸœžœžœžœ žœžœžœžœžœžœ˜ZJšœžœ˜ Jšžœžœ'˜QJšœ?˜?Jšžœžœ˜—š Ÿœžœžœžœžœžœ˜,Jš žœžœžœžœžœ˜$š žœžœžœžœž˜%Jšžœžœžœ ˜+Jšžœ˜ ——š Ÿœžœžœžœžœ%˜XJšœžœ˜ Jšžœžœžœ˜"J˜ Jšžœ<˜BJ˜—J˜,Jšžœžœžœ˜J˜Jšžœ žœžœžœ˜!Jšœ ˜?J˜J˜—šŸ œžœžœžœ*˜LJšžœ"žœ˜2J˜+J˜#J˜#J˜ Jšžœ žœ ˜J˜šžœ ž˜Jšœžœ˜šžœžœž˜Jšœžœžœ˜3˜ J˜šžœžœž˜˜ Jšœ)žœ˜/—˜ ˜ šžœ žœ˜šœžœžœžœ˜-J˜9J˜Jšœ žœ˜(J˜—Jšžœ˜—Jšœžœ˜——˜ Jš1™1˜J˜J˜šžœ ž˜šœ#˜$Jšžœ žœžœ˜2J˜5J˜Jšœ žœ˜(J˜,——˜J˜šžœ ž˜šœ˜Jšœžœ˜——Jš,™,J˜ Jšžœ žœžœ˜3J˜5J˜Jšœ žœ˜(J˜2J˜———Jšœ žœžœ˜5Jšžœžœ˜——Jšžœžœ ˜—Jšžœ˜—Jšžœ ˜J˜J˜—Jš™J˜š Ÿœžœžœ žœžœ˜8J˜4J˜+Jšœžœ˜ Jšœ žœ˜Jšœžœžœ˜.J˜$J˜šžœž˜šžœžœ˜5Jšžœ˜J˜—J˜5J˜Jšžœ˜—Jšžœžœžœ˜3J˜"J˜$J˜—šŸœžœžœ žœ˜>Jšžœžœžœ!˜:J˜—Jš™J˜šŸœžœžœžœ˜AJšœ žœ*˜:J˜—šŸœžœžœ%žœ˜UJ˜LJ˜—šŸ œžœ žœžœ˜BJšžœ˜Jšžœ˜J˜Jšžœ˜J˜—šŸœžœžœ žœ*˜OJšžœžœ˜Jšœžœ žœžœ˜3Jšœžœžœ žœ˜GJšžœ ˜J˜—šŸ œžœžœG˜]Jšžœžœ˜Jšžœ(žœ žœ˜GJ˜—Jš™J˜Jšœžœžœžœ˜9J˜Jšœžœžœ ˜'J˜šŸœžœžœ˜Jšœžœžœ˜4Jšœžœ˜ Jšœžœ˜ Jšœžœ)˜BJ˜Jš žœžœžœžœžœ˜-Jšžœžœžœžœ˜=Jšœžœžœžœ ˜3J˜Jšž ˜ šžœžœ!žœ˜,Jšœ)˜)Jšžœ˜ —J˜J˜—Jšžœ˜J˜—…—&ð5.