DIRECTORY Environment, Rope, Space; RopeReader: CEDAR DEFINITIONS IMPORTS Rope, Space = BEGIN Ref: TYPE = REF Body; -- Body of reader is a private record (declared below) ROPE: TYPE = Rope.ROPE; Offset: TYPE = INT; MaxLen: Offset = Rope.MaxLen; ReadOffEnd: ERROR; Create: PROC RETURNS [Ref]; SetPosition: PROC [reader: Ref, rope: ROPE, index: Offset _ 0] = INLINE { IF GetRope[reader]#rope OR GetIndex[reader]#index THEN { reader.current _ reader.first _ reader.after _ 0; reader.chars _ NIL; reader.text _ NIL; reader.rope _ rope; reader.index _ index}}; SetIndex: PROC [reader: Ref, index: Offset _ 0] = INLINE { IF GetIndex[reader]#index THEN { reader.current _ reader.first _ reader.after _ 0; reader.chars _ NIL; reader.text _ NIL; reader.index _ index}}; BackupIndex: PROC [reader: Ref, amount: Offset] = INLINE { SetIndex[reader, GetIndex[reader]-amount] }; BumpIndex: PROC [reader: Ref, amount: Offset] = INLINE { SetIndex[reader, GetIndex[reader]+amount] }; Position: PROC [reader: Ref] RETURNS [rope: ROPE, index: Offset] = INLINE { RETURN [reader.rope, reader.index+reader.current-reader.first] }; GetRope: PROC [reader: Ref] RETURNS [rope: ROPE] = INLINE { RETURN [reader.rope] }; GetIndex: PROC [reader: Ref] RETURNS [index: Offset] = INLINE { RETURN [reader.index+reader.current-reader.first] }; GetEndChar: PROC [reader: Ref] RETURNS [endChar: CHAR] = INLINE { RETURN [reader.endChar] }; CharForEndOfRope: PROC [reader: Ref] RETURNS [BOOLEAN] = INLINE { RETURN [reader.charForEndOfRope] }; SetCharForEndOfRope: PROC [reader: Ref, char: CHAR] = INLINE { reader.endChar _ char; reader.charForEndOfRope _ TRUE }; ClearCharForEndOfRope: PROC [reader: Ref] = INLINE { reader.charForEndOfRope _ FALSE }; ReaderProc: TYPE = PROC [reader: Ref] RETURNS [CHAR]; Get: ReaderProc = INLINE { current: NAT; IF (current_reader.current) >= reader.after THEN RETURN[ReadChar[reader,get]]; reader.current _ current+1; RETURN[IF reader.txtFlag THEN reader.text[current] ELSE reader.chars[current]]}; Backwards: ReaderProc = INLINE { current: NAT; IF (current_reader.current) <= reader.first THEN RETURN[ReadChar[reader,backwards]]; reader.current _ current _ current-1; RETURN[IF reader.txtFlag THEN reader.text[current] ELSE reader.chars[current]]}; Peek: ReaderProc = INLINE { current: NAT; IF (current_reader.current) >= reader.after THEN RETURN[ReadChar[reader,peek]]; RETURN[IF reader.txtFlag THEN reader.text[current] ELSE reader.chars[current]]}; PeekBackwards: ReaderProc = INLINE { current: NAT; IF (current_reader.current) <= reader.first THEN RETURN[ReadChar[reader,peekbackwards]]; RETURN[IF reader.txtFlag THEN reader.text[current-1] ELSE reader.chars[current-1]]}; Mode: PRIVATE TYPE = {get, backwards, peek, peekbackwards}; ReadChar: PRIVATE PROC [reader: Ref, mode: Mode] RETURNS [CHAR]; Equal: PROC [r1,r2: ROPE, rdr1,rdr2: Ref _ NIL] RETURNS [BOOLEAN] = INLINE { RETURN [EqSubstrs[r1,r2,0,0,MaxLen,rdr1,rdr2]] }; EqSubstrs: PROC [r1,r2: ROPE, start1,start2,len: Offset, rdr1,rdr2: Ref _ NIL] RETURNS [BOOLEAN]; Compare: PROC [r1,r2: ROPE, rdr1,rdr2: Ref _ NIL, case: BOOLEAN _ TRUE] RETURNS [Environment.Comparison] = INLINE { RETURN [CompareSubstrs[r1,r2,0,MaxLen,0,MaxLen,rdr1,rdr2,case]] }; CompareSubstrs: PROC [ r1,r2: ROPE, start1,len1,start2,len2: Offset, rdr1,rdr2: Ref _ NIL, case: BOOLEAN _ TRUE] RETURNS [Environment.Comparison]; GetText: PROC [reader: Ref, txt: Rope.Text, length: NAT _ LAST[NAT]] RETURNS [count: NAT]; BackwardsGetText: PROC [reader: Ref, txt: Rope.Text, length: NAT _ LAST[NAT]] RETURNS [count: NAT]; GetString: PROC [reader: Ref, str: REF TEXT, length: NAT _ LAST[NAT]] RETURNS [count: NAT]; BackwardsGetString: PROC [reader: Ref, str: REF TEXT, length: NAT _ LAST[NAT]] RETURNS [count: NAT]; Chars: TYPE = REF READONLY CharsArray; -- CharsArray is a packed array of characters CharsRope: PROC [chars: Chars, space: Space.Handle _ Space.nullHandle] RETURNS [ROPE]; GetChars: PROC [ reader: Ref, chars: REF CharsArray, length: NAT _ LAST[NAT], offset: NAT _ 0] RETURNS [count: NAT]; BackwardsGetChars: PROC [ reader: Ref, chars: REF CharsArray, length: NAT _ LAST[NAT], offset: NAT _ 0] RETURNS [count: NAT]; GetRopeReader: PROC RETURNS [reader: Ref]; FreeRopeReader: PROC [reader: Ref]; Body: TYPE = PRIVATE RECORD [ current: NAT _ 0, -- index of current character first: NAT _ 0, -- index of first character to read after: NAT _ 0, -- index beyond last character to read chars: Chars, -- character array that we are currently reading text: Rope.Text, -- text rope that we are currently reading rope: ROPE, -- rope that we are reading index: Offset _ 0, -- index in rope of first character txtFlag: BOOLEAN _ FALSE, -- if true, read from text. else read from chars charForEndOfRope: BOOLEAN _ FALSE, endChar: CHAR _ 0C -- char to return when reach end of rope ]; charsPerPage: NAT = 512; pagesPerArray: NAT = 19; -- 4*n-1 pages since RTStorage quanta are four pages charsPerArray: NAT = charsPerPage*pagesPerArray; CharsArray: TYPE = PACKED ARRAY [0..charsPerArray) OF CHAR; END. î-- RopeReader.mesa; written by Bill Paxton, January 1981 -- edited by Paxton, September 13, 1982 9:33 am -- edited by McGregor, February 8, 1983 11:00 am RopeReader provides fast inline access to characters in ropes designed for speed in reading a sequence of characters, either forwards or backwards from packed arrays (such as created by RopeIO) or from text ropes (the packed sequence of characters variant) create a reader by RopeReader.Create reader: RopeReader.Ref _ RopeReader.Create[]; position it where you want to read by SetPosition RopeReader.SetPosition[reader,rope,index]; where rope is to the one to read from, and index is the initial position for the reader you can reposition a reader at any time read its position in any of the following ways: [rope,index] _ RopeReader.Position[reader]; rope _ RopeReader.GetRope[reader]; index _ RopeReader.GetIndex[reader]; to read in ascending order (left to right) initialize position at index of first character to be read for example, use 0 to start at beginning of rope then call Get which reads to the right and increments the position char _ RopeReader.Get[reader]; to read in descending order (right to left) initialize position after first character to be read for example, use size of rope to start at end then call Backwards which reads to the left and decrements the position char _ RopeReader.Backwards[reader]; can also get a character without changing the reader position to look at the next character that Get would return, call Peek char _ RopeReader.Peek[reader]; to look at what Backwards would return, call PeekBackwards char _ RopeReader.PeekBackwards[reader]; can intermix reading or peeking to left and right don't need to reinitialize the reader to change direction if read off either end of rope, you can choose either to get an error or a client-specified character there are equality and comparison routines that use readers for efficiency Equal, EqSubstr, EqSubstrs Compare, CompareSubstr, CompareSubstrs operations are also provided to read a block of characters destination given by either a REF TEXT or a REF chars array can read either forward or backwards from source Last Edited by: Maxwell, January 5, 1983 8:36 am ***** RopeReader Declarations ***** RopeReader Operations Returns the current end char. This will be returned rather than giving ReadOffEnd error if CharForEndOfRope is true. get character, then increment reader location decrement reader location, then get character get character without incrementing reader location like Backwards, but doesn't change position Here are some rope comparison operations that make use of readers for efficiency. uses readers rdr1 and rdr2 to read ropes r1 and r2 to test for equality uses readers rdr1 and rdr2 to read ropes r1 and r2 to test for equality returns TRUE if r1 starting at start1 is same as len chars of r2 starting at start2 returns FALSE if not enough chars available in either rope i.e., if start1+len > size[r1] or start2+len > size[r2] if rdr1 or rdr2 is NIL, gets own readers from cache uses readers rdr1 and rdr2 to compare ropes r1 and r2 returns less for r1 < r2; equal for r1 = r2; and greater for r1 > r2 if ~case then all characters forced lowercase for comparison uses readers rdr1 and rdr2 to compare substrings of ropes r1 and r2 if rdr1 or rdr2 is NIL, gets own readers from cache The following operations provide for reading blocks of characters appends characters to text from rope; returns number of characters updates txt.length appends characters to text from rope; returns number of characters updates txt.length appends characters to string from rope; returns number of characters updates str.length appends characters to string from rope; returns number of characters updates str.length ***** Private declarations if the Chars array was acquired by calling RTStorageOps, pass the space to CharsRope so it can set up finalization for it this routine is mainly for internal use appends characters to CharsArray from rope; returns number of characters The next routines provide a small cache of rope readers so can avoid creating a lot of garbage readers don't use these unless you are certain to free the reader at most once no harm if fail to free it, but total chaos if you free it more than once if true, return endChar; else give ERROR ReadOffEnd Ê d˜JšÏc9™9Jš/™/Jš0™0J˜š=™=JšT™TJš.™.Jš>™>J˜—š$™$Jš-™-J˜—š1™1Jš*™*JšW™WJš'™'J˜—š/™/Jš+™+Jš"™"Jš$™$J˜—š*™*š:™:Jš0™0—šB™BJš™J˜——š+™+š4™4Jš-™-—šG™GJš$™$J˜——š=™=š>™>Jš™—š:™:Jš(™(J˜——š1™1Jš9™9J˜—še™eJ˜—šJ™JJš™Jš&™&J˜—š:™:Jš;™;Jš0™0JšÏk0™0—šž ˜ J˜ J˜J˜J˜—Jšœ žœž˜9J˜š™J˜Jšœžœžœ6˜LJšžœžœžœ˜Jšœžœžœ˜J˜Jšœ žœ˜J˜—š™J˜JšÏnœžœžœ˜J˜šŸ œžœžœžœ˜Išžœžœžœ˜8J˜1Jšœžœžœ˜&J˜+J˜——šŸœžœ$žœ˜:šžœžœ˜ J˜1Jšœžœžœ˜>J˜——šŸ œžœ!žœ˜:J˜,J˜—šŸ œžœ!žœ˜8J˜,J˜—š Ÿœžœžœžœžœ˜KJšžœ;˜AJ˜—š Ÿœžœžœžœžœžœ˜SJ˜—šŸœžœžœž˜=šœžœ.˜6J˜——šŸ œžœ˜Jšžœ žœžœžœ˜=Jšœu™uJ˜—šŸœžœžœžœ˜8Jšžœžœ˜,J˜—šŸœžœžœžœ˜>Jšœ1žœ˜8J˜—šŸœžœžœ˜4Jšœžœ˜"J˜—Jš Ÿ œžœžœžœžœ˜5J˜JšŸœžœ˜š-™-Jšœ žœ˜ šžœ*ž˜0Jšžœ˜—J˜Jšžœžœžœžœ˜PJ˜—JšŸ œžœ˜ š-™-Jšœ žœ˜ šžœ*ž˜0Jšžœ˜#—J˜%Jšžœžœžœžœ˜PJ˜—JšŸœžœ˜š2™2Jšœ žœ˜ šžœ*ž˜0Jšžœ˜—Jšžœžœžœžœ˜PJ˜—JšŸ œžœ˜$š+™+Jšœ žœ˜ šžœ*ž˜0Jšžœ!˜'—Jšžœžœžœžœ˜TJ˜—Jšœžœžœ)˜;Jš Ÿœžœžœžœžœ˜@J˜—šQ™QJ˜šŸœžœ žœžœžœžœžœ˜LJšG™GJšžœ+˜1J˜—šŸ œžœ žœ.žœ˜NJšžœžœ˜JšG™Gš0™0Jš"™"—š:™:Jš7™7—Jš3™3J˜—š Ÿœžœ žœžœžœžœ˜GJšžœžœ˜+Jš5™5Jšœœ ™DJš<™Jšœ*˜;Jšœžœ˜'Jšœ#˜6Jšœ žœžœ1˜Kšœžœžœ˜"Jš4™4—Jšœ žœ(˜;J˜J˜—Jšœžœ˜Jšœžœ4˜MJšœžœ˜0Jš œ žœžœžœžœžœ˜;J˜—Jšžœ˜J˜J˜—…—Ü..