<<>> <> <> <> <> <> <> <> <> <> <<>> DIRECTORY Basics USING [CompareCard, CompareInt, Comparison], Rope USING [AppendChars, ROPE, Size, Text], RopeReader USING [Body, Get, GetIndex, GetRope, MaxLen, Mode, ReadChar, Ref, SetPosition]; RopeReaderImpl: CEDAR MONITOR IMPORTS Basics, Rope, RopeReader EXPORTS RopeReader = BEGIN OPEN RopeReader; ROPE: TYPE = Rope.ROPE; Text: TYPE = Rope.Text; ReadOffEnd: PUBLIC ERROR = CODE; ReadChar: PUBLIC PROC [reader: Ref, mode: Mode] RETURNS [char: CHAR] = { rope: ROPE ~ reader.rope; -- the rope being read size: INT ~ rope.Size[]; -- size of the rope index: INT ~ reader.index+reader.current; -- index of next char that Get would read text: REF TEXT ~ reader.text; -- text buffer length: NAT ¬ text.maxLength; -- number of chars to be read into buffer forward: BOOL ~ SELECT mode FROM get, peek => TRUE, backwards, peekbackwards => FALSE, ENDCASE => ERROR; inBounds: BOOL ~ IF forward THEN index IN[0..size) ELSE index IN(0..size]; IF NOT inBounds THEN { IF reader.charForEndOfRope THEN RETURN[reader.endChar] ELSE ERROR ReadOffEnd; }; IF forward THEN { rem: INT ~ size-index; IF rem { reader.current ¬ i+1; RETURN[text[i]] }; backwards => { RETURN[text[reader.current ¬ i-1]] }; peek => { RETURN[text[i]] }; peekbackwards => { RETURN[text[i-1]] }; ENDCASE => ERROR; } ELSE ERROR; }; EqSubstrs: PUBLIC PROC [r1, r2: ROPE, start1, start2, len: INT, rdr1, rdr2: Ref ¬ NIL] RETURNS [eq: BOOL] = { <> <> free1, free2: BOOL ¬ FALSE; size1: INT ¬ Rope.Size[r1]; size2: INT ¬ Rope.Size[r2]; start1 ¬ MIN[start1, size1]; start2 ¬ MIN[start2, size2]; IF len=MaxLen THEN { IF (len ¬ size1-start1) # size2-start2 THEN RETURN [FALSE] } ELSE IF start1+len > size1 THEN RETURN [FALSE] ELSE IF start2+len > size2 THEN RETURN [FALSE]; IF rdr1 = NIL THEN { rdr1 ¬ GetRopeReader[]; free1 ¬ TRUE }; IF rdr2 = NIL THEN { rdr2 ¬ GetRopeReader[]; free2 ¬ TRUE }; SetPosition[rdr1, r1, start1]; SetPosition[rdr2, r2, start2]; eq ¬ TRUE; WHILE len > 0 DO num: NAT ¬ NAT.LAST; -- loop on NAT instead of INT IF len NULL; ENDLOOP; IF free1 THEN FreeRopeReader[rdr1]; IF free2 THEN FreeRopeReader[rdr2]; }; CompareSubstrs: PUBLIC PROC [r1, r2: ROPE, start1, len1, start2, len2: INT, rdr1, rdr2: Ref ¬ NIL, case: BOOL ¬ TRUE] RETURNS [result: Basics.Comparison] = { <> <> size1: INT ¬ Rope.Size[r1]; size2: INT ¬ Rope.Size[r2]; rem, rem1, rem2: INT; free1, free2: BOOL ¬ FALSE; rem1 ¬ IF start1 > size1 THEN 0 ELSE size1-start1; rem2 ¬ IF start2 > size2 THEN 0 ELSE size2-start2; IF rdr1 = NIL THEN { rdr1 ¬ GetRopeReader[]; free1 ¬ TRUE }; IF rdr2 = NIL THEN { rdr2 ¬ GetRopeReader[]; free2 ¬ TRUE }; len1 ¬ MIN[len1, rem1]; len2 ¬ MIN[len2, rem2]; rem ¬ MIN[len1, len2]; SetPosition[rdr1, r1, start1]; SetPosition[rdr2, r2, start2]; result ¬ equal; WHILE rem > 0 DO num: NAT ¬ NAT.LAST; IF rem> IF LOOPHOLE[c1-'A, CARDINAL] <= ('Z-'A) THEN c1 ¬ LOOPHOLE[LOOPHOLE[c1, CARDINAL] + ('a-'A), CHAR]; IF LOOPHOLE[c2-'A, CARDINAL] <= ('Z-'A) THEN c2 ¬ LOOPHOLE[LOOPHOLE[c2, CARDINAL] + ('a-'A), CHAR]; }; IF c1 # c2 THEN { result ¬ Basics.CompareCard[LOOPHOLE[c1, CARDINAL], LOOPHOLE[c2, CARDINAL]]; GO TO Finis; }; ENDLOOP; REPEAT Finis => NULL; ENDLOOP; IF free1 THEN FreeRopeReader[rdr1]; IF free2 THEN FreeRopeReader[rdr2]; IF result # equal THEN RETURN; -- if a character differerence, then return it RETURN [Basics.CompareInt[len1, len2]]; -- if equal so far, the length determines }; <<***** rope reader cache>> defaultSize: NAT ¬ 200; roperdr1: Ref ¬ NIL; roperdr2: Ref ¬ NIL; roperdr3: Ref ¬ NIL; SetDefaultSize: PUBLIC ENTRY PROC [size: NAT] = { defaultSize ¬ size; roperdr1 ¬ roperdr2 ¬ roperdr3 ¬ NIL; }; Create: PUBLIC PROC [size: NAT ¬ 0] RETURNS [Ref] = { IF size=0 THEN size ¬ defaultSize; RETURN[NEW[Body ¬ [text: NEW[TEXT[size]]]]]; }; GetRopeReader: PUBLIC ENTRY PROC RETURNS [reader: Ref] = { SELECT Ref.NIL FROM # roperdr3 => { reader ¬ roperdr3; roperdr3 ¬ NIL }; # roperdr2 => { reader ¬ roperdr2; roperdr2 ¬ NIL }; # roperdr1 => { reader ¬ roperdr1; roperdr1 ¬ NIL }; ENDCASE => reader ¬ Create[]; }; FreeRopeReader: PUBLIC ENTRY PROC [reader: Ref] = { SetPosition[reader, NIL]; IF reader.text.maxLength#defaultSize THEN RETURN; reader.charForEndOfRope ¬ FALSE; IF roperdr3 = reader OR roperdr2 = reader OR roperdr1 = reader THEN ERROR; SELECT Ref.NIL FROM roperdr3 => roperdr3 ¬ reader; roperdr2 => roperdr2 ¬ reader; roperdr1 => roperdr1 ¬ reader; ENDCASE => NULL; }; END.