home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / Tickle-4.0 (tcl) / tcl / extend / src / tclXhandles.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-26  |  14.9 KB  |  461 lines  |  [TEXT/MPS ]

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