/* * tclhandle.c -- * * adapted from tclXhandles.c tclXutil.c and tclExtend.h */ /* * * tclXhandles.c -- * * Tcl handles. Provides a mechanism for managing expandable tables that are * addressed by textual handles. *----------------------------------------------------------------------------- * Copyright 1991-1994 Karl Lehenbauer and Mark Diekhans. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies. Karl Lehenbauer and * Mark Diekhans make no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. *----------------------------------------------------------------------------- * $Id: tclhandle.c,v 1.1 2004/05/04 21:50:56 yakimoto Exp $ *----------------------------------------------------------------------------- */ #include <stdlib.h> #include <stdio.h> #include "tclhandle.h" /* Added 2000-09-19 by KG for memcpy, ... decls */ #include <string.h> #ifdef DMALLOC #include "dmalloc.h" #endif /* * Variable set to contain the alignment factor (in bytes) for this machine. * It is set on the first table initialization. */ static int tclhandleEntryAlignment = 0; /*============================================================================= * tclhandleLinkInNewEntries -- * Build free links through the newly allocated part of a table. * * Parameters: * o tblHdrPtr (I) - A pointer to the table header. * o newIdx (I) - Index of the first new entry. * o numEntries (I) - The number of new entries. *----------------------------------------------------------------------------- */ static void tclhandleLinkInNewEntries (tblHeader_pt tblHdrPtr, int newIdx, int numEntries) { int entIdx, lastIdx; entryHeader_pt entryPtr; lastIdx = newIdx + numEntries - 1; for (entIdx = newIdx; entIdx < lastIdx; entIdx++) { entryPtr = TBL_INDEX (tblHdrPtr, entIdx); entryPtr->freeLink = entIdx + 1; } entryPtr = TBL_INDEX (tblHdrPtr, lastIdx); entryPtr->freeLink = tblHdrPtr->freeHeadIdx; tblHdrPtr->freeHeadIdx = newIdx; } /*============================================================================= * tclhandleExpandTable -- * Expand a handle table, doubling its size. * Parameters: * o tblHdrPtr (I) - A pointer to the table header. * o neededIdx (I) - If positive, then the table will be expanded so that * this entry is available. If -1, then just expand by the number of * entries specified on table creation. MUST be smaller than this size. *----------------------------------------------------------------------------- */ static void tclhandleExpandTable (tblHeader_pt tblHdrPtr, int neededIdx) { ubyte_pt oldbodyPtr = tblHdrPtr->bodyPtr; int numNewEntries; int newSize; if (neededIdx < 0) numNewEntries = tblHdrPtr->tableSize; else numNewEntries = (neededIdx - tblHdrPtr->tableSize) + 1; newSize = (tblHdrPtr->tableSize + numNewEntries) * tblHdrPtr->entrySize; tblHdrPtr->bodyPtr = (ubyte_pt) malloc (newSize); memcpy (tblHdrPtr->bodyPtr, oldbodyPtr, (tblHdrPtr->tableSize * tblHdrPtr->entrySize)); tclhandleLinkInNewEntries (tblHdrPtr, tblHdrPtr->tableSize, numNewEntries); tblHdrPtr->tableSize += numNewEntries; free (oldbodyPtr); } /*============================================================================= * tclhandleAlloc -- * Allocate a table entry, expanding if necessary. * * Parameters: * o headerPtr (I) - A pointer to the table header. * o handle (O) - If not NULL, the handle is returned here. * o entryIdxPtr (O) - If not NULL, the index is returned here. * Returns: * The a pointer to the entry. *----------------------------------------------------------------------------- */ entryHeader_pt tclhandleAlloc (tblHeader_pt headerPtr, char *handle, unsigned long *entryIdxPtr) { tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr; entryHeader_pt entryPtr; int entryIdx; if (tblHdrPtr->freeHeadIdx == NULL_IDX) tclhandleExpandTable (tblHdrPtr, -1); entryIdx = tblHdrPtr->freeHeadIdx; entryPtr = TBL_INDEX (tblHdrPtr, entryIdx); tblHdrPtr->freeHeadIdx = entryPtr->freeLink; entryPtr->freeLink = ALLOCATED_IDX; if (handle) sprintf(handle, tblHdrPtr->handleFormat, entryIdx); if (entryIdxPtr) *entryIdxPtr = entryIdx; return USER_AREA (entryPtr); } /*============================================================================= * tclhandleInit -- * Create and initialize a Tcl dynamic handle table. * Parameters: * o prefix (I) - The character string prefix to be used. * o entrySize (I) - The size of an entry, in bytes. * o initEntries (I) - Initial size of the table, in entries. * Returns: * A pointer to the table header. *----------------------------------------------------------------------------- */ tblHeader_pt tclhandleInit (char *prefix, int entrySize, int initEntries) { tblHeader_pt tblHdrPtr; /* * It its not been calculated yet, determine the entry alignment required * for this machine. */ if (tclhandleEntryAlignment == 0) { tclhandleEntryAlignment = sizeof (void *); if (sizeof (unsigned long) > tclhandleEntryAlignment) tclhandleEntryAlignment = sizeof (unsigned long); if (sizeof (double) > tclhandleEntryAlignment) tclhandleEntryAlignment = sizeof (double); } /* * Set up the table entry. */ tblHdrPtr = (tblHeader_pt) malloc (sizeof (tblHeader_t) ); /* * Calculate entry size, including header, rounded up to sizeof (void *). */ tblHdrPtr->entrySize = ENTRY_HEADER_SIZE + ROUND_ENTRY_SIZE (entrySize); tblHdrPtr->freeHeadIdx = NULL_IDX; tblHdrPtr->tableSize = initEntries; tblHdrPtr->handleFormat = (char *)malloc(strlen(prefix)+4); strcpy(tblHdrPtr->handleFormat,prefix); strcat(tblHdrPtr->handleFormat,"%lu"); tblHdrPtr->bodyPtr = (ubyte_pt) malloc (initEntries * tblHdrPtr->entrySize); tclhandleLinkInNewEntries (tblHdrPtr, 0, initEntries); return tblHdrPtr; } /*============================================================================= * tclhandleDestroy -- * Destroy a Tcl dynamic handle table. * Parameters: * tblHdrPtr - A pointer to the table header. * Returns: * TCL_OK if success * TCL_ERROR if the table was not empty. *----------------------------------------------------------------------------- */ int tclhandleDestroy (tblHeader_pt tblHdrPtr) { int entIdx, lastIdx; entryHeader_pt entryPtr; lastIdx = tblHdrPtr->tableSize; for (entIdx = 0; entIdx < lastIdx; entIdx++) { entryPtr = TBL_INDEX (tblHdrPtr, entIdx); if (entryPtr->freeLink == ALLOCATED_IDX) return TCL_ERROR; } free(tblHdrPtr->bodyPtr); free(tblHdrPtr->handleFormat); free(tblHdrPtr); return TCL_OK; } /*============================================================================= * tclhandleReset -- * Reset a Tcl dynamic handle table. * Parameters: * tblHdrPtr - A pointer to the table header. * initEntries - The number of initial entries in the reset table. * Returns: * TCL_OK if success * TCL_ERROR if any handles still in use in the old handle table. *----------------------------------------------------------------------------- */ int tclhandleReset (tblHeader_pt tblHdrPtr, int initEntries) { int entIdx, lastIdx; entryHeader_pt entryPtr; lastIdx = tblHdrPtr->tableSize; for (entIdx = 0; entIdx < lastIdx; entIdx++) { entryPtr = TBL_INDEX (tblHdrPtr, entIdx); if (entryPtr->freeLink == ALLOCATED_IDX) return TCL_ERROR; } free(tblHdrPtr->bodyPtr); tblHdrPtr->freeHeadIdx = NULL_IDX; tblHdrPtr->tableSize = initEntries; tblHdrPtr->bodyPtr = (ubyte_pt) malloc (initEntries * tblHdrPtr->entrySize); tclhandleLinkInNewEntries (tblHdrPtr, 0, initEntries); return TCL_OK; } /*============================================================================= * tclhandleIndex -- * Translate a string handle to a handleTable Index. * * Parameters: * o headerPtr (I) - A pointer to the table header. * o handle (I) - The handle string -- <prefix><int> * o entryIdxPtr (O) - If not NULL, the index is returned here. * Returns: * TCL_OK if the handle was valid. * TCL_ERROR if the handle was invalid. *----------------------------------------------------------------------------- */ int tclhandleIndex (tblHeader_pt tblHdrPtr, char *handle, unsigned long *entryIdxPtr) { unsigned long entryIdx; if ((sscanf(handle, tblHdrPtr->handleFormat, &entryIdx)) != 1) return TCL_ERROR; if (entryIdxPtr) *entryIdxPtr = entryIdx; return TCL_OK; } /*============================================================================= * tclhandleString -- * Translate a handleTable Index into a string handle * NB. No check is performed on the Index provided. * * Parameters: * o headerPtr (I) - A pointer to the table header. * o handle (O) - The handle string -- <prefix><int> * o entryIdxPtr (I) - If not NULL, the index is returned here. *----------------------------------------------------------------------------- */ void tclhandleString (tblHeader_pt tblHdrPtr, char *handle, unsigned long entryIdx) { sprintf(handle, tblHdrPtr->handleFormat, entryIdx); } /*============================================================================= * tclhandleXlateIndex -- * Translate an index to an entry pointer. * * Parameters: * o headerPtr (I) - A pointer to the table header. * o index (I) - The index of an entry. * Returns: * A pointer to the entry, or NULL if an error occured. *----------------------------------------------------------------------------- */ void * tclhandleXlateIndex (tblHeader_pt headerPtr, unsigned long entryIdx) { tblHeader_pt tblHdrPtr = headerPtr; entryHeader_pt entryPtr; entryPtr = TBL_INDEX (tblHdrPtr, entryIdx); if ((entryIdx >= tblHdrPtr->tableSize) || (entryPtr->freeLink != ALLOCATED_IDX)) { return NULL; } return USER_AREA (entryPtr); } /*============================================================================= * tclhandleXlate -- * Translate a string handle to an entry pointer. * * Parameters: * o headerPtr (I) - A pointer to the table header. * o handle (I) - The handle string -- <prefix><int> * Returns: * A pointer to the entry, or NULL if an error occured. *----------------------------------------------------------------------------- */ void * tclhandleXlate (tblHeader_pt tblHdrPtr, char *handle) { unsigned long entryIdx; if ((tclhandleIndex(tblHdrPtr, handle, &entryIdx)) != TCL_OK) return NULL; return (tclhandleXlateIndex(tblHdrPtr, entryIdx)); } /*============================================================================ * tclhandleFreeIndex -- * Frees a handle table entry by index. * * Parameters: * o headerPtr (I) - A pointer to the table header. * o index (I) - The index of an entry. *---------------------------------------------------------------------------- * Returns: * The contents of the entry, if success, or NULL if an error occured. *---------------------------------------------------------------------------- */ void * tclhandleFreeIndex (tblHeader_pt headerPtr, unsigned long entryIdx) { tblHeader_pt tblHdrPtr = headerPtr; entryHeader_pt entryPtr, freeentryPtr; entryPtr = TBL_INDEX (tblHdrPtr, entryIdx); if ((entryIdx >= tblHdrPtr->tableSize) || (entryPtr->freeLink != ALLOCATED_IDX)) { return NULL; } entryPtr = USER_AREA (entryPtr); freeentryPtr = HEADER_AREA (entryPtr); freeentryPtr->freeLink = tblHdrPtr->freeHeadIdx; tblHdrPtr->freeHeadIdx = (((ubyte_pt) entryPtr) - tblHdrPtr->bodyPtr) / tblHdrPtr->entrySize; return entryPtr; } /*============================================================================ * tclhandleFree -- * Frees a handle table entry by handle. * * Parameters: * o headerPtr (I) - A pointer to the table header. * o handle (I) - The handle of an entry. *---------------------------------------------------------------------------- * Returns: * The contents of the entry, if success, or NULL if an error occured. *---------------------------------------------------------------------------- */ void * tclhandleFree (tblHeader_pt tblHdrPtr, char *handle) { unsigned long entryIdx; if ((tclhandleIndex(tblHdrPtr, handle, &entryIdx)) != TCL_OK) return NULL; return (tclhandleFreeIndex(tblHdrPtr, entryIdx)); }