#include <curses.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern "C" {
#include "error.h"
}
#include "utils.h"

void * mymalloc(int size, char *what)
{
	void *dummy = malloc(size);
	if (!dummy)
		error_exit("failed to allocate %d bytes for %s\n", size, what);

	return dummy;
}

void * myrealloc(void *oldp, int newsize, char *what)
{
	void *dummy = realloc(oldp, newsize);
	if (!dummy)
		error_exit("failed to reallocate to %d bytes for %s\n", newsize, what);

	return dummy;
}

char * mystrdup(char *in)
{
	char *dummy = strdup(in);
	if (!dummy)
		error_exit("failed to copy string '%s': out of memory?\n", in);

	return dummy;
}

buffered_reader::buffered_reader(int cur_fd, int cur_block_size)
{
	fd = cur_fd;
	block_size = cur_block_size;

	buffer = NULL;
	buffer_length = buffer_pointer = 0;
}

buffered_reader::~buffered_reader()
{
	free(buffer);
}

int buffered_reader::number_of_bytes_in_buffer(void)
{
	return buffer_length - buffer_pointer;
}

int buffered_reader::garbage_collect(char shrink_buffer)
{
	if (buffer_pointer)
	{
		int n_to_move = number_of_bytes_in_buffer();

		memmove(&buffer[0], &buffer[buffer_pointer], n_to_move);
		buffer_length -= buffer_pointer;
		buffer_pointer = 0;

		if (shrink_buffer)
		{
			char *dummy = (char *)realloc(buffer, buffer_length);
			if (!dummy)
				error_exit("buffered_reader::garbage_collect: realloc failed\n");

			buffer = dummy;
		}
	}

	return 0;
}

int buffered_reader::read_into_buffer(void)
{
	char *dummy;
	int n_read = 0;

	garbage_collect();

	dummy = (char *)realloc(buffer, buffer_length + block_size);
	if (!dummy)
		error_exit("buffered_reader::read_into_buffer: realloc failed\n");
	buffer = dummy;

	for(;;)
	{
		n_read = read(fd, &buffer[buffer_length], block_size);

		if (n_read == -1)
		{
			if (errno == EINTR)
				continue;

			error_exit("buffered_reader::read_into_buffer(): read failed (%s)\n", strerror(errno));
		}

		buffer_length += n_read;

		break;
	}

	return n_read;
}

char * buffered_reader::read_line(void)
{
	char *out = NULL;
	int lf_offset = -1;
	int n_bytes;

	if (number_of_bytes_in_buffer() == 0)
	{
		if (read_into_buffer() == 0)
		{
			// EOF
			return NULL;
		}
	}

	for(;;)
	{
		for(int loop=buffer_pointer; loop<buffer_length; loop++)
		{
			if (buffer[loop] == '\n')
			{
				lf_offset = loop;
				break;
			}
		}

		if (lf_offset != -1)
			break;

		if (read_into_buffer() == 0)
		{
			lf_offset = buffer_length;
			break;
		}
	}

	n_bytes = lf_offset - buffer_pointer;

	out = (char *)malloc(n_bytes + 1);
	if (!out)
		error_exit("buffered_reader::read_line(): malloc(%d) failed\n", n_bytes + 1);

	memcpy(out, &buffer[buffer_pointer], n_bytes);
	out[n_bytes] = 0x00;

	buffer_pointer = lf_offset + 1;

	return out;
}


syntax highlighted by Code2HTML, v. 0.9.1