#ifdef RCS
static char rcsid[]="$Id: debugmem.c,v 1.1.1.1 2000/11/13 02:42:41 holsta Exp $";
#endif
/******************************************************************************
 *                    Internetting Cooperating Programmers
 * ----------------------------------------------------------------------------
 *
 *  ____    PROJECT
 * |  _ \  __ _ _ __   ___ ___ _ __ 
 * | | | |/ _` | '_ \ / __/ _ \ '__|
 * | |_| | (_| | | | | (_|  __/ |   
 * |____/ \__,_|_| |_|\___\___|_|   the IRC bot
 *
 * All files in this archive are subject to the GNU General Public License.
 *
 * $Source: /cvsroot/dancer/dancer/src/debugmem.c,v $
 * $Revision: 1.1.1.1 $
 * $Date: 2000/11/13 02:42:41 $
 * $Author: holsta $
 * $State: Exp $
 * $Locker:  $
 *
 * ---------------------------------------------------------------------------
 *****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "debugmem.h"

#undef malloc
#undef free

static int bytes_alloc_I=0;
static struct DebugMem *MallocKey =NULL;
static char Verbose=0;

struct DebugMem {
	struct DebugMem *prev;
	struct DebugMem *next;
	int size_I;
#ifdef SOURCE_INFO
	char *source_PC;
	int line_I;
#endif
};

void UnLinkMemory( struct DebugMem * );
void LinkMemory ( struct DebugMem * );

/*************************************************************************
*
* Function   : DBG_realloc
* Purpose    : Debug version of the system function realloc()
* Parameters : memory pointer, new size, source file, line number
* Returns    : new allocation or NULL if failed
*
****************************************************************************/

void * DBG_realloc( OldBuf_P, size_I, source_PC, line_I )
	 void *		OldBuf_P;
	 int	 	size_I;	
	 char *		source_PC;
	 int		line_I;
{
	struct DebugMem *debug_PS;
	void	*NewBuf_P;

	if ( OldBuf_P == NULL )
		/* *NOT* ANSI return!!! */
		return DBG_malloc( size_I, source_PC, line_I );

	debug_PS = (struct DebugMem *)
		((char *) OldBuf_P - sizeof( struct DebugMem ) - PRE_COOKIE_SIZE);

    if ( (NewBuf_P = DBG_malloc( size_I, source_PC, line_I )) == NULL )
		return NULL;

	memcpy( NewBuf_P, OldBuf_P, debug_PS->size_I );
	DBG_free( OldBuf_P, source_PC, line_I );
	return NewBuf_P;
}

/***************************************************************************
*
* Function   : DBG_Verbose
* Purpose    : Switch on verbose mode for debugging
* Parameters : TRUE/FALSE
* Returns    : none
*
*****************************************************************************/

void DBG_Verbose (char verbose_C)
{
	Verbose = verbose_C;
}

/*************************************************************************
*
* Function   : DBG_calloc
* Purpose    : Add debug level to the system function calloc()
* Parameters : number of itmes, itemsize, source file, line
* Returns    : allocated [cleared] memory or NULL if failed
*
**********************************************************************/

void * DBG_calloc ( items_I, itemsize_I, source_PC, line_I )
	 int	 	items_I;
	 int	 	itemsize_I;
	 char *		source_PC;
	 int		line_I;
{
  int size_I = items_I * itemsize_I;
  void *mem = DBG_malloc(size_I, source_PC, line_I);
  if(mem)
    memset(mem, 0, size_I); /* clear it */
  return mem;
}

/*************************************************************************
*
* Function   : DBG_malloc
* Purpose    : Add debug level to the system function malloc()
* Parameters : size, source file, line
* Returns    : allocated memory or NULL if failed
*
**********************************************************************/

