DIRECTORY RopeFrom, RopeEdit, RopeEditingAlloc, RopeReader, Rope, RopeInline, File, Space, PropertyTypes, Directory, Inline, IO, RopeEditingBLT; RopeFromFileImpl: CEDAR MONITOR IMPORTS RopeEditingBLT, RopeEditingAlloc, Rope, RopeInline, RopeEdit, Space, Inline, Directory, IO EXPORTS RopeFrom SHARES Rope = BEGIN OPEN fileI:File, RopeFrom, RopeInline; pagesPerSpace: NAT = RopeReader.pagesPerArray; charsPerPage: NAT = RopeReader.charsPerPage; charsPerArray: NAT = RopeReader.charsPerArray; charsPerSpace: NAT = charsPerArray; spaceMin: NAT = charsPerSpace/2; -- put in shared array if less than 1/2 swapUnitSize: NAT = 16; -- based on Paul's advice CharsArray: TYPE = RopeReader.CharsArray; Chars: TYPE = REF CharsArray; File: PUBLIC PROC [ file: fileI.Capability, start: Offset _ 0, length: Offset _ MaxLen, -- defaults to rest of file fileLen: Offset _ MaxLen] RETURNS [rope: ROPE] = { MakeRope: PROC [startSpace, numToDo: Offset] RETURNS [rope: ROPE] = TRUSTED { chars: REF RopeReader.CharsArray; fileSpace: Space.Handle; len: NAT _ charsPerSpace; start, nwords: NAT; charOffset, skipWords: NAT _ 0; base: ROPE; firstSpace: BOOLEAN _ FALSE; IF numToDo = 0 THEN RETURN [NIL]; IF numToDo > 1 THEN { -- split into balanced parts half: Offset _ numToDo/2; front: ROPE _ MakeRope[startSpace, half]; back: ROPE _ MakeRope[startSpace+half, numToDo-half]; RETURN [Rope.Concat[front,back]] }; IF startSpace+1 = numSpaces THEN -- this is the last space len _ len - endSkip; IF startSpace = 0 THEN { -- this is the first space for the file len _ len - startSkip; firstSpace _ TRUE }; IF firstSpace THEN { charOffset _ startSkip MOD 2; skipWords _ startSkip/2 }; nwords _ (len+charOffset+1)/2; -- number to copy from file [chars, start, base] _ RopeEditingAlloc.AllocWords[nwords]; fileSpace _ GetSpace[]; Space.Map[fileSpace, Space.WindowOrigin[file, startPage+startSpace*pagesPerSpace]]; Space.Activate[fileSpace]; Inline.LongCOPY[from: Space.LongPointer[fileSpace]+skipWords, nwords: nwords, to: LOOPHOLE[chars,LONG POINTER]+start/2]; FreeSpace[fileSpace]; RETURN [NEW[Tsubstr _ [node[substr[len,base,start+charOffset,RopeEdit.Depth[base]+1]]]]] }; GetFileLen: PROC = TRUSTED { Directory.GetProperty[file: file, property: PropertyTypes.tByteLength, propertyValue: DESCRIPTOR[@fileLen, SIZE[Offset]]] }; startPage: Offset; startSkip, endSkip: NAT; numPages, numSpaces: Offset; start _ start+charsPerPage; -- to skip over leader page startPage _ start/charsPerPage; startSkip _ start MOD charsPerPage; IF fileLen = MaxLen THEN GetFileLen; fileLen _ fileLen+charsPerPage; -- to compensate for leader page IF fileLen <= start THEN RETURN [NIL]; length _ MIN[length,fileLen-start]; IF length = 0 THEN RETURN[NIL]; numPages _ (start+length+charsPerPage-1)/charsPerPage-startPage; numSpaces _ (numPages+pagesPerSpace-1)/pagesPerSpace; endSkip _ numSpaces*charsPerSpace-length-startSkip; rope _ MakeRope[0,numSpaces]}; Stream: PUBLIC PROC [stream: IO.Handle, length: Offset _ MaxLen] RETURNS [rope: ROPE] = { MakeRope: PROC [len: Offset] RETURNS [ROPE] = { chars: REF RopeReader.CharsArray; start, nchars, charloc: NAT; base: ROPE; IF len = 0 THEN RETURN [NIL]; IF len > charsPerSpace THEN { -- split into balanced parts half: Offset _ MAX[len/2,charsPerSpace]; front: ROPE _ MakeRope[half]; back: ROPE _ MakeRope[len-half]; RETURN [Rope.Concat[front,back]] }; nchars _ Short[len]; [chars, start, base] _ RopeEditingAlloc.AllocWords[(nchars+1)/2]; charloc _ start; UNTIL nchars = 0 DO nread: NAT; block.length _ 0; nread _ IO.GetBlock[self: stream, block: block, startIndex: 0, stopIndexPlusOne: nchars]; RopeEditingBLT.StringToArrayBlt[block,0,chars,charloc,nread]; nchars _ nchars-nread; charloc _ charloc+nread; ENDLOOP; RETURN [NEW[Tsubstr _ [node[substr[len,base,start,1+RopeEdit.Depth[base]]]]]] }; start,fileLen: Offset; block: REF TEXT; fileLen _ IO.GetLength[stream]; start _ IO.GetIndex[stream]; IF fileLen <= start THEN RETURN [NIL]; length _ MIN[length,fileLen-start]; IF length = 0 THEN RETURN [NIL]; block _ RopeEditingAlloc.GetBlock[]; rope _ MakeRope[length]; RopeEditingAlloc.FreeBlock[block] }; fileSpace: Space.Handle _ Space.nullHandle; -- shared file space numSpaces: INT _ 0; -- number allocated freedSpaces: INT _ 0; GetSpace: ENTRY PROC RETURNS [space: Space.Handle] = TRUSTED { ENABLE UNWIND => NULL; IF fileSpace # Space.nullHandle THEN space _ fileSpace ELSE { -- need to allocate one space _ Space.Create[pagesPerSpace, Space.virtualMemory]; numSpaces _ numSpaces+1 }; fileSpace _ Space.nullHandle }; FreeSpace: ENTRY PROC [space: Space.Handle] = TRUSTED { ENABLE UNWIND => NULL; IF fileSpace = Space.nullHandle THEN Space.Unmap[fileSpace _ space] ELSE { Space.Delete[space]; freedSpaces _ freedSpaces+1 }}; END. €-- RopeFromFileImpl.Mesa; written by Bill Paxton, February 1981 -- edited by Paxton, August 19, 1983 6:12 pm -- edited by McGregor, February 8, 1983 11:03 am -- edited by Maxwell, January 5, 1983 12:11 pm -- ***** Operations -- make skipWords*2+charOffset=startSkip ***** These two routines are the only monitored procedures ***** They provide a shared space for reading files Êy˜JšÏc@™@Jš,™,Jš0™0Jš œ"™.J˜šÏk ˜ J˜ J˜ J˜J˜ J˜J˜ J˜J˜J˜J˜ J˜Jšžœ˜J˜J˜—šœž ˜JšžœYž˜bJšžœ ˜Jšžœ˜ —Jšž˜Jšžœ"˜&J˜Jšœžœ˜.Jšœžœ˜,Jšœžœ˜.Jšœžœ˜#Jšœ žœ'˜HJšœžœ˜1J˜Jšœ žœ˜)Jšœžœžœ ˜J˜Jš™J˜šÏnœžœžœ˜J˜J˜Jšœ˜4Jšœ˜Jšžœžœ˜J˜šŸœžœ˜,Jšžœžœžœ˜ Jšœžœ˜!J˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜ Jšœ žœžœ˜Jšžœ žœžœžœ˜!šžœ žœ˜2J˜Jšœžœ˜)Jšœžœ+˜5Jšžœ˜#—šžœžœ˜:J˜—šžœžœ'˜@Jšœ$žœ˜+—šžœ žœ˜Jš(™(Jšœžœ˜J˜—Jšœ˜:J˜;J˜J˜SJ˜˜=Jšœžœžœžœ ˜:—J˜šžœžœP˜[J˜——šŸ œžœžœ˜J˜FJšœž œ žœ ˜5J˜—J˜Jšœžœ˜J˜J˜Jšœ˜7J˜Jšœžœ˜#Jšžœžœ ˜$Jšœ ˜@Jšžœžœžœžœ˜&Jšœ žœ˜#Jšžœ žœžœžœ˜J˜@J˜5J˜3J˜J˜—šŸœžœžœ žœ!˜@Jšžœžœ˜J˜šŸœžœžœžœ˜/Jšœžœ˜!Jšœžœ˜Jšœžœ˜ Jšžœ žœžœžœ˜šžœžœ˜:Jšœžœ˜(Jšœžœ˜Jšœžœ˜ Jšžœ˜#—J˜J˜AJ˜šžœ ž˜Jšœžœ˜ J˜JšœžœO˜YJ˜=J˜/Jšžœ˜—JšžœžœE˜PJ˜—J˜Jšœžœžœ˜J˜Jšœ žœ˜Jšœžœ˜Jšžœžœžœžœ˜&Jšœ žœ˜#Jšžœ žœžœžœ˜ J˜$J˜J˜$J˜—Jš:™:Jš3™3J˜Jšœ,˜@Jšœ žœ˜'Jšœ žœ˜J˜š Ÿœžœžœžœžœ˜>Jšžœžœžœ˜Jšžœžœ˜6šžœ˜J˜9J˜—J˜J˜—šŸ œžœžœžœ˜7Jšžœžœžœ˜Jšžœžœ˜CJšžœ7˜;—J˜Jšžœ˜J˜—…—‰