DIRECTORY TextLooks, RunReader; LooksReader: CEDAR DEFINITIONS IMPORTS RunReader = BEGIN Offset: TYPE = TextLooks.Offset; Looks: TYPE = TextLooks.Looks; noLooks: Looks = TextLooks.noLooks; Runs: TYPE = TextLooks.Runs; Ref: TYPE = REF Body; Body: TYPE = PRIVATE RECORD [ rem: NAT, -- remainder of current run len: NAT, -- length of current run looks: Looks, -- looks for current run runreader: RunReader.Ref -- reader for runs ]; Create: PROC [] RETURNS [Ref]; SetPosition: PROC [reader: Ref, runs: Runs, index: Offset _ 0] = INLINE { reader.rem _ reader.len _ 0; RunReader.SetPosition[reader.runreader, runs, index] }; SetIndex: PROC [reader: Ref, index: Offset _ 0] = INLINE { reader.rem _ reader.len _ 0; RunReader.SetIndex[reader.runreader, 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 [runs: Runs, index: Offset] = INLINE { RETURN [GetRuns[reader], GetIndex[reader]] }; GetRuns: PROC [reader: Ref] RETURNS [Runs] = INLINE { RETURN [RunReader.GetRuns[reader.runreader]] }; GetIndex: PROC [reader: Ref] RETURNS [index: Offset] = INLINE { RETURN [ RunReader.GetIndex[reader.runreader]-reader.rem]}; ReaderProc: TYPE = PROC [reader: Ref] RETURNS [Looks]; Get: ReaderProc = INLINE { rem: NAT; IF (rem_reader.rem) = 0 THEN { -- go to the next run len: Offset; [len, reader.looks] _ RunReader.Get[reader.runreader]; IF len > LAST[NAT] THEN { RunReader.BackupIndex[reader.runreader,len-LAST[NAT]]; len _ LAST[NAT] }; reader.len _ rem _ len}; reader.rem _ rem-1; RETURN[reader.looks]}; Backwards: ReaderProc = INLINE { rem: NAT; IF (rem_reader.rem) >= reader.len THEN { -- go to the previous run len: Offset; [len, reader.looks] _ RunReader.Backwards[reader.runreader]; IF len > LAST[NAT] THEN { RunReader.BumpIndex[reader.runreader,len-LAST[NAT]]; len _ LAST[NAT] }; reader.len _ len; rem _ 0 }; reader.rem _ rem+1; RETURN[reader.looks]}; Peek: ReaderProc = INLINE { looks: Looks; IF reader.rem = 0 THEN [,looks] _ RunReader.Peek[reader.runreader] ELSE looks _ reader.looks; RETURN [looks]}; PeekBackwards: ReaderProc = INLINE { looks: Looks; IF reader.rem >= reader.len THEN [,looks] _ RunReader.PeekBackwards[reader.runreader] ELSE looks _ reader.looks; RETURN [looks]}; GetLooksReader: PROC RETURNS [Ref]; FreeLooksReader: PROC[Ref]; Start: PROC; -- for initialization only END. ´-- LooksReader.mesa -- written by Bill Paxton, March 1981 -- last edit by Bill Paxton, May 28, 1982 10:24 am -- LooksReader provides fast inline access to looks -- designed for speed in reading a sequence of looks -- either forwards or backwards -- supports looks as defined by TextLooks.Mesa -- create a reader by calling Create -- reader: LooksReader.Ref _ Create[]; -- position it where you want to read by SetPosition -- LooksReader.SetPosition[reader, runs, index]; -- where runs is TextLooks.Runs to read from -- and index is the initial position for the reader -- you can reposition a reader at any time -- read its position in the following ways: -- [runs, index] _ LooksReader.Position[reader]; -- runs _ LooksReader.GetRuns[reader]; -- index _ LooksReader.GetIndex[reader]; -- to read in ascending order (left to right) -- initialize position before first looks to be read -- for example, use 0 to start at beginning -- then call Get which reads to the right and increments the position -- looks _ LooksReader.Get[reader]; -- to read in descending order (right to left) -- initialize position after first looks to be read -- for example, use Size[runs] to start at end -- then call Backwards which reads to the left and decrements the position -- looks _ LooksReader.Backwards[reader]; -- can also get looks without changing the reader position -- to look at the next looks that Get would return, call Peek -- looks _ LooksReader.Peek[reader]; -- to look at what Backwards would return, call PeekBackwards -- looks _ LooksReader.PeekBackwards[reader]; -- can intermix reading or peeking to left and right -- don't need to reinitialize the reader to change direction -- create a reader for chars and looks -- set position of reader -- return position of looks reader -- get looks, then increment reader location -- decrement reader location, then get looks -- get looks without incrementing reader location -- like Backwards, but doesn't change position -- the following two routines implement a small cache of looks readers -- so can avoid creating a lot of garbage -- but don't use unless sure will not free more than once -- no harm if fail to free (garbage collector will get it) -- but chaos if free twice Ê̘JšÏc™Jš&™&Jš2™2J˜š3™3š4™4Jš™J˜——Jš.™.J˜š$™$Jš&™&J˜—š4™4Jš0™0Jš,™,Jš3™3Jš*™*J˜—š+™+Jš0™0Jš&™&Jš(™(J˜—š-™-š4™4Jš+™+—šE™EJš#™#J˜——š.™.š3™3Jš.™.—šJ™JJš)™)J˜——š:™:š=™=Jš$™$—š=™=Jš-™-J˜——š4™4Jš<™