#ifdef DOC_BUILD_INTERNAL
#endif
#include "memory.h"
const int memory__EOF = EOF;
const unsigned memory__ALIGN = sizeof(POINTER);
#ifdef SPASS_CHECK
unsigned int memory_OFFSET;
unsigned int memory_MARKSIZE;
#else
const unsigned int memory_MARKSIZE = 0;
const unsigned int memory_OFFSET = 0;
#endif
const unsigned int memory_MAGICMALLOC = 1;
const unsigned int memory_MAGICFREE = 2;
static size_t memory_AlignedSize(size_t Size)
{
  return ((Size + memory__ALIGN-1) & ~(size_t)(memory__ALIGN-1));
}
MEMORY_RESOURCE memory_GetResource(MEMORY mem, unsigned blocksize)
{
  return &(mem->resources[blocksize-1]);
}
unsigned long memory_GetRemainingMemory(MEMORY mem)
{
  return mem->newbytes-mem->freebytes;
}
unsigned memory_GetAlignedBlockSize(MEMORY Memory, unsigned BlockSize)
{
  if (BlockSize < Memory->dynmaxsize)
    return memory_GetResource(Memory, BlockSize)->aligned_size;
  else
    return memory_AlignedSize(BlockSize);
}
#ifdef SPASS_CHECK
void memory_SetBlockStatusAndSize(MEMORY Memory, POINTER Mem, unsigned Status, unsigned Size)
{
  *((unsigned *)Mem - 1) = Size;
  *((unsigned *)((char *)Mem + memory_GetAlignedBlockSize(Memory, Size))) = Status;
}
unsigned memory_GetBlockSize(POINTER Mem)
{
  return *((unsigned *)Mem - 1);
}
unsigned memory_GetRealBlockSize(MEMORY Memory, POINTER Mem)
{
  return memory_GetAlignedBlockSize(Memory, memory_GetBlockSize(Mem));
}
unsigned memory_GetBlockStatus(MEMORY Memory, POINTER Mem)
{
  unsigned Size;
  Size = memory_GetBlockSize(Mem);
  return *((unsigned *)((char *)Mem + memory_GetAlignedBlockSize(Memory, Size)));
}
void memory_SetInfo(MEMORY_INFO Info, const char * MallocInFile,
          unsigned short int MallocAtLine,
          const char * FreeInFile,
          unsigned short int FreeAtLine)
{
  if (!Info) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Memory Error. Info is a NULL pointer.\n");
    misc_FinishErrorReport();
  }
  Info->mallocAtLine = MallocAtLine;
  Info->mallocInFile = MallocInFile;
  Info->freeAtLine = FreeAtLine;
  Info->freeInFile = FreeInFile;
}
#endif
unsigned long memory_DemandedBytes(MEMORY Memory)
{
  return Memory->newbytes;
}
unsigned long memory_UsedBytes(MEMORY Memory)
{
  return Memory->newbytes - Memory->freebytes;
}
void memory_SetOutOfMemString(MEMORY Memory, const char* OutOfString)
{
  Memory->outofmem = OutOfString;
}
MEMORY memory_Create(void)
{
  MEMORY Memory;
  Memory = (MEMORY)malloc(sizeof(MEMORY_NODE));
  Memory->resources = NULL;
  Memory->dynmaxsize = 0;
  Memory->freeshredder = '0';
#if defined(SPASS_CHECK)
  Memory->inuse = 'N';
#endif
  Memory->unlimited = 0;
  Memory->pagesize = 0;
  Memory->maxmem = 0;
  Memory->outofmem = "";
  Memory->newbytes = 0;
  Memory->freebytes = 0;
  Memory->bigblocks = NULL;
  return Memory;
}
void memory_SetDynmaxSize(MEMORY Memory, unsigned Size)
{
  Memory->dynmaxsize = Size;
}
unsigned memory_GetDynmaxSize(MEMORY Memory)
{
  return Memory->dynmaxsize;
}
void memory_SetFreeShredder(MEMORY Memory, char Shredder)
{
  Memory->freeshredder = Shredder;
}
void memory_SetMaxMem(MEMORY Memory, int Maxmem)
{
  Memory->maxmem = Maxmem;
}
MEMORY memory_Init(MEMORY Memory)
{
#ifdef SPASS_NO_MEMORY_MANAGEMENT
  return Memory;
#else
  unsigned extra, i;
  if (Memory->dynmaxsize == 0)
    Memory->dynmaxsize = 1024;
  if (Memory->freeshredder == '0')
    Memory->freeshredder = 'S';
  if (Memory->maxmem <= 0)
    Memory->maxmem = -1;
  Memory->outofmem = "Ran out of Memory";
#ifdef SPASS_CHECK
  memory_OFFSET = memory_AlignedSize(sizeof(MEMORY_INFONODE) + sizeof(unsigned int));
  memory_MARKSIZE = memory_OFFSET + memory_AlignedSize(sizeof(unsigned int));
#endif
  extra = memory_AlignedSize(sizeof(POINTER));
  Memory->pagesize = memory_MALLOCPAGESIZE*((extra + 4*(Memory->dynmaxsize + memory_MARKSIZE))/memory_MALLOCPAGESIZE + 1);
  Memory->resources = (MEMORY_RESOURCE)malloc(sizeof(MEMORY_RESOURCENODE)*(Memory->dynmaxsize-1));
  for (i=1; i < Memory->dynmaxsize; i++) {
    MEMORY_RESOURCE CurrentResource;
    CurrentResource = &(Memory->resources[i-1]);
    CurrentResource->free = (POINTER)&memory__EOF;
    CurrentResource->next = (POINTER)&memory__EOF;
    CurrentResource->end_of_page = (POINTER)&memory__EOF;
    CurrentResource->page = (POINTER)&memory__EOF;
    CurrentResource->aligned_size = memory_AlignedSize(i);
    CurrentResource->total_size = memory_MARKSIZE + CurrentResource->aligned_size;
    CurrentResource->offset =
      ((Memory->pagesize-extra)/CurrentResource->total_size)*CurrentResource->total_size;
  }
  return Memory;
#endif
}
#ifdef SPASS_CHECK
static void memory_CheckIfPointerIsAlreadyFreed(MEMORY Memory,
            POINTER Pointer,
      const char * Function,
      const char * File,
      unsigned short int Line)
{
  if ( memory_GetBlockStatus(Memory, Pointer) == memory_MAGICFREE) {
    MEMORY_INFO Info;
    Info = (MEMORY_INFO) ((char *) Pointer - memory_OFFSET);
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", Function);
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Pointer %p was allocated in file %s at line %d.",
    Pointer, Info->mallocInFile, Info->mallocAtLine);
    misc_UserErrorReport("\n It has already been freed in file %s at line %d.",
    Info->freeInFile, Info->freeAtLine);
    misc_UserErrorReport("\n Size of memory block is %d bytes.",
    memory_GetBlockSize(Pointer));
    misc_UserErrorReport("\n Error occurred in %s", Function);
    misc_UserErrorReport(" called from file %s at line %d.\n",
    File, Line);
    misc_FinishUserErrorReport();
  }
}
void memory_CheckPointer(MEMORY Memory, POINTER Pointer, unsigned Size)
{
  MEMORY_INFO Info;
  unsigned BlockSize, RealBlockSize, BlockStatus;
  RealBlockSize = memory_GetAlignedBlockSize(Memory, Size);
  if (Pointer == NULL) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Memory Error. Pointer is a NULL pointer.\n");
    misc_FinishUserErrorReport();
  }
  if (Size == 0) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Pointer %p points to a block of memory", Pointer);
    misc_UserErrorReport(" with size 0.\n");
    misc_FinishUserErrorReport();
  }
  if ((unsigned long)Pointer % (unsigned long)memory__ALIGN){
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Pointer %p is not a legal pointer.\n", Pointer);
    misc_FinishUserErrorReport();
  }
  Info = (MEMORY_INFO) ((char *)Pointer - memory_OFFSET);
  BlockStatus = memory_GetBlockStatus(Memory, Pointer);
  BlockSize = memory_GetBlockSize(Pointer);
  if (BlockStatus != memory_MAGICMALLOC
      && BlockStatus != memory_MAGICFREE) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Pointer %p was not (de)allocated by the module,",
    Pointer);
    misc_UserErrorReport("\n or the memory block was corrupted.\n");
    misc_FinishUserErrorReport();
  }
  if (BlockStatus == memory_MAGICMALLOC) {
    if (BlockSize != Size) {
      misc_StartUserErrorReport();
      misc_UserErrorReport("\n In %s:", __func__);
      misc_UserErrorReport("\n Memory Error.");
      misc_UserErrorReport(" Pointer %p was apparently allocated for",
      Pointer);
      misc_UserErrorReport(" a block of size %d,",
      BlockSize);
      misc_UserErrorReport("\n but it is expected to be a block of size %d.",
      Size);
      misc_UserErrorReport("\n Probably the memory block was corrupted.\n");
      misc_FinishUserErrorReport();
    }
    if (Size % memory__ALIGN) {
      char * ptr, * limit;
      limit = (char *)Pointer + RealBlockSize;
      for (ptr = (char *)Pointer + Size; ptr < limit; ptr++) {
 if (*ptr != Memory->freeshredder) {
   misc_StartUserErrorReport();
   misc_UserErrorReport("\n In %s:", __func__);
   misc_UserErrorReport("\n Memory Error.");
   misc_UserErrorReport(" Pointer %p was allocated in file %s at line %d,",
          Pointer, Info->mallocInFile, Info->mallocAtLine);
   misc_UserErrorReport("\n for a block of size %d.",
          BlockSize);
   misc_UserErrorReport("\n The memory block was corrupted.\n");
   misc_FinishUserErrorReport();
 }
      }
    }
  }
  if (Size >= Memory->dynmaxsize) {
    MEMORY_BIGBLOCKHEADER BigBlockHeader;
    BigBlockHeader = (MEMORY_BIGBLOCKHEADER) ((char *) Pointer - memory_OFFSET
                                              - memory_AlignedSize(sizeof(MEMORY_BIGBLOCKHEADERNODE)));
    if (((BigBlockHeader->previous != NULL)
  && (BigBlockHeader->previous->next != BigBlockHeader))
 || ((BigBlockHeader->previous == NULL)
  && (Memory->bigblocks != BigBlockHeader))
 || ((BigBlockHeader->next != NULL)
     && (BigBlockHeader->next->previous != BigBlockHeader))) {
      misc_StartUserErrorReport();
      misc_UserErrorReport("\n In %s:", __func__);
      misc_UserErrorReport("\n Memory Error.");
      misc_UserErrorReport(" Pointer %p was not allocated by the module,",
      Pointer);
      misc_UserErrorReport("\n or the memory block was corrupted.\n");
      misc_FinishUserErrorReport();
    }
  }
  if (BlockStatus == memory_MAGICFREE) {
    char * ptr, * limit;
    limit = (char *)Pointer + RealBlockSize;
    for (ptr = (char *)Pointer + sizeof(POINTER); ptr < limit ; ptr++){
      if (*ptr != Memory->freeshredder) {
 misc_StartUserErrorReport();
 misc_UserErrorReport("\n In %s:", __func__);
 misc_UserErrorReport("\n Memory Error.");
 misc_UserErrorReport(" Pointer %p was allocated in file %s at line %d",
        Pointer, Info->mallocInFile, Info->mallocAtLine);
 misc_UserErrorReport("\n for a block of size %d",BlockSize);
 misc_UserErrorReport("\n and freed in file %s at line %d.",
        Info->freeInFile, Info->freeAtLine);
 misc_UserErrorReport("\n The memory block was used after deallocation.\n");
 misc_FinishUserErrorReport();
      }
    }
  }
}
void memory_CheckFree(MEMORY Memory, POINTER Freepointer, unsigned Size,
        unsigned int RealBlockSize, const char * File,
        unsigned short int Line)
{
  MEMORY_INFO Info;
  memory_CheckPointer(Memory, Freepointer, Size);
  memory_CheckIfPointerIsAlreadyFreed(Memory, Freepointer, "memory_Free", File, Line);
  memset (Freepointer, Memory->freeshredder, RealBlockSize);
  Info = (MEMORY_INFO) ((char *) Freepointer - memory_OFFSET);
  memory_SetInfo(Info,Info->mallocInFile, Info->mallocAtLine, File, Line);
  memory_SetBlockStatusAndSize(Memory, Freepointer, memory_MAGICFREE, Size);
}
#endif
#ifdef SPASS_NO_MEMORY_MANAGEMENT
POINTER memory_Malloc(MEMORY Memory, unsigned Bytes)
{
  char *mem;
  mem = (char *)malloc(Bytes);
#ifdef SPASS_CHECK
  if (mem == NULL) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Memory Error. Out of memory.\n");
    misc_FinishUserErrorReport();
  }
