/*
 *	Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
 *	This will be free software, but only when it is finished.
 */

/* customized routines to read in lines of potentially infinite length */

#include "hostenv.h"
#include "mailer.h"
#include <sys/file.h>
#include "../libsh/io.h"

#ifndef	L_INCR
#define	L_INCR	1
#endif	/* L_INCR */

/*
 *  Returns the number of characters of the next line to be read. The line
 *  is pointed at by (char *)linebuf. This storage is part of a dynamically
 *  allocated buffer known only within this module. Code external to here
 *  should treat linebuf as a read-only (constant) buffer.
 */

static u_char	*block;		/* malloc()'ed input buffer */
static u_char	*bend;		/* end of line pointer */
static u_int	blen;		/* bytes available to consume */
static u_int	bsize;		/* size of malloc()'ed buffer */

u_char	*linebuf = NULL;	/* where to start consuming */

/*
 * This routine should be called between opening a file
 * and calling getline() for the first time on that file.
 */

void
initline(blksize)
	long blksize;
{
	if (block == NULL) {
		bsize = blksize;
		if (bsize < BUFSIZ)
			bsize = BUFSIZ;
		block = (u_char *)emalloc(bsize);
	}
	blen = 0;
}

/*
 * Return the number of bytes starting from linebuf, which make up a line.
 */

int
getline(fp)
	FILE *fp;
{
	register u_char	*cp;
	register int	n;

	/* assert block != NULL */
	if (blen <= 0 || bend >= block + bsize) {
		blen = fread((char *)block, 1, (int)bsize, fp);
		if (blen == 0)
			return 0;
		bend = block;
	}
	while (1) {
		/* look for end of line in what remains of the input buffer */
		for (cp = bend, n = 0; n < blen; ++n, ++cp)
			if (*cp == '\n') {
				linebuf = bend;
				bend = ++cp;
				blen -= ++n;
				return n;
			}
		/* copy the partial line to the beginning of the input buffer */
		if (bend > block)
			bcopy((char *)bend, (char *)block, (int)blen);
		/* get some more bytes which will hopefully contain a newline */
		n = bsize - blen;
		if (n <= 0) {		/* grow the buffer */
			n = bsize;
			bsize *= 2;
			block = (u_char *)erealloc((char *)block, bsize);
		}
		n = fread((char *)(block+blen), 1, n, fp);
		if (n == 0) {
			/* the file doesn't terminate in a newline */
			n = blen;
			blen = 0;
			linebuf = block;
			return n;
		}
		blen += n;
		bend = block;
	}
	/* NOTREACHED */
}

/*
 * Return the number of bytes starting from linebuf, left in linebuf.
 * This is used to get the remaining bytes that have been read from the
 * file descriptor (and perhaps cannot be reread when the fp refers to
 * a pipe), to enable efficient copying of the rest of the data.
 */

int
getrest()
{
	/* assert block != NULL */
	if (blen <= 0 || bend >= block + bsize)
		return 0;
	linebuf = bend;
	return blen;
}

/*
 *  Determine the position of linebuf in the open file described by fp.
 */

long
offset(fp)
	FILE *fp;
{
	return ftell(fp) - blen;
}