void * DBG_malloc ( size_I, source_PC, line_I )
	 int	 	size_I;	
	 char *		source_PC;
	 int		line_I;
{
	struct DebugMem *debug_PS;
	void *p;

	/* Get some extra memory to make room for an extra
	   integer storage to store the malloc()'ed size! */

	debug_PS = (struct DebugMem *) malloc( size_I +
										  sizeof( struct DebugMem ) +
										  PRE_COOKIE_SIZE +
										  POST_COOKIE_SIZE );

	if ( !debug_PS )
		return NULL;
	
	if(Verbose) {
		MALLOCED(size_I, source_PC, line_I);
	}
	/* The malloc() did succeed */
	debug_PS->size_I = size_I ; /* remember size of malloc() */
	bytes_alloc_I += size_I ; /* count the malloc()s */

	LinkMemory( debug_PS );
	
#ifdef SOURCE_INFO
	debug_PS->source_PC = source_PC;
	debug_PS->line_I    = line_I;
#endif
	
#if PRE_COOKIE_SIZE > 0
	memset((char*)debug_PS + sizeof( struct DebugMem ), PRE_COOKIE_FILL_BYTE,
		   PRE_COOKIE_SIZE);
#endif
	
#if POST_COOKIE_SIZE > 0
	memset((char*)debug_PS + sizeof( struct DebugMem ) + size_I + PRE_COOKIE_SIZE,
		   POST_COOKIE_FILL_BYTE, POST_COOKIE_SIZE);
#endif
	

	p = (char*)debug_PS + sizeof( struct DebugMem ) + PRE_COOKIE_SIZE;

        ((char *)p)[0]='M';
	
	return p;
}

/********************************************************************
 *
 * Function   : DBG_free
 * Purpose    : Add debug level to the system function free()
 * Parameters : memory pointer, source file, source line
 * Returns    : none
 *
 ***********************************************************************/

void DBG_free ( mem_P, source_PC, line_I )
	 void *		mem_P;
	 char *		source_PC;
	 int		line_I;
{
	struct DebugMem *debug_PS;

	if( !mem_P) {
          /* freeing NULL is allowed, this is just an indicator */
          fprintf(stderr,
                  "DEBUG", "Freeing NULL pointer at %s line %d\n",
                  source_PC, line_I);
          return;
	}
	debug_PS = (struct DebugMem *)
		((char *) mem_P - sizeof( struct DebugMem ) - PRE_COOKIE_SIZE);

        if(debug_PS->size_I>7) {
          if(!strcmp(mem_P, "\001FrEeD\001")) {
            FREE_2ND(source_PC, line_I);
            return;
          }
        }
	DBG__CheckMem(mem_P, source_PC, line_I);

	bytes_alloc_I -= debug_PS->size_I;

        if(debug_PS->size_I>7) {
          strcpy(mem_P, "\001FrEeD\001");
        }

	if(Verbose) {
		FREED(debug_PS->size_I, source_PC, line_I);
	}
	UnLinkMemory( debug_PS );

	free( debug_PS );

}


/***************************************************************************
 *
 * Function   : DBG_UsedMem
 * Purpose    : Return number of allocated bytes.
 * Parameters : none
 * Returns    : Number of bytes
 *
 ***************************************************************************/

int DBG_UsedMem( )
{
	return bytes_alloc_I;
}

/*************************************************************************
 *
 * Function   : DBG__CheckMem
 * Purpose    : Check the cookies around the memory allocation for overwritten
 *              memory areas!
 * Parameters : memory pointer, source file, source line
 *
 ***************************************************************************/

