/*
 * @(#)LineReader.cpp
 *
 * This file is part of webCDwriter - Network CD Writing.
 *
 * Copyright (C) 2001 Jörg P. M. Haeger
 *
 * webCDwriter is free software. See CDWserver.cpp for details.
 */

#include <sys/time.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "Exception.h"
#include "LineReader.h"

const char BS = 8, LF = '\n', CR = '\r';

LineReader::LineReader(int fd) {
	cursor = 0;
	eob = 0;
	eof = 0;
	eol = 0;
	this->fd = fd;
}

int LineReader::available() {
	while (eol < eob
		&& buf[eol] != BS
		&& buf[eol] != CR
		&& buf[eol] != LF)
		eol++;
	return eol < eob || eol == bufSize;
}

const char *LineReader::next(int timeout) {
	while (!available() && !eof) {
		if (timeout > 0) {
			fd_set fdSet;
			FD_ZERO(&fdSet);
			FD_SET(fd, &fdSet);
			struct timeval tv;
			tv.tv_sec = timeout;
			tv.tv_usec = 0;
			if (select(FD_SETSIZE, &fdSet, NULL, NULL, &tv) == 0)
				throw new Exception("timeout");
		}
		read();
	}

	if (eob == 0)
		return NULL;

	for (int i = 0; i < eol; i++)
		line[cursor++] = buf[i];
	line[cursor] = 0;

	// go to the first character of the next line
	int next = eol;
	if (next == eob || buf[next] != BS) {
		cursor = 0;
		if (next + 1 < eob && buf[next + 1] == LF)
			next++;
		if (next < eob)
			next++;
	}
	else {
		for (; next < eob && buf[next] == BS; next++)
			if (cursor > 0)
				cursor--;
	}

//	for (int j = 0; j < eob - next; j++)
//		buf[j] = buf[j + next];
	memmove(buf, buf + next, eob - next);
	eob -= next;
	eol = 0;

	return line;
}

void LineReader::read() {
	int n;
	while ((n = ::read(fd, &buf[eob], bufSize - eob)) == -1
		&& errno == EINTR)
		;

	if (n == 0)
		eof = 1;
	else
	if (n > 0)
		eob += n;
}
