(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) (* Last modified on Sat Nov 28 15:10:01 PST 1992 by meehan *) (* modified on Tue Jun 30 16:01:44 PDT 1992 by mhb *) (* modified on Tue Jun 16 13:16:22 PDT 1992 by muller *) (* modified on Sat Feb 29 11:46:47 PST 1992 by kalsow *) (* modified on Mon May 7 8:49:45 PDT 1990 by mcjones *) (* modified on Wed Nov 15 10:29:45 1989 by chan *) (* modified on Thu May 4 9:27:56 PDT 1989 by mbrown *) MODULE MTextRd; IMPORT RdClass, MText, MTextDs, MTextPrivate, Rd, Text, TextF, Thread; FROM MTextPrivate IMPORT Node, NodeType; CONST BufferSize = 512; REVEAL T = Public BRANDED "MTextRd.T.2" OBJECT m : MText.T; rangeStart, rangeEnd: CARDINAL; len, first : CARDINAL; last : INTEGER; version : INTEGER; reverse : BOOLEAN; chars : REF ARRAY OF CHAR := NIL OVERRIDES length := Length; seek := Seek; init := Init END; PROCEDURE New (m : MText.T := NIL; start : CARDINAL := 0; rangeStart: CARDINAL := 0; rangeEnd : CARDINAL := LAST (CARDINAL); reverse : BOOLEAN := FALSE; ): T RAISES {Rd.Failure, Thread.Alerted} = BEGIN RETURN NEW (T).init (m, start, rangeStart, rangeEnd, reverse) END New; PROCEDURE Init (rd : T; m : MText.T := NIL; start : CARDINAL := 0; rangeStart: CARDINAL := 0; rangeEnd : CARDINAL := LAST (CARDINAL); reverse : BOOLEAN := FALSE ): T RAISES {Rd.Failure, Thread.Alerted} = BEGIN IF m # NIL THEN rd.m := m END; rd.first := rangeStart; rd.last := MIN (rangeEnd, rd.m.length) - 1; rd.len := MAX (rd.last - rd.first + 1, 0); rd.reverse := reverse; rd.closed := FALSE; rd.seekable := TRUE; rd.intermittent := FALSE; rd.st := 0; rd.lo := 0; rd.hi := 0; IF rd.chars = NIL THEN rd.chars := NEW (REF ARRAY OF CHAR, BufferSize) END; rd.buff := rd.chars; IF reverse THEN IF rd.len = 0 THEN rd.cur := 0 ELSIF start < rd.first THEN rd.cur := rd.len ELSIF start > rd.last THEN rd.cur := 0 ELSE rd.cur := rd.last + 1 - start END ELSE IF rd.len = 0 THEN rd.cur := 0 ELSIF start < rd.first THEN rd.cur := 0 ELSIF start > rd.last THEN rd.cur := rd.len ELSE rd.cur := start - rd.first END END; Rd.Seek (rd, rd.cur); RETURN rd END Init; PROCEDURE Seek (rd: T; dontBlock: BOOLEAN): RdClass.SeekResult RAISES {Rd.Failure, Thread.Alerted} = BEGIN IF rd.reverse THEN RETURN RevSeek (rd, dontBlock) ELSE RETURN ForwardSeek (rd, dontBlock) END END Seek; PROCEDURE ForwardSeek (rd: T; <* UNUSED *> dontBlock: BOOLEAN): RdClass.SeekResult RAISES {Rd.Failure, Thread.Alerted} = VAR beginN : Node; beginI, count, i: CARDINAL; result := RdClass.SeekResult.Ready; BEGIN IF rd.cur >= rd.len THEN RETURN RdClass.SeekResult.Eof END; MTextDs.LocateB (rd.m, rd.cur + rd.first, beginN, beginI); count := MIN (MIN (beginN.length - beginI, BufferSize), rd.len - rd.cur); CASE beginN.type OF | NodeType.text => SUBARRAY (rd.buff^, 0, count) := SUBARRAY (beginN.text^, beginI, count); | NodeType.buf => SUBARRAY (rd.buff^, 0, count) := SUBARRAY (beginN.buffer^, beginI, count); | NodeType.file => Rd.Seek (beginN.file, beginI + beginN.start); i := 0; TRY WHILE i < count DO rd.buff [i] := Rd.GetChar (beginN.file); INC (i) END EXCEPT Rd.EndOfFile => END; count := i; ELSE <* ASSERT FALSE *> END; rd.lo := rd.cur; rd.hi := rd.lo + count; RETURN result END ForwardSeek; PROCEDURE RevSeek (rd: T; <* UNUSED *> dontBlock: BOOLEAN): RdClass.SeekResult RAISES {Rd.Failure, Thread.Alerted} = VAR beginN : Node; beginI, count, first, i: CARDINAL; PROCEDURE RevCopy (READONLY v: ARRAY OF CHAR) = BEGIN FOR i := 1 TO count DO rd.buff [count - i] := v [first + i - 1] END END RevCopy; BEGIN IF rd.cur >= rd.len THEN RETURN RdClass.SeekResult.Eof END; MTextDs.Locate (rd.m, rd.last + 1 - rd.cur, beginN, beginI); count := MIN (MIN (beginI, BufferSize), rd.len - rd.cur); first := beginI - count; CASE beginN.type OF | NodeType.text => RevCopy (SUBARRAY (beginN.text^, 0, Text.Length (beginN.text))) | NodeType.file => Rd.Seek (beginN.file, beginN.start + first); i := 0; TRY WHILE i < count DO rd.buff [count - 1 - i] := Rd.GetChar (beginN.file); INC (i) END EXCEPT Rd.EndOfFile => END; count := i | NodeType.buf => RevCopy (beginN.buffer^) ELSE <* ASSERT FALSE *> END; rd.lo := rd.cur; rd.hi := rd.lo + count; RETURN RdClass.SeekResult.Ready END RevSeek; PROCEDURE Length (rd: T): CARDINAL = BEGIN RETURN rd.len END Length; BEGIN END MTextRd.