// IfsIsf.bcpl -- implement indexed sequential files // Copyright Xerox Corporation 1979, 1980 // last modified February 26, 1980 3:53 PM by Taft // last modified October 1, 1979 6:13 PM by Wobber // last modified by Butterfield, October 26, 1979 1:21 PM get "IfsIsf.d" external // entry procedures [ IndexedPageIO // (fmap, firstpage, core, npg, wflag[, lastnc]) -> lastnc MorePageIO // (fmap, firstpage, scratch, npg, wflag) WriteFmap // (fmap) FreeFmap // (fmap) LookupFmap // (fmap, page, [force]) ] external [ // O.S. SetBlock; Zero CallSwat ActOnDiskPages WriteDiskPages DeleteDiskPages Allocate; Free Usc; Min; Max Dvec MoveBlock ] //--------------------------------------------------------------------------- let IndexedPageIO(fmap, firstpage, core, npg, wflag, lastnc; numargs na)=valof // wflag=-1 for write, 0 for read, 1 for read + extend // returns numchars of last page transferred //--------------------------------------------------------------------------- [ let action = (wflag ls 0? DCwriteD, DCreadD); let pagesize = 1 lshift fmap>>FM.disk>>DSK.lnPageSize; if na ls 6 then lastnc = pagesize*2; let extrapage = (wflag eq 0 % lastnc ls pagesize*2)? 0, 1; if Usc(firstpage+npg+extrapage, NextFmap(fmap)) gr 0 then MorePageIO(fmap, firstpage, core, npg+extrapage, wflag); let CAs = vec ppc+1; let DAs = vec ppc+1; // ppc+2 words! CAs!0 = core - pagesize; DAs!0 = (firstpage eq 0? eofDA, LookupFmap(fmap, firstpage-1)); DAs!1 = LookupFmap(fmap, firstpage); let pagesleft = npg; let nextDA = nil; let writeLast = wflag ls 0 & lastnc ls pagesize*2; if writeLast then [ nextDA = LookupFmap(fmap, firstpage+npg); if nextDA eq fillInDA then CallSwat("fillInDA nextDA"); //not read before! pagesleft = pagesleft - 1; ] let page = firstpage; let nch = nil; while pagesleft gr 0 do [ let np = Min(pagesleft, ppc); for j = 1 to np do [ CAs!j = CAs!(j-1)+pagesize; DAs!(j+1) = LookupFmap(fmap, page+j); ] ActOnDiskPages(fmap>>FM.disk, CAs+1-page, DAs+1-page, lv fmap>>FM.fp, page, page+np-1, action, lv nch); CAs!0 = CAs!np; DAs!0 = DAs!np; DAs!1 = DAs!(np+1); page = page+np; pagesleft = pagesleft-np; ] test writeLast ifnot if page eq NextFmap(fmap) then ExtendFmap(fmap, page, DAs!1); ifso [ CAs!1 = CAs!0 + pagesize; DAs!2 = eofDA; WriteDiskPages(fmap>>FM.disk, CAs + 1 - page, DAs + 1 - page, lv fmap>>FM.fp, page, page, DCwriteD, lv nch, lastnc); ExtendFmap(fmap, page + 1, eofDA); //shorten the map if nextDA ne eofDA then [ DeleteDiskPages(fmap>>FM.disk, CAs!1,nextDA, lv fmap>>FM.fp, page+1); ActOnDiskPages(fmap>>FM.disk, CAs+1-page, DAs+1-page, lv fmap>>FM.fp, page, page, DCreadD, lv nch); //read it back until we get DCZeroD ] ] resultis nch ] //--------------------------------------------------------------------------- and MorePageIO(fmap, firstpage, scratch, npg, wflag) be //--------------------------------------------------------------------------- [ if Usc(firstpage + npg, NextFmap(fmap)) le 0 then return; fmap>>FM.onern = firstpage; fmap>>FM.oneda = fillInDA //in case map is full let pagesize = 1 lshift fmap>>FM.disk>>DSK.lnPageSize let zone = fmap>>FM.zone if wflag eq -1 then test zone eq -1 ifso [ scratch = pagesize; Dvec(MorePageIO, lv scratch) ] ifnot scratch = Allocate(zone, pagesize) let lastpage = firstpage+npg-1; let lastmappage = NextFmap(fmap) let nch = nil; let page = lastmappage-1; let DAs = vec ppc+2 // ppc+3 words! if firstpage gr page then [ fmap>>FM.onern = firstpage; fmap>>FM.oneda = fillInDA ] DAs!0 = (page eq 0? eofDA, LookupFmap(fmap, page-1)); DAs!1 = LookupFmap(fmap, page) while page ls lastpage do [ let np = Min(ppc, lastpage-page); let lastxpage = page + np; SetBlock(DAs+2, fillInDA, np+1); let pageDA = DAs+1-page; let npage = ActOnDiskPages(fmap>>FM.disk, 0, pageDA, lv fmap>>FM.fp, page, lastxpage, DCreadD, lv nch, DCreadD, scratch) for xpage = page+1 to npage+1 do ExtendFmap(fmap, xpage, pageDA!xpage); page = npage; DAs!0 = pageDA!(page-1); DAs!1 = pageDA!page if page eq lastxpage loop //else extend the file unless (fmap>>FM.extend gr 0) & (wflag ne 0) do CallSwat("Attempt to access non-existent page") lastpage = Max(lastpage, page+fmap>>FM.extend) if nch ne 0 then [ pageDA = DAs+1-page; DAs!2 = eofDA ActOnDiskPages(fmap>>FM.disk, 0, pageDA, lv fmap>>FM.fp, page, page, DCreadD, lv nch, DCreadD, scratch) DAs!2 = fillInDA; DAs!3 = eofDA WriteDiskPages(fmap>>FM.disk, 0, pageDA, lv fmap>>FM.fp, page, page+1, DCwriteD, 0, 0, scratch) page = page+1; ExtendFmap(fmap,page,DAs!2); DAs!0 = DAs!1; DAs!1 = DAs!2 ] Zero(scratch, pagesize) while page ls lastpage do [ pageDA = DAs+1-page; np = Min(ppc, lastpage-page) SetBlock(DAs+2, fillInDA, np); (DAs+2)!np = eofDA WriteDiskPages(fmap>>FM.disk, 0, pageDA, lv fmap>>FM.fp, page, page+np, DCwriteD, 0, 0, scratch) for xpage=page+1 to page+np+1 do ExtendFmap(fmap, xpage, pageDA!xpage); page = page+np; DAs!0 = pageDA!(page-1); DAs!1 = pageDA!page ] break ] if NextFmap(fmap) gr lastmappage then WriteFmap(fmap) if (wflag eq -1) & (zone ne -1) then Free(zone, scratch) ] //--------------------------------------------------------------------------- and WriteFmap(fmap) be //--------------------------------------------------------------------------- if fmap>>FM.rewrite then ActOnDiskPages(fmap>>FM.disk, 0, lv fmap>>FM.DA0, lv fmap>>FM.fp, 1, 1, DCwriteD, 0, DCwriteD, fmap) //--------------------------------------------------------------------------- and LookupFmap(fmap, page, force; numargs n) = valof //--------------------------------------------------------------------------- [ if (page eq fmap>>FM.onern) & (fmap>>FM.oneda ne fillInDA) & ((n ls 3) % (not force)) resultis fmap>>FM.oneda let hi = fmap>>FM.last; let lo = mapoffset; fmap = fmap>>FM.fmap; switchon Usc(page, fmap!hi) into [ case 1: resultis fillInDA; case 0: resultis fmap!(hi+1); ] while hi-lo gr 2 do [ let mid = ((lo+hi) rshift 1) & -2 test Usc(page, fmap!mid) ge 0 ifso lo = mid ifnot hi = mid ] let lp = lv (fmap!lo) resultis (lp!1+page-@lp) ] //--------------------------------------------------------------------------- and ExtendFmap(fmap, page, da) = valof //--------------------------------------------------------------------------- [ if page eq fmap>>FM.onern then fmap>>FM.oneda = da; let last = fmap>>FM.last; let lastp = lv fmap>>FM.fmap!last; if da eq fillInDA then CallSwat("fillInDA ExtendFmap"); test da eq eofDA ifso [ if Usc(page, @lastp) gr 0 % page eq 0 then resultis false; [ lastp = lastp - 2; ] repeatuntil Usc(page, @lastp) gr 0; lastp!2=page; lastp!3=eofDA; fmap>>FM.last = lastp + 2 - fmap>>FM.fmap; ] ifnot [ if page ne @lastp then resultis false; test da eq (lastp!-1)+@lastp-(lastp!-2) ifso @lastp = @lastp+1; // still in same chunk ifnot [ if last eq fmap>>FM.end then test fmap>>FM.extendmap ifnot resultis false; // out of space ifso [ let maplength = fmap>>FM.end + lenMapEntry - mapoffset; let delta = fmap>>FM.extendmap + 1 & -2; let newMap = Allocate(fmap>>FM.zone, maplength + delta); MoveBlock(newMap, lv (fmap>>FM.fmap)>>FM.map, maplength); fmap>>FM.end = fmap>>FM.end + delta; FreeFmap(fmap); fmap>>FM.fmap = newMap - mapoffset; lastp = lv fmap>>FM.fmap!last; ] lastp!1 = da; lastp!2 = @lastp+1; lastp!3 = fillInDA; fmap>>FM.last = last+2; ] ] resultis true ] //--------------------------------------------------------------------------- and NextFmap(fmap) = fmap>>FM.fmap!(fmap>>FM.last) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- and FreeFmap(fmap) = valof //--------------------------------------------------------------------------- [ if fmap>>FM.fmap ne fmap then Free(fmap>>FM.zone, fmap>>FM.fmap + mapoffset); resultis fmap; ]