#endif
  return mem;
}
POINTER memory_Realloc(MEMORY Memory, POINTER Ptr, unsigned int OldSize, unsigned int NewSize) {
  return realloc(Ptr,NewSize);
}
#else
#ifdef SPASS_CHECK
POINTER memory_ReallocAndCheck(MEMORY Memory, POINTER Ptr,
        unsigned int OldSize,
        unsigned int NewSize,
        const char * File,
        unsigned short int Line)
#else
POINTER memory_Realloc(MEMORY Memory, POINTER Ptr, unsigned int OldSize, unsigned int NewSize)
#endif
{
  POINTER NewMem;
#ifdef SPASS_CHECK
  NewMem = memory_MallocAndCheck(Memory, NewSize, File, Line);
#else
  NewMem = memory_Malloc(Memory, NewSize);
#endif
  memcpy(NewMem,Ptr,OldSize>NewSize?NewSize:OldSize);
#ifdef SPASS_CHECK
  memory_FreeAndCheck(Memory, Ptr, OldSize, File, Line);
#else
  memory_Free(Memory, Ptr, OldSize);
#endif
  return NewMem;
}
#ifdef SPASS_CHECK
POINTER memory_MallocAndCheck(MEMORY Memory, unsigned Bytes,
       const char * File,
       unsigned short int Line)
