home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / devel / tcl / tclx7_31.z / tclx7_31 / tcldev / tclX7.3a-p1 / src / tclXhandles.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-12  |  15.0 KB  |  466 lines

  1. /*
  2.  *
  3.  * tclXhandles.c --
  4.  *
  5.  * Tcl handles.  Provides a mechanism for managing expandable tables that are
  6.  * addressed by textual handles.
  7.  *-----------------------------------------------------------------------------
  8.  * Copyright 1991-1993 Karl Lehenbauer and Mark Diekhans.
  9.  *
  10.  * Permission to use, copy, modify, and distribute this software and its
  11.  * documentation for any purpose and without fee is hereby granted, provided
  12.  * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  13.  * Mark Diekhans make no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without express or
  15.  * implied warranty.
  16.  *-----------------------------------------------------------------------------
  17.  * $Id: tclXhandles.c,v 3.1 1993/12/19 18:31:33 markd Exp $
  18.  *-----------------------------------------------------------------------------
  19.  */
  20.  
  21. #include "tclExtdInt.h"
  22.  
  23. /*
  24.  * Marco to rounded up a size to be a multiple of (void *).  This is required
  25.  * for systems that have alignment restrictions on pointers and data.
  26.  */
  27. #define ROUND_ENTRY_SIZE(size) \
  28.     ((((size) + sizeof (void *) - 1) / sizeof (void *)) * sizeof (void *))
  29.  
  30. /*
  31.  * This is the table header.  It is separately allocated from the table body,
  32.  * since it must keep track of a table body that might move.  Each entry in the
  33.  * table is preceded with a header which has the free list link, which is a
  34.  * entry index of the next free entry.  Special values keep track of allocated
  35.  * entries.
  36.  */
  37.  
  38. #define NULL_IDX      -1
  39. #define ALLOCATED_IDX -2
  40.  
  41. typedef unsigned char ubyte_t;
  42. typedef ubyte_t *ubyte_pt;
  43.  
  44. typedef struct {
  45.     int      useCount;          /* Keeps track of the number sharing       */
  46.     int      entrySize;         /* Entry size in bytes, including overhead */
  47.     int      tableSize;         /* Current number of entries in the table  */
  48.     int      freeHeadIdx;       /* Index of first free entry in the table  */
  49.     ubyte_pt bodyPtr;           /* Pointer to table body                   */
  50.     int      baseLength;        /* Length of handleBase.                   */
  51.     char     handleBase [1];    /* Base handle name.  MUST BE LAST FIELD!  */
  52.     } tblHeader_t;
  53. typedef tblHeader_t *tblHeader_pt;
  54.  
  55. typedef struct {
  56.     int freeLink;
  57.   } entryHeader_t;
  58. typedef entryHeader_t *entryHeader_pt;
  59.  
  60. #define ENTRY_HEADER_SIZE (ROUND_ENTRY_SIZE (sizeof (entryHeader_t)))
  61.  
  62. /*
  63.  * This macro is used to return a pointer to an entry, given its index.
  64.  */
  65. #define TBL_INDEX(hdrPtr, idx) \
  66.     ((entryHeader_pt) (hdrPtr->bodyPtr + (hdrPtr->entrySize * idx)))
  67.  
  68. /*
  69.  * This macros to convert between pointers to the user and header area of
  70.  * an table entry.
  71.  */
  72. #define USER_AREA(entryPtr) \
  73.  (void_pt) (((ubyte_pt) entryPtr) + ENTRY_HEADER_SIZE);
  74. #define HEADER_AREA(entryPtr) \
  75.  (entryHeader_pt) (((ubyte_pt) entryPtr) - ENTRY_HEADER_SIZE);
  76.  
  77. /*
  78.  * Prototypes of internal functions.
  79.  */
  80. static void
  81. LinkInNewEntries _ANSI_ARGS_((tblHeader_pt tblHdrPtr,
  82.                               int          newIdx,
  83.                               int          numEntries));
  84.  
  85. static void
  86. ExpandTable _ANSI_ARGS_((tblHeader_pt tblHdrPtr,
  87.                          int          neededIdx));
  88.  
  89. static entryHeader_pt
  90. AllocEntry _ANSI_ARGS_((tblHeader_pt  tblHdrPtr,
  91.                         int          *entryIdxPtr));
  92.  
  93. static int
  94. HandleDecode _ANSI_ARGS_((Tcl_Interp   *interp,
  95.                           tblHeader_pt  tblHdrPtr,
  96.                           CONST char   *handle));
  97.  
  98. /*=============================================================================
  99.  * LinkInNewEntries --
  100.  *   Build free links through the newly allocated part of a table.
  101.  *   
  102.  * Parameters:
  103.  *   o tblHdrPtr (I) - A pointer to the table header.
  104.  *   o newIdx (I) - Index of the first new entry.
  105.  *   o numEntries (I) - The number of new entries.
  106.  *-----------------------------------------------------------------------------
  107.  */
  108. static void
  109. LinkInNewEntries (tblHdrPtr, newIdx, numEntries)
  110.     tblHeader_pt tblHdrPtr;
  111.     int          newIdx;
  112.     int          numEntries;
  113. {
  114.     int            entIdx, lastIdx;
  115.     entryHeader_pt entryPtr;
  116.     
  117.     lastIdx = newIdx + numEntries - 1;
  118.  
  119.     for (entIdx = newIdx; entIdx < lastIdx; entIdx++) {
  120.         entryPtr = TBL_INDEX (tblHdrPtr, entIdx);
  121.         entryPtr->freeLink = entIdx + 1;
  122.     }
  123.     entryPtr = TBL_INDEX (tblHdrPtr, lastIdx);
  124.     entryPtr->freeLink = tblHdrPtr->freeHeadIdx;
  125.     tblHdrPtr->freeHeadIdx = newIdx;
  126.  
  127. }
  128.  
  129. /*=============================================================================
  130.  * ExpandTable --
  131.  *   Expand a handle table, doubling its size.
  132.  * Parameters:
  133.  *   o tblHdrPtr (I) - A pointer to the table header.
  134.  *   o neededIdx (I) - If positive, then the table will be expanded so that
  135.  *     this entry is available.  If -1, then just expand by the number of 
  136.  *     entries specified on table creation.  MUST be smaller than this size.
  137.  *-----------------------------------------------------------------------------
  138.  */
  139. static void
  140. ExpandTable (tblHdrPtr, neededIdx)
  141.     tblHeader_pt tblHdrPtr;
  142.     int          neededIdx;
  143. {
  144.     ubyte_pt oldbodyPtr = tblHdrPtr->bodyPtr;
  145.     int      numNewEntries;
  146.     int      newSize;
  147.     
  148.     if (neededIdx < 0)
  149.         numNewEntries = tblHdrPtr->tableSize;
  150.     else
  151.         numNewEntries = (neededIdx - tblHdrPtr->tableSize) + 1;
  152.     newSize = (tblHdrPtr->tableSize + numNewEntries) * tblHdrPtr->entrySize;
  153.  
  154.     tblHdrPtr->bodyPtr = (ubyte_pt) ckalloc (newSize);
  155.     memcpy (tblHdrPtr->bodyPtr, oldbodyPtr, 
  156.             (tblHdrPtr->tableSize * tblHdrPtr->entrySize));
  157.     LinkInNewEntries (tblHdrPtr, tblHdrPtr->tableSize, numNewEntries);
  158.     tblHdrPtr->tableSize += numNewEntries;
  159.     ckfree (oldbodyPtr);
  160.     
  161. }
  162.  
  163. /*=============================================================================
  164.  * AllocEntry --
  165.  *   Allocate a table entry, expanding if necessary.
  166.  *
  167.  * Parameters:
  168.  *   o tblHdrPtr (I) - A pointer to the table header.
  169.  *   o entryIdxPtr (O) - The index of the table entry is returned here.
  170.  * Returns:
  171.  *    The a pointer to the entry.
  172.  *-----------------------------------------------------------------------------
  173.  */
  174. static entryHeader_pt
  175. AllocEntry (tblHdrPtr, entryIdxPtr)
  176.     tblHeader_pt  tblHdrPtr;
  177.     int          *entryIdxPtr;
  178. {
  179.     int            entryIdx;
  180.     entryHeader_pt entryPtr;
  181.  
  182.     if (tblHdrPtr->freeHeadIdx == NULL_IDX)
  183.         ExpandTable (tblHdrPtr, -1);
  184.  
  185.     entryIdx = tblHdrPtr->freeHeadIdx;    
  186.     entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
  187.     tblHdrPtr->freeHeadIdx = entryPtr->freeLink;
  188.     entryPtr->freeLink = ALLOCATED_IDX;
  189.     
  190.     *entryIdxPtr = entryIdx;
  191.     return entryPtr;
  192.     
  193. }
  194.  
  195. /*=============================================================================
  196.  * HandleDecode --
  197.  *   Decode handle into an entry number.
  198.  *
  199.  * Parameters:
  200.  *   o interp (I) - A error message may be returned in result.
  201.  *   o tblHdrPtr (I) - A pointer to the table header.
  202.  *   o handle (I) - Handle to decode.
  203.  * Returns:
  204.  *   The entry index decoded from the handle, or a negative number if an error
  205.  *   occured.
  206.  *-----------------------------------------------------------------------------
  207.  */
  208. static int
  209. HandleDecode (interp, tblHdrPtr, handle)
  210.     Tcl_Interp   *interp;
  211.     tblHeader_pt  tblHdrPtr;
  212.     CONST char   *handle;
  213. {
  214.     unsigned entryIdx;
  215.  
  216.     if ((strncmp (tblHdrPtr->handleBase, (char *) handle, 
  217.              tblHdrPtr->baseLength) != 0) ||
  218.              !Tcl_StrToUnsigned (&handle [tblHdrPtr->baseLength], 10, 
  219.                                  &entryIdx)) {
  220.         Tcl_AppendResult (interp, "invalid ", tblHdrPtr->handleBase,
  221.                           " handle: ", handle, (char *) NULL);
  222.         return -1;
  223.     }
  224.     return entryIdx;
  225.  
  226. }
  227.  
  228. /*=============================================================================
  229.  * Tcl_HandleTblInit --
  230.  *   Create and initialize a Tcl dynamic handle table.  The use count on the
  231.  *   table is set to one.
  232.  * Parameters:
  233.  *   o handleBase(I) - The base name of the handle, the handle will be returned
  234.  *     in the form "baseNN", where NN is the table entry number.
  235.  *   o entrySize (I) - The size of an entry, in bytes.
  236.  *   o initEntries (I) - Initial size of the table, in entries.
  237.  * Returns:
  238.  *   A pointer to the table header.  
  239.  *-----------------------------------------------------------------------------
  240.  */
  241. void_pt
  242. Tcl_HandleTblInit (handleBase, entrySize, initEntries)
  243.     CONST char *handleBase;
  244.     int         entrySize;
  245.     int         initEntries;
  246. {
  247.     tblHeader_pt tblHdrPtr;
  248.     int          baseLength = strlen ((char *) handleBase);
  249.  
  250.     tblHdrPtr = (tblHeader_pt) ckalloc (sizeof (tblHeader_t) + baseLength + 1);
  251.  
  252.     tblHdrPtr->useCount = 1;
  253.     tblHdrPtr->baseLength = baseLength;
  254.     strcpy (tblHdrPtr->handleBase, (char *) handleBase);
  255.  
  256.     /* 
  257.      * Calculate entry size, including header, rounded up to sizeof (void *). 
  258.      */
  259.     tblHdrPtr->entrySize = ENTRY_HEADER_SIZE + ROUND_ENTRY_SIZE (entrySize);
  260.     tblHdrPtr->freeHeadIdx = NULL_IDX;
  261.     tblHdrPtr->tableSize = initEntries;
  262.     tblHdrPtr->bodyPtr =
  263.         (ubyte_pt) ckalloc (initEntries * tblHdrPtr->entrySize);
  264.     LinkInNewEntries (tblHdrPtr, 0, initEntries);
  265.  
  266.     return (void_pt) tblHdrPtr;
  267.  
  268. }
  269.  
  270. /*=============================================================================
  271.  * Tcl_HandleTblUseCount --
  272.  *   Alter the handle table use count by the specified amount, which can be
  273.  *   positive or negative.  Amount may be zero to retrieve the use count.
  274.  * Parameters:
  275.  *   o headerPtr (I) - Pointer to the table header.
  276.  *   o amount (I) - The amount to alter the use count by.
  277.  * Returns:
  278.  *   The resulting use count.
  279.  *-----------------------------------------------------------------------------
  280.  */
  281. int
  282. Tcl_HandleTblUseCount (headerPtr, amount)
  283.     void_pt  headerPtr;
  284.     int      amount;
  285. {
  286.     tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  287.         
  288.     tblHdrPtr->useCount += amount;
  289.     return tblHdrPtr->useCount;
  290. }
  291.  
  292. /*=============================================================================
  293.  * Tcl_HandleTblRelease --
  294.  *   Decrement the use count on a Tcl dynamic handle table.  If the count
  295.  * goes to zero or negative, then release the table.
  296.  *
  297.  * Parameters:
  298.  *   o headerPtr (I) - Pointer to the table header.
  299.  *-----------------------------------------------------------------------------
  300.  */
  301. void
  302. Tcl_HandleTblRelease (headerPtr)
  303.     void_pt headerPtr;
  304. {
  305.     tblHeader_pt  tblHdrPtr = (tblHeader_pt) headerPtr;
  306.  
  307.     tblHdrPtr->useCount--;
  308.     if (tblHdrPtr->useCount <= 0) {
  309.         ckfree (tblHdrPtr->bodyPtr);
  310.         ckfree ((char *) tblHdrPtr);
  311.     }
  312. }
  313.  
  314. /*=============================================================================
  315.  * Tcl_HandleAlloc --
  316.  *   Allocate an entry and associate a handle with it.
  317.  *
  318.  * Parameters:
  319.  *   o headerPtr (I) - A pointer to the table header.
  320.  *   o handlePtr (O) - Buffer to return handle in. It must be big enough to
  321.  *     hold the name.
  322.  * Returns:
  323.  *   A pointer to the allocated entry (user part).
  324.  *-----------------------------------------------------------------------------
  325.  */
  326. void_pt
  327. Tcl_HandleAlloc (headerPtr, handlePtr)
  328.     void_pt   headerPtr;
  329.     char     *handlePtr;
  330. {
  331.     tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  332.     entryHeader_pt entryPtr;
  333.     int            entryIdx;
  334.  
  335.     entryPtr = AllocEntry ((tblHeader_pt) headerPtr, &entryIdx);
  336.     sprintf (handlePtr, "%s%d", tblHdrPtr->handleBase, entryIdx);
  337.      
  338.     return USER_AREA (entryPtr);
  339.  
  340. }
  341.  
  342. /*=============================================================================
  343.  * Tcl_HandleXlate --
  344.  *   Translate a handle to a entry pointer.
  345.  *
  346.  * Parameters:
  347.  *   o interp (I) - A error message may be returned in result.
  348.  *   o headerPtr (I) - A pointer to the table header.
  349.  *   o handle (I) - The handle assigned to the entry.
  350.  * Returns:
  351.  *   A pointer to the entry, or NULL if an error occured.
  352.  *-----------------------------------------------------------------------------
  353.  */
  354. void_pt
  355. Tcl_HandleXlate (interp, headerPtr, handle)
  356.     Tcl_Interp *interp;
  357.     void_pt     headerPtr;
  358.     CONST char *handle;
  359. {
  360.     tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  361.     entryHeader_pt entryPtr;
  362.     int            entryIdx;
  363.     
  364.     if ((entryIdx = HandleDecode (interp, tblHdrPtr, handle)) < 0)
  365.         return NULL;
  366.     entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
  367.  
  368.     if ((entryIdx >= tblHdrPtr->tableSize) ||
  369.             (entryPtr->freeLink != ALLOCATED_IDX)) {
  370.         Tcl_AppendResult (interp, tblHdrPtr->handleBase, " is not open",
  371.                           (char *) NULL);
  372.         return NULL;
  373.     }     
  374.  
  375.     return USER_AREA (entryPtr);
  376.  
  377. }
  378.  
  379. /*=============================================================================
  380.  * Tcl_HandleWalk --
  381.  *   Walk through and find every allocated entry in a table.  Entries may
  382.  *   be deallocated during a walk, but should not be allocated.
  383.  *
  384.  * Parameters:
  385.  *   o headerPtr (I) - A pointer to the table header.
  386.  *   o walkKeyPtr (I/O) - Pointer to a variable to use to keep track of the
  387.  *     place in the table.  The variable should be initialized to -1 before
  388.  *     the first call.
  389.  * Returns:
  390.  *   A pointer to the next allocated entry, or NULL if there are not more.
  391.  *-----------------------------------------------------------------------------
  392.  */
  393. void_pt
  394. Tcl_HandleWalk (headerPtr, walkKeyPtr)
  395.     void_pt   headerPtr;
  396.     int      *walkKeyPtr;
  397. {
  398.     tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  399.     int            entryIdx;
  400.     entryHeader_pt entryPtr;
  401.  
  402.     if (*walkKeyPtr == -1)
  403.         entryIdx = 0;
  404.     else
  405.         entryIdx = *walkKeyPtr + 1;
  406.         
  407.     while (entryIdx < tblHdrPtr->tableSize) {
  408.         entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
  409.         if (entryPtr->freeLink == ALLOCATED_IDX) {
  410.             *walkKeyPtr = entryIdx;
  411.             return USER_AREA (entryPtr);
  412.         }
  413.         entryIdx++;
  414.     }
  415.     return NULL;
  416.  
  417. }
  418.  
  419. /*=============================================================================
  420.  * Tcl_WalkKeyToHandle --
  421.  *   Convert a walk key, as returned from a call to Tcl_HandleWalk into a
  422.  *   handle.  The Tcl_HandleWalk must have succeeded.
  423.  * Parameters:
  424.  *   o headerPtr (I) - A pointer to the table header.
  425.  *   o walkKey (I) - The walk key.
  426.  *   o handlePtr (O) - Buffer to return handle in. It must be big enough to
  427.  *     hold the name.
  428.  *-----------------------------------------------------------------------------
  429.  */
  430. void
  431. Tcl_WalkKeyToHandle (headerPtr, walkKey, handlePtr)
  432.     void_pt   headerPtr;
  433.     int       walkKey;
  434.     char     *handlePtr;
  435. {
  436.     tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  437.  
  438.     sprintf (handlePtr, "%s%d", tblHdrPtr->handleBase, walkKey);
  439.  
  440. }
  441.  
  442. /*=============================================================================
  443.  * Tcl_HandleFree --
  444.  *   Frees a handle table entry.
  445.  *
  446.  * Parameters:
  447.  *   o headerPtr (I) - A pointer to the table header.
  448.  *   o entryPtr (I) - Entry to free.
  449.  *-----------------------------------------------------------------------------
  450.  */
  451. void
  452. Tcl_HandleFree (headerPtr, entryPtr)
  453.     void_pt headerPtr;
  454.     void_pt entryPtr;
  455. {
  456.     tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  457.     entryHeader_pt freeentryPtr;
  458.  
  459.     freeentryPtr = HEADER_AREA (entryPtr);
  460.     freeentryPtr->freeLink = tblHdrPtr->freeHeadIdx;
  461.     tblHdrPtr->freeHeadIdx = (((ubyte_pt) entryPtr) - tblHdrPtr->bodyPtr) /
  462.                            tblHdrPtr->entrySize;
  463.     
  464. }
  465.  
  466.