// P A R T S   
// errors 300
//
//Stuff for dealing with "parts" of windows.
//
// SetPartBounds(window,frec,nrecs)
//	Sets bounds on "window" starting at Press record # frec,
//	and going for nrecs.
// GetPositioninPart(window,dp)
//	Returns dp position within bounds.
// SetPositioninPart(window,dp)
//	Sets position relative to bounds.
// SetBytePositioninPart(window,bdp)
//	bdp is BYTE position relative to bounds.
// CheckAvailinPart(window,how,n)
//	Checks availablity of n "things" in bounds.
//	h=0	n in bytes
//	h=1	n in words
//	h=2	n is dp word count
// h=3	n is dp byte count
// SkipinPart(window,how,n)
//	Skips n "things" -- how as above.
//

get "PressInternals.df"
get "PressParams.df"

// outgoing procedures
external
	[
	SetPartBounds
	GetPositioninPart
	SetPositioninPart
	SetBytePositioninPart
	CheckAvailinPart
	SkipinPart
	]

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

// incoming procedures
external
	[
//PRESS
	PressError

//WINDOW,FILES
	WindowInit
	WindowClose
	WindowGetPosition
	WindowSetPosition
	WindowReadBlock
	WindowReadByte
	WindowFlush
	FileStuff
	FileWritePage

//PRESS
	DblShift

//OS
	MoveBlock

//PRESSML
	MulDiv
	DoubleAdd; DoubleSub; DoubleCop
	]

// incoming statics
//external
//	[
//	]

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

// File-wide structure and manifest declarations.

structure WP: 			//"Window Part"
 [
   RPos	word 2			//Relocation position
   Len	word 2			//Length of part
   Base	word			//Lines up with W
 ]


// Procedures

//"Part" functions

let SetPartBounds(w,frec,nrecs) be
 [
   compileif offset WP.Base ne offset W.Base then [ foo=0 ]
//Get file size
   let f=w>>W.File
   let fsiz=vec 1
   FileStuff(f,fsiz)		//Get file size
//Now convert to Press records
   DblShift(fsiz,LogPressRecordSize)
   if fsiz!0 then PressError(300)	//Too big
   let nPressRecs=fsiz!1		//All for this

   if frec ls 0 % nrecs ls 1 % frec+nrecs-1 ge nPressRecs then
	PressError(301)		//Part bounds wrong

//Record part length
   fsiz!1=nrecs
   DblShift(fsiz,-LogPressRecordSize)
   DoubleCop(lv w>>WP.Len,fsiz)		//Length of area.

//Record part starting position
   fsiz!0=0
   fsiz!1=frec
   DblShift(fsiz,-LogPressRecordSize)
   DoubleCop(lv w>>WP.RPos,fsiz)
 ]


and GetPositioninPart(w,p) be
 [
   WindowGetPosition(w,p)
   DoubleSub(p,lv w>>WP.RPos)
 ]

and SetPositioninPart(w,p) be
 [
   let t=vec 1
//Condition is: len-position => 0
   DoubleCop(t,lv w>>WP.Len); DoubleSub(t,p);
   if p!0 ls 0 % t!0 ls 0 then PressError(302)
   DoubleCop(t,p); DoubleAdd(t,lv w>>WP.RPos)
   WindowSetPosition(w,t)
 ]

and SetBytePositioninPart(w,p) be
 [
   let b=(p!1)&1				//Byte odd
   let t=vec 1
   DoubleCop(t,p); DblShift(t,1); SetPositioninPart(w,t)
   if b then WindowReadByte(w)
 ]

and CheckAvailinPart(w,how,n) be
 [
   if how gr 1 & n!0 eq 0 then [ n=n!1; how=1 ]
   if how eq 0 then
     [
      if w>>W.WhichByte then n=n-1		//A byte there already
      n=(n+1)/2
     ]

//Following is a quick check so that ordinary things work fast,
// but is not strictly speaking correct.  The reason is that if several
// Press records will fit in one window buffer, then the check could
// allow a check to succeed even though the range is outside the
// specified number of Press records.
   if how le 1 & n le -w>>W.Offset then return //Enuf in this buffer

//Condition is position+needed <= length
   let t=vec 1
   t!0=0;t!1=n
   if how gr 1 then DoubleCop(t,n)
   let s=vec 1
   GetPositioninPart(w,s)
   DoubleAdd(s,t)				//s=pos+needed
   DoubleCop(t,lv w>>WP.Len)
   DoubleSub(t,s)			//t=len-(pos+needed)
   if t!0 ls 0 then PressError(303)
 ]

and SkipinPart(w,how,n) be
 [
//Get current byte pos.
   let t=vec 1
   GetPositioninPart(w,t)
   DblShift(t,-1)
   if w>>W.WhichByte then DoubleAdd(t,table [ 0;1 ])
//Convert n to bytes
   let s=vec 1
   s!0=0; s!1=n
   if how ne 0 then
     [
      if how ge 2 then DoubleCop(s,n)
      unless how eq 3 do DblShift(s,-1)
     ]
//Now set position to pos+n
   DoubleAdd(s,t)
   SetBytePositioninPart(w,s)
 ]