#else
POINTER memory_Malloc(MEMORY Memory, unsigned Bytes)
#endif
{
  char *NewMemory;
  MEMORY_RESOURCE Resource;
#ifdef SPASS_CHECK
  MEMORY_INFO NewInfo;
  NewInfo = NULL;
#endif
#ifdef SPASS_CHECK
  if (Bytes == 0) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Memory Error. Tried to allocate 0 Bytes!");
    misc_UserErrorReport("\n Error occurred in memory_Malloc");
    misc_UserErrorReport(" called from file %s at line %d.\n", File, Line);
    misc_FinishUserErrorReport();
  }
  if (Memory->resources == NULL) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Memory management is not initialized.");
    misc_UserErrorReport("\n You have to call memory_Init()");
    misc_UserErrorReport("\n before you can use memory management functions.\n");
    misc_FinishUserErrorReport();
  }
#endif
  if (Bytes >= Memory->dynmaxsize) {
    unsigned int RealBigBlockSize;
    RealBigBlockSize = memory_AlignedSize(sizeof(MEMORY_BIGBLOCKHEADERNODE)) +
      memory_MARKSIZE + memory_AlignedSize(Bytes);
    if (Memory->maxmem >= 0) {
      if ((unsigned int)Memory->maxmem < RealBigBlockSize) {
        misc_StartUserErrorReport();
        misc_UserErrorReport("\n In %s:", __func__);
        misc_UserErrorReport("\n Memory Error.");
 misc_UserErrorReport("\n %s", Memory->outofmem);
        misc_UserErrorReport(" Terminated by user given memory restriction,\n");
        misc_UserErrorReport("\n while trying to allocate %lu bytes.\n",
          RealBigBlockSize);
        misc_UserErrorReport("\n Maximum amount of memory");
        misc_UserErrorReport(" left for allocation is %l bytes.\n",
          Memory->maxmem);
#ifdef SPASS_CHECK
        misc_UserErrorReport("\n Error occurred in memory_Malloc");
        misc_UserErrorReport(" called from file %s at line %d.\n",
          File, Line);
#endif
        misc_FinishUserErrorReport();
      }
      else
        Memory->maxmem -= RealBigBlockSize;
    }
    NewMemory = (char *)malloc(RealBigBlockSize);
    if (NewMemory != NULL) {
      MEMORY_BIGBLOCKHEADER NewBigBlock;
      NewBigBlock = (MEMORY_BIGBLOCKHEADER) NewMemory;
      NewBigBlock->next = Memory->bigblocks;
      NewBigBlock->previous = NULL;
      if (Memory->bigblocks != NULL) {
        Memory->bigblocks->previous = NewBigBlock;
      }
      Memory->bigblocks = NewBigBlock;
      NewMemory += memory_AlignedSize(sizeof(MEMORY_BIGBLOCKHEADERNODE));
#ifdef SPASS_CHECK
      NewInfo = (MEMORY_INFO) NewMemory;
      NewMemory += memory_OFFSET;
#endif
      Memory->newbytes += RealBigBlockSize;
    }
    else {
      misc_StartUserErrorReport();
      misc_UserErrorReport("\n In %s:", __func__);
      misc_UserErrorReport("\n Memory Error. Out of misc.");
      misc_UserErrorReport("\n %s", Memory->outofmem);
      misc_UserErrorReport("\n Failed to allocate %d bytes.\n",
        RealBigBlockSize);
#ifdef SPASS_CHECK
      misc_UserErrorReport("\n Error occurred in memory_Malloc");
      misc_UserErrorReport(" called from file %s at line %d.\n",
        File, Line);
#endif
      misc_FinishUserErrorReport();
    }
  }
  else {
    Resource = &(Memory->resources[Bytes-1]);
    if (*((int *)Resource->free) != EOF) {
      NewMemory = (char *) Resource->free;
      Resource->free = *((POINTER *)(NewMemory));
      Memory->freebytes -= Resource->total_size;
#ifdef SPASS_CHECK
      NewInfo = (MEMORY_INFO) ((char*) NewMemory - memory_OFFSET);
      memory_CheckPointer(Memory, NewMemory, Bytes);
#endif
    }
    else {
      if (Resource->next != Resource->end_of_page) {
        NewMemory = (char *)Resource->next;
        Resource->next = NewMemory + Resource->total_size;
        Memory->newbytes += Resource->total_size;
#ifdef SPASS_CHECK
        if ((char *)NewMemory > (char *) Resource->end_of_page) {
          misc_StartErrorReport();
          misc_ErrorReport("\n In %s:", __func__);
          misc_ErrorReport("\n Memory Error. Address overflow %d.",Bytes);
          misc_ErrorReport("\n Error occurred in memory_Malloc");
          misc_ErrorReport(" called from file %s at line %d.\n", File, Line);
          misc_FinishErrorReport();
        }
        NewInfo = (MEMORY_INFO)(NewMemory);
        NewMemory = NewMemory + memory_OFFSET;
#endif
      }
      else {
        if (Memory->maxmem >=0) {
          if ((unsigned int)Memory->maxmem < Memory->pagesize) {
            misc_StartUserErrorReport();
            misc_UserErrorReport("\n In %s:", __func__);
            misc_UserErrorReport("\n Memory Error.");
            misc_UserErrorReport(" Terminated by user given memory restriction.\n");
#ifdef SPASS_CHECK
            misc_UserErrorReport("\n Error occurred in memory_Malloc");
            misc_UserErrorReport(" called from file %s at line %d.\n",
              File, Line);
#endif
            misc_FinishUserErrorReport();
          }
          else {
            Memory->maxmem -= Memory->pagesize;
          }
        }
        NewMemory=(char *)malloc(Memory->pagesize);
        if (NewMemory == NULL) {
          misc_StartUserErrorReport();
          misc_UserErrorReport("\n In %s:", __func__);
          misc_UserErrorReport("\n Memory Error.");
   misc_UserErrorReport("\n %s", Memory->outofmem);
          misc_UserErrorReport(" Terminated, ran out of system memory.\n");
#ifdef SPASS_CHECK
          misc_UserErrorReport("\n Error occurred in memory_Malloc");
          misc_UserErrorReport(" called from file %s at line %d.\n",
            File, Line);
#endif
          misc_FinishUserErrorReport();
        }
        *((POINTER *)NewMemory) = Resource->page;
        Resource->page = NewMemory;
        NewMemory += memory_AlignedSize(sizeof(POINTER));
        Resource->end_of_page = NewMemory + Resource->offset;
        Resource->next = NewMemory + Resource->total_size;
        Memory->newbytes += Resource->total_size;
#ifdef SPASS_CHECK
        NewInfo = (MEMORY_INFO) NewMemory;
        NewMemory += memory_OFFSET;
#endif
      }
    }
  }
