/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include 
#include 
#include 
#include "arch.hh"

#include "memory/malloc.hh"
#include "error/error.hh"
#include "threads/threads.hh"
#include "time/profile.hh"
#include "init/init.hh"
#include "file/file.hh"
#include "file/static_file.hh"
#include "string/string.hh"

// define this to override the native memcpy to check for overwriting memory leaks
//#define i4_MEMCPY_CHECK
#define i4_FREE_CHECK

#ifdef i4_NEW_CHECK
#undef new
#endif

#undef i4_malloc
#undef i4_realloc

static i4_critical_section_class mem_lock;


#ifndef __MAC__

static i4_profile_class pf_malloc("i4_malloc");
static i4_profile_class pf_free("i4_free");


// declare the new()s before we include malloc.hh so that the new 
// macro doesn't mess up their definition
int i4_m_instance=0;
int i4_mem_break=-1;

#if (__linux && i4_NEW_CHECK)

void *operator new( size_t size, char *file, w32 line)
{  
  return i4_malloc(size, file, line);
}


void *operator new [](size_t size, char *file, w32 line)
{
  return i4_malloc(size, file, line);
}
#endif

#include 

#undef new


void *operator new( size_t size)
{  
  return i4_malloc(size,"unknown",0);
}

void operator delete(void *ptr)
{
  i4_free(ptr);
}


#endif

#ifdef i4_MEM_CHECK
#define i4_MEM_CLEAR
#endif


#include "memory/bmanage.hh"

extern void free_up_memory();

#ifdef i4_MEM_CHECK
// can be set in debugger, break mem fun will be called when this address is allocated
long break_mem_point=0;     
void break_mem_fun()
{
  printf("memory breakpoint\n");
}

#ifdef i4_MEMCPY_CHECK
// can set this memory range to check for mem copies over memory
w32 i4_check_min=0, i4_check_max=0;

extern "C" void *memcpy(void* dest, const void *src,size_t n)
{
  if (((w32)dest)i4_check_min)
    break_mem_fun();

  bcopy(src,dest,n);
}
#endif

#endif


i4_block_manager_class bmanage[5];
int bmanage_total=0;


void inspect_memory()
{
  mem_lock.lock();
  for (int i=0;ialloc_list&(1<next; 
      }
    }
  }
}


void i4_malloc_uninit()
{
#ifdef i4_MEM_CHECK
  i4_mem_report("end.mem");
#endif

  mem_lock.lock();

  for (int i=0;i=i4_malloc_min_size;)
    {
      mem=malloc(size);
      if (!mem) size-=0x100;        
    }

    if (mem)
    {
      bmanage[bmanage_total].init(mem,size);
      bmanage_total++; 
      size-=0x1000;
    }  
    else
      i4_error(not_enough_total_memory_message);
  }
}



class i4_memory_init_class : public i4_init_class
{
public:
  int init_type() { return I4_INIT_TYPE_MEMORY_MANAGER; }

  void init() { i4_malloc_init(); }

  void uninit() { i4_malloc_uninit(); }

} i4_memory_init_instance;


long i4_available()
{
  mem_lock.lock();
  long size=0;
  for (int i=0;il)
      l=t;
  }
  mem_lock.unlock();
  return l;
}

long i4_allocated()
{
  mem_lock.lock();
  
  long size=0;
  for (int i=0;i=(void *)bmanage[i].sfirst)  // is the pointer in this block?
    {
      if (ptr<=(void *)bmanage[i].slast)  // is it in static space?
      {
        bmanage[i].free(ptr);
        mem_lock.unlock();
        pf_free.stop();
        return ;
      } 
    }
 
  mem_lock.unlock();
  
  i4_error("i4_free : bad pointer\n");
  pf_free.stop();
}


void *i4_realloc(void *ptr, w32 size, char *file, int line)
{  
  if (!ptr) 
  {
    // malloc is already lock protected
    return i4_malloc(size, file, line);
  }


  if (!bmanage_total) 
  { 
    // thread protect the c library realloc
    mem_lock.lock();
    void *ret=realloc(ptr,size); 
    mem_lock.unlock();
    return ret;
  }

  if (size==0) 
  { 
    // free is already lock protected
    i4_free(ptr); 
    return NULL; 
  }

  sw32 old_size=0;
  for (int i=0;i=(void *)bmanage[i].sfirst && 
        ptr<=(void *)(((char *)bmanage[i].sfirst)+bmanage[i].block_size))
    {
      old_size=bmanage[i].pointer_size(ptr);  
      if (ptr<=(void *)bmanage[i].slast)
      {
        void *nptr=i4_malloc(size, file, line);
        if ((sw32)size>old_size)
          memcpy(nptr,ptr,old_size);
        else memcpy(nptr,ptr,size);

        bmanage[i].free(ptr);


        return nptr;
      }
    }

  i4_error("jrealloc : bad pointer\n");
  return NULL;
}


void dmem_report()
{
  i4_mem_report("debug.mem");
}

static i4_static_file_class mem_report;

void i4_mem_report(char *filename)
{
  i4_file_class *fp=mem_report.open(filename);

  if (fp)
  {
    for (int i=0;iprintf("Total available=%d, allocated=%d\n", i4_available(), i4_allocated());    
  }
}


long small_ptr_size(void *ptr)
{
  return ((small_block *)(((long *)ptr)[-1]))->size;
}


int valid_ptr(void *ptr)
{
  if (!bmanage_total) { return 0; }
  for (int i=0;i=(void *)bmanage[i].sfirst)  // is the pointer in this block?
    {
      if (ptr<=(void *)bmanage[i].slast)
      {
        int ret=bmanage[i].valid_ptr(ptr);
        return ret;
      }
    }

  return 0;
}




int valid_memory(void *ptr)
{
  for (int i=0; i=(void *)bmanage[i].sfirst)  // is the pointer in this block?
      if (ptr<=(void *)bmanage[i].slast)
        return 1;

  return 0;
}