// Files.bcpl - derived from Files.bcpl (Press) 2/7/83   

// errors 400
//
//Disk i/o for PD printer
//
//A "file" is described by a structure. Files must be initialized by the
// user, as the structure contains data required from a directory
// (see PressInit for initialization)
//
//
//FileStuff(file,dp)
//	Returns in dp (double precision) the file size, in words.
//	Returns as value the page size.
//
//FileVDA(file,page)
//	Returns virtual disk address of the given page of the file.
//
//FileChangeType(file,filetype)
//	Changes file type
//
//FileReadPage(file,page,coreaddress[,cnt[,lvdoneflag]])
//	Reads a number of pages from the file.  "Page" starts numbering
//	at 0.  Cnt is the number of pages to read; default 1.
//	Lvdoneflag, if provided, means that the routine is not to wait until
//	the transfer is complete, but should return immediately, and set
//	@lvdoneflag=true when the transfer completes.
//
//FileWritePage(file,page,coreaddress[,cnt[,lvdoneflag]])
//	Similar, but for writing pages.
//
//A note about how "files" on the Model 31 are represented:
// Since every file that PRESS printing deals with is an integral number
// of pages long, we conform to the operating system conventions for such
// files.  That is:
//	-- a leader page
//	-- n useful pages
//	-- a final page with the "number of chars" =0
// The table of disk addresses recorded in the F structure is for
// all three kinds.  Hence there are +1's in various places.


get "PDInternals.d"
get "AltoFileSys.d"
get "Disks.d"
get "IfsIsf.d"

// outgoing procedures
external
	[
	FileReadPage
	FileWritePage
	FileStuff
	FileChangeType
	FileVDA
	]

// outgoing statics
//external
//	[
//	]
//static
//	[
//	]

// incoming procedures
external
	[
//METER
	MeterBlock

//PDPRINT
	DblShift
	PDError

//BFS for Model 31
	ActOnDiskPages

//IfsIsf
	LookupFmap
	]

// incoming statics
external
	[
	sysDisk
	tridentVec
	]

// internal statics
//static
//	[
//	]

// File-wide structure and manifest declarations.


// Procedures

let FileStuff(file,length; numargs n)=valof
 [
   if n ne 1 then
     [
      length!0=0
      length!1=file>>F.Pagecnt
      DblShift(length,-file>>F.LogPagesize)
     ]
   resultis file>>F.Pagesize
 ]

and FileChangeType(file,type) be
 [
   file>>F.Type=type
 ]

//----------------------------------------------------------------------------
and FileVDA(file, page) = valof
//----------------------------------------------------------------------------
[
let pageCount = nil;
test file>>F.Name eq FILEBits
   ifnot pageCount = file>>F.Pagecnt;
   ifso
      [
      let device = file>>F.Device;
      let disk = (device ge DISKT80? tridentVec!(device - 2), sysDisk);
      if disk eq 0 then PDError(401);
      pageCount = file>>F.Pagecnt lshift (10 - disk>>DSK.lnPageSize);
      ]
if page ge pageCount then PDError(403, file>>F.Name);
let fda = file>>F.DAFirst;
if fda then resultis fda + page;
let fmap = lv file>>F.fmap;
fmap>>FM.fmap = fmap;  // assure that fmap is current
resultis LookupFmap(fmap, page + 1);
]

and FileReadPage(file,page,coreaddress,cnt,lvdoneflag;numargs n) be
 [
   if file>>F.Type eq FILEWO then return	//No need to read
   FileDoPage(file,page,coreaddress,cnt,lvdoneflag,n,DCreadD)
 ]

and FileWritePage(file,page,coreaddress,cnt,lvdoneflag;numargs n) be
 [
   if file>>F.Type eq FILERO then PDError(400)
   FileDoPage(file,page,coreaddress,cnt,lvdoneflag,n,DCwriteD)
 ]

and FileDoPage(file,page,coreaddress,cnt,lvdoneflag,n,how) be
 [
   if n ls 4 then cnt=1
   let flg=nil
   if n ls 5 then lvdoneflag=lv flg
   compileif MeterSw then
     [
      let b=vec (size FLStat/16)
      b>>FLStat.File=file>>F.Name
      b>>FLStat.Cnt=cnt
      b>>FLStat.Page=page
      MeterBlock( ((how eq DCreadD)? METERRead,METERWrite),
	b,size FLStat/16)
     ]

	let dev=file>>F.Device
   let disk=(dev ge DISKT80)? (tridentVec!(dev-2)), sysDisk
	if dev eq DISK31B then sysDisk>>DSK.driveNumber=1
   if disk eq 0 then PDError(401)

//Check last page within bounds on file.
   let pageSize=file>>F.Pagesize
   let pageCnt=file>>F.Pagecnt
   if dev ls DISKT80 & pageSize eq 1024 then
	[				//Simulating 1024-word pages on Model 31
	page=page*4
	cnt=cnt*4
	pageSize=256
	pageCnt=pageCnt*4
	]

//Prepare CA vector just for those pages transferred
   if cnt gr 50 then PDError(402)
   let CAs=vec 50
   for i=0 to cnt-1 do
	[
	CAs!i=coreaddress
	coreaddress=coreaddress+pageSize
	]

//Prepare DAs vector just for those pages transferred
   let seqDAs = vec 50;
   seqDAs!0 = FileVDA(file, page);
   for i = 1 to cnt - 1 do seqDAs!i = fillInDA;
   let DAs = seqDAs - page - 1;

   page=page+1
   let lastpage=page+cnt-1
   if lastpage gr pageCnt then
		[
		PDError(403, file>>F.Name)
		lastpage=pageCnt
		]
   ActOnDiskPages(disk,CAs-page,DAs,lv file>>F.fp,page,
		lastpage,how, 0, 0, 0, 0, lv FileError)
   @lvdoneflag=true
   sysDisk>>DSK.driveNumber=0		//Return sysDisk to original condition
 ]

and FileError(a, b, c) be
 [
   sysDisk>>DSK.driveNumber=0		//Return sysDisk to original condition
   PDError(404)
 ]