#ifdef SPASS_CHECK
  memory_SetInfo(NewInfo, File, Line, NULL, 0);
  memory_SetBlockStatusAndSize(Memory, NewMemory,
    memory_MAGICMALLOC, Bytes);
  memset(NewMemory, Memory->freeshredder,
    memory_GetAlignedBlockSize(Memory, Bytes));
#endif
  return NewMemory;
}
#ifdef SPASS_CHECK
POINTER memory_MallocAlignedAndCheck(MEMORY Memory,
                                     unsigned int Size,
                                     unsigned char Alignment,
                                     const char * File,
                                     unsigned short int Line)
#else
POINTER memory_MallocAligned(MEMORY Memory, unsigned Size, unsigned char Alignment)
#endif
{
  char* newblock;
  unsigned char padding;
#ifdef SPASS_CHECK
  newblock = memory_MallocAndCheck(Memory, Size + Alignment, File, Line);
#else
  newblock = memory_Malloc(Memory, Size + Alignment);
#endif
  padding = Alignment - ((uintptr_t)newblock % Alignment);
  newblock += padding;
  *((unsigned char*)(newblock - 1)) = padding;
  return newblock;
}
#endif
#ifdef SPASS_NO_MEMORY_MANAGEMENT
void memory_Free(MEMORY Memory, POINTER Freepointer, unsigned int Size)
{
  free((char*)Freepointer);
}
#else
#ifdef SPASS_CHECK
void memory_FreeAndCheck(MEMORY Memory,
         POINTER Freepointer,
         unsigned Size,
         const char * File,
         unsigned short int Line)
