#include "cdefs.h"
#include "mem.h"
#include <stdio.h>

static unsigned char* h[128];
static cint tot_free;

void init_mem(){
  cint i;
  for (i = 0; i<128; i++) {h[i] = 0;};
  tot_free = 0;
}

void mem_reclaim(){
  cint i; char* p;
  for (i = 0; i<128; i++){
    p = h[i];
    while (p) {h[i] = *((char**)p); free(p); p = h[i];};
  };
  tot_free = 0;
}

void* mem_malloc(cint siz){
  unsigned char* r;
  if (siz < 1 | siz > 128){
    r = (unsigned char*)malloc(siz+12); 
    if (!r) {mem_reclaim(); r = (char*)malloc(siz+12);}
    if (!r) 
	  {printf("Out of memory\n"); exit(255);};
  }else{
    tot_free -= siz;
    r = h[siz-1];
    if (r == 0){
      if (tot_free > 32000000) mem_reclaim();
      r = (unsigned char*)malloc(siz+12); 
      if (!r) {mem_reclaim(); r = (char*)malloc(siz+12);}
      if (!r) 
	    {printf("Out of memory\n"); exit(255);};
    }else{
      h[siz-1] = *((void**)r);
	  check_if_still_preserved(r, siz);
    };
  };
  *((cint*)r) = siz; *((cint*)(r+4)) = 0; *((cint*)(r+8)) = siz; return r+12;
}

void mem_free(cint p){
  unsigned char* q = (unsigned char*)p; cint siz;
  q -= 12;
  siz = *((cint*)q);
  if (*((cint*)(q+4)) == 182937465)
	  {printf("Freed already free buf %i\n", q); exit(254);};
  if (*((cint*)q) != *((cint*)(q+8)))
      {printf("Non user area of freed buf corruped\n"); exit(253);};
  if (siz < 1 | siz > 128) {free(q); return;};
  *((unsigned char**)q) = h[siz-1];
  *((cint*)(q+4)) = 182937465;
  h[siz-1] = q;
  pickle(q, siz);
  tot_free += siz;
}

int pickle(unsigned char *p, int siz){
	int i;
	for (i = 12; i < siz; i++) p[i] = 0xfc;
}

int check_if_still_preserved(unsigned char *p, int siz){
	int i;
	if (*((cint*)(p+4)) != 182937465 || *((cint*)(p+8)) != siz)
           {printf("Free buf %i has been modified while on free list\n", p); exit(252);}
	for (i = 12; i < siz; i++)
 	  if (p[i] != 0xfc)
           {printf("Free buf %i has been modified while on free list\n", p); exit(251);}
}





