home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lstbx1.zip / HEAPMGR.C < prev    next >
C/C++ Source or Header  |  1994-01-07  |  29KB  |  847 lines

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