-- PPRopeFileImpl.mesa -- last edit by Russ Atkinson, 10-Mar-82 10:23:26 DIRECTORY IOStream USING [GetBlock, GetChar, GetLength, Handle, SetIndex], Inline USING [LowHalf, HighHalf], Mopcodes USING [zME, zMXD], PPRopeFile, Rope USING [ActionType, FromProc, MakeRope, Ref]; PPRopeFileImpl: MONITOR LOCKS handle USING handle: Handle IMPORTS IOStream, Inline, Rope EXPORTS PPRopeFile = BEGIN OPEN Inline; Int: TYPE = LONG INTEGER; RopeRef: TYPE = Rope.Ref; Handle: TYPE = REF RopeFileRep; AcquireLock: PROC [h: Handle] RETURNS [BOOLEAN] = MACHINE CODE { -- returns TRUE if lock acquired, FALSE if not Mopcodes.zME}; ReleaseLock: PROC [h: Handle] = MACHINE CODE { Mopcodes.zMXD}; RopeFileRep: PUBLIC TYPE = MONITORED RECORD [file: IOStream.Handle, bufSize: NAT, data: SEQUENCE buffers: NAT OF Buf]; Buf: TYPE = REF BufRec; BufRec: TYPE = RECORD [start: Int, len: NAT, text: REF TEXT]; Create: PUBLIC PROC [file: IOStream.Handle, bufSize,buffers: NAT, useMap: BOOLEAN] RETURNS [handle: Handle, rope: RopeRef] = { bytes: Int _ 0; IF buffers = 0 OR buffers > 64 OR file = NIL THEN ERROR; IF bufSize < 64 THEN bufSize _ 64; file.SetIndex[0]; bytes _ file.GetLength[]; IF bytes <= LONG[buffers]*LONG[bufSize] THEN {get: PROC RETURNS [CHARACTER] = { RETURN [file.GetChar[]]}; rope _ Rope.FromProc[bytes, get]; handle _ NEW[RopeFileRep[0]]; handle.bufSize _ 0; RETURN}; handle _ NEW[RopeFileRep[buffers]]; handle.bufSize _ bufSize; handle.file _ file; FOR i: NAT IN [0..buffers) DO handle[i] _ NEW[BufRec _ [start: 0, len: 0, text: NEW[TEXT[bufSize]]]]; ENDLOOP; rope _ Rope.MakeRope [handle, IOStream.GetLength[file], MyFetch, IF useMap THEN MyMap ELSE NIL]; }; Destroy: PUBLIC ENTRY PROC [handle: Handle] = { IF handle = NIL THEN RETURN; handle.file _ NIL; handle.bufSize _ 0; FOR i: NAT IN [0..handle.buffers) DO handle[i].len _ 0; handle[i].text _ NIL; ENDLOOP; }; GetFile: PUBLIC PROC [handle: Handle] RETURNS [IOStream.Handle] = { RETURN [handle.file]}; MyFetch: PROC [ref: REF, index: Int] RETURNS [CHARACTER] = { handle: Handle = NARROW[ref]; last: NAT = handle.buffers-1; i: NAT _ 0; IF handle.file = NIL THEN ERROR; UNTIL AcquireLock[handle] DO ENDLOOP; DO buf: Buf _ handle[i]; delta: Int _ index - buf.start; SELECT TRUE FROM HighHalf[delta] = 0 AND LowHalf[delta] < buf.len => {}; i < last => {i _ i+1; LOOP}; ENDCASE => { -- need to swap in new buffer length: Int _ handle.bufSize; start: Int = index - (delta _ index MOD length); IOStream.SetIndex[handle.file, start]; length _ IOStream.GetBlock [handle.file, buf.text, 0, LowHalf[length]]; IF length = 0 THEN {ReleaseLock[handle]; ERROR}; buf.start _ start; buf.len _ LowHalf[length]; }; IF i # 0 THEN { -- swap to speed searches handle[i] _ handle[i-1]; handle[i-1] _ buf; }; {c: CHARACTER _ buf.text[LowHalf[delta]]; ReleaseLock[handle]; RETURN [c]}; ENDLOOP; }; MyMap: PROC [base: REF, start,len: Int, action: Rope.ActionType] RETURNS [BOOLEAN] = { handle: Handle _ NARROW[base]; last: NAT = handle.buffers-1; i: NAT _ 0; IF handle.file = NIL THEN ERROR; IF len <= 0 THEN RETURN [FALSE]; UNTIL AcquireLock[handle] DO ENDLOOP; DO buf: Buf _ handle[i]; bufStart: Int _ buf.start; delta: Int _ start - bufStart; SELECT TRUE FROM HighHalf[delta] = 0 AND LowHalf[delta] < buf.len => { rem: NAT _ buf.len-LowHalf[delta]; chars: CARDINAL _ 0; IF len < rem THEN rem _ LowHalf[len]; WHILE chars < rem DO c: CHARACTER _ buf.text[LowHalf[delta]+chars]; -- eval this while locked ReleaseLock[handle]; IF action[c] THEN RETURN [TRUE]; -- eval this while unlocked chars _ chars + 1; UNTIL AcquireLock[handle] DO ENDLOOP; IF buf.start # bufStart THEN EXIT; -- abort & retry if buf changed ENDLOOP; len _ len - chars; -- update according to the amount done start _ start + chars; IF len > 0 THEN {i _ 0; LOOP}; }; i < last => { -- missed it, unfortunately i _ i+1; LOOP}; ENDCASE => { -- need to swap in new buffer length: NAT _ handle.bufSize; base: Int = start - (start MOD length); IOStream.SetIndex[handle.file, base]; length _ IOStream.GetBlock [handle.file, buf.text, 0, LowHalf[length]]; IF length = 0 THEN {ReleaseLock[handle]; ERROR}; buf.start _ base; buf.len _ LowHalf[length]; LOOP; }; IF i # 0 AND handle[i] = buf THEN { -- swap to speed searches handle[i] _ handle[i-1]; handle[i-1] _ buf; }; ReleaseLock[handle]; RETURN [FALSE]; ENDLOOP; }; END.