
/****************************************************************
*								*
*		CP/M-68K BDOS Disk Read/Write Module		*
*								*
*	This module contains functions to perform sequential   	*
*	or random access read or write to the disk for CP/M-68K	*
*								*
*	It includes the following external functions:		*
*								*
*		seqread()     - sequential disk read		*
*								*
*								*
*	Compiled with Alcyon C on the VAX			*
*								*
****************************************************************/

#include "stdio.h"		/* Standard I/O declarations */

#include "bdosdef.h"		/* Type and structure declarations for BDOS */


/* External function definitions */
EXTERN	UWORD	rdsec();	/* disk read routine	*/
EXTERN	WORD	swap();		/* assembly language byte swapper */
EXTERN	UWORD	dirscan();	/* directory scanning routine	*/
EXTERN	BOOLEAN openfile();	/* open file function passed to dirscan */


/**********************************************************/
/*  First, some utility functions used by seqio and ranio */
/**********************************************************/

/******************************
*  FCB block number routines  *
******************************/

WORD	blkindx(fcbp)
/*  return index into fcb disk map	*/

REG struct fcb	*fcbp;		/* pointer to fcb	*/
{
    REG struct dpb *dparmp;	/* pointer to disk parameter block */
    REG WORD i;
    REG WORD blkshf;
    BSETUP

    dparmp = GBL.parmp;
    blkshf = dparmp->bsh;
    i = ((fcbp->extent) & dparmp->exm) << (7 - blkshf);
    return (i + (UBWORD(fcbp->cur_rec) >> blkshf) );
}


UWORD	blknum(fcbp, index, wrdfcb)
/* return block number in fcb indicated by index */

REG struct fcb	*fcbp;		/* pointer to fcb	*/
REG WORD	index;		/* index into disk map of fcb */
WORD		wrdfcb;		/* boolean, fcb disk map of words? */
{
    if (wrdfcb)
	return( swap(fcbp->dskmap.big[index]) );
    else return( UBWORD(fcbp->dskmap.small[index]) );
}


/*********************
*  disk read routine *
*********************/

UWORD do_io(block, rcrd)

UWORD	block;		/* block number		*/
UBYTE	rcrd;		/* record number	*/
{
    LONG lsec;
    REG struct dpb *dparmp;
    BSETUP

    dparmp = GBL.parmp;		/* init dpb pointer */
    lsec = ((LONG)block << (dparmp->bsh)) +
		(LONG)(rcrd & (dparmp->blm));
    return( rdsec(lsec, GBL.dmaadr) );
}


/*******************************************
*  routine for crossing extent boundaries  *
*******************************************/

WORD new_ext(fcbp)
/*  If sequential I/O, open the next extent	*/

REG struct fcb	*fcbp;		/* pointer to fcb */
{
    REG UBYTE mod;		/* module number		*/
    REG UBYTE ext;		/* extent number		*/
    BSETUP

    mod = (fcbp->s2) & 0x3f;
    ext = (fcbp->extent) + 1;	/* for sequential, incr extent	*/
    if (ext >= 32)
    {
	ext = 0;
	mod += 1;
    }
    if (mod >= 64) return(6);	/* past maximum file size */
    if ( mod == ((fcbp->s2) & 0x3f) )
	if ( ! ((ext ^ (fcbp->extent)) & ~((GBL.parmp)->exm) & 0x1f) )
	{			/* we're in same logical extent */
	    fcbp->extent = ext;
	    return(0);
	}
    /* Extent or Module numbers don't match	*/
    /* Close the old extent and open a new one	*/
    fcbp->s2 = mod;
    fcbp->extent = ext;
    if ( dirscan(openfile, fcbp) >= 255 )  /* open new extent */
	return(4);		/* reading unwritten extent */
    return(0);
}


/************************************
* Routine to calculate the maximum  *
* extent number of an FCB in a	    *
* extent-folded environment	    *
************************************/

UWORD calcext(fcbp)

REG struct fcb *fcbp;

{
    REG UWORD i;
    REG BYTE *p;
    BSETUP

    i = 15;
    p = &(fcbp->dskmap.small[16]);
    do
    {
	if (*--p) break;
	i -= 1;
    } while (i);
/* Now i contains the index of the last non-zero block in the FCB */
    if ((GBL.parmp)->dsm > 255) i >>= 1;
    i >>= 7 - ((GBL.parmp)->bsh);
    return ( (fcbp->extent) & ~((GBL.parmp)->exm) & 0x1f | i );
}


/*********************************
* Routine to get the actual	 *
* record count of the currently  *
* active logical extent of a FCB *
*********************************/

UWORD get_rc(fcbp)

REG struct fcb *fcbp;

{
    REG UWORD ext;

    ext = calcext(fcbp);	/* find last active extent in fcb */
    if (ext == fcbp->extent) return(UBWORD(fcbp->rcdcnt));
			/* if this is the last active fcb, return fcb's rc */
    else if (ext > fcbp->extent) return(128);
			/* if the fcb has more extents past this one, then */
			/* the current one is logically full	*/
    else return (0);
			/* if we seeked past the last active extent, rc = 0 */
}


/************************
*  seqread entry point	*
************************/

UWORD seqread(fcbp)

REG struct fcb *fcbp;		/* fcbp is a pointer to a fcb */

{
    REG UWORD	block;		/* block number from fcb	*/
    REG WORD	index;		/* index into disk map of fcb	*/
    REG WORD	parm;		/* parameter to do-io		*/
    REG WORD	bigfile;	/* file system is in word mode	*/
    BSETUP

    bigfile = ((GBL.parmp)->dsm) & ~0xff;
    if (fcbp->cur_rec == 128)
    {				/* time to try next extent */
	if ( new_ext(fcbp) )
		return(1);	/* if can't open new extent, error */
	fcbp->cur_rec = 0;	/* opened new extent, zero cur_rec */
    }
    if ( UBWORD(fcbp->cur_rec) >= get_rc(fcbp) )
	return(1);		/* this is end of file */
    index = blkindx(fcbp);	/* get index into fcb disk map */
    block = blknum(fcbp, index, bigfile);
    if ( ! block)		/* no data allocated at that position */
	return(1);		/* reading unwritten data	*/
    return( do_io(block, (fcbp->cur_rec)++) );
}

