// Dirs.sr

// Last modified October 25, 1979  8:36 PM by Taft

get "BFS.DEF";
get "bravo1.df";
get "q.DF";
get "st.DF";
get "AltoFileSys.d";
get "VM.DF";
get "dir.DF";
// Incoming Procedures

external [
	movec;
	move;
	flushvm;
	Enqueue;
	remakevmtb;
	ScanPages;
	errhlta
	Dequeue;
	umin;
	sbwsize;
	ugt;
	ult;
	RealDA
	min;
	divmod;
	stput;
	stcopy;
	AllocVm;
	];

// Incoming Statics

external [
	dnbp;
	macbp;
	rgvpa;
	fpSysDir;
	rgbs
	diskKd
	rglastused
	defaultVersionsKept
	];

// Outgoing Procedures

external [
	FindFptr;
	NormalizeSbFile;
	FMatchDe;
	DirLkup;
	InitNmd;
	VerNext;
	AppendVer;
	];


manifest	[ 
	pidLlNmd = 5
	pidCwRem = 8
	pidBuf = 9
	pidFnewDe = 10
	pidCwNeeded = 11
	pidCwRead = 12
	pidDe = 13
	pidWaDe = 14
	pidCwMac = 15
	waNil = -1
	] 

// F I N D F P T R
//
let FindFptr(cfaDirEnd,llNmd,mpPgnDa,pgnMax) be
[ let cwRem = 0; let buf = 0; let fnewDe = true; let cwNeeded = nil;
let cwRead = 0; let de = vec ldeMax; let waDe = nil; let cwMac = nil

let fptrDir = lv (cfaDirEnd >> CFA.fp)
// SortAndNorm(llNmd)
cfaDirEnd >> CFA.fa.da = RealDA(cfaDirEnd >> CFA.fp.leaderVirtualDa);
cfaDirEnd >> CFA.fa.pageNumber = 0;
let poolBuf = vec maxbp*lBuf
let qBufFree = vec lQ; AllocVm(qBufFree,poolBuf,4);
let tc = ScanPages(cfaDirEnd,qBufFree,TcCollectDe,mpPgnDa,pgnMax)
] 

// S O R T A N D N O R M
// the sort got tossed as not worth it
// and SortAndNorm(llNmd) = valof
// [ let nmd = @llNmd
// while nmd ne 0 do
// 	[ let sbFile = lv nmd >> NMD.asbFile
// 	NormalizeSbFile(sbFile,lv nmd >> NMD.ver)
// 	if nmd >> NMD.ver ne 0 then nmd >> NMD.vc eq vcExact
// 	let nmdNext = nmd >> NMD.next;
// 	let pLinkPrev = lv tll 
// 		[ let nmd1 = @pLinkPrev
// 		let comp = valof
// 			[ if nmd1 eq 0 then
// 				resultis 1
// 			let tsb = lv nmd1 >> NMD.asbFile
// 			for i = 0 to sbwsize(sbFile)-1 do
// 				[ let td = sbFile ! i-tsb ! i
// 				unless td eq 0 then
// 					resultis td
// 				] 
// 			resultis 0
// 			] 
// 		if comp eq 0 then errhlt("sb=")
// 		if comp gr 0 then
// 			[ nmd >> NMD.next = nmd1
// 			@pLinkPrev = nmd
// 			break
// 			] 
// 		pLinkPrev = @pLinkPrev
// 		] repeat
// 	nmd = nmd >> NMD.next
// 	] 
// ] 

