/*	
 *	clipbuf.c
 *
 *	ユーティリティ：リングバッファ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015 Naoyuki Sawa
 *
 *	* Tue Jan 06 21:26:41 JST 2015 Naoyuki Sawa
 *	- 新規作成。
 *	- 「ユーティリティ：リングバッファ」を、clipmisc.*⇒clipbuf.*へ分離しました。
 *	  使用頻度が低いので、無駄にリンクして容量が増加する事を防ぐためです。
 */
#include "clip.h"

/*****************************************************************************
 *	ユーティリティ：リングバッファ
 *****************************************************************************/

BUFFER*
create_buffer(int capacity)
{
	BUFFER* buffer;

	if(capacity < 0) {
		DIE();
	}

	/* ヘッダとストレージのメモリを確保します。 */
	buffer = malloc(sizeof(BUFFER) + capacity);
	if(!buffer) {
		DIE(); /* メモリ不足 */
	}

	/* ヘッダを初期化します。 */
	buffer->capacity = capacity;
	buffer->size = 0;

	return buffer;
}

void
delete_buffer(BUFFER* buffer)
{
	/* ヘッダとストレージのメモリを開放します。 */
	free(buffer);
}

void
clear_buffer(BUFFER* buffer)
{
	buffer->size = 0;
}

int
write_buffer(BUFFER* buffer, const void* data/*[length]*/, int length)
{
	unsigned char* storage = (unsigned char*)(buffer + 1);

	if(length < 0) {
		DIE();
	}

	/* 書き込むデータ長を、ストレージの空き容量へ切り詰めます。 */
	if(length > (buffer->capacity - buffer->size)) {
		length = (buffer->capacity - buffer->size);
	}

	/* ストレージへ、データを書き込みます。 */
	memcpy(storage + buffer->size, data, length);
	buffer->size += length;

	/* 実際に書き込んだデータ長を返します。 */
	return length;
}

int
read_buffer(BUFFER* buffer, void* data/*[maxlength]*/, int maxlength)
{
	unsigned char* storage = (unsigned char*)(buffer + 1);
	int length;

	if(maxlength < 0) {
		DIE();
	}

	/* 読み出すデータ長を、指定されたメモリ領域サイズへ切り詰めます。 */
	length = maxlength < buffer->size
	       ? maxlength : buffer->size;

	/* ストレージ先頭のデータを、指定されたメモリ領域にコピーします。
	 * ただし、data=NULLならば、読み出したデータを破棄します。
	 */
	if(data) {
		memcpy(data, storage, length);
	}

	/* ストレージ先頭のデータを削除し、その分、ストレージを詰めます。 */
	buffer->size -= length;
	memmove(storage, storage + length, buffer->size);

	/* 実際に読み出したデータ長を返します。 */
	return length;
}

const void*
peek_buffer(BUFFER* buffer, int* length)
{
	/* データ長を格納します。 */
	if(length) {
		*length = buffer->size;
	}

	/* ストレージの先頭アドレスを返します。 */
	return buffer + 1;
}

int
buffer_space(BUFFER* buffer)
{
	/* 書き込み可能な最大データ長は、ストレージの空き容量です。 */
	return buffer->capacity - buffer->size;
}
