/*
 *	string_buffer.c
 *
 *	JoyToyインタプリタ
 *
 *	* Sun Jan 01 00:00:00 JST 2006 Naoyuki Sawa
 *	- 作成開始。
 *	* Tue Jan 31 00:00:00 JST 2006 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sat Jun 17 05:26:02 JST 2006 Naoyuki Sawa
 *	- FIELD_OFFSET()→offsetof()に変更。
 */
#include "app.h"

/*****************************************************************************
 *	STRING_BUFFER
 *****************************************************************************/

typedef struct _STRING_BUFFER {
	int refcnt;
	STRING_BUFFER_INTERFACE* string_buffer_interface;
	//
	char* str;	/* 文字列バッファ */
} STRING_BUFFER;

IMPLEMENT_STRING_BUFFER_INTERFACE(STRING_BUFFER, string_buffer)

const INTERFACE_MAP string_buffer_interface_map[] = {
	{ STRING_BUFFER_INTERFACE_ID, offsetof(STRING_BUFFER, string_buffer_interface), &string_buffer_interface },
	{ 0/*終端*/ },
};

STRING_BUFFER_INTERFACE**
string_buffer_create()
{
	STRING_BUFFER* this = calloc(1, sizeof(STRING_BUFFER));
	if(!this) {
		DIE(); /* メモリ不足 */
	}
	this->refcnt = 1;
	apply_interface_map(this, string_buffer_interface_map);

	/* 文字列バッファの初期状態は、空文字列とします。 */
	string_buffer_empty(&this->string_buffer_interface);

	return &this->string_buffer_interface;
}

static void
string_buffer_delete(STRING_BUFFER* this)
{
	/* 文字列バッファを開放します。 */
	free(this->str);

	free(this);
}

/*****************************************************************************
 *	STRING_BUFFER_INTERFACE
 *****************************************************************************/

static void
string_buffer_empty(STRING_BUFFER_INTERFACE** intf)
{
	STRING_BUFFER* this = CONTAINING_RECORD(intf, STRING_BUFFER, string_buffer_interface);

	/* 文字列バッファの内容を、空文字列とします。 */
	this->str = realloc(this->str, 0 + 1/*nul*/);
	if(!this->str) {
		DIE(); /* メモリ不足 */
	}
	this->str[0] = '\0';
}

static void
string_buffer_append_char(STRING_BUFFER_INTERFACE** intf, int c)
{
	/* 長さ1の文字列として追加します。 */
	char str[2] = { c, '\0' };
	(*intf)->append_string(intf, str);
}

static void
string_buffer_append_string(STRING_BUFFER_INTERFACE** intf, const char* str)
{
	STRING_BUFFER* this = CONTAINING_RECORD(intf, STRING_BUFFER, string_buffer_interface);
	//
	int len1;
	int len2;
	int new_len;

	/* 文字列の合計長さを求めます。 */
	len1 = strlen(this->str);
	len2 = strlen(str);
	new_len = len1 + len2;

	/* 文字列バッファを拡張します。 */
	this->str = realloc(this->str, new_len + 1/*nul*/);
	if(!this->str) {
		DIE(); /* メモリ不足 */
	}

	/* 文字列を追加します。 */
	strcat(this->str, str);
}

static char*
string_buffer_lock(STRING_BUFFER_INTERFACE** intf, int min_len)
{
	STRING_BUFFER* this = CONTAINING_RECORD(intf, STRING_BUFFER, string_buffer_interface);
	//
	int len;

	/* 現在の文字列長よりも、要求された文字数が大きければ... */
	len = strlen(this->str);
	if(min_len > len) {

		/* 文字列バッファを拡張します。 */
		this->str = realloc(this->str, min_len + 1/*nul*/);
		if(!this->str) {
			DIE(); /* メモリ不足 */
		}
		this->str[min_len] = '\0';
	}

	return this->str;
}

static void
string_buffer_unlock(STRING_BUFFER_INTERFACE** intf, int new_len)
{
	STRING_BUFFER* this = CONTAINING_RECORD(intf, STRING_BUFFER, string_buffer_interface);

	/* 文字列長が明示されていなければ、実際の文字列長を求めます。 */
	if(new_len < 0) {
		new_len = strlen(this->str);
	}

	/* 文字列バッファをリサイズします。(文字列以降の不要部分を切り詰め) */
	this->str = realloc(this->str, new_len + 1/*nul*/);
	if(!this->str) {
		DIE(); /* メモリ不足 */
	}
	this->str[new_len] = '\0';
}

