// W I N D O W // errors 500 // //Window routines for accessing disk files. // //WindowInit(file [,number-of-buffers [,strategy [,filetype]]]) // Initializes a window on the given number of page buffers (default // is 1), with the given paging strategy, which is: // WINDOWNoStrategy -- none default // WINDOWPageAhead -- sequential file // If there is a filetype, set the type of the file to it. // Returns a pointer to a "window" structure // //WindowClose(window [,length]) // Closes the window, and affects the length of the file if a second // argument is provided: // 0 Do not change length of file (default) // -1 Truncate to present position // else Length is a double-precision length to use. // //WindowFlush(window) // Makes sure all dirty pages are on the disk. // //WindowChangeType(window,strategy [,file-type]) // Changes windowing strategy if strategy ne 0. // Changes file-type if file-type ne 0 (also flushes pages if type // indeed needs to be changed). // //WindowSetPosition(window,dppos) //WindowGetPosition(window,dppos) // Routines for setting and reading the (double-precision) file // position (units are words). // //WindowRead(window) //WindowWrite(window,value) // Routines for reading or writing a single (aligned) word. // //WindowReadBlock(window,address,length) //WindowWriteBlock(window,address,length) // Routines for reading or writing a vector of words. // //WindowReadByte(window) //WindowRead2Bytes(window) // Special routines for reading bytes (8-bit) from the file. // Warning: if file is left at an odd byte position, strange things // may happen on subsequent operations. // //WindowCopy(fromwindow,towindow,length) // Copies great quantities of data -- length is double-precision. // //In order to make efficient access to window buffers (rather than using // the read and write word routines, the following conventions are // available: // call window>>W.Offset the "offset" // call window>>W.Base the "base" // //To read a word: // if offset=0 then WindowNext(window,false) // w=base!offset // offset=offset+1 // //To write a word: // if offset=0 then WindowNext(window,true) // base!offset=w // offset=offset+1 // //For convenience, if WindowNext has additional arguments, they are the // addresses of "cached" values of window>>W.Offset and window>>W.Base, // and the cached values are fixed up. Note: the call WindowDirty(window) // is used after a bunch of writes with the above technique to mark the // current buffer dirty (this is also accomplished by making the WindowNext // argument "true"). // //Note: The buffer size used in a window and the page size of the under- // lying file need not be the same, but the code here assumes that they // are. get "pressinternals.df" // // outgoing procedures external [ WindowInit WindowClose WindowFlush WindowSetPosition WindowGetPosition WindowRead WindowWrite WindowReadBlock WindowWriteBlock WindowReadByte WindowRead2Bytes WindowNext WindowDirty WindowCopy ] // outgoing statics //external // [ // ] //static // [ // ] // incoming procedures external [ //Free storage FSGetX FSPut //PRESS PressError DblShift //PRESSML DoubleAdd; DoubleSub; DoubleCop //OS MoveBlock SetBlock Zero //File operations FileWritePage FileReadPage FileStuff ] // incoming statics //external // [ // ] // internal statics //static // [ // ] manifest [ WINDOWheader=(offset W.NumBlocks/16)+1 //Minimum header for window str. CLEAN=0 DIRTY=1 ] let WindowInit(file,numbuffers,strategy,filetype;numargs n) = valof //allocates window and numbuffers (default 1) page(s) //of core space. Initializes window information. //resultis window, a pointer to structure info. [ if n ls 2 then numbuffers=1 if n ls 3 then strategy=WINDOWNoStrategy if n eq 4 then file>>F.Type=filetype let pagesize=FileStuff(file) let window=FSGetX(WINDOWheader+numbuffers*(size block/16)) window>>W.BufSize=pagesize window>>W.LogBufSize=(pagesize eq 256)? 8,10 window>>W.CurBuf=1 window>>W.CurPN=-1 //So will start out at zero. window>>W.File=file window>>W.Offset=0 //So will trap right away. window>>W.WhichByte=0 window>>W.Strategy=strategy window>>W.NumBlocks=numbuffers for b=1 to numbuffers do [ window>>W.CoreAdr↑b=FSGetX(pagesize) window>>W.PN↑b=-1 window>>W.Age↑b=0 window>>W.Status↑b=CLEAN ] resultis window ] and WindowClose(window; numargs n) be [ if n gr 1 then [ PressError(500) WindowFlush(window); return ] WindowFlush(window) for b=1 to window>>W.NumBlocks do [ FSPut(window>>W.CoreAdr↑b) ] FSPut(window) ] and WindowFlush(window) be [ for b=1 to window>>W.NumBlocks do [ let pn=window>>W.PN↑b let ca=window>>W.CoreAdr↑b if window>>W.Status↑b eq DIRTY then FileWritePage(window>>W.File,pn,ca) ] ] and WindowChangeType(window,strategy,filetype; numargs n) be [ if n eq 2 then filetype=0 let f=window>>W.File if filetype ne 0 & filetype ne f>>F.Type then [ WindowFlush(window) //Flush dirty pages. f>>F.Type=filetype ] if strategy then window>>W.Strategy=strategy ] and WindowSetPosition(window,filepos) be [ let t=vec 1 t!0=(filepos!0)Ź //Mask off any "file number" code t!1=filepos!1 //Calculate word position: let wordnum=(t!1)&(window>>W.BufSize-1) window>>W.Offset=-window>>W.BufSize+wordnum window>>W.WhichByte=0 //Use new byte, left half //And page number: let page=DblShift(t,window>>W.LogBufSize) WindowSetUp(window,page) ] and WindowGetPosition(window,filepos) be [ if window>>W.CurPN eq -1 then [ filepos!0=0; filepos!1=0 //File at beginning. return ] let offsetv=vec 1 offsetv!0=0 offsetv!1=window>>W.BufSize+window>>W.Offset filepos!0=0 filepos!1=window>>W.CurPN DblShift(filepos,-window>>W.LogBufSize) DoubleAdd(filepos,offsetv) ] and WindowNext(window,dirtyflag,lvbase,lvoffset; numargs n) = valof [ let c=window>>W.CurBuf if dirtyflag then window>>W.Status↑c=DIRTY window>>W.Offset=-window>>W.BufSize WindowSetUp(window,window>>W.CurPN+1) //Next page! if n gr 2 then [ @lvbase=window>>W.Base @lvoffset=window>>W.Offset ] resultis window>>W.CurPN ] // Work-horse routine that sets up a window for access to a given page. // The Offset entry is assumed already set. and WindowSetUp(window,page) be [ //Find current page (if buffered, and around), or oldest one if not. let current=window>>W.CurBuf let curAge=window>>W.Age↑current let lowestAge=curAge let b=nil let found=false for nb=1 to window>>W.NumBlocks do [ if page eq window>>W.PN↑nb then [ b=nb found=true break ] if window>>W.PN↑nb eq -1 % window>>W.Age↑nb le lowestAge then [ lowestAge=window>>W.Age↑nb b=nb ] ] let ca=window>>W.CoreAdr↑b unless found then [ let pn=window>>W.PN↑b //If page we are replacing is dirty, write it out. if window>>W.Status↑b eq DIRTY & pn ne -1 then FileWritePage(window>>W.File,pn,ca) //Read in desired page (no-op if file is ReadOnly) FileReadPage(window>>W.File,page,ca) window>>W.PN↑b=page window>>W.Status↑b=CLEAN ] window>>W.Base=ca+window>>W.BufSize window>>W.Age↑b=curAge+1 window>>W.CurBuf=b window>>W.CurPN=page ] and WindowDirty(window) be [ let c=window>>W.CurBuf window>>W.Status↑c=DIRTY ] //Routines for reading and writing single and multiple words, using // the basic routines above. and WindowRead(window) = valof [ if window>>W.Offset eq 0 then WindowNext(window,false) let off=window>>W.Offset let rslt=(window>>W.Base)!off window>>W.Offset=off+1 resultis rslt ] and WindowWrite(window,value,Baselv,Offsetlv;numargs n) be [ if window>>W.Offset eq 0 then WindowNext(window,true) let off=window>>W.Offset (window>>W.Base)!off=value window>>W.Offset=off+1 window>>W.Status↑(window>>W.CurBuf)=DIRTY ] and WindowWriteBlock(W,corestart,length) be [ let off=W>>W.Offset if (length+off) le 0 then [ MoveBlock(W>>W.Base+off,corestart,length) W>>W.Offset=length+off WindowDirty(W) return ] unless off eq 0 do //Write out odd stuff in window space [ MoveBlock(W>>W.Base+off,corestart,-off) W>>W.Offset=0 //Ditto WindowDirty(W) ] let evenpages=(length+off) rshift W>>W.LogBufSize unless evenpages eq 0 do //Spew out all of these pages together [ let firstpage=W>>W.CurPN+1 let lastpage=firstpage+evenpages-1 FileWritePage(W>>W.File,firstpage,corestart-off,evenpages) for i=1 to W>>W.NumBlocks do//Invalidate old core copies of pages [ let thispage=W>>W.PN↑i if (thispage ge firstpage)&(thispage le lastpage) then W>>W.PN↑i=-1 ] W>>W.CurPN=lastpage ] let StillLeft=(length+off)&(W>>W.BufSize-1) //odd words left to write out unless StillLeft eq 0 do [ WindowNext(W,false) let off=W>>W.Offset MoveBlock(W>>W.Base+off,corestart+length-StillLeft,StillLeft) W>>W.Offset=off+StillLeft WindowDirty(W) ] ] and WindowReadBlock(W,corestart,length) be [ let off=W>>W.Offset if (length+off) le 0 then [ MoveBlock(corestart,W>>W.Base+off,length) W>>W.Offset=length+off return ] unless off eq 0 do //Read out odd stuff in window space [ MoveBlock(corestart,W>>W.Base+off,-off) W>>W.Offset=0 ] let evenpages=(length+off) rshift W>>W.LogBufSize unless evenpages eq 0 do //Spew in all of these pages together [ let firstpage=W>>W.CurPN+1 let lastpage=firstpage+evenpages-1 //some of the pages in the block to be read may already be in core //this is unlikely, however. Because most of the disk time is taken //in the initial SEEK, we'll write out any such pages in order to be //able to read in the whole contiguous block for i=1 to W>>W.NumBlocks do [ let P=W>>W.PN↑i if (P ge firstpage)&(P le lastpage)&(W>>W.Status↑i eq DIRTY) then FileWritePage(W>>W.File,W>>W.PN↑i,W>>W.CoreAdr↑i) ] FileReadPage(W>>W.File,firstpage,corestart-off,evenpages) W>>W.CurPN=lastpage ] let StillLeft=(length+off)&(W>>W.BufSize-1) //Odd words left to read in unless StillLeft eq 0 do [ WindowNext(W,false) let off=W>>W.Offset MoveBlock(corestart+length-StillLeft,W>>W.Base+off,StillLeft) W>>W.Offset=off+StillLeft ] ] and WindowCopy(fromw,tow,len) be [ let dp=vec 1 DoubleCop(dp,len) let b=vec 1024 let dl=table [ 0;1024 ] while dp!0 ge 0 do [ let l=dp!1 if DoubleSub(dp,dl) ge 0 then l=1024 WindowReadBlock(fromw,b,l) WindowWriteBlock(tow,b,l) ] ] and WindowReadByte(window) = valof [ window>>W.ByteCount=window>>W.ByteCount+1 test window>>W.WhichByte eq 0 then [ //Get a new word. window>>W.WhichByte=1 if window>>W.Offset eq 0 then WindowNext(window,false) resultis ((window>>W.Base)!(window>>W.Offset)) rshift 8 ] or [ //Right byte window>>W.WhichByte=0 let off=window>>W.Offset let a=((window>>W.Base)!off) Ź window>>W.Offset=off+1 resultis a ] ] and WindowRead2Bytes(window) = valof [ test window>>W.WhichByte eq 0 then [ //Read a whole word. window>>W.ByteCount=window>>W.ByteCount+2 resultis WindowRead(window) ] or [ resultis (WindowReadByte(window) lshift 8)+ WindowReadByte(window) ] ]