/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1990-2006 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * read at most size chars according to op
 *
 *	CS_EXACT	read exactly size chars
 *			multiple reads possible
 *	CS_LIMIT	one read up to size chars
 *	CS_LINE		'\n' '\r\n' '\n\r' terminated line up to size
 *			multiple reads possible
 *	CS_RESTART	restart on interrupt
 *
 * 0 returned on eof
 */

#include "cslib.h"

ssize_t
csread(Cs_t* state, int fd, void* buf, size_t size, int op)
{
	register ssize_t	n;
	register char*		p;
	register char*		e;
	int			restart;

	if (restart = !!(op & CS_RESTART))
		op &= ~CS_RESTART;
	p = (char*)buf;
	e = p + size;
	messagef((state->id, NiL, -9, "read(%d,%d,%s) before", fd, size, op == CS_EXACT ? "EXACT" : op == CS_LIMIT ? "LIMIT" : "LINE"));
	if (op == CS_LINE && size > 1)
	{
		if ((n = cspeek(state, fd, buf, size - 1)) > 0 && (p[n] = 0, e = strchr(p, '\n')))
		{
			e++;
			op = CS_EXACT;
		}
		else
		{
			while (p < e && (n = read(fd, p, 1)) == 1 && *p++ != '\n');
			if (n <= 0 || p == (char*)buf || *(p - 1) != '\n')
				goto bad;
			n = p - (char*)buf;
			messagef((state->id, NiL, -9, "read(%d,%d,%s) [%d] `%-.*s'", fd, size, op == CS_EXACT ? "EXACT" : op == CS_LIMIT ? "LIMIT" : "LINE", n, n, buf));
			return n;
		}
	}
	while (n = read(fd, p, e - p))
	{
		if (n < 0)
		{
			if (restart && errno == EINTR)
				continue;
			break;
		}
		messagef((state->id, NiL, -9, "read(%d,%d,%s) [%d] `%-.*s'", fd, size, op == CS_EXACT ? "EXACT" : op == CS_LIMIT ? "LIMIT" : "LINE", n, n, p));
		p += n;
		if (op == CS_LIMIT || op == CS_LINE && (*(p - 1) == '\n' || n > 1 && *(p - 1) == '\r' && *(p - 2) == '\n'))
			return p - (char*)buf;
		if (p >= e)
		{
			if (op == CS_EXACT)
				return p - (char*)buf;
			break;
		}
		messagef((state->id, NiL, -2, "read(%d,%d,%s) again [%d] `%-.*s'", fd, size, op == CS_EXACT ? "EXACT" : op == CS_LIMIT ? "LIMIT" : "LINE", p - (char*)buf, p - (char*)buf, (char*)buf));
	}
 bad:
	if (p != (char*)buf || n < 0)
	{
		errno = EINVAL;
		messagef((state->id, NiL, -2, "read(%d,%d,%s) invalid record [%d] `%-.*s'", fd, size, op == CS_EXACT ? "EXACT" : op == CS_LIMIT ? "LIMIT" : "LINE", p - (char*)buf, p - (char*)buf, (char*)buf));
		return -1;
	}
	messagef((state->id, NiL, -2, "read(%d,%d,%s) eof", fd, size, op == CS_EXACT ? "EXACT" : op == CS_LIMIT ? "LIMIT" : "LINE"));
	return 0;
}

ssize_t
_cs_read(int fd, void* buf, size_t size, int op)
{
	return csread(&cs, fd, buf, size, op);
}
