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