long DBG__CheckMem ( mem_P, source_PC, line_I )
	 void *		mem_P;
	 char *		source_PC;
	 int		line_I;
{
	struct DebugMem *debug_PS;
	int		a, b, c;

	debug_PS = (struct DebugMem *)
		((char *) mem_P - sizeof( struct DebugMem ) - PRE_COOKIE_SIZE);

#if PRE_COOKIE_SIZE > 0
	for(a=b=0; a<PRE_COOKIE_SIZE; a++)
		if( *((unsigned char *)mem_P - PRE_COOKIE_SIZE + a ) != PRE_COOKIE_FILL_BYTE )
			b++;
	if ( b ) {
		PRE_COOKIE_ACTION(b, source_PC, line_I
						  , debug_PS->source_PC, debug_PS->line_I
						  );
	}
#endif

#if POST_COOKIE_SIZE > 0
	for(a=c=0; a<POST_COOKIE_SIZE; a++)
		if(*((unsigned char *)mem_P + debug_PS->size_I + a) != POST_COOKIE_FILL_BYTE)
			c++;
	if ( c ) {
		POST_COOKIE_ACTION(c, source_PC, line_I, debug_PS->source_PC, debug_PS->line_I );
	}
#endif

	if(Verbose) {
		CHECKMEMED(debug_PS->size_I, source_PC, line_I);
	}

	return b + c;
}

/***************************************************************************
 *
 * Function   : DBG_Strdup
 * Purpose    : Replaces the system strdup() function for debugging.
 * Parameters : string, source file, source line
 * Returns    : Allocated string or NULL if failed
 *
 **************************************************************************/

char *DBG_Strdup(char *string_PC, char *source_PC, int line_I)
{
	int len   = strlen( string_PC );
	char *ptr = DBG_malloc( len+1, source_PC, line_I );
	if(ptr)
		strcpy(ptr, string_PC);
	return ptr;
}

/*************************************************************************
 *
 * Function   : DBG_MemList
 * Purpose    : Display all allocations on stdout!
 * Parameters : none
 * Returns    : none
 *
 *************************************************************************/

void DBG_MemList()
{
	struct 	DebugMem *point = MallocKey;
	
	printf("------> Total %d bytes <------\n",
		   DBG_UsedMem());
	
	while(point) {
		printf("source: %s line: %d size: %d\n",
			   point->source_PC,
			   point->line_I,
			   point->size_I);
		point = point->prev;
	} 

	printf("------> End of table <------\n");
}

/**********************************************************************
 *
 * Function   : LinkMemory
 * Purpose    : Link a memory pointer to the linked list of memory.
 * Parameters : (struct DebugMem *) to the memory to add
 * Returns    : none
 *
 ************************************************************************/

void LinkMemory(point)
	 struct DebugMem *point;
{
	point->prev=MallocKey;	 /* previous */
	point->next=NULL;		 /* next */
	if(MallocKey)
		point->prev->next=point;
	MallocKey = (void *)point;
}

/**********************************************************************
 *
 * Function   : UnLinkMemory
 * Purpose    : Remove a memory area from the linked list.
 * Parameters : (struct DebugMem *) to the area to remove
 * Returns    : none
 *
 ************************************************************************/

void UnLinkMemory(point)
	 struct DebugMem *point;
{
	if(MallocKey==point) {
		/* if this is the last Malloc, set `last' to `prev' */
		MallocKey=point->prev;
		if(MallocKey)
			MallocKey->next=NULL;
	} else {
		/* point the previous' `next' to our `next', and our next `previous'
		   to our `previous'. Unlink us from the chain */
		if(point->prev)
			/* only if we aren't the _first_ Malloc() ! */
			point->prev->next=point->next;
		if(point->next)
			/* only if there is a next! */
			point->next->prev=point->prev;
	}
}

/***********************************************************************
 *
 * Function   : FreeAll
 * Purpose    : Free all memory areas in the list
 * Parameters : none
 * Returns    : none
 *
 *************************************************************************/

void FreeAll()
{
	struct DebugMem *point;
	struct DebugMem *prev;

	if(!MallocKey)
		return;
		
	do {
		point = MallocKey;
		
		prev = point->prev;
		
		free(point);
	} while(MallocKey = prev);

}



syntax highlighted by Code2HTML, v. 0.9.1