/*=========================================================================
 *
 * GENMEM.CPP - 29 March 1999, Dave Humphrey
 *
 * Some of the general memory related functions and procedures that
 * I use often.
 *
 *=======================================================================*/

	/* Include Files */
#if defined(_WIN32)
  #include <windows.h>
#endif

#include "genutil.h"
#include "malloc.h"


#undef  __FUNC__
#define __FUNC__ "CreateString()"
/*=========================================================================
 *
 * Function - char *CreateString (pString)
 *
 * Attempts to allocate a new pointer and copies the contents of the given
 * string into it.  Exits program on allocation error.  Returns NULL only 
 * if passed string is NULL.
 *
 *=======================================================================*/
char* CreateString (const char *pString) {
  char* pNewString;	/* The new string pointer */
  size_t NewSize;	/* Size of new string */

	/* Make sure the passed string is valid */
  if (pString == NULL) return (NULL);

	/* Get the length of the new string and allocate it */
  NewSize = strlen(pString) + 1;
  pNewString = new char[NewSize];

	/* Ensure the new string was properly allocated */
  if (pNewString == NULL) {
    ErrorHandler.SetError(ERR_MEM);
    ErrorHandler.Exit ("Failed to allocate %u bytes of memory!", NewSize);
   }

	/* Copy the string to the new location */
  strcpy(pNewString, pString);
  return (pNewString);
 }
/*=========================================================================
 *		End of Function CreateString()
 *=======================================================================*/


#undef  __FUNC__
#define __FUNC__ "CreateString()"
/*=========================================================================
 *
 * Function - char *CreateString (StringSize);
 *
 * Same as CreateString() above but creates a string pointer of the given
 * length.  Returns NULL if l is 0.  Sets all elements of pointer to \0.
 *
 *=======================================================================*/
char* CreateString (const size_t StringSize) {
  char* pNewString;	/* Pointer to the new allocated string */

	/* Zero string length? */
  if (StringSize == 0) return (NULL);

	/* Allocate the new string pointer */
  pNewString = new char[StringSize];

	/* Ensure the new string was successfully allocated */
  if (pNewString == NULL) {
    ErrorHandler.SetError(ERR_MEM);
    ErrorHandler.Exit("Failed to allocate %u bytes of memory!", StringSize);
   }

	/* Set All Elements to zero initially */
  memset (pNewString, 0, StringSize);
  return (pNewString);
 }
/*=========================================================================
 *		End of Function CreateString()
 *=======================================================================*/


#undef  __FUNC__
#define __FUNC__ "GetFreeMemory()"
/*=========================================================================
 *
 * Function - long GetFreeMemory (void)
 *
 * Returns the number of bytes available for allocation.  Is used because
 * different compilers require various methods of calculating this.  Returns
 * GET_MEMORY_ERROR on any error and GET_MEMORY_NOTDEFINED if the free memory 
 * function is not defined for the current system.
 *
 *=======================================================================*/
long GetFreeMemory (void) {

/*---------- DOS real mode implementation -------------------------------*/
#if defined (__TURBOC__)
  return (farcoreleft());


/*---------- Windows implementation -------------------------------------*/
#elif defined(_WIN32)
  MEMORYSTATUS Status;

  GlobalMemoryStatus(&Status);
  return (long) (Status.dwAvailVirtual); 
 

/*---------- DJGPP DOS protected mode implementation --------------------*/
#elif defined(__DJGPP)
  __dpmi_free_mem_info MemoryInfo;
  long PageSize;

	/* Attempt to get the memory information */
  if (__dpmi_get_free_memory_information(&MemoryInfo)) return (GET_MEMORY_ERROR);

	/* Get the size of the memory pages */
  if (__dpmi_get_page_size(&PageSize)) return (GET_MEMORY_ERROR);

	/* Return the free bytes available */
  return (MemoryInfo.total_number_of_free_pages * PageSize);

	
/*---------- Any unknown system implementation --------------------------*/
#endif

  return (GET_MEMORY_NOTDEFINED);
 }
/*=========================================================================
 *		End of Function GetFreeMemory()
 *=======================================================================*/


#undef  __FUNC__
#define __FUNC__ "GetTotalMemory()"
/*=========================================================================
 *
 * Function - long GetTotalMemory (void)
 *
 * Returns the total amount of memory on the heap in bytes.  On error the
 * function returns GET_MEMORY_ERROR or GET_MEMORY_NOTDEFINED if the
 * memory function is not defined on the current system.
 *
 *=======================================================================*/
long GetTotalMemory (void) {

/*---------- DOS real mode implementation -------------------------------*/
#if defined(__TURBOC__)
  struct heapinfo HeapInfo;
  long            MemorySize = 0l;

	/* Make sure the heap is not corrupt */
  if (heapcheck() != _HEAPOK) return(GET_MEMORY_ERROR);

	/* Walk through the heap counting used and free blocks */
  HeapInfo.ptr = NULL;

  while (heapwalk(&HeapInfo) == _HEAPOK) {
    if (HeapInfo.in_use) MemorySize += HeapInfo.size;

  #if DEBUG
    SystemLog.Printf ("Memory Block: Size=%8lu Used=%1d ", HeapInfo.size, HeapInfo.in_use);
  #endif
   }

  return (MemorySize + farcoreleft());


/*---------- Windows implementation -------------------------------------*/
#elif defined(_WIN32)
  MEMORYSTATUS Status;

  GlobalMemoryStatus(&Status);
  return (long) (Status.dwTotalVirtual); 


/*---------- DJGPP DOS protected mode implementation --------------------*/
#elif defined(__DJGPP)
  __dpmi_free_mem_info MemoryInfo;
  long PageSize;

        /* Attempt to get the information */
  if (__dpmi_get_free_memory_information(&MemoryInfo)) return (GET_MEMORY_ERROR);

        /* Get the size of the pages */
  if (__dpmi_get_page_size(&PageSize)) return (GET_MEMORY_ERROR);

        /* Return the total number of bytes */
  return (MemoryInfo.total_number_of_physical_pages * PageSize);
#endif

/*---------- Any unknown system implementation --------------------------*/
  return (GET_MEMORY_NOTDEFINED);
 }
