Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/klib/write.c
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

316 lines
13 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#define RETERR(x,y) return(x)
/****************************************************************************/
/* */
/* W r i t e F u n c t i o n */
/* --------------------------- */
/* Copyright 1982 by Digital Research Inc. All rights reserved. */
/* */
/* Function "write" simulates the UNIX write system call. Any */
/* arbitrary number of bytes are written to the file specified by */
/* file descriptor. No special alignment of file or buffer is */
/* required. */
/* */
/* Calling Sequence: */
/* */
/* ret = write(fd,buffer,bytes); */
/* */
/* Where: */
/* */
/* fd is an open file descriptor */
/* buffer is the buffer address */
/* bytes is the number of bytes to be written */
/* */
/* ret is the number of bytes actually written */
/* */
/****************************************************************************/
#include "stdio.h"
#include "cpm.h"
WORD write(fd,buff,pbytes) /****************************/
/* */
WORD fd; /* File descriptor */
REG BYTE *buff; /* Buffer address */
WORD pbytes; /* Number of bytes to xfer */
/* */
{ /****************************/
REG FILE *fp; /* File (ccb) pointer */
EXTERN LONG _chkc(); /* fd -> fp Convertor */
LOCAL LONG ofs; /* Buffer offset */
LOCAL LONG written; /* Number of bytes written */
LOCAL LONG xsector; /* Sector number temporary */
REG BYTE *p1; /* Move loop pointers */
REG BYTE c; /* Character temp */
REG LONG xbytes; /* Saved bytes */
REG LONG bytes; /* Bytes for everyone else */
/****************************/
/* */
bytes = (LONG)pbytes; /* Convert to long */
/****************************/
if((LONG)(fp=_chkc(fd)) == FAILURE) /* Get CCB address */
return(FAILURE); /* Can't */
/* */
if(bytes <= 0) /* Trying to write 0 or less*/
return(0); /* Yes, a wise guy! */
/* */
if((fp->flags & ISREAD) != 0) /* Check for readonly file */
RETERR(FAILURE,EBADF); /* Barf if so */
/* */
if((fp->flags & ISTTY) != 0) /* TTY File? */
return(_chrout(buff,bytes,CONOUT));/* Yes, out to TTY */
/* */
if((fp->flags & ISLPT) != 0) /* LIST file? */
return(_chrout(buff,bytes,LSTOUT));/* Yes, out to LST: */
/****************************/
if((fp->flags & ISASCII) == 0) /* If binary file */
return(_wrtbin(fp,buff,bytes)); /* do binary style */
/****************************/
written = bytes; /* Remember original request*/
/****************************/
/* */
/****************************************************************************/
/* Here begins the actual write loop */
/****************************************************************************/
/* */
c = 0; /* Init to garbage value */
/* */
while(bytes >0) /* While more bytes to write*/
{ /* */
xsector = fp->offset >> 7; /* Compute beginning sector */
ofs = 0; /* start on sector boundary */
/* */
if(xsector != fp -> sector) /* Have to read it first */
{ /* */
if((fp->flags & DIRTY) != 0) /* Buffer has data? */
{ /* Yes */
if(_blkio(fp,fp->sector, /* */
fp->buffer,1L,B_WRITE) != 1) /* Try to write */
RETERR(FAILURE,EIO); /* Couldn't */
fp->flags &= ~DIRTY; /* Nice clean buffer now */
} /****************************/
} /* */
/* */
if((fp-> offset & (SECSIZ-1)) != 0 /* Beginning on crazy offset*/
&& (fp -> offset < fp -> hiwater)) /* and below hiwater mark */
{ /* */
if(_blkio(fp,xsector,fp->buffer, /* */
1L,B_READ) != 1) /* Now read the correct sec */
RETERR(FAILURE,EIO); /* Couldn't */
} /****************************/
fp->sector = xsector; /* Mark buffer correctly */
ofs = fp->offset & (SECSIZ-1); /* Compute 1st char offset */
/* */
p1 = &(fp->buffer[ofs]); /* first char to write */
/* */
xbytes = bytes; /* Save byte count remaining*/
while (p1 < &(fp->buffer[SECSIZ]) /* Until buffer is full */
&& (bytes > 0)) /* or until request done */
{ /****************************/
if(*buff == '\n' && c != '\r') /* need to insert C/R */
c = '\r'; /* */
else /* Don't need to */
{ /* */
c = *buff++; /* */
bytes--; /* */
} /****************************/
*p1++ = c; /* Put char in buffer */
fp->offset++; /* Increment file offset */
} /****************************/
if(p1 >= &(fp->buffer[SECSIZ])) /* Need to write buffer */
{ /* */
if(_blkio(fp,xsector,fp->buffer, /* */
1L,B_WRITE) !=1) /* Try the write */
return(written-xbytes); /* return # actually written*/
} /****************************/
else /* */
fp -> flags |= DIRTY; /* Buffer dirty again */
if(bytes == 0) /* If done, */
{ /* Check offset here */
if(fp->offset > fp->hiwater) /* */
fp->hiwater = fp->offset; /* Fix hiwater if necessary */
return(written); /* return */
} /* */
} /****************************/
}
/****************************************************************************/
/* */
/* W r t b i n F u n c t i o n */
/* ------------------------------ */
/* */
/* Function "wrtbin" is called from "write" to take advantage of a */
/* potential multi-sector transfer for binary files. */
/* */
/* 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 */
/* */
/****************************************************************************/
LONG _wrtbin(fp,buff,bytes) /****************************/
/* */
REG FILE *fp; /* -> CCB */
REG BYTE *buff; /* -> User's buffer */
REG LONG bytes; /* # bytes to write */
{ /****************************/
LOCAL LONG xsector; /* Sector temp */
LOCAL LONG nsector; /* Multi-sector count */
LOCAL LONG written; /* # bytes to write */
REG BYTE *p1; /* Temp buffer pointer */
/****************************/
written = bytes; /* Remember request length */
xsector = fp->offset >> 7; /* Calculate present sector */
/****************************/
if((fp -> offset & (SECSIZ-1)) != 0) /* Are we at a boundary? */
{ /* */
if(xsector != fp->sector) /* No, do sectors match? */
{ /* */
if((fp->flags & DIRTY) != 0) /* No, is buffer dirty? */
{ /* */
if(_blkio(fp,fp->sector, /* */
fp->buffer,1L,B_WRITE) != 1) /* Yes, write it */
RETERR(FAILURE,EIO); /* Couldn't write buffer */
fp->flags &= ~DIRTY; /* Clear dirty bit */
} /****************************/
/* */
if(fp->offset < fp->hiwater) /* Within the hiwater area? */
{ /* If yes, then read it */
if(_blkio(fp,xsector,fp->buffer, /* */
1L,B_READ) != 1) /* Try to read the correct */
RETERR(FAILURE,EIO); /* Can't */
} /****************************/
else _clear(fp->buffer,SECSIZ); /* Zero out the buffer */
/* */
/* */
fp->sector = xsector; /* Label buffer */
/* */
} /****************************/
p1 = &fp->buffer[fp->offset&(SECSIZ-1)];/* p1->1st loc in buffer */
/* */
while (p1 < &(fp->buffer[SECSIZ]) && /* while still in buffer */
bytes > 0) /* And still writing */
{ /* */
*p1++ = *buff++; /* Move a byte */
bytes--; /* Decrement counter */
} /****************************/
if (bytes <= 0) /* Byte count exhausted?? */
{ /* */
fp->flags |= DIRTY; /* Yes, buffer is now dirty */
fp->offset += written; /* fix offset */
if(fp->offset > fp->hiwater) /* See if above hiwater mark*/
fp->hiwater = fp->offset; /* Fix if necessary */
return(written); /* Return original byte cnt */
} /****************************/
if(_blkio(fp,xsector,fp->buffer,1L, /* Write full buffer */
B_WRITE) != 1) /* */
RETERR(FAILURE,EIO); /* Couldn't */
xsector++; /* Bump sector counter */
} /* End boundary problem code*/
/****************************/
/* */
/************************************************* */
/* The observant reader will note that after the above malarkey, we are now */
/* aligned on a sector boundary. The following code exploits the oppor- */
/* tunity to do a multi-sector write. */
/************************************************* */
/* */
nsector = bytes >> 7; /* divide by 128 for sectors*/
if(nsector > 0) /* Check for no more left */
if(_blkio(fp,xsector,buff, /* */
nsector,B_WRITE) != nsector) /* Multi-sector xfer */
RETERR(FAILURE,EIO); /* Just quit on error */
/****************************/
bytes -= (nsector << 7); /* Subtract multi-sector */
/* Byte count */
buff += (nsector << 7); /* Update address */
fp->offset += written; /* Update offset now */
/* (All I/O is complete) */
if(fp->offset > fp->hiwater) /* Fix up hiwater mark */
fp->hiwater = fp->offset; /* */
if(bytes == 0) /* If done, */
return(written); /* return success */
/****************************/
if((fp->flags & DIRTY) != 0) /* Is buffer dirty? */
{ /* Test (again) here in case*/
if(_blkio(fp,fp->sector, /* of boundary condition */
fp->buffer,1L,B_WRITE) != 1) /* Yes, write it */
RETERR(FAILURE,EIO); /* Couldn't write buffer */
} /****************************/
fp -> flags |= DIRTY; /* Let's dirty the buffer */
fp -> sector = fp -> offset >> 7; /* Mark sector number */
/****************************/
if(fp->offset < fp->hiwater) /* Sector in high water area*/
_blkio(fp,fp->sector,fp->buffer,1L, /* Read sector */
B_READ); /* */
else _clear(fp->buffer,SECSIZ); /* Or clear it */
/****************************/
p1 = &(fp->buffer[0]); /* p1 -> address */
while(bytes > 0) /* Move the bytes */
{ /* */
*p1++ = *buff++; /* One at a time */
bytes--; /* Decrement count */
} /****************************/
/* */
return(written); /* Return requested # */
} /****************************/
_clear(ptr,bytes) /****************************/
/* Clear a memory area */
REG BYTE *ptr; /* -> area to be cleared */
REG WORD bytes; /* # of bytes to zero */
{ /****************************/
while (bytes-- > 0) /* Until all exhausted */
*ptr++ = 0; /* Clear 1 byte */
} /****************************/
/****************************************************************************/
/* */
/* _ c h r o u t F u n c t i o n */
/* ------------------------------- */
/* */
/* Function "_chrout" is called to perform "write" operations to the */
/* console or list device. */
/* */
/* Calling Sequence: */
/* */
/* ret = _chrout(buffer,count,func); */
/* */
/* Where: */
/* */
/* buffer -> the output buffer */
/* count = the number of bytes to output */
/* func = BDOS function to use */
/* */
/* ret = count on return */
/* */
/****************************************************************************/
_chrout(buffer,count,func) /***************************/
/* */
REG BYTE *buffer; /* -> 1st char output */
REG LONG count; /* = # bytes to xfer */
REG WORD func; /* BDOS Function */
/* */
{ /***************************/
LONG xcount; /* save area for count */
/* */
xcount = count; /* Copy for later */
/* */
while(count > 0) /* Until all written */
{ /* */
if(*buffer == '\n') /* New line char?? */
{ /* */
__BDOS(func,(LONG)'\r'); /* Output carriage return */
} /* */
__BDOS(func,(LONG)*buffer++); /* Output next character */
count--; /* Decrement count */
} /* */
return(xcount); /* return original count */
} /***************************/