#else
void memory_Free(MEMORY Memory, POINTER Freepointer, unsigned Size)
#endif
{
  unsigned int RealBlockSize;
  RealBlockSize = memory_GetAlignedBlockSize(Memory, Size);
#ifdef SPASS_CHECK
  memory_CheckFree(Memory, Freepointer, Size, RealBlockSize, File, Line);
#endif
  if (Size >= Memory->dynmaxsize) {
    MEMORY_BIGBLOCKHEADER BigBlockHeader;
    BigBlockHeader =
      (MEMORY_BIGBLOCKHEADER) ((char *) Freepointer - memory_OFFSET
                               - memory_AlignedSize(sizeof(MEMORY_BIGBLOCKHEADERNODE)));
    if (BigBlockHeader->previous != NULL) {
      BigBlockHeader->previous->next = BigBlockHeader->next;
    }
    else {
      Memory->bigblocks = BigBlockHeader->next;
    }
    if (BigBlockHeader->next != NULL) {
      BigBlockHeader->next->previous = BigBlockHeader->previous;
    }
    Memory->freebytes += RealBlockSize + memory_MARKSIZE +
      memory_AlignedSize(sizeof(MEMORY_BIGBLOCKHEADERNODE));
    if (Memory->maxmem >= 0) {
      Memory->maxmem += RealBlockSize + memory_MARKSIZE +
        memory_AlignedSize(sizeof(MEMORY_BIGBLOCKHEADERNODE));
    }
#ifdef SPASS_CHECK
    free((char *)Freepointer - memory_OFFSET
         - memory_AlignedSize(sizeof(MEMORY_BIGBLOCKHEADERNODE)));
#else
    free((char*) Freepointer - memory_AlignedSize(sizeof(MEMORY_BIGBLOCKHEADERNODE)));
#endif
  }
  else {
    Memory->freebytes += Memory->resources[Size-1].total_size;
    *(POINTER *)Freepointer = Memory->resources[Size-1].free;
    Memory->resources[Size-1].free = Freepointer;
  }
}
#ifdef SPASS_CHECK
void memory_FreeAlignedAndCheck(MEMORY Memory,
                                POINTER FreePointer,
                                unsigned Size,
                                unsigned char Alignment,
                                const char * File,
                                unsigned short int Line)
