#ifdef HAVE_AST
#include                <ast.h>
#include                <vmalloc.h>
#else
#include                <sys/types.h>
#include                <stdlib.h>
#include                <string.h>
#include                <unistd.h>
#endif        

#include "tcl.h"

#ifndef ulong
#define ulong unsigned long
#endif

#ifndef FALSE
#define FALSE (0)
#endif

#ifndef TRUE
#define TRUE (1)
#endif

#define ISSPACE(c) (isspace ((unsigned char) c))

/*
 * Marco to rounded up a size to be a multiple of (void *).  This is required
 * for systems that have alignment restrictions on pointers and data.
 */
#define ROUND_ENTRY_SIZE(size) \
    ((((size) + entryAlignment - 1) / entryAlignment) * entryAlignment)

#define NULL_IDX      -1
#define ALLOCATED_IDX -2

typedef unsigned char ubyte_t;
typedef ubyte_t *ubyte_pt;

/*
 * This is the table header.  It is separately allocated from the table body,
 * since it must keep track of a table body that might move.  Each entry in the
 * table is preceded with a header which has the free list link, which is a
 * entry index of the next free entry.  Special values keep track of allocated
 * table is preceded with a header which has the free list link, which is a
 * entry index of the next free entry.  Special values keep track of allocated
 * entries.
 */

typedef struct {
    int      entrySize;         /* Entry size in bytes, including overhead */
    int      tableSize;         /* Current number of entries in the table  */
    int      freeHeadIdx;       /* Index of first free entry in the table  */
    ubyte_pt bodyPtr;           /* Pointer to table body                   */
    } tblHeader_t;
typedef tblHeader_t *tblHeader_pt;

typedef struct {
    int freeLink;
  } entryHeader_t;
typedef entryHeader_t *entryHeader_pt;

#define ENTRY_HEADER_SIZE (ROUND_ENTRY_SIZE (sizeof (entryHeader_t)))

/*
 * This macro is used to return a pointer to an entry, given its index.
 */
#define TBL_INDEX(hdrPtr, idx) \
    ((entryHeader_pt) (hdrPtr->bodyPtr + (hdrPtr->entrySize * idx)))

/*
 * This macro is used to return an index to an entry, given its pointer.
 *    **** This macro provides no checks *****
 */
#define TBL_ENTRY(hdrPtr, entryPtr) \
    ((ulong) ((entryPtr - (hdrPtr->bodyPtr)) / (hdrPtr->entrySize)))

/*
 * This macros to convert between pointers to the user and header area of
 * an table entry.
 */
#define USER_AREA(entryPtr) \
 (void *) (((ubyte_pt) entryPtr) + ENTRY_HEADER_SIZE);
#define HEADER_AREA(entryPtr) \
 (entryHeader_pt) (((ubyte_pt) entryPtr) - ENTRY_HEADER_SIZE);

/*
 * Function prototypes.
 */

int dghandleFree (void *headerPtr, ulong  entryIdx);
tblHeader_pt dghandleInit (int entrySize, int initEntries);
int dghandleReset (tblHeader_pt tblHdrPtr, int initEntries);
void * dghandleXlate (void *headerPtr, ulong entryIdx);
entryHeader_pt dghandleAlloc (tblHeader_pt  tblHdrPtr, ulong *entryIdxPtr);