/*=========================================================================
 *		End of Function GetTotalMemory()
 *=======================================================================*/


#undef  __FUNC__
#define __FUNC__ "GetUsedMemory()"
/*=========================================================================
 *
 * Function - long GetUsedMemory (void);
 *
 * Returns the amount of allocated memory in bytes.  On error the function
 * returns GET_MEMORY_ERROR or GET_MEMORY_NOTDEFINED if the memory function
 * is not defined in the current system.
 *
 *=======================================================================*/
long GetUsedMemory (void) {

/*---------- DOS real mode implementation -------------------------------*/
#if defined(__TURBOC__)
  struct heapinfo HeapInfo;
  long MemorySize = 0;

	/* Make sure the heap is ok first */
  if (heapcheck() != _HEAPOK) return(GET_MEMORY_ERROR);

	/* Walk through the heap counting used and free blocks */
  HeapInfo.ptr = NULL;

  while (heapwalk(&HeapInfo) == _HEAPOK) {
    if (HeapInfo.in_use) MemorySize += HeapInfo.size;
   }

  return (MemorySize);


/*---------- Windows implementation -------------------------------------*/
#elif defined(_WIN32)
  return (GetTotalMemory() - GetFreeMemory());

/*---------- DJGPP DOS protected mode implementation --------------------*/
#elif defined(__DJGPP)
  __dpmi_free_mem_info MemoryInfo;
  long PageSize;

	/* Attempt to get the information */
  if (__dpmi_get_free_memory_information(&MemoryInfo)) return (GET_MEMORY_ERROR);

	/* Get the size of the pages */
  if (__dpmi_get_page_size(&PageSize)) return (GET_MEMORY_ERROR);

	/* Return the number of used bytes */
  return ((MemoryInfo.total_number_of_physical_pages - MemoryInfo.total_number_of_free_pages) * PageSize);
#endif

/*---------- Any unknown system implementation --------------------------*/	
  return (GET_MEMORY_NOTDEFINED);
 }
/*=========================================================================
 *		End of Function GetUsedMemory()
 *=======================================================================*/


#undef  __FUNC__
#define __FUNC__ "GetHeapStatus()"
/*=========================================================================
 *
 * Function - int GetHeapStatus (void)
 *
 * Checks and returns the validity of the heap.  Return values include
 *	_HEAPOK		- Heap is ok.
 *      _HEAPEMPTY	- Heap doesn't exist or not initialized..
 *	_HEAPCORRUPT	- Heap is corrupt.
 *	_HEAPBADBEGIN	- Initial heap info bad or not found.
 *	_HEAPBADNODE	- Bad heap node or heap is damaged.
 *	_HEAPBADPTR	- Pointer into heap is not valid.
 *	_HEAPNOTDEFINED - No defined heap status function on current system.
 *
 * Not all values are defined in all systems.
 *
 *=======================================================================*/
int GetHeapStatus (void) {

/*---------- DOS real mode implementation -------------------------------*/
#if defined(__TURBOC__)
  return (farheapcheck());


/*---------- Windows implementation -------------------------------------*/	
#elif defined(_WIN32)


  #ifdef _DEBUG
    if (_CrtCheckMemory()) return (_HEAPOK);
    return (_HEAPCORRUPT);
  #else
    return (_HEAPNOTDEFINED);
  #endif


/*---------- DJGPP DOS protected mode implementation --------------------*/
#elif defined(__DJGPP)
  return (_HEAPNOTDEFINED);
#endif

/*---------- Any unknown system implementation --------------------------*/	
  return (_HEAPNOTDEFINED);
 }
/*=========================================================================
 *		End of Function get_heapcheck()
 *=======================================================================*/


#undef  __FUNC__
#define __FUNC__ "GetHeapStatusString()"
/*=========================================================================
 *
 * Function - char *GetHeapStatusString (void)
 *
 * Returns a string based on the status of the heap.  Always returns a 
 * valid string, never NULL.
 *
 *=======================================================================*/
char *GetHeapStatusString (void) {

  switch (GetHeapStatus()) {
    case _HEAPOK:	  return ("Ok");
    case _HEAPCORRUPT:    return ("Corrupt");
    case _HEAPEMPTY:      return ("Empty or not Initialized" );
    case _HEAPBADBEGIN:   return ("Corrupt (invalid heap start)");
    case _HEAPBADNODE:    return ("Corrupt (invalid or damaged node)");
    case _HEAPBADPTR:     return ("Corrupt (bad pointer into heap)");
    case _HEAPNOTDEFINED: return ("Status Not Defined in Current System");
    default:              return ("Error, Invalid Heap Status");
   }
 }
/*=========================================================================
 *		End of Function GetHeapStatusString()
 *=======================================================================*/