V10/cmd/spitbol/osread.c
/*
* osread( mode,recsiz,ioptr,scptr ) reads the next record from
* the designated input file into the scblk. recsiz determines
* whether the read should be line or raw mode. line mode records
* are teminated with a new-line character (the new-line is not
* put in the scblk though). raw records are simply the next recsiz
* characters.
*/
#include "spitblks.h"
#include "spitio.h"
int osread( mode, recsiz, ioptr, scptr )
int mode;
int recsiz;
struct ioblk *ioptr;
struct scblk *scptr;
{
register struct bfblk *bfptr = ioptr -> buf;
register char *cp = scptr -> str;
register char *bp;
register int cnt = 0;
int fdn = ioptr -> fdn;
register int n;
/*
* Handle unbuffered reads.
*/
if ( ioptr -> flg & IO_WRC ) {
/* no line mode with unbuffered */
if ( mode > 0 )
return -2;
/* attempt to read in scblk */
n = read( fdn,cp,recsiz );
/* if read error then take action */
if ( n < 0 )
return -2;
/* check for eof */
if ( n == 0 )
return -1;
/* everything ok, so return */
return n;
}
/*
* Handle buffered reads.
*/
if ( mode > 0 ) {
/* line mode */
register char *savecp;
char savechar;
/*
* First phase: copy characters to the result
* buffer either until recsiz is exhausted or
* we have copied the last character of a line.
* This loop is speeded up by pretending that
* the input line is no longer than the result.
*/
do {
char *oldbp;
/* if the buffer is empty, try to fill it */
if ( bfptr -> rem == 0 ) {
n = read ( fdn, bfptr -> buf, bfptr -> siz );
/* eof is only ok at the beginning of a line */
if ( n == 0 )
return cnt > 0? -2: -1;
/* input errors are never ok */
if ( n < 0 )
return -2;
bfptr -> off = 0;
bfptr -> rem = n;
}
/* set n to max # chars we can process this time */
n = recsiz - cnt;
if ( n > bfptr -> rem )
n = bfptr -> rem;
/* point bp and oldbp at the first char to be copied */
oldbp = bp = bfptr -> buf + bfptr -> off;
/* plant a newline at the end of the valid input */
savecp = bp + n;
savechar = *savecp;
*savecp = '\n';
/* copy characters until we hit a newline */
while ( *bp != '\n' )
*cp++ = *bp++;
/* restore the stolen character */
*savecp = savechar;
/* calculate how many characters were moved */
n = bp - oldbp;
cnt += n;
bfptr -> off += n;
bfptr -> rem -= n;
} while ( bp == savecp && cnt < recsiz );
/* loop until we hit a real \n or recsiz is exhausted */
/*
* Second phase: discard characters up to and
* including the next newline in the input.
* This loop is optimized to miminize startup
* overhead, because it will usually be executed
* only once (but never less than once!)
*/
do {
/*
* decrement count of characters remaining
* in the buffer, check for buffer underflow
*/
if ( --bfptr -> rem < 0 ) {
n = read ( fdn, bfptr -> buf, bfptr -> siz );
/* eof and input errors are never ok */
if ( n < 0 )
return -2;
bfptr -> off = 0;
bfptr -> rem = n - 1;
}
/*
* The buffer is guaranteed non-empty,
* and the count of characters remaining
* has already been decremented by 1.
* Pick up a character and bump the offset.
*/
n = bfptr -> buf [bfptr -> off++];
} while (n != '\n');
/* loop until we see a newline */
} else {
/* raw mode, try to read exactly "recsiz" characters */
while ( recsiz > 0 ) {
/* if the buffer is empty, try to fill it */
if ( bfptr -> rem == 0 ) {
n = read ( fdn, bfptr -> buf, bfptr -> siz );
/* input error, no good */
if ( n < 0 )
return -2;
/* eof, return what we got so far */
if ( n == 0 )
break;
bfptr -> rem = n;
bfptr -> off = 0;
}
/* calculate how many chars we can move */
n = bfptr -> rem;
if ( n > recsiz )
n = recsiz;
bp = bfptr -> buf + bfptr -> off;
/* update pointers to move n characters */
cnt += n;
recsiz -= n;
bfptr -> off += n;
bfptr -> rem -= n;
/* move n characters from bp to cp */
if ( n & 1 )
*cp++ = *bp++;
n >>= 1;
if ( n > 0 ) {
do {
*cp++ = *bp++;
*cp++ = *bp++;
} while ( --n > 0 );
}
}
/* if we couldn't make any progress, signal end of file */
if ( cnt == 0 )
return -1;
}
return cnt;
}