// file.sr


get "BFS.DEF";
get "BRAVO1.DF";
get "CHAR.DF";
get "ALTOFILESYS.D";
get "VM.DF";
get "ST.DF";
get "DIR.DF";
get "COM.DF";
get "RN1.DF";


// Incoming Procedures

external	[
	InitNmd
	move
	stappend
	FindFptr
	SetVab
	VerNext
	SetRegionW
	stcopy
	ReName
	stsize
	hpalloca
	AppendVer
	RealDA
	movec
	setmacfp
	readformattedfile
	ActOnPages
	errhlta
	sbwsize
	CreateFile
	gets
	puts
	flushfn
	trims
	inheap
	hpfree
	doDc
	ReadCalendar
	ckdoc
	remakevmtb
	stcompare
	];

// Incoming Statics

external	[
	diskKd
	cfaSysDirEnd
	mpfnof
	vrlwsys
	fillInDA
	macfda
	DCread
	dnbp
	vfloppy
	rgmpbifc
	rgmpbifb
	vkcb
	DCwrite
	macbp
	rgvpa
	rglastused
	fpSysLog
	vfIniting
	];

// Outgoing Procedures

external	[
	FtyOpen;
	opens;
	fnalloc;
	closes;
	deallocfn;
	fCkFilePtr;
	LeaderPage;
// 	BrMakeLogEntry
	updateofs;
	BravoCreateFile;
	TryOpenLog;
	];

// Outgoing Statics

external	[
	mpfnsb;
	vpos;
	vdeltafp;
	vformattedfile;
	rgcfn;
	macfn;
	vnewfile
	vFNoLog
	defaultVersionsKept
	]; 

// Local Statics

static	[
	mpfnsb;
	vpos;
	vdeltafp;
	vformattedfile;
	rgcfn;
	macfn;
	vnewfile
	vFNoLog
	defaultVersionsKept
	];


structure KLABEL:
	[ next	word
	previous	word
	blank	word
	numchars	word
	pgn	word
	version	word
	sn	word 2
	] 

manifest	[ lnklabel = (size KLABEL)/16
	DcCkHeaderCkLabelRdData = #44120;
	] 

manifest	[ 
	cvmneeded = 2;
	] 