#else
void memory_FreeAligned(MEMORY Memory, POINTER FreePointer, unsigned Size, unsigned char Alignment)
#endif
{
  FreePointer = (char*)FreePointer - *((unsigned char*)FreePointer - 1);
#ifdef SPASS_CHECK
  memory_FreeAndCheck(Memory, FreePointer, Size + Alignment, File, Line);
#else
  memory_Free(Memory, FreePointer, Size + Alignment);
#endif
}
#endif
#ifdef SPASS_NO_MEMORY_MANAGEMENT
POINTER memory_Calloc(MEMORY Memory, unsigned int Elements, unsigned int Bytes)
{
  char *mem;
  mem = (char *)calloc(Elements, Bytes);
  if (mem == NULL) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Memory Error. Out of memory.\n");
    misc_FinishUserErrorReport();
  }
  return mem;
}
#else
#ifdef SPASS_CHECK
POINTER memory_CallocAndCheck(MEMORY Memory, unsigned int Elements, unsigned int Bytes,
       const char * File, unsigned short int Line)
#else
  POINTER memory_Calloc(MEMORY Memory, unsigned int Elements, unsigned int Bytes)
#endif
{
  char * mem;
#ifdef SPASS_CHECK
  mem = (char *)memory_MallocAndCheck(Memory, Elements * Bytes, File, Line);
#else
  mem = (char *)memory_Malloc(Memory, Elements * Bytes);
#endif
  if (mem != NULL) {
    memset(mem,0, Elements * Bytes);
  }
  else {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Memory Error. Out of memory.\n");
#ifdef SPASS_CHECK
    misc_UserErrorReport("\n Error occurred in memory_Calloc");
    misc_UserErrorReport(" called from file %s at line %d.\n",
    File, Line);
#endif
    misc_FinishUserErrorReport();
  }
  return mem;
}
#endif
#ifdef SPASS_NO_MEMORY_MANAGEMENT
void memory_Delete(MEMORY Memory)
{
  free(Memory);
}
#else
void memory_FreeAllMem(MEMORY Memory)
{
  memory_Reset(Memory);
}
void memory_Delete(MEMORY Memory)
{
  memory_Reset(Memory);
  free(Memory->resources);
  free(Memory);
}
void memory_Reset(MEMORY Memory)
{
  size_t i;
  for (i = 1; i < Memory->dynmaxsize; i++) {
    POINTER thispage, nextpage;
    MEMORY_RESOURCE Resource;
    Resource = &(Memory->resources[i-1]);
    thispage = Resource->page;
    if (*((int *)thispage) != EOF) {
      do {
        nextpage = *((POINTER *)thispage);
        free(thispage);
        thispage = nextpage;
      } while (*((int *)thispage) != EOF);
      Resource->page = (POINTER)&memory__EOF;
      Resource->free = (POINTER)&memory__EOF;
      Resource->next = (POINTER)&memory__EOF;
      Resource->end_of_page = (POINTER)&memory__EOF;
    }
  }
  if (Memory->bigblocks != NULL) {
    MEMORY_BIGBLOCKHEADER thisblock, nextblock;
    for (thisblock = Memory->bigblocks;
      thisblock != NULL;
      thisblock = nextblock) {
        nextblock = thisblock->next;
        free(thisblock);
    }
    Memory->bigblocks= NULL;
  }
}
#endif
void memory_Print(MEMORY Memory, char comment)
{
#ifndef SPASS_NO_MEMORY_MANAGEMENT
  memory_FPrint(Memory, stdout, comment);
#endif
}
void memory_FPrint(MEMORY Memory, FILE* File, char comment)
{
#ifndef SPASS_NO_MEMORY_MANAGEMENT
  int Pages;
  size_t i;
  POINTER ActPage;
  Pages = 0;
  for (i = 1; i < Memory->dynmaxsize; i++) {
    ActPage = Memory->resources[i-1].page;
    while (*((int *)ActPage) != EOF) {
      Pages++;
      ActPage = *((POINTER *)ActPage);
    }
  }
  fprintf(File, "\n%c ###\n", comment);
  fprintf(File,"%c ### Pagesize: %u\n",
   comment, Memory->pagesize);
  fprintf(File,"%c ### Marksize: %d\n",
   comment, (int)memory_MARKSIZE);
  if (Memory->newbytes < 1024)
    fprintf(File,"%c ### Memory demanded:  %lu Bytes\n",
     comment, Memory->newbytes);
  else
    fprintf(File,"%c ### Memory demanded:  %lu KBytes\n",
     comment, Memory->newbytes/1024);
  if (Memory->freebytes < 1024)
    fprintf(File,"%c ### Memory freed:     %lu Bytes\n",
     comment, Memory->freebytes);
  else
    fprintf(File,"%c ### Memory freed:     %lu KBytes\n",
     comment, Memory->freebytes/1024);
  if (Memory->newbytes-Memory->freebytes < 1024)
    fprintf(File,"%c ### Memory remaining: %lu Bytes\n",
     comment, Memory->newbytes-Memory->freebytes);
  else
    fprintf(File,"%c ### Memory remaining: %lu KBytes\n",
     comment, (Memory->newbytes-Memory->freebytes)/1024);
  fprintf(File,"%c ### Pages allocated:  %d Pages\n",
   comment, Pages);
  fprintf(File, "%c ###\n", comment);
#endif
}
#ifdef SPASS_CHECK
void memory_PrintAllocatedBlocks(MEMORY mem, unsigned int Size)
{
#ifndef SPASS_NO_MEMORY_MANAGEMENT
  MEMORY_RESOURCENODE Resource;
  POINTER ActPage;
  POINTER ActNext;
#ifdef SPASS_CHECK
  POINTER ActEndOfPage;
  unsigned int BlockSize;
  MEMORY_INFO Info;
#endif
  if (Size >= mem->dynmaxsize) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", __func__);
    misc_UserErrorReport("\n Parameter size is too big: %d.",
    Size);
    misc_UserErrorReport("\n Maximal allowed value is: %d.\n",
    mem->dynmaxsize);
    misc_FinishUserErrorReport();
  }
  else {
    Resource = (mem->resources)[Size-1];
    ActPage = Resource.page;
    ActNext = Resource.next;
#ifdef SPASS_CHECK
    ActEndOfPage = Resource.end_of_page;
    BlockSize = Resource.total_size;
#endif
    if (*((int *)ActPage) == EOF) {
      if (*((int *)ActNext) == EOF) {
 puts("   No request so far");
      }
      else {
  misc_StartErrorReport();
  misc_ErrorReport("\n In %s:", __func__);
  misc_ErrorReport("\n Memory Error. No Page entry but Next entry.\n");
  misc_FinishErrorReport();
      }
    }
    else {
#ifdef SPASS_CHECK
      char* ActData;
      char* ActStart;
      while (*((int *)ActPage) != EOF) {
        ActStart = (char *)ActPage + memory_AlignedSize(sizeof(POINTER));
        ActData = ActStart + memory_OFFSET;
        ActEndOfPage = ActStart + Resource.offset;
        while (ActStart != ActNext
               && ActStart != ActEndOfPage
               && memory_GetBlockStatus(mem, ActData) != memory_MAGICMALLOC) {
          ActStart += BlockSize;
          ActData += BlockSize;
        }
        if (ActStart == ActNext || ActStart == ActEndOfPage) {
          printf("\n\n   No memory allocated from page at address %p\n", ActPage);
        }
        else {
          fputs("\n\n   Allocated but not freed: ", stdout);
          do {
            Info = (MEMORY_INFO)ActStart;
            if (memory_GetBlockStatus(mem, ActData) == memory_MAGICMALLOC
                && memory_GetBlockSize(ActData) == Size) {
              printf("\n\t%p allocated in file %s at line %d ",
                     (void*) ActData, Info->mallocInFile, Info->mallocAtLine);
            }
            ActData += BlockSize;
            ActStart += BlockSize;
          } while (ActStart != ActNext && ActStart != ActEndOfPage);
        }
        ActPage = *((POINTER *)ActPage);
      }
#endif
    }
  }
