home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / edctl1.zip / heapmgr.c < prev    next >
C/C++ Source or Header  |  1994-03-03  |  29KB  |  842 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 "entryfld.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-01-05                        */
  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.    PHEAPBLK         phblkStart;   /* Starting User Memory Pointer    */
  99.    PHEAPBLK         phblkLast;       /* Starting Free User Memory    Pointer    */
  100.    PHEAPBLK         phblkFree;       /* Starting Free List Memory    Pointer    */
  101.    struct _HEAPBASE *phbaseNext;   /* Next Block Pointer        */
  102.    struct _HEAPBASE *phbaseLast;   /* Last Block Pointer        */
  103.    } HEAPBASE ;           /* hbase */
  104.  
  105. typedef    HEAPBASE *PHEAPBASE;
  106.  
  107. #pragma    subtitle("   Heap Manager - Heap Allocation Function")
  108. #pragma    page( )
  109.  
  110. /* --- HeapAlloc --------------------------------------- [ Public ] ---    */
  111. /*                                    */
  112. /*     This function is    used to    allocate a heap    for the    user using    */
  113. /*     heap start size requested along with the    resizing values.    */
  114. /*     The heap    returns    a handle which is the actual memory address    */
  115. /*     such that the entire heap can be    released quickly.        */
  116. /*                                    */
  117. /*     Upon Entry:                            */
  118. /*                                    */
  119. /*     ULONG cbInitial;    = Initial Heap Size                */
  120. /*     ULONG cbNewBlks;    = New Heap Blocks Size                */
  121. /*                                    */
  122. /*     Upon Exit:                            */
  123. /*                                    */
  124. /*     HeapAlloc = Heap    Handle                        */
  125. /*                                    */
  126. /* --------------------------------------------------------------------    */
  127.  
  128. HHEAPMEM HeapAlloc(ULONG cbInitial, ULONG cbNewBlks)
  129.  
  130. {
  131. PHEAPBASE phbase;           /* Heap Base    Pointer            */
  132.  
  133.                /* Check    to see if the initial heap size    is the    */
  134.                /* default                    */
  135.  
  136. if ( cbInitial == HALLOC_DEFAULT )
  137.    cbInitial = 32768UL;
  138.                /* Check    to see if the initial block size is the    */
  139.                /* default                    */
  140.  
  141. if ( cbNewBlks == HALLOC_DEFAULT )
  142.    cbNewBlks = 32768UL;
  143.                /* Allocate the base memory for the heap    with it    */
  144.                /* being    totally    committed            */
  145.  
  146. if ( DosAllocMem((PPVOID)(PVOID)&phbase, cbInitial, PAG_READ | PAG_WRITE | PAG_COMMIT) )
  147.    return(0UL);
  148.                /* Check    to see if the size requested was not an    */
  149.                /* even page size in which case more memory has    */
  150.                /* been allocated than requested.  In this case,    */
  151.                /* the memory routines will utilize the memory    */
  152.                /* as though it was normally allocated.        */
  153.     
  154. if ( cbInitial % 4096UL    )
  155.    phbase->cbInitial  =    ((cbInitial / 4096UL) +    1UL) * 4096UL;
  156. else
  157.    phbase->cbInitial  =    cbInitial;
  158.  
  159.                /* Check    to see if the new block    size is    not an    */
  160.                /* even page size in which case more memory has    */
  161.                /* been allocated than requested.  In this case,    */
  162.                /* the memory routines will utilize the memory    */
  163.                /* as though it was normally allocated.        */
  164.     
  165. if ( cbNewBlks % 4096UL    )
  166.    phbase->cbNewBlks  =    ((cbNewBlks / 4096UL) +    1UL) * 4096UL;
  167. else
  168.    phbase->cbNewBlks  =    cbNewBlks;
  169.  
  170.                /* Return the memory address as the handle for    */
  171.                /* the heap                    */
  172.  
  173. return((HHEAPMEM)(phbase->phbaseLast = phbase));
  174. }
  175. #pragma    subtitle("   Heap Manager - Heap Release Function")
  176. #pragma    page( )
  177.  
  178. /* --- HeapRelease ------------------------------------- [ Public ] ---    */
  179. /*                                    */
  180. /*     This function is    used to    release    a heap for the user using    */
  181. /*     the heap    handle that was    returned through the HeapAlloc(    )    */
  182. /*     function.  The routine walks the    heap blocks releasing each    */
  183. /*     block.                                */
  184. /*                                    */
  185. /*     Upon Entry:                            */
  186. /*                                    */
  187. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  188. /*                                    */
  189. /*     Upon Exit:                            */
  190. /*                                    */
  191. /*     Nothing                                */
  192. /*                                    */
  193. /* --------------------------------------------------------------------    */
  194.  
  195. VOID HeapRelease(HHEAPMEM hHeap)
  196.  
  197. {
  198. PHEAPBASE phbase = (PHEAPBASE)hHeap;   /* Heap Base Pointer        */
  199. PHEAPBASE phbaseNext;           /* Heap Base    Pointer            */
  200.  
  201.                /* Move through the heap    blocks releasing the    */
  202.                /* allocated blocks back    to the system        */
  203. while (    phbase )
  204.    {
  205.    phbaseNext =    phbase->phbaseNext;
  206.    DosFreeMem((PVOID)phbase);
  207.    phbase = phbaseNext;
  208.    }
  209. }
  210.  
  211. #define    DEBUG_LISTBOX
  212.  
  213. #if defined(DEBUG_LISTBOX)
  214.  
  215. #pragma    subtitle("   Heap Manager - Heap Release Function")
  216. #pragma    page( )
  217.  
  218. /* --- HeapSize    ---------------------------------------- [ Public ] ---    */
  219. /*                                    */
  220. /*     This function is    used to    determine the size of the heap.        */
  221. /*                                    */
  222. /*     Upon Entry:                            */
  223. /*                                    */
  224. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  225. /*                                    */
  226. /*     Upon Exit:                            */
  227. /*                                    */
  228. /*     HeapSize    = Size of Heap                        */
  229. /*                                    */
  230. /* --------------------------------------------------------------------    */
  231.  
  232. ULONG HeapSize(HHEAPMEM    hHeap)
  233.  
  234. {
  235. PHEAPBASE phbase;           /* Heap Base    Pointer            */
  236. ULONG      ulSize = 0UL;           /* Heap Size    Holder            */
  237.  
  238.                /* Convert the heap handle to the heap base    */
  239.                /* address                    */
  240.  
  241. phbase = (PHEAPBASE)hHeap;
  242.  
  243.                /* Move through the heap    blocks counting    the    */
  244.                /* allocated blocks size    for the    total memory    */
  245.                /* allocated in the heap                */
  246. while (    phbase )
  247.    {
  248.    ulSize += phbase->cbInitial;
  249.    phbase = phbase->phbaseNext;
  250.    }
  251.                /* Return the allocated size of the heap        */
  252. return(ulSize);
  253. }
  254. #pragma    subtitle("   Heap Manager - Heap Status Function")
  255. #pragma    page( )
  256.  
  257. /* --- HeapStatus -------------------------------------- [ Public ] ---    */
  258. /*                                    */
  259. /*     This function is    used to    determine the status of    the heap by    */
  260. /*     gathering various statistics for    the heap.            */
  261. /*                                    */
  262. /*     Upon Entry:                            */
  263. /*                                    */
  264. /*     HHEAPMEM    hHeap;         = Heap Handle                */
  265. /*     PULONG    pcBlocks;    = Blocks Count Pointer            */
  266. /*     PULONG    pulSize;     = Total Heap Size Pointer            */
  267. /*     PULONG    pulUsed;     = Total Used Pointer            */
  268. /*     PULONG    pulFree;     = Total Free Pointer            */
  269. /*     PULONG    pulUnused;   = Total Unused Pointer            */
  270. /*     PULONG    pulOverhead; = Total Overhead Pointer            */
  271. /*                                    */
  272. /*     Upon Exit:                            */
  273. /*                                    */
  274. /*     Nothing                                */
  275. /*                                    */
  276. /* --------------------------------------------------------------------    */
  277.  
  278. VOID HeapStatus(HHEAPMEM hHeap,    PULONG pcBlocks, PULONG    pulSize,
  279.         PULONG pulUsed,    PULONG pulFree,    PULONG pulUnused, PULONG pulOverhead)
  280.  
  281. {
  282. PHEAPBASE phbase = (PHEAPBASE)hHeap;   /* Heap Base Pointer        */
  283. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  284.  
  285. *pcBlocks = *pulSize = *pulUsed    = *pulFree = *pulUnused    = *pulOverhead = 0UL;
  286.  
  287.                /* Move through the heap    blocks counting    the    */
  288.                /* allocated blocks size    for the    total memory    */
  289.                /* allocated in the heap                */
  290. while (    phbase )
  291.    {
  292.    ++*pcBlocks;
  293.    *pulSize   += phbase->cbInitial;
  294.    *pulUnused += (phbase->cbInitial - sizeof(HEAPBASE));
  295.    *pulOverhead    += sizeof(HEAPBASE);
  296.    phblk = (PVOID)((PBYTE)phbase + sizeof(HEAPBASE));
  297.  
  298.    while ( (phblk <= phbase->phblkLast)    && phblk->cb )
  299.        {
  300.        if ( phblk->cbUsed )
  301.        {
  302.        *pulUsed += phblk->cb;
  303.        *pulOverhead    += sizeof(HEAPBLK);
  304.        *pulUnused -= (phblk->cb + sizeof(HEAPBLK));
  305.        }
  306.        phblk = (PVOID)((PBYTE)phblk + phblk->cb    + sizeof(HEAPBLK));
  307.        }
  308.    phblk = phbase->phblkFree;
  309.  
  310.    while ( phblk )
  311.        {
  312.        if ( phblk->cb )
  313.        {
  314.        *pulFree += phblk->cb;
  315.        *pulOverhead    += sizeof(HEAPBLK);
  316.        *pulUnused -= (phblk->cb + sizeof(HEAPBLK));
  317.        }
  318.        phblk = phblk->phblkFree;
  319.        }
  320.    phbase = phbase->phbaseNext;
  321.    }
  322. }
  323. #pragma    subtitle("   Heap Manager - Heap Status Function")
  324. #pragma    page( )
  325.  
  326. /* --- HeapDisplayStatus ------------------------------- [ Public ] ---    */
  327. /*                                    */
  328. /*     This function is    used to    display    the status of the heap by    */
  329. /*     gathering various statistics for    the heap.            */
  330. /*                                    */
  331. /*     Upon Entry:                            */
  332. /*                                    */
  333. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  334. /*                                    */
  335. /*     Upon Exit:                            */
  336. /*                                    */
  337. /*     Nothing                                */
  338. /*                                    */
  339. /* --------------------------------------------------------------------    */
  340.  
  341. VOID HeapDisplayStatus(HHEAPMEM    hHeap)
  342.  
  343. {
  344. CHAR  szStrBuf[256];           /* Display Buffer            */
  345. ULONG cBlocks;               /* Blocks Count            */
  346. ULONG ulFree;               /* Free Memory Count            */
  347. ULONG ulOverhead;           /* Overhead Count            */
  348. ULONG ulSize;               /* Total Size Count            */
  349. ULONG ulUnused;               /* Unused Count            */
  350. ULONG ulUsed;               /* Used Count            */
  351.  
  352. if ( hHeap )
  353.    {
  354.    HeapStatus(hHeap, &cBlocks, &ulSize,    &ulUsed, &ulFree, &ulUnused, &ulOverhead);
  355.  
  356.    sprintf(szStrBuf, "Heap Size: %d\nHeap Used: %d (%d%%)\nHeap Free: %d (%d%%)\nHeap Unused: %d (%d%%)\nHeap Overhead: %d (%d%%)",
  357.              ulSize, ulUsed, (ulUsed * 100UL) /    ulSize,    ulFree,    (ulFree    * 100UL) / ulSize,
  358.              ulUnused, (ulUnused * 100UL) / ulSize, ulOverhead,    (ulOverhead * 100UL) / ulSize);
  359.    }
  360. else
  361.    strcpy(szStrBuf, "NULL heap handle.");
  362.  
  363. WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szStrBuf,
  364.           "Heap Debug Status Report", 1UL,
  365.           MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
  366. }    
  367.  
  368. #endif
  369.  
  370. #pragma    subtitle("   Heap Manager - Heap Suballocation Function")
  371. #pragma    page( )
  372.  
  373. /* --- HeapMalloc -------------------------------------- [ Public ] ---    */
  374. /*                                    */
  375. /*     This function is    used to    allocate a block of memory from    the    */
  376. /*     heap using the heap handle that was returned through the        */
  377. /*     HeapAlloc( ) function.  The routine walks the heap blocks    */
  378. /*     releasing each looking for either the first free    block        */
  379. /*     that can    accommodate the    request    or the start of    free memory    */
  380. /*     which is    first.    If there is no more memory within the heap    */
  381. /*     block, another block is allocated.  The memory block returned    */
  382. /*     unlike the traditional malloc( )    will be    initialized to 0    */
  383. /*     for all of the memory elements.    The placement of each        */
  384. /*     subblock    is such    that the housekeeping structure    starts on a    */
  385. /*     4 byte boundary.     To achieve this, the memory being requested    */
  386. /*     is padded as required.                        */
  387. /*                                    */
  388. /*     Upon Entry:                            */
  389. /*                                    */
  390. /*     HHEAPMEM    hHeap;    = Heap Handle                    */
  391. /*     ULONG    cbSize;    = Memory Size Requested                */
  392. /*                                    */
  393. /*     Upon Exit:                            */
  394. /*                                    */
  395. /*     HeapMalloc =  0 : Error Return, Out of Memory            */
  396. /*          = >0 : Memory    Address                    */
  397. /*                                    */
  398. /* --------------------------------------------------------------------    */
  399.  
  400. PVOID HeapMalloc(HHEAPMEM hHeap, ULONG cbSize)
  401.  
  402. {
  403. PHEAPBASE phbase = (PHEAPBASE)hHeap;   /* Heap Base Pointer        */
  404. PHEAPBASE phbaseNext;           /* Heap Base    Pointer            */
  405. PHEAPBASE phbaseStart;           /* Heap Base    Pointer            */
  406. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  407. PHEAPBLK  phblkPrev = NULL;       /* Heap Base    Pointer            */
  408. PHEAPBLK  phblkNext;           /* Heap Base    Pointer            */
  409. ULONG      cbNewBlks;           /* New Block    Size            */
  410. ULONG      cb = (cbSize / 4L + 1L) * 4L;/* Block    Size            */
  411.  
  412.                /* Walk through the base    addresses looking for    */
  413.                /* a subblock of    memory that can    satisfy    the    */
  414.                /* request                    */
  415. while (    phbase )
  416.    {
  417.                /* Get the start    of the free memory subblocks    */
  418.  
  419.    if (    (phblk = phbase->phblkFree) != NULL )
  420.        {
  421.        while ( phblk )
  422.        {
  423.                /* Have found a subblock    not being used,    see if    */
  424.                /* the subblock is large    enough for the request    */
  425.  
  426.        if (    phblk->cb >= cb    )
  427.            {
  428.            if ( phblk->cb >    (cb + sizeof(HEAPBLK)) )
  429.            {
  430.                /* Form the address of the start    of memory    */
  431.                /* subblock by creating the block from the high    */
  432.                /* part of the subblock                */
  433.  
  434.            phblkNext = (PHEAPBLK)((PBYTE)phblk + phblk->cb - cb);
  435.  
  436.                /* Save the amount of memory being used within    */
  437.                /* the subblock                    */
  438.  
  439.            phblkNext->cb     = cb;
  440.            phblkNext->phbase = phbase;
  441.  
  442.                /* Adjust the size of the block allocated from    */
  443.                /* to be    less the size of the block requested    */
  444.                /* and the block    overhead            */
  445.  
  446.            phblk->cb -=    (cb + sizeof(HEAPBLK));
  447.  
  448.                /* Set the current pointer to the new subblock    */
  449.  
  450.            phblk = phblkNext;
  451.            }
  452.            else
  453.                /* No subblock division possible, update    the    */
  454.                /* first    list pointers to exclude the block    */
  455.  
  456.            if (    phblk == phbase->phblkFree )
  457.                phbase->phblkFree = phblk->phblkFree;
  458.            else
  459.                phblkPrev->phblkFree = phblk->phblkFree;
  460.  
  461.                /* Save the requested size in the used portion    */
  462.  
  463.            phblk->cbUsed    = cbSize;
  464.            phblk->phblkFree    = NULL;
  465.  
  466.                /* Clear    the block of memory as is the norm and    */
  467.                /* return the address back to the User        */
  468.  
  469.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  470.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  471.            }
  472.                /* Current free list pointer is not adequate for    */
  473.                /* the request, check the next one        */
  474.  
  475.        phblkPrev = phblk;
  476.        phblk = phblkPrev->phblkFree;
  477.        }
  478.        }
  479.                /* Check    to see if the last block has been    */
  480.                /* defined for the current memory block        */
  481.  
  482.    if (    phbase->phblkLast )
  483.        {
  484.                /* Check    to see if the last block of the    current    */
  485.                /* memory block has been    released in which case    */
  486.                /* it would not have been added to the free list    */
  487.                /* chain    since the last block would then    have    */
  488.                /* been undefined                */
  489.  
  490.        if ( phbase->phblkLast->cbUsed == 0UL )
  491.        {
  492.                /* Last block of    the current memory block    */
  493.                /* is a free block, check to see    if the block    */
  494.                /* can be sub-divided                */
  495.  
  496.        if (    phbase->phblkLast->cb >= cb )
  497.            {
  498.            phblk = phbase->phblkLast;
  499.  
  500.                /* See if the block is dividable            */
  501.  
  502.            if ( phbase->phblkLast->cb > (cb    + sizeof(HEAPBLK)) )
  503.            {
  504.                /* Form the address of the start    of memory    */
  505.                /* subblock by creating the block from the high    */
  506.                /* part of the subblock                */
  507.  
  508.            phblkNext = (PHEAPBLK)((PBYTE)phbase->phblkLast + sizeof(HEAPBLK) + cb);
  509.  
  510.                /* Update the next last block pointer to    take    */
  511.                /* into consideration the new block being    */
  512.                /* allocated                    */
  513.  
  514.            phblkNext->phbase    = phbase;
  515.            phblkNext->cb    = phbase->phblkLast->cb    - (cb +    sizeof(HEAPBLK));
  516.            phblkNext->cbUsed    = 0UL;
  517.            phblkNext->phblkFree    = NULL;
  518.  
  519.                /* Update the last block    pointer    to point to the    */
  520.                /* next block created from the larger block    */
  521.  
  522.            phbase->phblkLast = phblkNext;
  523.  
  524.                /* Save the amount of memory being used within    */
  525.                /* the subblock                    */
  526.  
  527.            phblk->cb     = cb;
  528.            }
  529.                /* Save the requested size in the used portion    */
  530.  
  531.            phblk->cbUsed    = cbSize;
  532.            phblk->phblkFree    = NULL;
  533.  
  534.                /* Clear    the block of memory as is the norm and    */
  535.                /* return the address back to the User        */
  536.  
  537.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  538.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  539.            }
  540.        }
  541.        else
  542.                /* Check    to see if no free subblocks found, in    */
  543.                /* which    case a new subblock needs to be    added    */
  544.                /* after    the last current subblock        */
  545.  
  546.        if (    (((PBYTE)phbase->phblkLast + (sizeof(HEAPBLK) *    2L) + phbase->phblkLast->cb) + cb) <
  547.          ((PBYTE)phbase    + phbase->cbInitial) )
  548.            {
  549.                /* Using    the address of the last    subblock,    */
  550.                /* calculate the    address    of the new subblock    */
  551.                /* such that it is just after the block of    */
  552.                /* memory being used by the User            */
  553.  
  554.            phbase->phblkLast = phblk = (PVOID)((PBYTE)phbase->phblkLast + sizeof(HEAPBLK) +    phbase->phblkLast->cb);
  555.  
  556.                /* Subblock is adequate for the memory request,    */
  557.                /* save the requested size in the used portion    */
  558.  
  559.            phblk->cb    = cb;
  560.            phblk->cbUsed    = cbSize;
  561.  
  562.                /* Save the base    of the memory block to allow    */
  563.                /* easy compaction of free memory blocks    when    */
  564.                /* memory is released                */
  565.  
  566.            phblk->phbase    = phbase;
  567.  
  568.                /* Clear    the block of memory as is the norm and    */
  569.                /* return the address back to the User        */
  570.  
  571.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  572.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  573.            }
  574.        }
  575.        else
  576.        if (    (phbase->cbInitial - sizeof(HEAPBASE) -    sizeof(HEAPBLK)) > cb )
  577.            {
  578.                /* No subblocks created yet, start the first    */
  579.                /* subblock after the base housekeeping area    */
  580.  
  581.            phbase->phblkLast = phblk = phbase->phblkStart =    (PVOID)((PBYTE)phbase +    sizeof(HEAPBASE));
  582.  
  583.                /* Save the requested size in the used portion    */
  584.  
  585.            phblk->cb    = cb;
  586.            phblk->cbUsed    = cbSize;
  587.  
  588.                /* Save the base    of the memory block to allow    */
  589.                /* easy compaction of free memory blocks    when    */
  590.                /* memory is released                */
  591.  
  592.            phblk->phbase    = phbase;
  593.  
  594.                /* Clear    the block of memory as is the norm and    */
  595.                /* return the address back to the User        */
  596.  
  597.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  598.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  599.            }
  600.  
  601.    phbase = phbase->phbaseNext;
  602.    }
  603.                /* Convert the heap handle to the heap base    */
  604.                /* address                    */
  605.  
  606. phbaseStart = (PHEAPBASE)hHeap;
  607.  
  608.                /* Point    to the next memory block        */
  609.  
  610. phbase = phbaseStart->phbaseLast;
  611.  
  612.                /* Last block found, check to see if the    amount    */
  613.                /* of memory requested is larger    than the new    */
  614.                /* block    size in    which case the full block is    */
  615.                /* allocated                    */
  616.  
  617. if ( cb    > (phbaseStart->cbNewBlks - sizeof(HEAPBASE) - sizeof(HEAPBLK))    )
  618.  
  619.                /* Size of memory requested larger than the    */
  620.                /* block    size, calculate    the amount of memory    */
  621.                /* needed including the housekeeping records    */
  622.  
  623.    cbNewBlks = cb + sizeof(HEAPBASE) + sizeof(HEAPBLK);
  624. else
  625.    cbNewBlks = phbaseStart->cbNewBlks;
  626.  
  627.                /* Allocate the necessary memory            */
  628.  
  629. if ( DosAllocMem((PPVOID)(PVOID)&phbaseNext, cbNewBlks,    PAG_READ | PAG_WRITE | PAG_COMMIT) )
  630.  
  631.                /* Error    in allocating the memory, return NULL    */
  632.                /* to indicate no memory    was allocated        */
  633.    return(NULL);
  634. else
  635.                /* Save the new block address in    the last block    */
  636.                /* next pointer                    */
  637.  
  638.    phbase->phbaseNext =    phbaseStart->phbaseLast    = phbaseNext;
  639.  
  640.                /* Check    to see if the new block    size is    not an    */
  641.                /* even page size in which case more memory has    */
  642.                /* been allocated than requested.  In this case,    */
  643.                /* the memory routines will utilize the memory    */
  644.                /* as though it was normally allocated.        */
  645.     
  646. if ( (phbaseNext->cbNewBlks = cbNewBlks) % 4096UL )
  647.    phbaseNext->cbInitial  = ((cbNewBlks    / 4096UL) + 1) * 4096UL;
  648. else
  649.    phbaseNext->cbInitial  = cbNewBlks;
  650.  
  651.                /* Form the address of the start    of memory    */
  652.                /* subblock                    */
  653.  
  654. phbaseNext->phblkLast =    phblk =    phbaseNext->phblkStart = (PVOID)((PBYTE)phbaseNext + sizeof(HEAPBASE));
  655.  
  656.                /* Save the amount of memory being used within    */
  657.                /* the subblock                    */
  658. phblk->cb     =    cb;
  659. phblk->cbUsed =    cbSize;
  660.                /* Save the base    of the memory block to allow    */
  661.                /* easy compaction of free memory blocks    when    */
  662.                /* memory is released                */
  663.  
  664. phblk->phbase     = phbaseNext;
  665.  
  666.                /* Return the address of    the User memory    block    */
  667.  
  668. return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  669. }
  670. #pragma    subtitle("   Heap Manager - Heap Suballocation Function")
  671. #pragma    page( )
  672.  
  673. /* --- HeapCalloc -------------------------------------- [ Public ] ---    */
  674. /*                                    */
  675. /*     This function is    used to    release    a heap for the user using    */
  676. /*     the heap    handle that was    returned through the HeapAlloc(    )    */
  677. /*     function.  The routine uses the HeapMalloc( ) since it is    */
  678. /*     designed    to clear the memory allocated like a normal        */
  679. /*     calloc( ) function.                        */
  680. /*                                    */
  681. /*     Upon Entry:                            */
  682. /*                                    */
  683. /*     HHEAPMEM    hHeap;    = Heap Handle                    */
  684. /*     ULONG    cItems;    = Items    Count                    */
  685. /*     ULONG    cbSize;    = Item Size                    */
  686. /*                                    */
  687. /*     Upon Exit:                            */
  688. /*                                    */
  689. /*     HeapCalloc =  0 : Error Return, Out of Memory            */
  690. /*          = >0 : Memory    Address                    */
  691. /*                                    */
  692. /* --------------------------------------------------------------------    */
  693.  
  694. PVOID HeapCalloc(HHEAPMEM hHeap, ULONG cItems, ULONG cbSize)
  695.  
  696. {
  697. return(HeapMalloc(hHeap, cItems    * cbSize));
  698. }
  699. #pragma    subtitle("   Heap Manager - Heap Re-allocation Function")
  700. #pragma    page( )
  701.  
  702. /* --- HeapRealloc ------------------------------------- [ Public ] ---    */
  703. /*                                    */
  704. /*     This function is    used to    reallocate a block of memory for the    */
  705. /*     user.  If the block is smaller, the same    memory is returned    */
  706. /*     otherwise a new block is    returned and the old block released.    */
  707. /*                                    */
  708. /*     Upon Entry:                            */
  709. /*                                    */
  710. /*     HHEAPMEM    hHeap;    = Heap Handle                    */
  711. /*     PVOID    pv;    = Current Memory Block Address            */
  712. /*     ULONG    cbSize;    = Required Memory Size                */
  713. /*                                    */
  714. /*     Upon Exit:                            */
  715. /*                                    */
  716. /*     HeapRealloc =  0    : Error    Return,    Out of Memory            */
  717. /*           = >0    : Memory Address                */
  718. /*                                    */
  719. /* --------------------------------------------------------------------    */
  720.  
  721. PVOID HeapRealloc(HHEAPMEM hHeap, PVOID    pv, ULONG cbSize)
  722.  
  723. {
  724. PVOID      pvNew;           /* New Memory Block Address        */
  725. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  726.  
  727.                /* Check    to make    sure that the pointer is not    */
  728.                /* NULL which would cause a GP            */
  729. if ( pv    == NULL    )
  730.    return(NULL);
  731.                /* Form the address of the subblock housekeeping    */
  732.                /* record                    */
  733.  
  734. phblk =    (PHEAPBLK)((PBYTE)pv - sizeof(HEAPBLK));
  735.  
  736.                /* Determine if the size    requested is smaller    */
  737.                /* than the current block size in which case the    */
  738.                /* the block size should    be used    and returned    */
  739.  
  740. if ( phblk->cb >= cbSize )
  741.    {
  742.    phblk->cbUsed = cbSize;
  743.    return(pv);
  744.    }
  745. else
  746.                /* New size larger than current block size,    */
  747.                /* allocate a new block                */
  748.  
  749.    if (    (pvNew = HeapMalloc(hHeap, cbSize)) != NULL )
  750.        {
  751.                /* Transfer the memory from the old block to the    */
  752.                /* new block                    */
  753.  
  754.        memmove(pvNew, pv, phblk->cbUsed);
  755.  
  756.                /* Release the memory block for the old block    */
  757.  
  758.        HeapFree(hHeap, pv);
  759.  
  760.                /* Return the address of    the new    block        */
  761.        return(pvNew);
  762.        }
  763.    else
  764.                /* Error    occurred during    the memory allocation,    */
  765.                /* return NULL to indicate problem        */
  766.        return(NULL);
  767. }
  768. #pragma    subtitle("   Heap Manager - Heap Release Function")
  769. #pragma    page( )
  770.  
  771. /* --- HeapFree    ---------------------------------------- [ Public ] ---    */
  772. /*                                    */
  773. /*     This function is    used to    release    a block    of memory that has    */
  774. /*     been allocated by the user.  The    routine    performs free block    */
  775. /*     compaction to allow for proper reallocation of unused blocks.    */
  776. /*                                    */
  777. /*     Upon Entry:                            */
  778. /*                                    */
  779. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  780. /*     PVOID    pv;    = Address of User Memory    to Release        */
  781. /*                                    */
  782. /*     Upon Exit:                            */
  783. /*                                    */
  784. /*     Nothing                                */
  785. /*                                    */
  786. /* --------------------------------------------------------------------    */
  787.  
  788. VOID HeapFree(HHEAPMEM hHeap, PVOID pv)
  789.  
  790. {
  791. PHEAPBASE phbase;           /* Heap Base    Pointer            */
  792. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  793. PHEAPBLK  phblkNext;           /* Heap Base    Pointer            */
  794.  
  795.                /* Check    to make    sure that a valid pointer is    */
  796.                /* being    released                */
  797. if ( !hHeap || !pv )
  798.    return;
  799.                /* Form the address of the subblock housekeeping    */
  800.                /* record                    */
  801.  
  802. phblk =    (PHEAPBLK)((PBYTE)pv - sizeof(HEAPBLK));
  803.  
  804. if ( phblk->cbUsed )
  805.    {
  806.                /* Clear    the used component for the subblock    */
  807.                /* to indicate that it is freed and make    sure    */
  808.                /* that the free    list pointer is    initialized    */
  809.                /* as the end of    the chain            */
  810.  
  811.    phblk->cbUsed    = 0UL;
  812.    phblk->phblkFree = NULL;
  813.    phbase = phblk->phbase;
  814.  
  815.                /* Check    to make    sure that the last block    */
  816.                /* pointer is not the one being added to    the    */
  817.                /* free list chain                */
  818.  
  819.    if (    phbase->phblkLast != phblk )
  820.  
  821.                /* Check    to see if the free list    pointer    chain    */
  822.                /* has been started                */
  823.  
  824.        if ( (phblkNext = phbase->phblkFree) != NULL )
  825.        {
  826.                /* Free list pointer chain exists, find the end    */
  827.                /* of the chain and add the newly released    */
  828.                /* block    to it                    */
  829.  
  830.        while ( phblkNext->phblkFree    )
  831.            phblkNext = phblkNext->phblkFree;
  832.  
  833.        phblkNext->phblkFree    = phblk;
  834.        }
  835.        else
  836.                /* No free list pointer chain exists, use the    */
  837.                /* released block as the    starting point        */
  838.  
  839.        phbase->phblkFree = phblk;
  840.    }
  841. }
  842.