#include <ncbi.h>
#include <gish.h>
#include <gishlib.h>

/*
	vfgets -- variable-length fgets

"base" argument points to a pointer to a block of memory obtained from malloc.
"basemax" points to an integer that contains the size of the base block.
"bp" points to a pointer that points to the current buffer location for
        reading within the "base" block.
"fp" is the standard file FILE pointer from which to read.
*/
CharPtr LIBCALL
vfgets(base, basemax, bp, fp)
	CharPtr	PNTR base;
	size_t	PNTR basemax;
	CharPtr	PNTR bp;
	FILE	*fp;
{
	register CharPtr	cp;
	size_t	buflen, bpoff, cpoff;

	cp = *bp;
	
	for (;;) {
		buflen = *basemax - (cp - *base);
		if (buflen > 1) {
			cp[buflen-1] = 'X'; /* lay down sentinel bytes */
			cp[buflen-2] = '\n';
			if (fgets(cp, buflen, fp) == NULL)
				return (cp == *bp ? NULL : *bp);
			if (cp[buflen-1] != '\0' /* entire buffer was not needed */
					|| cp[buflen-2] == '\n') /* line fit perfectly in buffer */
				return *bp;
		}
		else
			buflen = 1;
		
		bpoff = *bp - *base;
		cpoff = (cp - *base) + buflen - 1;
		if (*base == NULL) {
			if (buflen == 0)
				cp = mem_malloc(buflen = 256);
			else
				cp = mem_malloc(buflen);
		}
		else
			cp = mem_realloc(*base, buflen = *basemax * 1.5 + 20*KBYTE);
		if (cp == NULL)
			return NULL;
		*base = cp;
		*basemax = buflen;
		*bp = cp + bpoff;
		cp += cpoff;
	}
	/*NOTREACHED*/
}

CharPtr LIBCALL
xfgets(xltab, buf, buflen, bpend, fp)
	register CharPtr	xltab;
	register CharPtr	buf;
	CharPtr	PNTR bpend;
	size_t	buflen;
	FILE	*fp;
{
	CharPtr	buf0 = buf;
	register CharPtr	sp;
	register int	ch;
	register CharPtr	spend;

	sp = buf;
	spend = buf + buflen;
	while (sp < spend && (ch = getc_unlocked(fp)) != EOF) {
		if (xltab[ch])
			*sp++ = ch;
	}

	if (ch == EOF && buf0 == buf)
		return NULL;

	*bpend = sp;
	return buf0;
}

CharPtr LIBCALL
vxfgets(xltab, base, basemax, bp, bpend, fp)
	CharPtr	xltab;
	CharPtr	PNTR base;
	size_t	PNTR basemax;
	CharPtr	PNTR bp;
	CharPtr	PNTR bpend;
	FILE	*fp;
{
	register CharPtr	cp;
	size_t	buflen, bpoff, cpoff;

	cp = *bp;
	for (;;) {
		buflen = *basemax - (cp - *base);
		if (buflen > 1) {
			cp[buflen-1] = 'X'; /* lay down sentinel bytes */
			cp[buflen-2] = '\n';
			if (xfgets(xltab, cp, buflen, bpend, fp) == NULL)
				return (cp == *bp ? NULL : *bp);
			if (cp[buflen-1] != '\0') /* entire buffer was not needed */
				return *bp;
		}
		else
			buflen = 1;

		bpoff = *bp - *base;
		cpoff = (cp - *base) + buflen - 1;
		if (*base == NULL) {
			if (buflen == 0)
				cp = mem_malloc(buflen = 256);
			else
				cp = mem_malloc(buflen);
		}
		else
			cp = mem_realloc(*base, buflen = *basemax * 1.5 + 10*KBYTE);
		if (cp == NULL)
			return NULL;
		*base = cp;
		*basemax = buflen;
		*bp = cp + bpoff;
		cp += cpoff;
	}
	/*NOTREACHED*/
}