#endif
}
void memory_PrintFreedBlocks(MEMORY mem, unsigned int Size)
{
#ifndef SPASS_NO_MEMORY_MANAGEMENT
  POINTER ActFree;
#ifdef SPASS_CHECK
  MEMORY_INFO Info;
#endif
  if (Size >= mem->dynmaxsize) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s.", __func__);
    misc_UserErrorReport("\n Parameter Size is too big: %d.",
    Size);
    misc_UserErrorReport("\n Maximal allowed value is: %d.\n",
    mem->dynmaxsize);
    misc_FinishUserErrorReport();
  }
  else {
    ActFree = (mem->resources[Size-1]).free;
    if (*((int *)ActFree) == EOF) {
      puts("\n\n   No freed memory");
    }
    else {
      fputs("\n\n   Free: ", stdout);
      while (*((int *)ActFree) != EOF) {
#ifdef SPASS_CHECK
 if ( memory_GetBlockSize(ActFree) == Size) {
   Info = (MEMORY_INFO) ((char *) ActFree - memory_OFFSET);
   printf("\n\t%p\tallocated in file %s at line %d",
   ActFree, Info->mallocInFile, Info->mallocAtLine);
   printf("\n\t\tfreed in file %s at line %d",
   Info->freeInFile, Info->freeAtLine);
 }
 else {
   if (1 ) {
     misc_StartUserErrorReport();
     misc_UserErrorReport("\n In %s:", __func__);
     misc_UserErrorReport("\n Memory Error. Memory block size mismatch.");
     misc_UserErrorReport("\n Expected %d found %d for memory block at %p.\n",
     Size, memory_GetBlockSize(ActFree), ActFree);
     misc_UserErrorReport("\n Probably the memory block was corrupted.\n");
     misc_FinishUserErrorReport();
   }
 }
#endif
 ActFree = *((POINTER *)ActFree);
      }
    }
  }
