/*
 * (c) Copyright 1990, 1991, 1992 Conor P. Cahill (uunet!virtech!cpcahil).  
 * You may copy, distribute, and use this software as long as this
 * copyright statement is not removed.
 */

#ifndef lint
static
char rcs_hdr[] = "$Id: realloc.c,v 1.24 1992/07/03 00:03:25 cpcahil Exp $";
#endif

#include <stdio.h>

#include "mallocin.h"

DATATYPE *
realloc(cptr,size)
	DATATYPE		* cptr;
	SIZETYPE		  size;
{
	return( debug_realloc(NULL,-1,cptr,size) );
}

DATATYPE *
debug_realloc(file,line,cptr,size)
	CONST char		* file;
	int			  line;
	DATATYPE		* cptr;
	SIZETYPE		  size;
{
	static IDTYPE		  call_counter;

	/*
	 * increment the call counter
	 */
	call_counter++;

	return( DBFrealloc("realloc",M_T_REALLOC,call_counter,
			  file,line,cptr,size) );

}

/*
 * Function:	DBFrealloc()
 *
 * Purpose:	to re-allocate a data area.
 *
 * Arguments:	cptr	- pointer to area to reallocate
 *		size	- size to change area to
 *
 * Returns:	pointer to new area (may be same area)
 *
 * Narrative:	verify pointer is within malloc region
 *		obtain mlist pointer from cptr
 *		verify magic number is correct
 *		verify inuse flag is set
 *		verify connection to adjoining segments is correct
 *		save requested size
 *		round-up size to appropriate boundry
 *		IF size is bigger than what is in this segment
 *		    try to join next segment to this segment
 *		IF size is less than what is is this segment
 *		    determine leftover amount of space
 *		ELSE
 *		    allocate new segment of size bites
 *		    IF allocation failed
 *		        return NULL
 *		    copy previous data to new segment
 *		    free previous segment
 *		    return new pointer
 *		split of extra space in this segment (if any)
 *		clear bytes beyound what they had before
 *		return pointer to data 
 */

DATATYPE *
DBFrealloc(func,type,call_counter,file,line,cptr,size)
	CONST char		* func;
	int			  type;
	IDTYPE			  call_counter;
	CONST char		* file;
	int			  line;
	DATATYPE		* cptr;
	SIZETYPE		  size;
{
	SIZETYPE		  i;
	char			* new_cptr;
	int			  marked;
	struct mlist		* ptr;
	SIZETYPE		  r_size;

	MALLOC_INIT();

	/*
	 * IF malloc chain checking is on, go do it.
	 */
	if( malloc_opts & MOPT_CKCHAIN )
	{
		VOIDCAST DBFmalloc_chain_check(func,file,line,1);
	}

	/*
	 * if the user wants to be warned about zero length mallocs, do so
	 */
	if( ((malloc_opts & MOPT_ZERO) != 0) && (size == 0) )
	{
		malloc_errno = M_CODE_ZERO_ALLOC;
		malloc_warning(func,file,line,(struct mlist *)NULL);
	}

	/*
	 * if this is an ansi-c compiler and we want to use the realloc(0) 
	 * paradigm, or if this is a call from xtrealloc, then if the 
	 * pointer is a null, act as if this is a call to malloc.
	 */
#if defined(ANSI_NULLS) || (__STDC__ && ! defined(NO_ANSI_NULLS))
	if( cptr == NULL )
#else
	if( (cptr == NULL) && (type == M_T_XTREALLOC) )
#endif
	{
		/*
		 * allocate the new chunk
		 */
		new_cptr = DBFmalloc(func,type,call_counter,file,line,size);

		return(new_cptr);
	}

	/*
	 * verify that cptr is within the malloc region...
	 */
	if(    (cptr < malloc_data_start)
	    || (cptr > malloc_data_end) 
	    || ((((long)cptr) & malloc_round) != 0 ) )
	{
		malloc_errno = M_CODE_BAD_PTR;
		malloc_warning(func,file,line,(struct mlist *)NULL);
		return (NULL);
	}

	/* 
	 * convert pointer to mlist struct pointer.  To do this we must 
	 * move the pointer backwards the correct number of bytes...
	 */
	
	ptr = (struct mlist *) (((char *)cptr) - M_SIZE);
	
	if( (ptr->flag&M_MAGIC_BITS) != M_MAGIC )
	{
		malloc_errno = M_CODE_BAD_MAGIC;
		malloc_warning(func,file,line,(struct mlist *)NULL);
		return(NULL);
	}

	if( ! (ptr->flag & M_INUSE) )
	{
		malloc_errno = M_CODE_NOT_INUSE ;
		malloc_warning(func,file,line,ptr);
		return(NULL);
	}

 	if( (ptr->prev && (ptr->prev->next != ptr) ) ||
	    (ptr->next && (ptr->next->prev != ptr) ) ||
	    ((ptr->next == NULL) && (ptr->prev == NULL)) )
	{
		malloc_errno = M_CODE_BAD_CONNECT;
		malloc_warning(func,file,line,ptr);
		return(NULL);
	}

	/*
	 * save the marked status
	 */
	marked = ptr->flag & M_MARKED;

	/*
	 * save the requested size;
	 */
	r_size = size;

	/*
	 * make sure we have the full boundary that is needed
	 */
	size += malloc_boundsize;

	M_ROUNDUP(size);

	if( size > ptr->s.size )
	{
		malloc_join(ptr,ptr->next,INUSEOK,DOFILL);
	}

	if( size > ptr->s.size )
	{
		/*
		 * else we can't combine it, so lets allocate a new chunk,
		 * copy the data and free the old chunk...
		 */
		new_cptr = DBFmalloc(func,type,call_counter,file,line,size);

		if( new_cptr == (char *) 0)
		{
			return(new_cptr);
		}

		if( r_size < ptr->r_size )
		{
			i = r_size;
		}
		else
		{
			i = ptr->r_size;
		}
		in_malloc_code++;
		VOIDCAST memcpy(new_cptr,ptr->data,i);
		in_malloc_code--;

		/*
		 * if the old segment was marked, unmark it and mark the new
		 * segment.
		 */
		if( marked )
		{
			ptr->flag &= ~M_MARKED;
			malloc_mark(new_cptr);
		}

		/*
		 * free the old segment since it is no longer needed.
		 */
		DBFfree("realloc:free",F_T_REALLOC,call_counter,file,line,cptr);

		
		return(new_cptr);

	} /* if( size... */

	/*
	 * save amount of real data in new segment (this will be used in the
	 * memset later) and then save requested size of this segment.
	 */
	if( ptr->r_size < r_size )
	{
		i = ptr->r_size;
	}
	else
	{
		i = r_size;
	}

	ptr->r_size = r_size;

	/*
	 * split off extra free space at end of this segment, if possible...
	 */

	malloc_split(ptr);

	/*
	 * save the id info.
	 */	
	ptr->file      = file;
	ptr->line      = line;
	ptr->id        = call_counter;
	ptr->hist_id   = malloc_hist_id++;
	ptr->stack     = StackCurrent();
	ptr->freestack = NULL;
	SETTYPE(ptr,type);

	/*
	 * fill data and/or boundary areas
	 */
	FILLDATA(ptr,FILL_REALLOC,i, (struct mlist *) NULL);
	
	return(ptr->data);

} /* DBFrealloc(... */


