/*
**    $Id: handle.c,v 1.1 1993/06/26 22:10:49 pjs Exp $
**    Copyright (C) 1993  Patrick Sweeney
**
**    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 of the License, or
**    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 this program; if not, write to the Free Software
**    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "std.h"
#include "windows.h"
#include "handle.h"

typedef struct
{
	u8_t *p;
	u32_t size;
	bool_t alloced;
	u32_t refcount;
	u32_t flags;
} Handle_entry;

static Handle_entry *handle_pool = NULL;
static int num_handles = 0;
static int max_handles = 0;
#define INC_SIZE 512

static int
handlepool_grow()
{
	Handle_entry *pool;

	if ((pool = ALLOCN(Handle_entry, max_handles + INC_SIZE)) == NULL)
		return -1;
	if (handle_pool)
	{
		memcpy(pool, handle_pool, sizeof(Handle_entry) * max_handles);
		DEALLOC(handle_pool);
	}
	handle_pool = pool;
	max_handles += INC_SIZE;
	return 0;
}

HANDLE
handle_malloc(u32_t nbytes, u32_t flags)
{
	Handle_entry *e;

	if (num_handles == max_handles)
		if (handlepool_grow() != 0)
			return (HANDLE) NULL;
	e = &handle_pool[num_handles];
	if ((e->p = ALLOCZN(u8_t, nbytes)) == NULL)
		return (HANDLE) NULL;
	e->size = nbytes;
	e->alloced = TRUE;
	e->refcount = 1;
	e->flags = flags;
	return (HANDLE) num_handles;
}

/*
** This will give really crappy performance. Probably should use a hash
** table. But for now just get it to work...
*/
HANDLE
handle_create(u8_t *p, u32_t nbytes, u32_t flags)
{
	Handle_entry *e;

	if (num_handles == max_handles)
		if (handlepool_grow() != 0)
			return (HANDLE) NULL;
	e = &handle_pool[num_handles];
	e->p = p;
	e->size = nbytes;
	e->alloced = FALSE;
	e->refcount = 1;
	e->flags = flags;
	return (HANDLE) num_handles++;
}

void
handle_destroy(HANDLE h)
{
	int i;
	Handle_entry *e;

	e = &handle_pool[(int)h];
	e->refcount--;
	if (e->refcount == 0)
	{
		if (e->alloced)
			DEALLOC(e->p);
		/* Yuch!!!!!!!!! compact table */
		for(i=(int)h; i<num_handles-1; i++)
			handle_pool[i] = handle_pool[i + 1];
		num_handles--;
	}
	return;
}

u8_t *
handle_topointer(HANDLE h)
{
	return handle_pool[h].p;
}

u32_t
handle_size(HANDLE h)
{
	return handle_pool[h].size;
}

void
handle_reset(HANDLE h, u8_t *p, u32_t nbytes)
{
	Handle_entry *e;

	e = &handle_pool[h];
	if (e->alloced)
		DEALLOC(e->p);
	e->p = p;
	e->size = nbytes;
	return;
}

void
handle_incref(HANDLE h)
{
	handle_pool[h].refcount++;
	return;
}

void
handle_decref(HANDLE h)
{
	handle_pool[h].refcount--;
	return;
}

u32_t
handle_curref(HANDLE h)
{
	return handle_pool[h].refcount;
}

bool_t
handle_isvalid(HANDLE h)
{
	return (h >= 0 && h < num_handles);
}

u32_t
handle_getflags(HANDLE h)
{
	return handle_pool[h].flags;
}

void
handle_setflags(HANDLE h, u32_t flags)
{
	handle_pool[h].flags = flags;
	return;
}