// T C C O L L E C T D E
//
and TcCollectDe(zone,Freturn) = valof
[ let scanParams = zone >> CBZ.extra
let fm = scanParams >> SCP.fmCaller
let de = fm ! pidDe
	[ if Freturn(zone) then
		resultis tcNotDone;
	if fm ! pidCwRem le 0 then
		[ if fm ! pidCwRem ls 0 then errhlta(198)
		unless fm ! pidBuf eq 0 then
			[ Enqueue(scanParams >> SCP.qBufFree,fm ! pidBuf)
			if ((fm ! pidBuf) >> BUF.numChars ne #1000) then
				resultis tcDone
			] 
		fm ! pidBuf = Dequeue(scanParams >> SCP.qBufRead)
		test fm ! pidBuf eq 0 ifnot
			[ fm ! pidCwRem = ((fm ! pidBuf) >> BUF.numChars) rshift 1
			fm ! pidCwMac = fm ! pidCwRem
			] 
		ifso	resultis tcToYou
		] 
	let bcw = fm ! pidCwMac-fm ! pidCwRem
	let ca = (fm ! pidBuf) >> BUF.ca+bcw
	if fm ! pidFnewDe then
		[ fm ! pidCwNeeded = ca >> DE.l
		fm ! pidFnewDe = false
		fm ! pidCwRead = 0
		@de = @ca
		if fm ! pidCwNeeded eq 0 then resultis tcDone
		fm ! pidWaDe = (((fm ! pidBuf) >> BUF.pgn-1) lshift 8)+bcw
		] 
	let tcw = umin(fm ! pidCwNeeded,fm ! pidCwRem)
	unless de >> DE.ty eq tyDeFree then
		move(ca,de+fm ! pidCwRead,tcw)
	fm ! pidCwNeeded = fm ! pidCwNeeded-tcw
	fm ! pidCwRem = fm ! pidCwRem-tcw
	fm ! pidCwRead = fm ! pidCwRead+tcw
	if fm ! pidCwNeeded eq 0 then
		[ FMatchDe(de,fm ! pidWaDe,fm ! pidLlNmd)
		fm ! pidFnewDe = true
		] 
	] repeat
] 

// F M A T C H D E
//
and FMatchDe(de,waDe,llNmd) = valof
[ let ver = nil; let nmd = @llNmd
while nmd ne 0 do
	[ test de >> DE.ty eq tyDeFree ifso
		[ if (de >> DE.l gr nmd >> NMD.ldeFree) & (nmd >> NMD.waDeFree eq waNil) then
			[ nmd >> NMD.waDeFree = waDe
			resultis false
			] 
		] 
	ifnot	[ if de >> DE.l gr ldeMax then errhlta(199)
		let tsb = lv nmd >> NMD.asbFile
		let feq = valof
			[
// this check is just for efficiency
			unless (de>>DE.asbFile.ch↑0 & 137B) eq (tsb>>SB.ch↑0 & 137B) resultis false
			let sbFile = lv de >> DE.asbFile;
			NormalizeSbFile(sbFile,lv ver)
			if ver eq 0 then ver = 1
			let cwSb = sbwsize (sbFile)
			for i = 0 to cwSb-1 do
				[
				unless (sbFile!i & 157737B) eq (tsb!i & 157737B) then
					resultis false
				] 
			resultis true
			] 

		if feq then
			[ let vcWanted = nmd >> NMD.vc
			let fmove = false
			if (vcWanted eq vcExact) then
				test (ver eq nmd >> NMD.ver) ifso
					fmove = true
				ifnot	resultis false
			nmd >> NMD.cver = nmd >> NMD.cver+1
			unless ugt(ver,nmd >> NMD.verMin) then
				[ nmd >> NMD.verMin = ver
				if vcWanted eq vcOldest then
					fmove = true
				] 
			unless ult(ver,nmd >> NMD.verMac) then
				[ nmd >> NMD.verMac = ver
				if vcWanted eq vcNewest then
					fmove = true
				] 
			if fmove then
				[ nmd >> NMD.ver = ver
				nmd >> NMD.waDe = waDe
				move(lv de >> DE.afptr,lv nmd >> NMD.afptr,lFP)
// 				resultis false
				] 
// 			resultis false
			] 
		] 
	nmd = nmd >> NMD.next
	] 
resultis false
] 

// N O R M A L I Z E S B F I L E
//
and NormalizeSbFile(sbFile,lvver,sbDest; numargs na) be
[ if na ls 3 then sbDest = sbFile
let fversOn = defaultVersionsKept ne 0
let ver = 0; let finVer = false; let ichLast = nil
let lsb = sbFile >> SB.cch
let ch = nil
for ich = 0 to lsb-1 do
	[ ch = sbFile >> SB.ch ↑ ich
//	sbDest >> SB.ch ↑ ich = ch % #40
	test ch eq $. ifso
		loop
	ifnot	test (ch eq $!) & fversOn ifso
		[ ver = 0
		ichLast = ich
		finVer = true
		] 
	ifnot	test finVer & (ch le $9) & (ch ge $0) ifso
		ver = ver*10+(ch-$0)
	ifnot	[ finVer = false; ver = 0]
	] 
unless finVer & (ver ne 0) then ichLast = lsb-((ch eq $.) ? 1,0)
sbDest >> SB.ch ↑ ichLast = $.
sbDest >> SB.cch = ichLast+1
if ichLast << odd then
	sbDest >> SB.ch ↑ (ichLast+1) = 0
// if ver eq 0 then ver = 1
if na gr 1 then @lvver = ver
] 

// D I R L K U P
//
// and DirLkup(sb,nmd,mpPgnDa,pgnMax; numargs na) = valof
// [ FindFptr(fpSysDir,lv nmd,mpPgnDa,pgnMax)
// resultis (nmd >> NMD.cver gr 0)
// ] 

// I N I T N M D
// 
and InitNmd(nmd,lnmd,sb,vc) be
[ if vc eq vcNew then vc = vcOldest
if vc eq vcNewestOrNew then vc = vcNewest
movec(nmd,nmd+lnmd-1,0)	// inits cver, ver, vermin, etc
nmd >> NMD.verMin = -1
nmd >> NMD.vc = vc
nmd >> NMD.waDeFree = waNil
let sbFile = lv nmd >> NMD.asbFile
stcopy(sbFile,sb)
nmd >> NMD.next = 0
NormalizeSbFile(sbFile,lv nmd >> NMD.ver)
let lsb = sbwsize(sbFile)
nmd >> NMD.ldeFree = ovhDe+lsb+3
if nmd >> NMD.ver ne 0 then nmd >> NMD.vc = vcExact
] 

// V E R N E X T
//
and VerNext(nmd) = valof
[ if defaultVersionsKept eq 0 then resultis 1
if nmd >> NMD.cver eq 0 then resultis 1
resultis nmd >> NMD.verMac+1
] 

// A P P E N D V E R
//
and AppendVer(sbFile,ver) be
[ if (defaultVersionsKept eq 0) then return
if ver eq 0 then ver = 1
let ich = sbFile >> SB.cch
if (sbFile >> SB.ch↑(ich-1)) eq $. then
	ich = ich-1
stput(sbFile,ich, $!)
ich = ich+1
divmod(ver,1000,lv ver)
let divor = 100; let fstarted = false
while divor ne 0 do
	[ let digit = divmod(ver,divor,lv ver)
	divor = divor/10
	if fstarted % (digit ne 0) then
		[ stput(sbFile,ich,digit+$0)
		ich = ich+1
		fstarted = true
		] 
	] 
stput(sbFile,ich, $.)
sbFile >> SB.cch = ich+1
]