/***************************************************************************
 *									    
 *			W r t b i n    F u n c t i o n			    
 *			------------------------------			    
 *	Copyright 1984, Digital Research Inc.  All rights reserved.
 *									    
 *	Function "wrtbin" is called from "write" to take advantage of a	    
 *	potential multi-sector transfer for binary files.		    
 *
 *	Completely re-written 7 Feb 1984 whf.
 *									    
 *	Calling sequence:						    
 *		ret = _wrtbin(fp,buffer,bytes);				    
 *									    
 *	Where:								    
 *		fp	Points to the affected ccb.			    
 *		buffer	Is the buffer address				    
 *		bytes	Is the number of bytes to write			    
 *									    
 *		ret	Is the number of bytes actually written		    
 *									    
 ****************************************************************************/

#include "portab.h"
#include "osif.h"
#include "osiferr.h"
#include "errno.h"

#define NDEBUG
#include "assert.h"

#define OFFSECT   (fp->offset    & ~(SECSIZ-1))
#define HIWSECT   (fp->hiwater-1 & ~(SECSIZ-1))


UWORD	_wrtbin(fp,buff,bytes)			/****************************/
						/*			    */
REG	FD	*fp;				/* -> CCB		    */
	BYTE	*buff;				/* -> User's buffer	    */
	UWORD	bytes;				/* # bytes to write	    */
{						/****************************/

#if PCDOS    /*=============================================================*/
	UWORD ii;				/* Byte counter		    */
	UWORD _pc_writeblk();			/* OS function Write Rnd Blk*/
						/*			    */
	ii = _pc_writeblk(&(fp->fcb),fp->offset,buff,(WORD)bytes,1); /*	    */
	if( ii==0 )				/* Problems?		    */
		RETERR(FAILURE,EIO);		/* Tell them so		    */
	fp->offset += ii;			/* Incr pos in file	    */
	if( fp->offset > fp->hiwater )		/* Need to advance?	    */
		fp->hiwater = fp->offset;	/*   then do so		    */
	return ii;				/* Number written	    */
}						/****************************/
#endif       /*=============================================================*/

#if CPM      /*=============================================================*/
REG	UWORD	nbs;				/* counter		    */
	UWORD	xsector;			/* Current sector 	    */
	UWORD	nsector;			/* Multi-sector count	    */
	UWORD	written;			/* # bytes to written	    */
	UWORD	BufPos;				/* Position in buffer	    */
						/****************************/
						/****************************/
	written = 0;				/* Num written so far	    */
						/* Get buffer cleaned and   */
						/*   current:		    */
	xsector = fp->offset >> 7;		/* Calculate present sector */
	if(xsector != fp->sector) {		/* Do sectors match?	    */
	    if(fp->flags & DIRTY) 		/* No, is buffer dirty?	    */
		if(_blkio(fp,fp->sector,fp->buffer,1L,B_WRITE) != 1) /*	    */
		    RETERR(FAILURE,EIO);	/* Couldn't write buffer    */
	    if( OFFSECT > HIWSECT) 		/* Within the hiwater area? */
		 blkfill(fp->buffer,0,SECSIZ);	/* No: Zero out the buffer  */
	    else if(_blkio(fp,(LONG)xsector,fp->buffer,1L,B_READ) != 1)
		 RETERR(FAILURE,EIO);		/* Can't preread buffer	    */
	    fp->flags &= ~DIRTY;		/* Clear dirty bit	    */
	    fp->sector = xsector;		/* Buffer labelled	    */
	}					/****************************/
						/****************************/
						/* Xfer data to buffer until*/
						/* 1) end of data,	    */
						/* 2) end of buffer, or	    */
						/* 3) sector aligned multi- */
						/*    sector write.	    */
	BufPos = fp->offset & (SECSIZ-1);	/* Where are we in buffer?  */
	nbs = SECSIZ - BufPos;			/* Room left in buffer	    */
	if( nbs > bytes ) 			/* More room than we need?  */
	     nbs = bytes;			/*   Adjust to bytes to xfer*/
	else if( nbs == SECSIZ )		/* Sector aligned multi-sec?*/
	     nbs = 0;				/*   Don't buffer now.	    */
	if( nbs > 0 ) {				/* Any room/data to buffer? */
	    blkmove(fp->buffer+BufPos,buff,nbs);/* Move into write buffer   */
	    written += nbs;			/* Indicate we've written   */
	    fp->offset += nbs;			/*     "      "      "	    */
	    buff += nbs;			/* Ground we've covered	    */
	    bytes -= nbs;			/* num bytes left to write  */
	    if( BufPos + nbs != SECSIZ ) { 	/* Buffer full?		    */
		fp->flags |= DIRTY;		/* No, mark it		    */
		fp->sector = xsector;		/* Label buffer		    */
	    } else {				/*			    */
		if(_blkio(fp,(LONG)xsector,fp->buffer,1L,B_WRITE) != 1) 
		    RETERR(FAILURE,EIO);	/* Couldn't		    */
		fp->flags &= ~DIRTY;		/* turn off dirty bit	    */
		fp->sector = -1;		/* buffer clean		    */
		xsector++;			/* Bump sector counter	    */
	    }					/****************************/
	}					/****************************/
						/*			    */
						/****************************/
	if( bytes >= SECSIZ ) {			/* Can we do multisector io?*/
	    nsector = bytes >> 7;		/* divide by 128 for sectors*/
	    if(_blkio(fp,(LONG)xsector,buff,(LONG)nsector,B_WRITE) != nsector)
						/* Multi-sector xfer	    */
		RETERR(FAILURE,EIO);		/* Just quit on error	    */
	    xsector += nsector;			/* Update current sector    */
	    nbs = nsector << 7;			/* number bytes xferred	    */
	    written += nbs;			/* Indicate we've written   */
	    fp->offset += nbs;			/*     "      "      "	    */
	    buff += nbs;			/* Ground we've covered	    */
	    bytes -= nbs;			/* num bytes left to write  */
	}					/****************************/
						/****************************/
	if( bytes > 0 ) {			/* Any room/data to buffer? */
	    ASSERT( fp->flags & DIRTY  == 0 );	/* Buffer should be clean   */
	    if( OFFSECT > HIWSECT) 		/* Within the hiwater area? */
		 blkfill(fp->buffer,0,SECSIZ);	/* No: Zero out the buffer  */
	    else if(_blkio(fp,(LONG)xsector,fp->buffer,1L,B_READ) != 1) 
		 RETERR(FAILURE,EIO);		/* Can't preread buffer	    */
	    ASSERT( bytes < SECSIZ );		/* Should be cut to size    */
	    blkmove(fp->buffer,buff,bytes);	/* Move into write buffer   */
	    fp->flags |= DIRTY;			/* Mark buffer		    */
	    fp->sector = xsector;		/*   and label		    */
	    written += bytes;			/* Indicate we've written   */
	    fp->offset += bytes;		/*     "      "      "	    */
	    buff += bytes;			/* Ground we've covered	    */
	}					/****************************/
						/*			    */
	if(fp->offset > fp->hiwater)		/* See if above hiwater mark*/
		fp->hiwater = fp->offset;	/* Fix if necessary	    */
	return written;				/* Return requested #	    */
}						/****************************/

#endif       /*=============================================================*/
=====*/
=====*/