/*
 * $Log: realloc.c,v $
 * Revision 1.24  1992/07/03  00:03:25  cpcahil
 * more fixes for pl13, several suggestons from Rich Salz.
 *
 * Revision 1.23  1992/05/14  23:02:27  cpcahil
 * added support for ANSI NULL behavior even with non-ansi compilers (if
 * chosen at compile time).
 *
 * Revision 1.22  1992/05/08  02:30:35  cpcahil
 * minor cleanups from minix/atari port
 *
 * Revision 1.21  1992/05/06  05:37:44  cpcahil
 * added overriding of fill characters and boundary size
 *
 * Revision 1.20  1992/05/06  04:53:29  cpcahil
 * performance enhancments
 *
 * Revision 1.19  1992/04/22  18:17:32  cpcahil
 * added support for Xt Alloc functions, linted code
 *
 * Revision 1.18  1992/04/13  03:06:33  cpcahil
 * Added Stack support, marking of non-leaks, auto-config, auto-testing
 *
 * Revision 1.17  1992/03/01  12:42:38  cpcahil
 * added support for managing freed areas and fixed doublword bndr problems
 *
 * Revision 1.16  1992/01/30  12:23:06  cpcahil
 * renamed mallocint.h -> mallocin.h
 *
 * Revision 1.15  1992/01/10  17:28:03  cpcahil
 * Added support for overriding void datatype
 *
 * Revision 1.14  1991/12/06  08:54:19  cpcahil
 * cleanup of __STDC__ usage and addition of CHANGES file
 *
 * Revision 1.13  91/12/04  09:23:44  cpcahil
 * several performance enhancements including addition of free list
 * 
 * Revision 1.12  91/12/02  19:10:14  cpcahil
 * changes for patch release 5
 * 
 * Revision 1.11  91/11/25  14:42:05  cpcahil
 * Final changes in preparation for patch 4 release
 * 
 * Revision 1.10  91/11/24  00:49:32  cpcahil
 * first cut at patch 4
 * 
 * Revision 1.9  91/11/20  11:54:11  cpcahil
 * interim checkin
 * 
 * Revision 1.8  90/08/29  21:22:52  cpcahil
 * miscellaneous lint fixes
 * 
 * Revision 1.7  90/05/11  00:13:10  cpcahil
 * added copyright statment
 * 
 * Revision 1.6  90/02/25  11:01:20  cpcahil
 * added support for malloc chain checking.
 * 
 * Revision 1.5  90/02/24  21:50:31  cpcahil
 * lots of lint fixes
 * 
 * Revision 1.4  90/02/24  17:29:39  cpcahil
 * changed $Header to $Id so full path wouldnt be included as part of rcs 
 * id string
 * 
 * Revision 1.3  90/02/24  17:20:00  cpcahil
 * attempt to get rid of full path in rcs header.
 * 
 * Revision 1.2  90/02/24  15:14:20  cpcahil
 * 1. added function header 
 * 2. changed calls to malloc_warning to conform to new usage
 * 3. added setting of malloc_errno
 *  4. broke up bad pointer determination so that errno's would be more
 *    descriptive
 * 
 * Revision 1.1  90/02/22  23:17:43  cpcahil
 * Initial revision
 * 
 */
