PVALLOC.C
/* 
 -  P V A L L O C . C 
 - 
 *  Copyright (C) 1995 Microsoft Corporation 
 *  Purpose: 
 *      Implementation of a chained memory manager. 
 * 
 */ 
 
#include <string.h> 
#include <windows.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <pvalloc.h> 
 
#undef _PVALLOC_LOG 
 
#ifdef _PVALLOC_LOG 
static CB       cbTotalAlloc    = 0; 
static CB       ulTotalBlockNum = 0; 
#endif 
 
 
 
 
/* 
 -  PvAlloc 
 - 
 *  Purpose: 
 *      Allocates a chunk of memory on the global heap. 
 * 
 *  Parameters: 
 *      cbSize          - Count of bytes requested. 
 * 
 *  Returns: 
 *      lpv             - Pointer to the allocated memory 
 * 
 */ 
 
PV PvAlloc(CB cbSize) 
{ 
    PV      lpv         = pvNull; 
    HANDLE  hMem; 
    PPVINFO ppvinfo; 
#ifdef _PVALLOC_LOG 
    char    szFileName[80]; 
    LPSTR   lpszTemp    = NULL; 
    FILE    *pFile      = NULL; 
    char    szBuff[128]; 
#endif 
 
    /* Make sure allocations are in multiples of 4 */ 
 
    if(cbSize < 4) 
        cbSize = 4; 
    else if(cbSize & 3) 
        cbSize += 4 - (cbSize & 3); 
 
    /* Allocate the block */ 
 
    hMem = GlobalAlloc(GMEM_MOVEABLE, cbSize + sizeof(PVINFO)); 
    if(hMem) 
    { 
        ppvinfo = (PPVINFO)GlobalLock(hMem); 
        ppvinfo->hMem    = hMem; 
        ppvinfo->lpvNext = pvNull; 
        ppvinfo->lpvBuf  = ((PB)ppvinfo) + sizeof(PVINFO); 
#ifdef _PVALLOC_LOG 
        ppvinfo->cbSize  = cbSize; 
        ulTotalBlockNum++; 
        ppvinfo->ulBlockNum = ulTotalBlockNum; 
        cbTotalAlloc += cbSize; 
         
        // log to file 
        lpszTemp = getenv("TEMP"); 
 
        if(lpszTemp) 
            strcpy(szFileName, lpszTemp); 
        else 
            strcpy(szFileName, "c:\\temp"); 
 
        strcat(szFileName, "\\pvalloc.log"); 
 
         
        pFile = fopen(szFileName,"a"); 
        if (pFile == NULL)      
            goto NoFile;       
//           return NULL; 
 
        fprintf(pFile, "Block: \t%lu\tPvAlloc: %ld Bytes\t\tTotal: %ld Bytes\n", 
                 ulTotalBlockNum, cbSize, cbTotalAlloc); 
 
        if (pFile) 
            fclose(pFile); 
         
        // log to comm port 
        wsprintf(szBuff,"Block: \t%lu\tPvAlloc: %ld Bytes\t\tTotal: %ld Bytes\n", 
                 ulTotalBlockNum, cbSize, cbTotalAlloc); 
        OutputDebugString(szBuff); 
                         
NoFile:                            
 
#ifdef _WIN32 
        memset(ppvinfo->lpvBuf, 0xaa, (size_t)cbSize); 
#else 
        _fmemset(ppvinfo->lpvBuf, 0xaa, (size_t)cbSize); 
#endif  /* _WIN32 */ 
 
#endif  /* _PVALLOC_LOG */ 
        lpv = ppvinfo->lpvBuf; 
    } 
 
    return lpv; 
} 
 
/* 
 -  PvAllocMore 
 - 
 *  Purpose: 
 *      Allocates a chunk of memory and chains it to a parent block. 
 * 
 *  Parameters: 
 *      cbSize          - Count of additional bytes to allocate 
 *      lpvParent       - Pointer to parent in memory chain 
 * 
 *  Returns: 
 *      lpv             - Pointer to the allocated memory 
 * 
 */ 
 
PV PvAllocMore(CB cbSize, PV lpvParent) 
{ 
    PV          lpvStep = lpvParent; 
    PV          lpv     = pvNull; 
    PPVINFO     ppvinfoMore; 
    HANDLE      hMem; 
    PPVINFO     ppvinfo; 
 
    /* Step to the last link */ 
    do 
    { 
        ppvinfoMore = (PPVINFO)(((PB)lpvStep) - sizeof(PVINFO)); 
        lpvStep = ppvinfoMore->lpvNext; 
    } 
    while(ppvinfoMore->lpvNext != pvNull); 
 
    // beginning of section that was taken from PvAlloc 
 
    if(cbSize < 4) 
        cbSize = 4; 
    else if(cbSize & 3) 
        cbSize += 4 - (cbSize & 3); 
 
 
    hMem = GlobalAlloc(GMEM_MOVEABLE, cbSize + sizeof(PVINFO)); 
    if(hMem) 
    { 
        ppvinfo = (PPVINFO)GlobalLock(hMem); 
        ppvinfo->hMem       = hMem; 
        ppvinfo->lpvNext    = pvNull; 
        ppvinfo->lpvBuf     = ((PB)ppvinfo) + sizeof(PVINFO); 
#ifdef _PVALLOC_LOG 
        ppvinfo->cbSize     = cbSize; 
        ppvinfo->ulBlockNum = ppvinfoMore->ulBlockNum; 
        cbTotalAlloc += cbSize; 
 
#ifdef _WIN32 
        memset(ppvinfo->lpvBuf, 0xaa, (size_t)cbSize); 
#else 
        _fmemset(ppvinfo->lpvBuf, 0xaa, (size_t)cbSize); 
#endif 
 
#endif 
        lpv = ppvinfo->lpvBuf; 
    } 
    else 
        return lpv; 
         
    // end of section taken from pvalloc 
 
#ifdef _WIN32 
        memset(lpv, 0xbb, (size_t)cbSize); 
#else 
        _fmemset(lpv, 0xbb, (size_t)cbSize); 
#endif  /* _WIN32 */ 
 
    ppvinfoMore->lpvNext = lpv; 
 
    return lpv; 
} 
 
 
 
