/* # skkinput (Simple Kana-Kanji Input)
 *
 * This file is part of skkinput.
 * Copyright (C) 2002
 * Takashi SAKAMOTO (PXG01715@nifty.ne.jp)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with skkinput; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#ifndef varbuffer_h
#define varbuffer_h

#include <stdlib.h>
#include <assert.h>

enum {
	VARBUF_DEFAULTSIZE	= sizeof (long) / sizeof (unsigned char) * 64,
} ;

typedef struct {
	unsigned char	m_achInternal [VARBUF_DEFAULTSIZE] ;
	void*			m_pBuffer ;
	int				m_nIndex ;
	int				m_nSize ;
	int				m_nUsage ;
	int				m_nWidth ;
}	TVarbuffer ;


static inline	Boolean
TVarbuffer_Initialize (
	register TVarbuffer*	pVarbuf,
	register int			nWidth)
{
	assert (pVarbuf != NULL) ;
	assert (nWidth  > 0) ;
	
	pVarbuf->m_nSize	= VARBUF_DEFAULTSIZE / nWidth ;
	assert (pVarbuf->m_nSize > 0) ;
	pVarbuf->m_nUsage	= 0 ;
	pVarbuf->m_nWidth	= nWidth ;
	pVarbuf->m_pBuffer	= pVarbuf->m_achInternal ;
	return	True ;
}

static inline	Boolean
TVarbuffer_Uninitialize (
	register TVarbuffer*	pVarbuf)
{
	assert (pVarbuf != NULL) ;
	
	if (pVarbuf->m_pBuffer != pVarbuf->m_achInternal) {
		free (pVarbuf->m_pBuffer) ;
		pVarbuf->m_pBuffer	= pVarbuf->m_achInternal ;
	}
	pVarbuf->m_nUsage	= 0 ;
	pVarbuf->m_nWidth	= 1 ;
	pVarbuf->m_nSize	= VARBUF_DEFAULTSIZE ;
	return	True ;
}

static inline	Boolean
TVarbuffer_Clear (
	register TVarbuffer*	pVarbuf)
{
	assert (pVarbuf != NULL) ;

	pVarbuf->m_nUsage	= 0 ;
	return	True ;
}

static inline	Boolean
TVarbuffer_Sub (
	register TVarbuffer*	pVarbuf,
	register int			nData)
{
	assert (pVarbuf != NULL) ;

	pVarbuf->m_nUsage	-= nData ;
	if (pVarbuf->m_nUsage < 0) {
		pVarbuf->m_nUsage	= 0 ;
		return	False ;
	}
	return	True ;
}

static inline	Boolean
TVarbuffer_Require (
	register TVarbuffer*	pVarbuf,
	register int			nData)
{
	register int		nUsage, nPos ;

	if (nData < 0) 
		return	TVarbuffer_Sub (pVarbuf, - nData) ;

	nUsage	= pVarbuf->m_nUsage + nData ;
	nPos	= pVarbuf->m_nUsage * pVarbuf->m_nWidth ;

	if (nUsage >= pVarbuf->m_nSize) {
		void*	pNewBuffer ;
		int		nNewSize ;

		nNewSize	= (nUsage + VARBUF_DEFAULTSIZE) ;
		nNewSize	= nNewSize - nNewSize % VARBUF_DEFAULTSIZE ;
		assert (nNewSize >= nUsage) ;

		pNewBuffer	= malloc (pVarbuf->m_nWidth * nNewSize) ;
		if (pNewBuffer == NULL) 
			return	False ;

		memcpy (pNewBuffer, pVarbuf->m_pBuffer, nPos) ;
		if (pVarbuf->m_pBuffer != pVarbuf->m_achInternal) 
			free (pVarbuf->m_pBuffer) ;
		pVarbuf->m_pBuffer	= pNewBuffer ;
		pVarbuf->m_nSize	= nNewSize ;
	}
	pVarbuf->m_nUsage	= nUsage ;
	return	True ;
}

static inline	Boolean
TVarbuffer_Add (
	register TVarbuffer*	pVarbuf,
	register const void*	pData,
	register int			nData)
{
	register int	nPos ;

	assert (pVarbuf != NULL) ;

	nPos	= pVarbuf->m_nUsage * pVarbuf->m_nWidth ;
	if (! (TVarbuffer_Require (pVarbuf, nData)))
		return	False ;
	memcpy ((unsigned char *)pVarbuf->m_pBuffer + nPos, pData, nData * pVarbuf->m_nWidth) ;
	return	True ;
}

static inline	void*
TVarbuffer_GetBuffer (
	register TVarbuffer*	pVarbuf)
{
	assert (pVarbuf != NULL) ;
	
	return	pVarbuf->m_pBuffer ;
}

static inline	int
TVarbuffer_GetUsage (
	register TVarbuffer*	pVarbuf)
{
	assert (pVarbuf != NULL) ;

	return	pVarbuf->m_nUsage ;
}


#endif 

