home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkPreserve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-16  |  6.8 KB  |  248 lines

  1. /* 
  2.  * tkPreserve.c --
  3.  *
  4.  *    This file contains a collection of procedures that are used
  5.  *    to make sure that widget records and other data structures
  6.  *    aren't reallocated when there are nested procedures that
  7.  *    depend on their existence.
  8.  *
  9.  * Copyright (c) 1991-1993 The Regents of the University of California.
  10.  * All rights reserved.
  11.  *
  12.  * Permission is hereby granted, without written agreement and without
  13.  * license or royalty fees, to use, copy, modify, and distribute this
  14.  * software and its documentation for any purpose, provided that the
  15.  * above copyright notice and the following two paragraphs appear in
  16.  * all copies of this software.
  17.  * 
  18.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  19.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  20.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  21.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22.  *
  23.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  24.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  25.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  26.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  27.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  28.  */
  29.  
  30. #ifndef lint
  31. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkPreserve.c,v 1.7 93/06/16 17:14:59 ouster Exp $ SPRITE (Berkeley)";
  32. #endif /* not lint */
  33.  
  34. #include "tkConfig.h"
  35. #include "tk.h"
  36.  
  37. /*
  38.  * The following data structure is used to keep track of all the
  39.  * Tk_Preserve calls that are still in effect.  It grows as needed
  40.  * to accommodate any number of calls in effect.
  41.  */
  42.  
  43. typedef struct {
  44.     ClientData clientData;    /* Address of preserved block. */
  45.     int refCount;        /* Number of Tk_Preserve calls in effect
  46.                  * for block. */
  47.     int mustFree;        /* Non-zero means Tk_EventuallyFree was
  48.                  * called while a Tk_Preserve call was in
  49.                  * effect, so the structure must be freed
  50.                  * when refCount becomes zero. */
  51.     Tk_FreeProc *freeProc;    /* Procedure to call to free. */
  52. } Reference;
  53.  
  54. static Reference *refArray;    /* First in array of references. */
  55. static int spaceAvl = 0;    /* Total number of structures available
  56.                  * at *firstRefPtr. */
  57. static int inUse = 0;        /* Count of structures currently in use
  58.                  * in refArray. */
  59. #define INITIAL_SIZE 2
  60.  
  61. /*
  62.  *----------------------------------------------------------------------
  63.  *
  64.  * Tk_Preserve --
  65.  *
  66.  *    This procedure is used by a procedure to declare its interest
  67.  *    in a particular block of memory, so that the block will not be
  68.  *    reallocated until a matching call to Tk_Release has been made.
  69.  *
  70.  * Results:
  71.  *    None.
  72.  *
  73.  * Side effects:
  74.  *    Information is retained so that the block of memory will
  75.  *    not be freed until at least the matching call to Tk_Release.
  76.  *
  77.  *----------------------------------------------------------------------
  78.  */
  79.  
  80. void
  81. Tk_Preserve(clientData)
  82.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  83. {
  84.     register Reference *refPtr;
  85.     int i;
  86.  
  87.     /*
  88.      * See if there is already a reference for this pointer.  If so,
  89.      * just increment its reference count.
  90.      */
  91.  
  92.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  93.     if (refPtr->clientData == clientData) {
  94.         refPtr->refCount++;
  95.         return;
  96.     }
  97.     }
  98.  
  99.     /*
  100.      * Make a reference array if it doesn't already exist, or make it
  101.      * bigger if it is full.
  102.      */
  103.  
  104.     if (inUse == spaceAvl) {
  105.     if (spaceAvl == 0) {
  106.         refArray = (Reference *) ckalloc((unsigned)
  107.             (INITIAL_SIZE*sizeof(Reference)));
  108.         spaceAvl = INITIAL_SIZE;
  109.     } else {
  110.         Reference *new;
  111.  
  112.         new = (Reference *) ckalloc((unsigned)
  113.             (2*spaceAvl*sizeof(Reference)));
  114.         memcpy((VOID *) new, (VOID *) refArray, spaceAvl*sizeof(Reference));
  115.         ckfree((char *) refArray);
  116.         refArray = new;
  117.         spaceAvl *= 2;
  118.     }
  119.     }
  120.  
  121.     /*
  122.      * Make a new entry for the new reference.
  123.      */
  124.  
  125.     refPtr = &refArray[inUse];
  126.     refPtr->clientData = clientData;
  127.     refPtr->refCount = 1;
  128.     refPtr->mustFree = 0;
  129.     inUse += 1;
  130. }
  131.  
  132. /*
  133.  *----------------------------------------------------------------------
  134.  *
  135.  * Tk_Release --
  136.  *
  137.  *    This procedure is called to cancel a previous call to
  138.  *    Tk_Preserve, thereby allowing a block of memory to be
  139.  *    freed (if no one else cares about it).
  140.  *
  141.  * Results:
  142.  *    None.
  143.  *
  144.  * Side effects:
  145.  *    If Tk_EventuallyFree has been called for clientData, and if
  146.  *    no other call to Tk_Preserve is still in effect, the block of
  147.  *    memory is freed.
  148.  *
  149.  *----------------------------------------------------------------------
  150.  */
  151.  
  152. void
  153. Tk_Release(clientData)
  154.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  155. {
  156.     register Reference *refPtr;
  157.     int i;
  158.  
  159.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  160.     if (refPtr->clientData != clientData) {
  161.         continue;
  162.     }
  163.     refPtr->refCount--;
  164.     if (refPtr->refCount == 0) {
  165.         if (refPtr->mustFree) {
  166.         if (refPtr->freeProc == (Tk_FreeProc *) free) {
  167.             ckfree((char *) refPtr->clientData);
  168.         } else {
  169.             (*refPtr->freeProc)(refPtr->clientData);
  170.         }
  171.         }
  172.  
  173.         /*
  174.          * Copy down all of the trailing reference in the array
  175.          * to cover up the hole left by the unused reference.
  176.          */
  177.  
  178.         inUse--;
  179.         if (i != inUse) {
  180.         memcpy((VOID *) &refArray[i], (VOID *) &refArray[i+1],
  181.             (inUse-i)*sizeof(Reference));
  182.         }
  183.     }
  184.     return;
  185.     }
  186.  
  187.     /*
  188.      * Reference not found.  This is a bug in the caller.
  189.      */
  190.  
  191.     panic("Tk_Release couldn't find reference for 0x%x", clientData);
  192. }
  193.  
  194. /*
  195.  *----------------------------------------------------------------------
  196.  *
  197.  * Tk_EventuallyFree --
  198.  *
  199.  *    Free up a block of memory, unless a call to Tk_Preserve is in
  200.  *    effect for that block.  In this case, defer the free until all
  201.  *    calls to Tk_Preserve have been undone by matching calls to
  202.  *    Tk_Release.
  203.  *
  204.  * Results:
  205.  *    None.
  206.  *
  207.  * Side effects:
  208.  *    Ptr may be released by calling free().
  209.  *
  210.  *----------------------------------------------------------------------
  211.  */
  212.  
  213. void
  214. Tk_EventuallyFree(clientData, freeProc)
  215.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  216.     Tk_FreeProc *freeProc;    /* Procedure to actually do free. */
  217. {
  218.     register Reference *refPtr;
  219.     int i;
  220.  
  221.     /*
  222.      * See if there is a reference for this pointer.  If so, set its
  223.      * "mustFree" flag (the flag had better not be set already!).
  224.      */
  225.  
  226.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  227.     if (refPtr->clientData != clientData) {
  228.         continue;
  229.     }
  230.     if (refPtr->mustFree) {
  231.         panic("Tk_EventuallyFree called twice for 0x%x\n", clientData);
  232.         }
  233.         refPtr->mustFree = 1;
  234.     refPtr->freeProc = freeProc;
  235.         return;
  236.     }
  237.  
  238.     /*
  239.      * No reference for this block.  Free it now.
  240.      */
  241.  
  242.     if (freeProc == (Tk_FreeProc *) free) {
  243.     ckfree((char *) clientData);
  244.     } else {
  245.     (*freeProc)(clientData);
  246.     }
  247. }
  248.