home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lstbx2.zip / heapmgr.c < prev    next >
C/C++ Source or Header  |  1994-04-20  |  31KB  |  892 lines

  1. #pragma    title("List Box Replacement  --  Version 1.1 -- (HeapMgr.C)")
  2. #pragma    subtitle("   Heap Manager - Interface Definitions")
  3.  
  4. /* Program name: Listbox.C    Title: A List Box    Replacement        */
  5. /*                                    */
  6. /* OS/2    Developer Magazine, Issue:  Jan    '94, page 66                    */
  7. /* Author:  Mark Benge       IBM Corp.                    */
  8. /*        Matt Smith       Prominare Inc.                */
  9. /* Description:     Replacement for OS/2 List Box,    first of a series.    */
  10. /*                                    */
  11. /* Program Requirements:  OS/2 2.x                    */
  12. /*              IBM C    Set/2                    */
  13. /*              WATCOM C 386/9.0                */
  14. /*              Borland C++ for OS/2                */
  15. /*              OS/2 Toolkit                    */
  16.  
  17. /* Copyright ╕ International Business Machines Corp. 1991-1994        */
  18. /* Copyright ╕ 1989-1994  Prominare Inc.  All Rights Reserved.        */
  19.  
  20. /************************************************************************/
  21. /************************************************************************/
  22. /*               DISCLAIMER OF WARRANTIES.            */
  23. /************************************************************************/
  24. /************************************************************************/
  25. /*     The following [enclosed]    code is    source code created by the    */
  26. /*     authors.     This source code is  provided to you solely        */
  27. /*     for the purpose of assisting you    in the development of your    */
  28. /*     applications.  The code is provided "AS IS", without        */
  29. /*     warranty    of any kind.  The authors shall    not be liable        */
  30. /*     for any damages arising out of your use of the source code,    */
  31. /*     even if they have been advised of the possibility of such    */
  32. /*     damages.     It is provided    purely for instructional and        */
  33. /*     illustrative purposes.                        */
  34. /************************************************************************/
  35. /************************************************************************/
  36.  
  37. #pragma    info(noext)
  38. #pragma    strings(readonly)
  39.  
  40. #define    INCL_DOS           /* Include OS/2 DOS Kernal        */
  41. #define    INCL_WIN           /* Include OS/2 PM Windows Interface    */
  42.  
  43. #include <os2.h>
  44. #include <stdio.h>
  45.  
  46. /* #include <memory.h> */
  47. #include <string.h>
  48.  
  49. #include "listbox.h"
  50.  
  51. /* This    module contains    the routines that handle the heap management    */
  52. /* for the list    box.  All memory allocation requests are handled    */
  53. /* through these routines.                        */
  54. /*                                    */
  55. /* Equivalent command line invocation of each module using the        */
  56. /* IBM C Set++ Compiler    Version    2.0 is:                    */
  57. /*                                    */
  58. /*     Icc -G3e- -O+ -Rn -C -W3    -FoHeapMgr HeapMgr.C            */
  59.  
  60. /* Filename:   HeapMgr.C                        */
  61.  
  62. /*  Version:   1.1                            */
  63. /*  Created:   1993-10-14                        */
  64. /*  Revised:   1994-04-20                        */
  65.  
  66. /* Routines:   HHEAPMEM    HeapAlloc(ULONG    cbInitial, ULONG cbNewBlks);    */
  67. /*           VOID HeapRelease(HHEAPMEM hHeap);            */
  68. /*           ULONG HeapSize(HHEAPMEM hHeap);                */
  69. /*           VOID HeapStatus(HHEAPMEM    hHeap, PULONG pcBlocks,        */
  70. /*                   PULONG pulSize, PULONG pulUsed,        */
  71. /*                   PULONG pulFree, PULONG pulUnused,    */
  72. /*                   PULONG pulOverhead);            */
  73. /*           VOID HeapDisplayStatus(HHEAPMEM hHeap);            */
  74. /*           PVOID HeapMalloc(HHEAPMEM hHeap,    ULONG cbSize);        */
  75. /*           PVOID HeapCalloc(HHEAPMEM hHeap,    ULONG cItems,        */
  76. /*                ULONG cbSize);                */
  77. /*           PVOID HeapRealloc(HHEAPMEM hHeap, PVOID pv,        */
  78. /*                 ULONG cbSize);                */
  79. /*           VOID HeapFree(HHEAPMEM hHeap, PVOID pv);            */
  80.  
  81.  
  82. /* --------------------------------------------------------------------    */
  83.  
  84. typedef    struct _HEAPBLK
  85.    {
  86.    ULONG          cb;       /* Block Size            */
  87.    ULONG          cbUsed;       /* Used Block Size            */
  88.    struct _HEAPBASE  *phbase;       /* Base Block Pointer        */
  89.    struct _HEAPBLK   *phblkFree;   /* User Memory Pointer        */
  90.    } HEAPBLK ;           /* hblk */
  91.  
  92. typedef    HEAPBLK    *PHEAPBLK;
  93.  
  94. typedef    struct _HEAPBASE
  95.    {
  96.    ULONG         cbInitial;       /* Initial Heap Size            */
  97.    ULONG         cbNewBlks;       /* New Block    Allocation Size        */
  98.    ULONG         cBlksUsed;       /* Blocks Used Count            */
  99.    PHEAPBLK         phblkStart;   /* Starting User Memory Pointer    */
  100.    PHEAPBLK         phblkLast;       /* Starting Free User Memory    Pointer    */
  101.    PHEAPBLK         phblkFree;       /* Starting Free List Memory    Pointer    */
  102.    struct _HEAPBASE *phbaseNext;   /* Next Block Pointer        */
  103.    struct _HEAPBASE *phbaseLast;   /* Last Block Pointer        */
  104.    } HEAPBASE ;           /* hbase */
  105.  
  106. typedef    HEAPBASE *PHEAPBASE;
  107.  
  108. #pragma    subtitle("   Heap Manager - Heap Allocation Function")
  109. #pragma    page( )
  110.  
  111. /* --- HeapAlloc --------------------------------------- [ Public ] ---    */
  112. /*                                    */
  113. /*     This function is    used to    allocate a heap    for the    user using    */
  114. /*     heap start size requested along with the    resizing values.    */
  115. /*     The heap    returns    a handle which is the actual memory address    */
  116. /*     such that the entire heap can be    released quickly.        */
  117. /*                                    */
  118. /*     Upon Entry:                            */
  119. /*                                    */
  120. /*     ULONG cbInitial;    = Initial Heap Size                */
  121. /*     ULONG cbNewBlks;    = New Heap Blocks Size                */
  122. /*                                    */
  123. /*     Upon Exit:                            */
  124. /*                                    */
  125. /*     HeapAlloc = Heap    Handle                        */
  126. /*                                    */
  127. /* --------------------------------------------------------------------    */
  128.  
  129. HHEAPMEM HeapAlloc(ULONG cbInitial, ULONG cbNewBlks)
  130.  
  131. {
  132. PHEAPBASE phbase;           /* Heap Base    Pointer            */
  133.  
  134.                /* Check    to see if the initial heap size    is the    */
  135.                /* default                    */
  136.  
  137. if ( cbInitial == HALLOC_DEFAULT )
  138.    cbInitial = 32768UL;
  139.                /* Check    to see if the initial block size is the    */
  140.                /* default                    */
  141.  
  142. if ( cbNewBlks == HALLOC_DEFAULT )
  143.    cbNewBlks = 32768UL;
  144.                /* Allocate the base memory for the heap    with it    */
  145.                /* being    totally    committed            */
  146.  
  147. if ( DosAllocMem((PPVOID)(PVOID)&phbase, cbInitial, PAG_READ | PAG_WRITE | PAG_COMMIT) )
  148.    return(0UL);
  149.                /* Check    to see if the size requested was not an    */
  150.                /* even page size in which case more memory has    */
  151.                /* been allocated than requested.  In this case,    */
  152.                /* the memory routines will utilize the memory    */
  153.                /* as though it was normally allocated.        */
  154.     
  155. if ( cbInitial % 4096UL    )
  156.    phbase->cbInitial  =    ((cbInitial / 4096UL) +    1UL) * 4096UL;
  157. else
  158.    phbase->cbInitial  =    cbInitial;
  159.  
  160.                /* Check    to see if the new block    size is    not an    */
  161.                /* even page size in which case more memory has    */
  162.                /* been allocated than requested.  In this case,    */
  163.                /* the memory routines will utilize the memory    */
  164.                /* as though it was normally allocated.        */
  165.     
  166. if ( cbNewBlks % 4096UL    )
  167.    phbase->cbNewBlks  =    ((cbNewBlks / 4096UL) +    1UL) * 4096UL;
  168. else
  169.    phbase->cbNewBlks  =    cbNewBlks;
  170.  
  171.                /* Return the memory address as the handle for    */
  172.                /* the heap                    */
  173.  
  174. return((HHEAPMEM)(phbase->phbaseLast = phbase));
  175. }
  176. #pragma    subtitle("   Heap Manager - Heap Release Function")
  177. #pragma    page( )
  178.  
  179. /* --- HeapRelease ------------------------------------- [ Public ] ---    */
  180. /*                                    */
  181. /*     This function is    used to    release    a heap for the user using    */
  182. /*     the heap    handle that was    returned through the HeapAlloc(    )    */
  183. /*     function.  The routine walks the    heap blocks releasing each    */
  184. /*     block.                                */
  185. /*                                    */
  186. /*     Upon Entry:                            */
  187. /*                                    */
  188. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  189. /*                                    */
  190. /*     Upon Exit:                            */
  191. /*                                    */
  192. /*     Nothing                                */
  193. /*                                    */
  194. /* --------------------------------------------------------------------    */
  195.  
  196. VOID HeapRelease(HHEAPMEM hHeap)
  197.  
  198. {
  199. PHEAPBASE phbase = (PHEAPBASE)hHeap;   /* Heap Base Pointer        */
  200. PHEAPBASE phbaseNext;           /* Heap Base    Pointer            */
  201.  
  202.                /* Move through the heap    blocks releasing the    */
  203.                /* allocated blocks back    to the system        */
  204. while (    phbase )
  205.    {
  206.    phbaseNext =    phbase->phbaseNext;
  207.    DosFreeMem((PVOID)phbase);
  208.    phbase = phbaseNext;
  209.    }
  210. }
  211.  
  212. #define    DEBUG_LISTBOX
  213.  
  214. #if defined(DEBUG_LISTBOX)
  215.  
  216. #pragma    subtitle("   Heap Manager - Heap Release Function")
  217. #pragma    page( )
  218.  
  219. /* --- HeapSize    ---------------------------------------- [ Public ] ---    */
  220. /*                                    */
  221. /*     This function is    used to    determine the size of the heap.        */
  222. /*                                    */
  223. /*     Upon Entry:                            */
  224. /*                                    */
  225. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  226. /*                                    */
  227. /*     Upon Exit:                            */
  228. /*                                    */
  229. /*     HeapSize    = Size of Heap                        */
  230. /*                                    */
  231. /* --------------------------------------------------------------------    */
  232.  
  233. ULONG HeapSize(HHEAPMEM    hHeap)
  234.  
  235. {
  236. PHEAPBASE phbase;           /* Heap Base    Pointer            */
  237. ULONG      ulSize = 0UL;           /* Heap Size    Holder            */
  238.  
  239.                /* Convert the heap handle to the heap base    */
  240.                /* address                    */
  241.  
  242. phbase = (PHEAPBASE)hHeap;
  243.  
  244.                /* Move through the heap    blocks counting    the    */
  245.                /* allocated blocks size    for the    total memory    */
  246.                /* allocated in the heap                */
  247. while (    phbase )
  248.    {
  249.    ulSize += phbase->cbInitial;
  250.    phbase = phbase->phbaseNext;
  251.    }
  252.                /* Return the allocated size of the heap        */
  253. return(ulSize);
  254. }
  255. #pragma    subtitle("   Heap Manager - Heap Status Function")
  256. #pragma    page( )
  257.  
  258. /* --- HeapStatus -------------------------------------- [ Public ] ---    */
  259. /*                                    */
  260. /*     This function is    used to    determine the status of    the heap by    */
  261. /*     gathering various statistics for    the heap.            */
  262. /*                                    */
  263. /*     Upon Entry:                            */
  264. /*                                    */
  265. /*     HHEAPMEM    hHeap;         = Heap Handle                */
  266. /*     PULONG    pcBlocks;    = Blocks Count Pointer            */
  267. /*     PULONG    pulSize;     = Total Heap Size Pointer            */
  268. /*     PULONG    pulUsed;     = Total Used Pointer            */
  269. /*     PULONG    pulFree;     = Total Free Pointer            */
  270. /*     PULONG    pulUnused;   = Total Unused Pointer            */
  271. /*     PULONG    pulOverhead; = Total Overhead Pointer            */
  272. /*                                    */
  273. /*     Upon Exit:                            */
  274. /*                                    */
  275. /*     Nothing                                */
  276. /*                                    */
  277. /* --------------------------------------------------------------------    */
  278.  
  279. VOID HeapStatus(HHEAPMEM hHeap,    PULONG pcBlocks, PULONG    pulSize,
  280.         PULONG pulUsed,    PULONG pulFree,    PULONG pulUnused, PULONG pulOverhead)
  281.  
  282. {
  283. PHEAPBASE phbase = (PHEAPBASE)hHeap;   /* Heap Base Pointer        */
  284. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  285.  
  286. *pcBlocks = *pulSize = *pulUsed    = *pulFree = *pulUnused    = *pulOverhead = 0UL;
  287.  
  288.                /* Move through the heap    blocks counting    the    */
  289.                /* allocated blocks size    for the    total memory    */
  290.                /* allocated in the heap                */
  291. while (    phbase )
  292.    {
  293.    ++*pcBlocks;
  294.    *pulSize   += phbase->cbInitial;
  295.    *pulUnused += (phbase->cbInitial - sizeof(HEAPBASE));
  296.    *pulOverhead    += sizeof(HEAPBASE);
  297.    phblk = (PVOID)((PBYTE)phbase + sizeof(HEAPBASE));
  298.  
  299.    while ( (phblk <= phbase->phblkLast)    && phblk->cb )
  300.        {
  301.        if ( phblk->cbUsed )
  302.        {
  303.        *pulUsed += phblk->cb;
  304.        *pulOverhead    += sizeof(HEAPBLK);
  305.        *pulUnused -= (phblk->cb + sizeof(HEAPBLK));
  306.        }
  307.        phblk = (PVOID)((PBYTE)phblk + phblk->cb    + sizeof(HEAPBLK));
  308.        }
  309.    phblk = phbase->phblkFree;
  310.  
  311.    while ( phblk )
  312.        {
  313.        if ( phblk->cb )
  314.        {
  315.        *pulFree += phblk->cb;
  316.        *pulOverhead    += sizeof(HEAPBLK);
  317.        *pulUnused -= (phblk->cb + sizeof(HEAPBLK));
  318.        }
  319.        phblk = phblk->phblkFree;
  320.        }
  321.    phbase = phbase->phbaseNext;
  322.    }
  323. }
  324. #pragma    subtitle("   Heap Manager - Heap Status Function")
  325. #pragma    page( )
  326.  
  327. /* --- HeapDisplayStatus ------------------------------- [ Public ] ---    */
  328. /*                                    */
  329. /*     This function is    used to    display    the status of the heap by    */
  330. /*     gathering various statistics for    the heap.            */
  331. /*                                    */
  332. /*     Upon Entry:                            */
  333. /*                                    */
  334. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  335. /*                                    */
  336. /*     Upon Exit:                            */
  337. /*                                    */
  338. /*     Nothing                                */
  339. /*                                    */
  340. /* --------------------------------------------------------------------    */
  341.  
  342. VOID HeapDisplayStatus(HHEAPMEM    hHeap)
  343.  
  344. {
  345. CHAR  szStrBuf[256];           /* Display Buffer            */
  346. ULONG cBlocks;               /* Blocks Count            */
  347. ULONG ulFree;               /* Free Memory Count            */
  348. ULONG ulOverhead;           /* Overhead Count            */
  349. ULONG ulSize;               /* Total Size Count            */
  350. ULONG ulUnused;               /* Unused Count            */
  351. ULONG ulUsed;               /* Used Count            */
  352.  
  353. if ( hHeap )
  354.    {
  355.    HeapStatus(hHeap, &cBlocks, &ulSize,    &ulUsed, &ulFree, &ulUnused, &ulOverhead);
  356.  
  357.    sprintf(szStrBuf, "Heap Size: %d\nHeap Used: %d (%d%%)\nHeap Free: %d (%d%%)\nHeap Unused: %d (%d%%)\nHeap Overhead: %d (%d%%)",
  358.              ulSize, ulUsed, (ulUsed * 100UL) /    ulSize,    ulFree,    (ulFree    * 100UL) / ulSize,
  359.              ulUnused, (ulUnused * 100UL) / ulSize, ulOverhead,    (ulOverhead * 100UL) / ulSize);
  360.    }
  361. else
  362.    strcpy(szStrBuf, "NULL heap handle.");
  363.  
  364. WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szStrBuf,
  365.           "Heap Debug Status Report", 1UL,
  366.           MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
  367. }    
  368.  
  369. #endif
  370.  
  371. #pragma    subtitle("   Heap Manager - Heap Suballocation Function")
  372. #pragma    page( )
  373.  
  374. /* --- HeapMalloc -------------------------------------- [ Public ] ---    */
  375. /*                                    */
  376. /*     This function is    used to    allocate a block of memory from    the    */
  377. /*     heap using the heap handle that was returned through the        */
  378. /*     HeapAlloc( ) function.  The routine walks the heap blocks    */
  379. /*     releasing each looking for either the first free    block        */
  380. /*     that can    accommodate the    request    or the start of    free memory    */
  381. /*     which is    first.    If there is no more memory within the heap    */
  382. /*     block, another block is allocated.  The memory block returned    */
  383. /*     unlike the traditional malloc( )    will be    initialized to 0    */
  384. /*     for all of the memory elements.    The placement of each        */
  385. /*     subblock    is such    that the housekeeping structure    starts on a    */
  386. /*     4 byte boundary.     To achieve this, the memory being requested    */
  387. /*     is padded as required.                        */
  388. /*                                    */
  389. /*     Upon Entry:                            */
  390. /*                                    */
  391. /*     HHEAPMEM    hHeap;    = Heap Handle                    */
  392. /*     ULONG    cbSize;    = Memory Size Requested                */
  393. /*                                    */
  394. /*     Upon Exit:                            */
  395. /*                                    */
  396. /*     HeapMalloc =  0 : Error Return, Out of Memory            */
  397. /*          = >0 : Memory    Address                    */
  398. /*                                    */
  399. /* --------------------------------------------------------------------    */
  400.  
  401. PVOID HeapMalloc(HHEAPMEM hHeap, ULONG cbSize)
  402.  
  403. {
  404. PHEAPBASE phbase = (PHEAPBASE)hHeap;   /* Heap Base Pointer        */
  405. PHEAPBASE phbaseNext;           /* Heap Base    Pointer            */
  406. PHEAPBASE phbaseStart;           /* Heap Base    Pointer            */
  407. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  408. PHEAPBLK  phblkPrev;           /* Heap Base    Pointer            */
  409. PHEAPBLK  phblkNext;           /* Heap Base    Pointer            */
  410. ULONG      cbNewBlks;           /* New Block    Size            */
  411. ULONG      cb = (cbSize / 4L + 1L) * 4L;/* Block    Size            */
  412.  
  413.                /* Walk through the base    addresses looking for    */
  414.                /* a subblock of    memory that can    satisfy    the    */
  415.                /* request                    */
  416. while (    phbase )
  417.    {
  418.                /* Get the start    of the free memory subblocks    */
  419.  
  420.    if (    (phblk = phbase->phblkFree) != NULL )
  421.        {
  422.        while ( phblk )
  423.        {
  424.                /* Have found a subblock    not being used,    see if    */
  425.                /* the subblock is large    enough for the request    */
  426.  
  427.        if (    phblk->cb >= cb    )
  428.            {
  429.            if ( phblk->cb >    (cb + sizeof(HEAPBLK)) )
  430.            {
  431.                /* Form the address of the start    of memory    */
  432.                /* subblock by creating the block from the high    */
  433.                /* part of the subblock                */
  434.  
  435.            phblkNext = (PHEAPBLK)((PBYTE)phblk + phblk->cb - cb);
  436.  
  437.                /* Save the amount of memory being used within    */
  438.                /* the subblock                    */
  439.  
  440.            phblkNext->cb     = cb;
  441.            phblkNext->phbase = phbase;
  442.  
  443.                /* Adjust the size of the block allocated from    */
  444.                /* to be    less the size of the block requested    */
  445.                /* and the block    overhead            */
  446.  
  447.            phblk->cb -=    (cb + sizeof(HEAPBLK));
  448.  
  449.                /* Set the current pointer to the new subblock    */
  450.  
  451.            phblk = phblkNext;
  452.            }
  453.            else
  454.                /* No subblock division possible, update    the    */
  455.                /* first    list pointers to exclude the block    */
  456.  
  457.            if (    phblk == phbase->phblkFree )
  458.                phbase->phblkFree = phblk->phblkFree;
  459.            else
  460.                phblkPrev->phblkFree = phblk->phblkFree;
  461.  
  462.                /* Save the requested size in the used portion    */
  463.  
  464.            phblk->cbUsed    = cbSize;
  465.            phblk->phblkFree    = NULL;
  466.            ++phblk->phbase->cBlksUsed;
  467.  
  468.                /* Clear    the block of memory as is the norm and    */
  469.                /* return the address back to the User        */
  470.  
  471.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  472.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  473.            }
  474.                /* Current free list pointer is not adequate for    */
  475.                /* the request, check the next one        */
  476.  
  477.        phblkPrev = phblk;
  478.        phblk = phblkPrev->phblkFree;
  479.        }
  480.        }
  481.                /* Check    to see if the last block has been    */
  482.                /* defined for the current memory block        */
  483.  
  484.    if (    phbase->phblkLast )
  485.        {
  486.                /* Check    to see if the last block of the    current    */
  487.                /* memory block has been    released in which case    */
  488.                /* it would not have been added to the free list    */
  489.                /* chain    since the last block would then    have    */
  490.                /* been undefined                */
  491.  
  492.        if ( phbase->phblkLast->cbUsed == 0UL )
  493.        {
  494.                /* Last block of    the current memory block    */
  495.                /* is a free block, check to see    if the block    */
  496.                /* can be sub-divided                */
  497.  
  498.        if (    phbase->phblkLast->cb >= cb )
  499.            {
  500.            phblk = phbase->phblkLast;
  501.  
  502.                /* See if the block is dividable            */
  503.  
  504.            if ( phbase->phblkLast->cb > (cb    + sizeof(HEAPBLK)) )
  505.            {
  506.                /* Form the address of the start    of memory    */
  507.                /* subblock by creating the block from the high    */
  508.                /* part of the subblock                */
  509.  
  510.            phblkNext = (PHEAPBLK)((PBYTE)phbase->phblkLast + sizeof(HEAPBLK) + cb);
  511.  
  512.                /* Update the next last block pointer to    take    */
  513.                /* into consideration the new block being    */
  514.                /* allocated                    */
  515.  
  516.            phblkNext->phbase    = phbase;
  517.            phblkNext->cb    = phbase->phblkLast->cb    - (cb +    sizeof(HEAPBLK));
  518.            phblkNext->cbUsed    = 0UL;
  519.            phblkNext->phblkFree    = NULL;
  520.  
  521.                /* Update the last block    pointer    to point to the    */
  522.                /* next block created from the larger block    */
  523.  
  524.            phbase->phblkLast = phblkNext;
  525.  
  526.                /* Save the amount of memory being used within    */
  527.                /* the subblock                    */
  528.  
  529.            phblk->cb     = cb;
  530.            }
  531.                /* Save the requested size in the used portion    */
  532.  
  533.            phblk->cbUsed    = cbSize;
  534.            phblk->phblkFree    = NULL;
  535.            ++phblk->phbase->cBlksUsed;
  536.  
  537.                /* Clear    the block of memory as is the norm and    */
  538.                /* return the address back to the User        */
  539.  
  540.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  541.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  542.            }
  543.        }
  544.        else
  545.                /* Check    to see if no free subblocks found, in    */
  546.                /* which    case a new subblock needs to be    added    */
  547.                /* after    the last current subblock        */
  548.  
  549.        if (    (((PBYTE)phbase->phblkLast + (sizeof(HEAPBLK) *    2L) + phbase->phblkLast->cb) + cb) <
  550.          ((PBYTE)phbase    + phbase->cbInitial) )
  551.            {
  552.                /* Using    the address of the last    subblock,    */
  553.                /* calculate the    address    of the new subblock    */
  554.                /* such that it is just after the block of    */
  555.                /* memory being used by the User            */
  556.  
  557.            phbase->phblkLast = phblk = (PVOID)((PBYTE)phbase->phblkLast + sizeof(HEAPBLK) +    phbase->phblkLast->cb);
  558.  
  559.                /* Subblock is adequate for the memory request,    */
  560.                /* save the requested size in the used portion    */
  561.  
  562.            phblk->cb    = cb;
  563.            phblk->cbUsed    = cbSize;
  564.  
  565.                /* Save the base    of the memory block to allow    */
  566.                /* easy compaction of free memory blocks    when    */
  567.                /* memory is released                */
  568.  
  569.            phblk->phbase    = phbase;
  570.            ++phblk->phbase->cBlksUsed;
  571.  
  572.                /* Clear    the block of memory as is the norm and    */
  573.                /* return the address back to the User        */
  574.  
  575.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  576.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  577.            }
  578.        }
  579.        else
  580.        if (    (phbase->cbInitial - sizeof(HEAPBASE) -    sizeof(HEAPBLK)) > cb )
  581.            {
  582.                /* No subblocks created yet, start the first    */
  583.                /* subblock after the base housekeeping area    */
  584.  
  585.            phbase->phblkLast = phblk = phbase->phblkStart =    (PVOID)((PBYTE)phbase +    sizeof(HEAPBASE));
  586.  
  587.                /* Save the requested size in the used portion    */
  588.  
  589.            phblk->cb    = cb;
  590.            phblk->cbUsed    = cbSize;
  591.  
  592.                /* Save the base    of the memory block to allow    */
  593.                /* easy compaction of free memory blocks    when    */
  594.                /* memory is released                */
  595.  
  596.            phblk->phbase    = phbase;
  597.            ++phblk->phbase->cBlksUsed;
  598.  
  599.                /* Clear    the block of memory as is the norm and    */
  600.                /* return the address back to the User        */
  601.  
  602.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  603.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  604.            }
  605.  
  606.    phbase = phbase->phbaseNext;
  607.    }
  608.                /* Convert the heap handle to the heap base    */
  609.                /* address                    */
  610.  
  611. phbaseStart = (PHEAPBASE)hHeap;
  612.  
  613.                /* Point    to the next memory block        */
  614.  
  615. phbase = phbaseStart->phbaseLast;
  616.  
  617.                /* Last block found, check to see if the    amount    */
  618.                /* of memory requested is larger    than the new    */
  619.                /* block    size in    which case the full block is    */
  620.                /* allocated                    */
  621.  
  622. if ( cb    > (phbaseStart->cbNewBlks - sizeof(HEAPBASE) - sizeof(HEAPBLK))    )
  623.  
  624.                /* Size of memory requested larger than the    */
  625.                /* block    size, calculate    the amount of memory    */
  626.                /* needed including the housekeeping records    */
  627.  
  628.    cbNewBlks = cb + sizeof(HEAPBASE) + sizeof(HEAPBLK);
  629. else
  630.    cbNewBlks = phbaseStart->cbNewBlks;
  631.  
  632.                /* Allocate the necessary memory            */
  633.  
  634. if ( DosAllocMem((PPVOID)(PVOID)&phbaseNext, cbNewBlks,    PAG_READ | PAG_WRITE | PAG_COMMIT) )
  635.  
  636.                /* Error    in allocating the memory, return NULL    */
  637.                /* to indicate no memory    was allocated        */
  638.    return(NULL);
  639. else
  640.                /* Save the new block address in    the last block    */
  641.                /* next pointer                    */
  642.  
  643.    phbase->phbaseNext =    phbaseStart->phbaseLast    = phbaseNext;
  644.  
  645.                /* Check    to see if the new block    size is    not an    */
  646.                /* even page size in which case more memory has    */
  647.                /* been allocated than requested.  In this case,    */
  648.                /* the memory routines will utilize the memory    */
  649.                /* as though it was normally allocated.        */
  650.     
  651. if ( (phbaseNext->cbNewBlks = cbNewBlks) % 4096UL )
  652.    phbaseNext->cbInitial  = ((cbNewBlks    / 4096UL) + 1) * 4096UL;
  653. else
  654.    phbaseNext->cbInitial  = cbNewBlks;
  655.  
  656.                /* Form the address of the start    of memory    */
  657.                /* subblock                    */
  658.  
  659. phbaseNext->phblkLast =    phblk =    phbaseNext->phblkStart = (PVOID)((PBYTE)phbaseNext + sizeof(HEAPBASE));
  660.  
  661.                /* Save the amount of memory being used within    */
  662.                /* the subblock                    */
  663. phblk->cb     =    cb;
  664. phblk->cbUsed =    cbSize;
  665.                /* Save the base    of the memory block to allow    */
  666.                /* easy compaction of free memory blocks    when    */
  667.                /* memory is released                */
  668.  
  669. phblk->phbase     = phbaseNext;
  670. ++phblk->phbase->cBlksUsed;
  671.  
  672.                /* Return the address of    the User memory    block    */
  673.  
  674. return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  675. }
  676. #pragma    subtitle("   Heap Manager - Heap Suballocation Function")
  677. #pragma    page( )
  678.  
  679. /* --- HeapCalloc -------------------------------------- [ Public ] ---    */
  680. /*                                    */
  681. /*     This function is    used to    release    a heap for the user using    */
  682. /*     the heap    handle that was    returned through the HeapAlloc(    )    */
  683. /*     function.  The routine uses the HeapMalloc( ) since it is    */
  684. /*     designed    to clear the memory allocated like a normal        */
  685. /*     calloc( ) function.                        */
  686. /*                                    */
  687. /*     Upon Entry:                            */
  688. /*                                    */
  689. /*     HHEAPMEM    hHeap;    = Heap Handle                    */
  690. /*     ULONG    cItems;    = Items    Count                    */
  691. /*     ULONG    cbSize;    = Item Size                    */
  692. /*                                    */
  693. /*     Upon Exit:                            */
  694. /*                                    */
  695. /*     HeapCalloc =  0 : Error Return, Out of Memory            */
  696. /*          = >0 : Memory    Address                    */
  697. /*                                    */
  698. /* --------------------------------------------------------------------    */
  699.  
  700. PVOID HeapCalloc(HHEAPMEM hHeap, ULONG cItems, ULONG cbSize)
  701.  
  702. {
  703. return(HeapMalloc(hHeap, cItems    * cbSize));
  704. }
  705. #pragma    subtitle("   Heap Manager - Heap Re-allocation Function")
  706. #pragma    page( )
  707.  
  708. /* --- HeapRealloc ------------------------------------- [ Public ] ---    */
  709. /*                                    */
  710. /*     This function is    used to    reallocate a block of memory for the    */
  711. /*     user.  If the block is smaller, the same    memory is returned    */
  712. /*     otherwise a new block is    returned and the old block released.    */
  713. /*                                    */
  714. /*     Upon Entry:                            */
  715. /*                                    */
  716. /*     HHEAPMEM    hHeap;    = Heap Handle                    */
  717. /*     PVOID    pv;    = Current Memory Block Address            */
  718. /*     ULONG    cbSize;    = Required Memory Size                */
  719. /*                                    */
  720. /*     Upon Exit:                            */
  721. /*                                    */
  722. /*     HeapRealloc =  0    : Error    Return,    Out of Memory            */
  723. /*           = >0    : Memory Address                */
  724. /*                                    */
  725. /* --------------------------------------------------------------------    */
  726.  
  727. PVOID HeapRealloc(HHEAPMEM hHeap, PVOID    pv, ULONG cbSize)
  728.  
  729. {
  730. PVOID      pvNew;           /* New Memory Block Address        */
  731. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  732.  
  733.                /* Check    to make    sure that the pointer is not    */
  734.                /* NULL which would cause a GP            */
  735. if ( pv    == NULL    )
  736.    return(NULL);
  737.                /* Form the address of the subblock housekeeping    */
  738.                /* record                    */
  739.  
  740. phblk =    (PHEAPBLK)((PBYTE)pv - sizeof(HEAPBLK));
  741.  
  742.                /* Determine if the size    requested is smaller    */
  743.                /* than the current block size in which case the    */
  744.                /* the block size should    be used    and returned    */
  745.  
  746. if ( phblk->cb >= cbSize )
  747.    {
  748.    phblk->cbUsed = cbSize;
  749.    return(pv);
  750.    }
  751. else
  752.                /* New size larger than current block size,    */
  753.                /* allocate a new block                */
  754.  
  755.    if (    (pvNew = HeapMalloc(hHeap, cbSize)) != NULL )
  756.        {
  757.                /* Transfer the memory from the old block to the    */
  758.                /* new block                    */
  759.  
  760.        memmove(pvNew, pv, phblk->cbUsed);
  761.  
  762.                /* Release the memory block for the old block    */
  763.  
  764.        HeapFree(hHeap, pv);
  765.  
  766.                /* Return the address of    the new    block        */
  767.        return(pvNew);
  768.        }
  769.    else
  770.                /* Error    occurred during    the memory allocation,    */
  771.                /* return NULL to indicate problem        */
  772.        return(NULL);
  773. }
  774. #pragma    subtitle("   Heap Manager - Heap Release Function")
  775. #pragma    page( )
  776.  
  777. /* --- HeapFree    ---------------------------------------- [ Public ] ---    */
  778. /*                                    */
  779. /*     This function is    used to    release    a block    of memory that has    */
  780. /*     been allocated by the user.  The    routine    performs free block    */
  781. /*     compaction to allow for proper reallocation of unused blocks.    */
  782. /*                                    */
  783. /*     Upon Entry:                            */
  784. /*                                    */
  785. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  786. /*     PVOID    pv;    = Address of User Memory    to Release        */
  787. /*                                    */
  788. /*     Upon Exit:                            */
  789. /*                                    */
  790. /*     Nothing                                */
  791. /*                                    */
  792. /* --------------------------------------------------------------------    */
  793.  
  794. VOID HeapFree(HHEAPMEM hHeap, PVOID pv)
  795.  
  796. {
  797. PHEAPBASE phbase;           /* Heap Base    Pointer            */
  798. PHEAPBASE phbaseStart;           /* Heap Base    Pointer            */
  799. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  800. PHEAPBLK  phblkNext;           /* Heap Base    Pointer            */
  801.  
  802.                /* Check    to make    sure that a valid pointer is    */
  803.                /* being    released                */
  804. if ( !hHeap || !pv )
  805.    return;
  806.                /* Form the address of the subblock housekeeping    */
  807.                /* record                    */
  808.  
  809. phblk =    (PHEAPBLK)((PBYTE)pv - sizeof(HEAPBLK));
  810.  
  811. if ( phblk->cbUsed )
  812.    {
  813.                /* Clear    the used component for the subblock    */
  814.                /* to indicate that it is freed and make    sure    */
  815.                /* that the free    list pointer is    initialized    */
  816.                /* as the end of    the chain            */
  817.  
  818.    phblk->cbUsed    = 0UL;
  819.    phblk->phblkFree = NULL;
  820.  
  821.                /* Decrement the    usage count            */
  822.  
  823.    if (    --phblk->phbase->cBlksUsed == 0UL )
  824.        {
  825.                /* Get the heap base from the heap handle    */
  826.  
  827.        phbaseStart = phbase = (PHEAPBASE)hHeap;
  828.  
  829.                /* Move through the heap    blocks to try to locate    */
  830.                /* the block previous to    the current block    */
  831.        while ( phbase  )
  832.        {
  833.                /* See if the next heap base pointer matches the    */
  834.                /* current heap block base            */
  835.  
  836.        if (    phbase->phbaseNext == phblk->phbase )
  837.            {
  838.                /* Have matched the block pointer, update the    */
  839.                /* block    link to    point to the next block    after    */
  840.                /* current block                    */
  841.  
  842.            phbase->phbaseNext = phblk->phbase->phbaseNext;
  843.  
  844.                /* Check    to see if the heap base    last block    */
  845.                /* pointed to the current block that is being    */
  846.                /* released back    to the system and if the case,    */
  847.                /* update the pointer to    the previous block    */
  848.  
  849.            if ( phblk->phbase == phbaseStart->phbaseLast )
  850.            phbaseStart->phbaseLast = phbase;
  851.  
  852.                /* Release the current memory block back    to the    */
  853.                /* system and return back to the    caller        */
  854.  
  855.            DosFreeMem((PVOID)phblk->phbase);
  856.            return;
  857.            }
  858.                /* Point    to the next block            */
  859.  
  860.        phbase = phbase->phbaseNext;
  861.        }
  862.        }
  863.    phbase = phblk->phbase;
  864.  
  865.                /* Check    to make    sure that the last block    */
  866.                /* pointer is not the one being added to    the    */
  867.                /* free list chain                */
  868.  
  869.    if (    phbase->phblkLast != phblk )
  870.  
  871.                /* Check    to see if the free list    pointer    chain    */
  872.                /* has been started                */
  873.  
  874.        if ( (phblkNext = phbase->phblkFree) != NULL )
  875.        {
  876.                /* Free list pointer chain exists, find the end    */
  877.                /* of the chain and add the newly released    */
  878.                /* block    to it                    */
  879.  
  880.        while ( phblkNext->phblkFree    )
  881.            phblkNext = phblkNext->phblkFree;
  882.  
  883.        phblkNext->phblkFree    = phblk;
  884.        }
  885.        else
  886.                /* No free list pointer chain exists, use the    */
  887.                /* released block as the    starting point        */
  888.  
  889.        phbase->phblkFree = phblk;
  890.    }
  891. }
  892.