/*-------------------------------------------------------------------------
 *
 * pgtclId.c--
 *    useful routines to convert between strings and pointers
 *  Needed because everything in tcl is a string, but we want pointers
 *  to data structures
 *
 *  ASSUMPTION:  sizeof(long) >= sizeof(void*)
 *
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  $Header: /usr/cvs/NEOSOFT/nws/nws-3.2/neotcl8.1.1-lite/neo8.1.1/generic/neoCbuf.c,v 1.1.1.1 1999/03/31 20:34:37 damon Exp $
 *
 *	void Neo_initCursorBuf(Neo_CursorPool *pool, int startsize, int hardmax)
 *	int Neo_SetCursor(Tcl_Interp *interp, Neo_CursorPool *pool,
 *			void *res, char *handle)
 *	void * Neo_GetCursor(Neo_CursorPool *pool, int id)
 * 	void Neo_DelCursor(Neo_CursorPool *pool, int id)
 *
 *-------------------------------------------------------------------------
 */

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <tcl.h>
#include "neoCbuf.h"

/*
 * Initialize a cursor pool structure
 */
void
Neo_initCursorBuf(Neo_CursorPool *pool, int startsize, int hardmax)
{
    int			i;

    pool->res_count = 0;
    pool->res_last = -1;
    pool->res_max = startsize;
    pool->res_hardmax = hardmax;
    if (startsize)
	pool->results = (void **)ckalloc(sizeof(void *) * startsize);
    for (i = 0; i < startsize; i++) pool->results[i] = NULL;
}


/*
 * Find a slot for a new result id.  If the table is full, expand it by
 * a factor of 2.  However, do not expand past the hard max, as the client
 * is probably just not clearing result handles like they should.
 */
int
Neo_SetCursor(Tcl_Interp *interp, Neo_CursorPool *pool, void *res, char *handle)
{
    int			resid, i;
    char		buf[32];


    for (resid = pool->res_last+1; resid != pool->res_last; resid++) {
	if (resid == pool->res_max)
	    resid = 0;
	if (!pool->results[resid])
	{
	    pool->res_last = resid;
	    break;
	}
    }

    if (pool->results[resid]) {
	if (pool->res_max == pool->res_hardmax) {
	    Tcl_SetResult(interp, "hard limit on result handles reached",
		TCL_STATIC);
	    return -1;
	}
	pool->res_last = pool->res_max;
	resid = pool->res_max;
	pool->res_max *= 2;
	if (pool->res_max > pool->res_hardmax)
	    pool->res_max = pool->res_hardmax;
	pool->results = (void **)ckrealloc((void*)pool->results,
	    sizeof(void *) * pool->res_max);
	for (i = pool->res_last; i < pool->res_max; i++)
	    pool->results[i] = NULL;
    }

    pool->results[resid] = res;
    if (handle) {
	sprintf(buf, "%d", resid);
	Tcl_AppendResult(interp, handle, ".", buf, (char*) NULL);
    }
    return resid;
}

void *
Neo_GetCursor(Neo_CursorPool *pool, int id)
{
    return pool->results[id];
}


/*
 * Remove a result Id from the hash tables
 */
void
Neo_DelCursor(Neo_CursorPool *pool, int id)
{
    pool->results[id] = 0;
}