// O P E N
// catalogue no. = 124
let FtyOpen(fn, sb, wf, wmode, vc, fptrHint, fOflowOk, vecNmd, vecNmdDollar; numargs na) = valof
[ switchon na into
	[ 
case 3:	wmode = false
case 4:	vc = vcNewest;
case 5:	fptrHint = 0;
case 6:	fOflowOk = false;
	] 
let fty = ftyOld;
let tstream = nil;
let tchar = nil;
let fCreatedFile = false
let nverKept = defaultVersionsKept
let nmd = vec lnmdMax;
if (na gr 7) then nmd = vecNmd
let nmdDollar = vec lnmdMax;
if (na gr 8) then nmdDollar = vecNmdDollar
let nmdNeed = nmd
InitNmd(nmd,lnmdMax,sb,vc)
updateofs()
unless mpfnof ! fndir eq ofNil then 
	deallocfn(fndir);

if vc eq vcNew then
	[ if (nverKept eq 0) then
		[ move(nmd,nmdDollar,lnmdMax)
		let tsbFile = lv nmdDollar >> NMD.asbFile
		tsbFile >> SB.cch = tsbFile >> SB.cch-1
		stappend(tsbFile,"$.")
		nmd >> NMD.next = nmdDollar
		unless FnInBravo(nmdDollar) ne fnnil then
			nmdNeed = nmdDollar
		] 
	] 
test (fptrHint ne 0) & fCkFilePtr(fptrHint) ifso
	move(fptrHint,lv nmdNeed >> NMD.afptr,lFP) 
ifnot	[ let mpPgnDa = vec #100; 
	FindFptr(cfaSysDirEnd,lv nmd,mpPgnDa,#100)
	let fCreateFile = valof
		[ if vc eq vcNewestOrNew then
			resultis (nmdNeed >> NMD.cver eq 0)
		unless vc eq vcNew then
			resultis false
		if nmd >> NMD.cver eq 0 then
			nmdNeed = nmd;
		if FnInBravo(nmdNeed) ne fnnil then
			[ test (nverKept eq 0) % (nmdNeed >> NMD.vc eq vcExact) ifso
				[
//			"Can't write on that file - Command terminated"
				SetVab(abmsg, false, 43, 50)
// I want to return from open, not valof - so I kludge
				nmdNeed >> NMD.cver = 0
				resultis false
				] 
			ifnot	resultis true
			] 
		if nmdNeed >> NMD.cver eq 0 then resultis true
// for either old or new system
		if nmdNeed >> NMD.vc eq vcExact then
			[ fty = ftyOverwrite
			resultis false
			] 
		if nmdNeed >> NMD.cver ls nverKept then
			resultis true
		unless nmdNeed eq nmdDollar then
			fty = ftyNewOnOld
		resultis false
		] 
	test fCreateFile ifnot
		if nmdNeed >> NMD.cver eq 0 then
			[
//		"File foo not found - Command terminated"
			unless vfIniting then
				[ SetRegionW(vrlwsys, 0, sb)
				let rid = nil
				rid<<RID.nrl = 1
				rid<<RID.ri = 0
				SetVab(abmsg, false, 207, rid, 208, 50)
				]
			resultis ftyNil
			]
	ifso	[ if mpfnof ! fndir eq ofNil then 
			[ let pgnMac = cfaSysDirEnd >> CFA.fa.pageNumber
			opens(fndir,lv cfaSysDirEnd >> CFA.fp,true,true,false,false,pgnMac+2)
			let ofDir = mpfnof ! fndir;
			move(mpPgnDa,lv ofDir >> OF.rgda,pgnMac+1)
			ofDir >> OF.macpos = ((pgnMac-1) lshift 9)+cfaSysDirEnd >> CFA.fa.charPos
			] 
		unless nmdNeed >> NMD.vc eq vcExact then
			nmdNeed >> NMD.ver = VerNext(nmdNeed)
		BravoCreateFile(nmdNeed,true)
		fCreatedFile = true;
		fty = (nverKept eq 0) ? ftyNewFile,ftyNewVer
		] 
// 	BrMakeLogEntry(lv nmdNeed>>NMD.afptr,fCreatedFile ? typLogCreateFile,typLogOpenFile)
	if vc eq vcNew then 
		test nmdNeed eq nmdDollar ifso
			[ fty = ftyNewOnDollar
			let tsbFile = vec 30;
			stcopy(tsbFile,lv nmdDollar >> NMD.asbFile)
			ReName(nmdDollar,lv nmd >> NMD.asbFile,0)
			ReName(nmd,tsbFile,0)
			] 
		ifnot	if  fty eq ftyNewOnOld then
			ReName(nmd,lv nmd >> NMD.asbFile,VerNext(nmd))
	] 
unless opens(fn, lv nmdNeed>>NMD.afptr, wf, wmode, fCreatedFile, fOflowOk) do
	[
// "File too long - Command terminated"
	SetVab(abmsg, false, 44, 50)
	resultis ftyNil;
	] 
let siz = (stsize(sb)+8) rshift 1;
mpfnsb ! fn = hpalloca(siz);
(mpfnsb ! fn) ! 0 = 0;
stcopy(mpfnsb ! fn,lv nmdNeed >> NMD.asbFile);
AppendVer(mpfnsb ! fn,nmdNeed >> NMD.ver)
resultis fty;
]

and opens(fn,fptr,wf,wmode,fCreatedFile,fOflowOk,macfp; numargs na) = valof
[ switchon na into
	[ 
case 4:	fCreatedFile = false
case 5:	fOflowOk = false;
case 6:	macfp = 40
	] 
let tof = hpalloca(ofsiz+400);
tof >> OF.version = fptr >> FP.version;
move(lv fptr >> FP.serialNumber,lv tof >> OF.sn1,lSN)
tof >> OF.wf = wf;
tof >> OF.wmode = wmode;
tof >> OF.rgda = RealDA(fptr >> FP.leaderVirtualDa);
tof >> OF.pos = 0;
tof >> OF.macfp = 400;
tof >> OF.bphint = 1;
tof >> OF.fFullPages = false;
let rgda = lv (tof >> OF.rgda);
let lastpage = nil;
let numcharslast = nil;
let numcharsfullpages = nil;
movec(rgda+1,rgda+400,fillInDA);
tof >> OF.formatted = (vformattedfile & not wmode);
tof >> OF.macbi = 0;
tof >> OF.fda = macfda
mpfnof ! fn = tof;
test wf ifnot
	[ test tof >> OF.formatted ifnot
		lastpage = ActOnPages(0,rgda,lv(tof >> OF.fileid),0,400,DCread,lv numcharslast,0,dnbp ! bpbuff,0)
	ifso	lastpage = readformattedfile(fn,lv numcharslast);
	if (lastpage gr #200) & (fOflowOk eq false) then
		[ deallocfn(fn)
		resultis false;
		] 
	test lastpage ifso
		numcharsfullpages = (lastpage-1) lshift 9
	ifnot	numcharsfullpages = 0;
	(mpfnof ! fn) >> OF.macpos = numcharsfullpages+numcharslast;
	setmacfp(fn,lastpage+1);
	] 
ifso	[ tof >> OF.macpos = 0;
	setmacfp(fn,macfp);
	] 
LeaderPage(fptr, 0, wf eq 0)
macfda = macfda+(mpfnof ! fn) >> OF.macfp
if vfloppy & (macfda << FDA.track gr 77) then errhlta(185)
resultis true;
] 
// C R E A T E  
// 
// and Create(fn,sb,wf,wmode, fptrHint; numargs n) = valof
// [ if n ls 5 then fptrHint = 0
// vnewfile = false;
// // whats the deal on these 2 results?
// unless open(fn,sb,wf,wmode,vcNew,fptrHint) then resultis false
// resultis vnewfile;
// ] 



// B R A V O C R E A T E F I L E
//
and BravoCreateFile(nmd,fcreateOnDisk) be
	[ let tsbFile = vec 30; movec(tsbFile,tsbFile+29,0)
	stcopy(tsbFile,lv nmd >> NMD.asbFile)
	AppendVer(tsbFile,nmd >>NMD.ver)
	if mpfnof ! fndir eq ofNil then errhlta(186)
	let posMac = (mpfnof ! fndir) >> OF.macpos
	let cwDe = (offset DE.asbFile)/16+sbwsize(tsbFile);
// 	let cwDe = nmd >> NMD.ldeFree;
	let t = nmd >> NMD.waDeFree
	let posHole = (t eq -1) ? posMac,t lshift 1
	let b = dnbp!0
	test fcreateOnDisk ifso CreateFile(tsbFile,lv nmd >> NMD.afptr,b)
	ifnot	[ let posOld = nmd >> NMD.waDe lshift 1
		(mpfnof ! fndir) >> OF.pos = posOld;
		let t = gets(fndir);
		t << DE.ty = tyDeFree
		(mpfnof ! fndir) >> OF.pos = posOld;
		puts(fndir,t);
		] 
	let cwHole = 0;
	if posHole ne posMac then
		[ let tpos = posHole
			[ (mpfnof ! fndir) >> OF.pos = tpos;
			let t = gets(fndir);
			if t << DE.ty ne tyDeFree then errhlta(187)
			cwHole = cwHole+t << DE.l;
			tpos = tpos+((t << DE.l) lshift 1);
			] repeatwhile (cwHole ls cwDe)
		] 
	nmd >> NMD.waDeFree = posHole rshift 1;
	(mpfnof ! fndir) >> OF.pos = posHole;
	let t = nil; t << DE.l = cwDe; t << DE.ty = tyDeFile
	puts(fndir,t)
	let tp = lv nmd >> NMD.afptr
	for i = 0 to lFP-1 do
		puts(fndir,tp ! i);
	for i = lFP to cwDe-2 do
		puts(fndir,tsbFile ! (i-lFP));
	if cwDe ls cwHole then
		[ 
//		(mpfnof ! fndir) >> OF.pos = posHole;
		puts(fndir,cwHole-cwDe);
// 		posHole = posHole+((cwHole-cwDe) lshift 1);
		] 
	nmd >> NMD.waDe = nmd >> NMD.waDeFree
	flushfn(fndir);
	] 

// F N A L L O C
// catalogue no. = 128
and fnalloc( ) = valof
[ for fn = minuserfn to maxfn-1 do
	if mpfnof ! fn eq -1 then resultis fn;
resultis -1;
] 

// C L O S E S 
//
and closes(fn) be
[ if (mpfnof ! fn) >> OF.wf then
	[ flushfn(fn);
	trims(fn);
	(mpfnof ! fn) >> OF.wf = false;
	] 
]


// D E A L L O C F N 
//
and deallocfn(fn) be
[ if inheap(mpfnof ! fn) then
	hpfree(mpfnof ! fn);
if inheap(mpfnsb ! fn) then
	hpfree(mpfnsb ! fn);
mpfnsb ! fn = 0;
mpfnof ! fn = -1;
unless rgmpbifc ! fn eq 0 then
	[ hpfree(rgmpbifc ! fn);
	rgmpbifc ! fn = 0;
	] 
unless rgmpbifb ! fn eq 0 then
	[ hpfree(rgmpbifb ! fn);
	rgmpbifb ! fn = 0;
	] 
] 


// F C K F I L E P T R
//
and fCkFilePtr(filePtr) = valof
[ let klabel = vec lnklabel;
for i = 1 to 5 do
	[ movec(klabel,klabel+lnklabel-1,0);
	move((lv (filePtr>>FP.serialNumber)),(lv (klabel>>KLABEL.sn)),2)
//	klabel>>KLABEL.pgn = 0; ** done by movec !
	klabel>>KLABEL.version = filePtr>>FP.version
	doDc(RealDA(filePtr>>FP.leaderVirtualDa), DcCkHeaderCkLabelRdData, klabel);
	while (rv nextDiskCommand) ne 0 do loop
	if (vkcb>>KCB.status & DSgoodStatusMask) eq DSgoodStatus then
		resultis true
	] 
resultis false;
] 

// L E A D E R P A G E
//
and LeaderPage(fptr, nmd, fRead; numargs n) be // **
	[
	switchon n into
		[ 
case 1:		nmd = 0;
case 2:		fRead = false
		] 
	let b = vec (chperpage/2);
	let mpPgnDa = vec 2;
	mpPgnDa ! 0 = RealDA(fptr >> FP.leaderVirtualDa)
	let fileid = vec 3; fileid ! 0 = fptr >> FP.version
	move(lv fptr >> FP.serialNumber,fileid+1,lSN)
	ActOnPages(0, mpPgnDa, fileid,
		0, 0, DCread, 0, 0, b, 0)
	unless nmd eq 0 then
		[ let sbFile = lv nmd >> NMD.asbFile
		move(sbFile, lv b>>LD.name, sbwsize(sbFile))
		AppendVer(lv b>>LD.name,nmd >> NMD.ver)
		] 
	let todCur = vec lntod
	ReadCalendar(todCur)
	test fRead ifso
		move(todCur,lv b>>LD.read,lntod)
	ifnot	[
		move(todCur,lv b>>LD.written,lntod)
		move(todCur,lv b>>LD.created,lntod)
		]
	ActOnPages(0, mpPgnDa, fileid,
		0, 0, DCwrite, 0, 0, b, 0)
	]

// Make log entries -- but not references to system files.

// and BrMakeLogEntry(fptr,logType,fptrNew; numargs na) be
// 	[
// 	TryOpenLog()
// 	if vFNoLog then return
// 	let  sn = lv fptr >> FP.serialNumber
// 	unless (sn>>SN.nolog eq 0) then return
// 
// 	let ofLog = mpfnof ! fnLog
// 	ofLog>>OF.pos = ofLog>>OF.macpos
// 	let a=vec lLOGV+lFP
// 	movec(a,a+lLOGV-1,0)
// 	let fp = lv a>>LOGV.fp
// 	move(fptr,fp,lFP)
// 	ReadCalendar(lv a>>LOGV.time)
// 	a>>LOGV.type=logType
// 	let ln = lLOGV
// 	if logType eq typLogRenameFile then
// 		[ unless na eq 3 then errhlta(188);
// 		move(fptrNew,a+lLOGV,lFP)
// 		ln = ln+lFP
// 		] 
// 	a>>LOGV.length=ln
// 	for i = 0 to a>>LOGV.length-1 do
// 		puts(fnLog,a ! i)
// 	flushfn(fnLog)
// 	]


// U P D A T E O F S
// 
and updateofs( ) be
[ ckdoc( );
for fn = minuserfn to maxfn-1 do
	[ if fnscr eq fn then errhlta(189);
	if (rgcfn ! fn eq 0) & (mpfnof ! fn ne -1) & not (mpfnof ! fn) >> OF.wf & not (mpfnof ! fn) >> OF.wmode do
		deallocfn(fn);
	] 
for bp = 0 to macbp-1 do
	if mpfnof ! ((rgvpa+bp) >> VPA.fn) eq -1 then
		[ rgvpa ! bp = -1;
		rglastused ! bp = 1;
		] 
remakevmtb( );
] 

// F I N B R A VO
//
and FnInBravo(nmd) = valof
[ let sbFile = vec 30
stcopy(sbFile,lv nmd >> NMD.asbFile)
AppendVer(sbFile,nmd >> NMD.ver)
for fn = minuserfn to maxfn-1 do
	if mpfnof ! fn ne -1 do
		if stcompare(sbFile,mpfnsb ! fn) eq 0 then
			resultis fn 
resultis fnnil
] 

// T R Y O P E N L O G
//
// and TryOpenLog() be
// [ if vFNoLog then return
// if mpfnof ! fnLog eq ofNil then
// 	[ vFNoLog = true
// 	(mpfnof ! fndir) >> OF.wf = true;
// 	if FtyOpen(fnLog,"SYS.LOG",false,true,vcNewest,fpSysLog) eq ftyNil then
// 		return
// 	(mpfnof ! fnLog) >> OF.wf = true;
// 	vFNoLog = false
// 	] 
// ]