#endif
}
void memory_PrintAllocatedBigBlocks(MEMORY Memory)
{
#ifndef SPASS_NO_MEMORY_MANAGEMENT
#ifdef SPASS_CHECK
  MEMORY_BIGBLOCKHEADER Ptr;
  MEMORY_INFO Info;
  char * BlockStart;
  Ptr = Memory->bigblocks;
  if (Ptr != NULL) {
    do {
      BlockStart = (char *)Ptr + memory_OFFSET
        + memory_AlignedSize(sizeof(MEMORY_BIGBLOCKHEADERNODE));
      Info = (MEMORY_INFO) (BlockStart - memory_OFFSET);
      printf("\n\t%p %ud bytes allocated in file %s at line %d ",
      (void*)BlockStart, memory_GetBlockSize(BlockStart),
      Info->mallocInFile, Info->mallocAtLine);
      Ptr = Ptr->next;
    } while (Ptr != NULL);
    puts("");
  }
  else {
    puts("   No request so far");
  }
#endif
#endif
}
void memory_PrintDetailed(MEMORY Memory)
{
#ifndef SPASS_NO_MEMORY_MANAGEMENT
  MEMORY_RESOURCENODE Resource;
  POINTER ActPage;
  char* ActData;
  char* ActStart;
  POINTER ActEndOfPage;
  unsigned int BlockSize;
  unsigned int PageOffset;
  unsigned int i;
  printf("\n\nEOF Pointer: %p\n", (void*)&memory__EOF);
  for (i=1; i<Memory->dynmaxsize; i++) {
    Resource = Memory->resources[i-1];
    ActPage = Resource.page;
    ActStart = Resource.next;
    ActData = ActStart + memory_OFFSET;
    ActEndOfPage = Resource.end_of_page;
    PageOffset = Resource.offset;
    BlockSize = Resource.total_size;
    printf("\n\n Entry: %u aligned size: %u total size: %u\n",
    i , Resource.aligned_size, BlockSize);
    if (*((int *)ActPage) == EOF) {
      if (*((int *)ActData) == EOF) {
 puts("   No request so far");
      }
      else {
 misc_StartErrorReport();
 misc_ErrorReport("\n In %s:", __func__);
 misc_ErrorReport("\n Memory Error. No Page entry but Next entry.\n");
 misc_FinishErrorReport();
      }
    }
    else {
      while (*((int *)ActPage) != EOF) {
 printf("\n\n   Page: %p Next Page: %p\n",
        ActPage, *((POINTER *)ActPage));
 ActStart = (char *)ActPage + memory_AlignedSize(sizeof(POINTER));
 ActData = ActStart + memory_OFFSET;
 ActEndOfPage = ActStart + PageOffset;
 fputs("   Data: ", stdout);
 while (ActStart != ActEndOfPage) {
   int column;
   fputs("\n\t\t", stdout);
   for (column = 0; column < 6; column++) {
     printf("%p ", (void *) ActData);
      ActStart += BlockSize;
      ActData += BlockSize;
     if (ActStart == ActEndOfPage) {
       break;
     }
   }
 }
 ActPage = *((POINTER *)ActPage);
      }
      memory_PrintAllocatedBlocks(Memory, i);
      memory_PrintFreedBlocks(Memory, i);
    }
  }
#ifdef SPASS_CHECK
  printf("\n\n Allocated blocks of size >= %ud\n",
  Memory->dynmaxsize);
  memory_PrintAllocatedBigBlocks(Memory);
#endif
#endif
}
void memory_PrintLeaks(MEMORY mem)
{
#ifndef SPASS_NO_MEMORY_MANAGEMENT
  POINTER ActPage;
#ifdef SPASS_CHECK
  POINTER ActNext;
  POINTER ActEndOfPage;
#endif
  MEMORY_RESOURCENODE Resource;
  unsigned int Size;
#ifdef SPASS_CHECK
  unsigned int BlockSize;
#endif
  if (memory_UsedBytes(mem) != 0L) {
    for (Size = 1; Size < mem->dynmaxsize; Size++) {
      Resource = mem->resources[Size-1];
      ActPage = Resource.page;
#ifdef SPASS_CHECK
      ActNext = Resource.next;
      ActEndOfPage = Resource.end_of_page;
      BlockSize = Resource.total_size;
#endif
      if (*((int *)ActPage) != EOF) {
#ifdef SPASS_CHECK
 char* ActData;
 char* ActStart;
 BOOL LeakFound;
 LeakFound = FALSE;
 while (*((int *)ActPage) != EOF) {
          ActStart = (char *)ActPage + memory_AlignedSize(sizeof(POINTER));
          ActData = ActStart + memory_OFFSET;
          ActEndOfPage = ActStart + Resource.offset;
   while (ActStart != ActNext && ActStart != ActEndOfPage) {
     if (memory_GetBlockStatus(mem, ActData) == memory_MAGICMALLOC) {
       LeakFound = TRUE;
       break;
     }
      ActStart += BlockSize;
      ActData += BlockSize;
   }
   if (LeakFound) {
     printf("\n\n  Leaked blocks of size %u:", Size);
     memory_PrintAllocatedBlocks(mem,Size);
     putchar('\n');
     break;
   }
   else {
     ActPage = *((POINTER *)ActPage);
   }
 }
#endif
      }
    }
#ifdef SPASS_CHECK
    if (mem->bigblocks != NULL) {
      printf("\n\n  Leaked blocks of size >= %u\n",
      mem->dynmaxsize);
      memory_PrintAllocatedBigBlocks(mem);
      putchar('\n');
    }
#endif
  }
#endif
}
#endif
