#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <time.h>


#include "lib.h"
#include "thread.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>

#define DMID 7
#include "dmalloc.h"
#include "tmalloc.h"

#ifndef TRUE
#define FALSE 0
#define TRUE (!FALSE)
#endif
int  emsg(const char * arg_list, ...);


#define tmalloc_CODE 0x12345678
#define tmalloc_FREED 0x33334444
static FILE *flog;
int tmalloc_abort(int *xi,char *reason)
{
	int b = xi[1];

	lib_abort();
	return TRUE;
}
static int nsimple;
static int tmalloc_bytes;
int tmalloc_total(void)
{
	return tmalloc_bytes;
}
void tmalloc_free(void *x, char *src, int line)
{
	int b;
	int *xi = (int *)x;
	if (x==NULL) return;
	xi-=2;
	b = xi[1];
	nsimple--;
	tmalloc_bytes -= b*sizeof(int);
	if (xi[0] == tmalloc_FREED) {
		emsg("Bad simple freed TWICE %s:%d b=%d xi=%p xi[0]=%x\n",src,line,b,xi,xi[0]);
		tmalloc_abort(xi,"tmalloc_free4");
	}
	if (xi[0] != tmalloc_CODE) {
		emsg("Bad simple freea %s:%d b=%d xi=%p xi[0]=%x\n",src,line,b,xi,xi[0]);
		tmalloc_abort(xi,"tmalloc_free1");
	}
	if (xi[b+2] != tmalloc_CODE) {
		emsg("Bad tsimple free2 %s:%d b=%d %d %d\n",src,line,b,xi[b+2],tmalloc_CODE);
		tmalloc_abort(xi,"tmalloc_free2");
	}
	xi[0] = tmalloc_FREED;
	xi[b+2] = tmalloc_FREED+1;  // mARK BEGINNIN AND END SO WE WILL KNOW IF WE TRY AND FREE THEM AGAIN...
	free(xi);
	if (flog!=NULL) fprintf(flog,"%s:%d free %p\n",src,line,x);
}

void *tmalloc_malloc(int n, char *src, int line)
{
	int *xi;
	//void *x;
	int b = (sizeof(int)+n)/sizeof(int); // 0,1,2,3 = 1,  4,5,6,7=2
	
	nsimple++;
	xi = d_mallocid(DMID,(b+3)*sizeof(int),src,line);
	if (xi==NULL) {
		emsg("MALLOC FAILED %d %s:%d\n",n,src,line);
		tmalloc_abort(xi,"Malloc failed in tmalloc_malloc()");
		abort(); // to stop compiler warnings
	}
	xi[0] = tmalloc_CODE;
	xi[1] = b;
	xi[b+2] = tmalloc_CODE;
	// NEXT BIT FOR DEBUGGING... 
	//x = (void *) (xi+2);
	//memset(x,1,n);
	// 
	tmalloc_bytes += b*sizeof(int);

	if (flog!=NULL) fprintf(flog,"%s:%d malloc %d %p\n",src,line,n, (void *) (xi+2));
	return (void *) (xi+2);
}
void *tmalloc_realloc(void *x, int n, char *src, int line)
{
	int *xi = (int *)x;
	int b = (sizeof(int)+n)/sizeof(int); // 0,1,2,3 = 1,  4,5,6,7=2
	if (flog!=NULL) fprintf(flog,"%s:%d realloc %d %p\n",src,line,n,x);

	if (x==NULL) return tmalloc_malloc(n,src,line);
	if (n==0) { // realloc could be used to free memory! 
		tmalloc_free(x,src,line);
		return NULL; 
	}

	xi-=2;
	if (xi[0] != tmalloc_CODE) tmalloc_abort(xi,"tmalloc_realloc3");
	tmalloc_bytes -= xi[1]*sizeof(int);
	xi = realloc(xi,(b+3)*sizeof(int) );
	if (xi==NULL) {
		char bf[BFSZ];
		sprintf(bf,"realloc failed, out of memory %s:%d bytes %d",src,line,n);
		tmalloc_abort(xi,bf);
	}
	xi[0] = tmalloc_CODE;
	xi[1] = b;
	xi[b+2] = tmalloc_CODE;
	tmalloc_bytes += xi[1]*sizeof(int);
	if (flog!=NULL) fprintf(flog,"%s:%d realloc %d %p\n",src,line,n, (void *) (xi+2));
	return (void *) (xi+2);
}
void *tmalloc_calloc(int num, int size, char *src, int line)
{
	void *x = tmalloc_malloc(num*size,src,line);
	memset(x,0,num*size);
	return x;
}
char *tmalloc_strdup(const char *s, char *src, int line)
{
	char *n = tmalloc_malloc(lib_strlen(s)+1,src,line);
	strcpy(n,s);
	return n;
}
void tmalloc_open(void)
{
	if (flog==NULL) flog = fopen("tmalloc.log","w");
}
void tmalloc_flush(void)
{
	if (flog!=NULL) fclose(flog); flog = NULL;
}
