//
// OVERLAYSINIT.BCPL - initialize structures for OVERLAYS package
// last edited September 7, 1976  10:42 AM
//

	get "overlays.d"
	get "altofilesys.d"
	get "disks.d"

external	// procedures defined
[	OverlayScan	// (fptr, odvec, length[, fa, buf, bufsize, fixvec, fixsize]) -> npages/-1
	OverlayInit	// (odvec[, fixvec])
]

external	// procedures used
[		// O.S.
	SetBlock; MoveBlock; Zero
		// BFS
	ActOnDiskPages
]

external	// statics used
[		// O.S.
	sysDisk
]

structure ODV:	// first part of overlay vector
[	nov word	// # of overlays
	fp @FP	// FP for overlay file
]
manifest lODV = size ODV/16

manifest
[	MaxScanPages = 40
]

static
[	OVbuf	// page buffer
	OVbsize	// size of buffer in pages
	OVcurpn	// current first page in buffer
	OVcurnp	// current # of pages in buffer
	OVdas	// DA vector for pages in buffer +1
	OVfp	// overlay file FP
]


let OverlayInit(odv, fixv; numargs na) be
[	external	// in OVERLAYS
	 [ OverlayFp
	   OverlayFaults
	   @OverlayNumber
	   @OverlayFaultProc
	   FirstOD
	   LastOD
	 ]
	OverlayFp = lv odv>>ODV.fp
	OverlayFaults = odv+lODV
	let nov = odv>>ODV.nov
	SetBlock(OverlayFaults, #10000+lv OverlayNumber, nov)	// ISZ
	OverlayFaults!(nov-1) = #2000+lv OverlayFaultProc	// JMP @
	FirstOD = OverlayFaults+nov
	LastOD = FirstOD+(nov-1)*ODsize
	if na ge 2 then	// fix up swapped-out statics
	 [ let fixp, val = fixv, OverlayFaults
	   while @fixp ge 0 do
	    [ let nfixp = fixp+@fixp+1
	       [ fixp = fixp+1
	         if fixp eq nfixp break
	         (@fixp)!0 = val
	       ] repeat
	      val = val+1
	    ]
	 ]
]

let OverlayScan(fptr, odv, len, fa, pbuf, bsize, fixv, fsize; numargs na) = valof
[	// Initialize the work area
	Zero(odv, len)
	MoveBlock(lv odv>>ODV.fp, fptr, lFP)
	let maxovs = (len-lODV)/(ODsize+1)

	let mybuf = vec #402
	test (na ls 6) % (bsize ls #402)
	ifso OVbuf, OVbsize = mybuf, 1
	ifnot
	 [ OVbuf, OVbsize = pbuf, (bsize-1)/#401
	   if OVbsize gr MaxScanPages then OVbsize = MaxScanPages
	 ]
	OVdas = OVbuf+(OVbsize lshift 8)
	@OVdas = fptr>>FP.leaderVirtualDa
	OVcurpn, OVcurnp = 0, 0
	OVfp = fptr
	let buf = advancetopage(1, 2)	// read first data page
	let pn = buf!1+1
	if pn ls 2 resultis 0	// no overlays
	if na ge 4 then	// use fa
	 [ OVcurpn, OVcurnp, @OVdas = fa>>FA.pageNumber, 0, fa>>FA.da
	 ]
	let ovnum = 0
	let ofv = odv+lODV
	let fod = ofv+maxovs
	let od = fod
	let fixi = 0

	 [ if ovnum eq maxovs resultis -1
	   od>>OD.firstPn = pn
	   let buf = advancetopage(pn, MaxScanPages)
	   if buf eq 0 break
	   od>>OD.da = OVdas!((buf-OVbuf) rshift 8)
	   let skip = buf!1+#20
	   let npages = (buf!4+#377) rshift 8
	   let buf = advancetopage(pn + skip rshift 8, MaxScanPages)
	   let wn = skip&#377
	   let n = buf!wn
	   let nw = OVbuf+(OVcurnp lshift 8)-buf
	   if na ge 8 then
	    [ if fixi+n+1 ge fsize resultis -2
	      fixv!fixi = n
	      fixi = fixi+1
	    ]
	   for i = 1 to n do
	    [ wn = wn+1
	      if wn ge nw then
	       [ buf = advancetopage(OVcurpn+OVcurnp, MaxScanPages)
	         wn = wn-nw
	         nw = OVcurnp lshift 8
	       ]
	      let stat = buf!wn
	      @stat = ofv+ovnum
	      if na ge 8 then
	       [ fixv!fixi = stat
	         fixi = fixi+1
	       ]
	      wn = wn+1
	    ]
	   pn = pn+npages
	   ovnum = ovnum+1
	   od = od+ODsize
	 ] repeat

	MoveBlock(ofv+ovnum, fod, od+ODsize-fod)	// need 1 extra firstPn
	odv>>ODV.nov = ovnum
	OverlayInit(odv)
	if na ge 8 then fixv!fixi = -1
	resultis fixi+1
]

and advancetopage(newpn, npages) = valof
[	while newpn ge (OVcurpn+OVcurnp) do
     [	let nextda = OVdas!OVcurnp
	if nextda eq eofDA resultis 0
	OVcurpn = OVcurpn+OVcurnp
	let nsp0 = MaxScanPages-OVbsize
	let nsp1 = newpn-OVcurpn
	let nsp = (nsp0 ls nsp1? nsp0, nsp1)
	let np1 = nsp+OVbsize
	if npages gr np1 then npages = np1
	let CAs = vec MaxScanPages
	SetBlock(CAs, OVbuf, MaxScanPages)
	for i = 1 to OVbsize-1 do
	   CAs!(nsp+i) = OVbuf+(i lshift 8)
	let DAs = vec MaxScanPages+1
	DAs!0 = nextda
	SetBlock(DAs+1, fillInDA, MaxScanPages)
	let lastnc = nil
	let lastpn = ActOnDiskPages(sysDisk, CAs-OVcurpn, DAs-OVcurpn, OVfp, OVcurpn, OVcurpn+npages-1, DCreadD, lv lastnc)
	OVcurpn = OVcurpn+nsp
	OVcurnp = lastpn+1-OVcurpn
	MoveBlock(OVdas, DAs+nsp, OVcurnp+1)
	if lastnc eq 0 then
	 [ OVcurnp = OVcurnp-1; OVdas!OVcurnp = eofDA ]
     ]
	resultis OVbuf+(newpn-OVcurpn) lshift 8
]