/* 
 -  PvFree 
 - 
 *  Purpose: 
 *      This function frees memory allocated by PvAlloc or PvAllocMore. 
 *      After the call, the pointer memory will be invalid and should 
 *      not be referenced again. 
 *      When memory is allocated by PvAlloc and PvAllocMore, which can 
 *      contain several levels of pointers, all the application needs to 
 *      do to free the entire structure is call this routine with the 
 *      base pointer returned by the PvAlloc call. 
 * 
 *  Parameters: 
 *      lpv             - Pointer to memory to be freed. 
 * 
 *  Returns: 
 *      Void 
 * 
 */ 
 
BOOL PvFree(PV lpv) 
{ 
    PPVINFO ppvinfo; 
#ifdef _PVALLOC_LOG 
    CB      cbSize; 
    CB      ulBlockNum; 
    FILE    *pFile  = NULL; 
    CB      cbFree  = 0; 
    CB      cbTotalBeforeFree = cbTotalAlloc; 
    char    szFileName[80]; 
    LPSTR   lpszTemp    = NULL; 
    char    szBuff[128]; 
#endif 
 
    if(!lpv) 
        return 0; 
 
    ppvinfo = (PPVINFO)(((PB)lpv) - sizeof(PVINFO)); 
 
    while(ppvinfo) 
    { 
        lpv = ppvinfo->lpvNext; 
 
#ifdef _PVALLOC_LOG 
        cbSize      = ppvinfo->cbSize; 
        cbFree      += ppvinfo->cbSize; 
        ulBlockNum  = ppvinfo->ulBlockNum; 
 
#ifdef _WIN32 
        memset(ppvinfo->lpvBuf, 0xcc, (size_t)ppvinfo->cbSize); 
#else 
        _fmemset(ppvinfo->lpvBuf, 0xcc, (size_t)ppvinfo->cbSize); 
#endif  /* _WIN32 */ 
 
#endif  /* _PVALLOC_LOG */ 
 
        if(GlobalUnlock(ppvinfo->hMem)) 
            goto err;  // Our lock count is non-zero 
 
        if(GlobalFree(ppvinfo->hMem)) 
            goto err;  // Failure 
 
#ifdef _PVALLOC_LOG 
        cbTotalAlloc -= cbSize; 
#endif 
 
        if(lpv) 
            ppvinfo = (PPVINFO)(((PB)lpv) - sizeof(PVINFO)); 
        else 
            break; 
    } 
 
 
#ifdef _PVALLOC_LOG 
     
    if((cbTotalBeforeFree - cbTotalAlloc) != cbFree) 
       goto err; 
        
    // log to file 
    lpszTemp = getenv("TEMP"); 
 
    if(lpszTemp) 
        strcpy(szFileName, lpszTemp); 
    else 
        strcpy(szFileName, "c:\\temp"); 
 
    strcat(szFileName, "\\pvalloc.log"); 
         
    pFile = fopen(szFileName,"a"); 
        
    if (pFile == NULL) 
       goto err; 
 
    fprintf(pFile, "Block: \t%lu\t\t***PvFree***,  Freeing  %lu Bytes(Alloc and AllocMore)\tUnFreed: %ld Bytes\n", 
                    ulBlockNum, cbFree, cbTotalAlloc); 
    if (pFile) 
        fclose(pFile); 
 
     // log to comm port 
    wsprintf(szBuff,"Block: \t%lu\t\t***PvFree***,  Freeing  %lu Bytes(Alloc and AllocMore)\tUnFreed: %ld Bytes\n", 
                    ulBlockNum, cbFree, cbTotalAlloc); 
    OutputDebugString(szBuff); 
 
#endif  /* _PVALLOC_LOG */ 
 
    return 0; // Success! 
 
err: 
#ifdef _PVALLOC_LOG 
 
    // find file to open 
    lpszTemp = getenv("TEMP"); 
 
    if(lpszTemp) 
        strcpy(szFileName, lpszTemp); 
    else 
        strcpy(szFileName, "c:\\temp"); 
 
    strcat(szFileName, "\\pvalloc.log"); 
 
         
    pFile = fopen(szFileName,"a"); 
 
    if (pFile == NULL) 
       return 1; 
 
    fprintf(pFile, "Block: %lu Failure freeing: %ld Bytes\tUnFreed: %ld Bytes\n", 
             ulBlockNum, cbSize, cbTotalAlloc); 
    if (pFile) 
        fclose(pFile); 
 
#endif  /* _PVALLOC_LOG */ 
 
    return 1; // Failure! 
}