/* $Header$ */
/*
 *
 * alloc.c : Memory checked Malloc. This malloc keeps track of memory usage.
 *
 * Routines:
 *	char * 		Malloc();
 *	char *		Calloc();
 *	char *		Realloc();
 *	void 		Free();
 *	unsigned	MemStat();
 *	unsigned	MemPtr();
 *	void		MemChain();
 *
 * $Log$
 * Revision 1.2  2007-12-06 11:55:14  bap
 * flush compiler warnings of various levels of severity
 *
 * Revision 1.1.1.1  1999/12/03 23:15:53  heideman
 * xgraph-12.0
 *
 * Revision 1.10  1991/02/01  08:12:55  christos
 * Overhaul... Simplified and added calloc.
 *
 * Revision 1.9  1990/10/02  18:11:24  christos
 * Another Realloc() bug!
 *
 * Revision 1.8  90/10/02  17:32:45  christos
 * Fixed Realloc() bug.
 *
 * Revision 1.7  90/08/24  02:28:15  christos
 * Changed bigstruct_t to align_t
 * for lint.
 *
 * Revision 1.6  90/07/15  17:31:33  christos
 * Fixed MemPtr Bug
 *
 * Revision 1.5  90/07/11  16:19:31  christos
 * Added Realloc()
 *
 * Revision 1.4  90/03/21  12:58:44  christos
 * Fixed void buggy computations.
 *
 * Revision 1.3  90/02/26  02:15:11  christos
 * ANSI conformance.
 *
 * Revision 1.2  89/08/29  14:08:25  christos
 * Fixed.
 *
 * Revision 1.1  89/03/27  14:23:40  christos
 * Initial revision
 *
 */

#include <stdio.h>
#ifdef __STDC__
#include <stdlib.h>
#include <memory.h>
#else
extern char *malloc();
extern char *calloc();
extern char *realloc();
extern void free();
extern void abort();
extern char *memset();

#endif

#ifndef NIL
#define NIL(a) ((a *) 0)
#endif				/* NIL */

#ifndef MIN
#define MIN(a, b) 		((a) > (b) ? (b) : (a))
#endif				/* MIN */

#ifndef MAX
#define MAX(a, b) 		((a) < (b) ? (b) : (a))
#endif				/* MAX */

#ifndef private
#define private static
#endif				/* private */

#ifndef public
#define public
#endif				/* public */


#define SIG_GOOD	0x01020304
#define SIG_FREE	0x04030201
#define OVERHEAD	(sizeof(long) + sizeof(unsigned))

private unsigned memused = 0;
private unsigned memalloc = 0;

#ifdef __STDC__
typedef void *Ptr;

#else
typedef char *Ptr;

#endif

/* _chaina():
 *	Check things for validity and allocate space
 */
private Ptr
_chaina(n, routine, action, tptr)
unsigned n;

Ptr(*routine) ();
char   *action;
Ptr     tptr;
{
    char   *ptr;

    if (n == 0) {
	(void) fprintf(stderr, "*** %s zero length block.\n",
		       action);
	if (tptr != (Ptr) 0) {
	    ptr = tptr;
	    *((long *) ptr) = SIG_GOOD;
	    memused += *((unsigned *) &ptr[sizeof(long)]);
	    memalloc++;
	}
	abort();
    }

    ptr = (tptr == (Ptr) 0) ? (char *) (*routine) (n + OVERHEAD) :
	(char *) (*routine) (tptr, n + OVERHEAD);

    if (ptr == NIL(char)) {
	if (tptr != (Ptr) 0)
	    *((long *) tptr) = SIG_GOOD;
	(void) fprintf(stderr,
		       "*** Out of memory in %s (current allocation %d, allocating %d).\n",
		       action, memused, n);

	abort();
    }
    *((long *) ptr) = SIG_GOOD;
    memused += (*((unsigned *) &ptr[sizeof(long)]) = n);
    memalloc++;
    ptr += OVERHEAD;
    return ((Ptr) ptr);
}				/* end _chaina */


/* _chainc():
 *	Check the pointer given
 */
private unsigned
_chainc(ptr, action)
char  **ptr;
char   *action;
{
    static char *msg = "*** %s %s pointer.\n";

    if (*ptr == NIL(char)) {
	(void) fprintf(stderr, msg, action, "nil");
	abort();
    }
    *ptr -= OVERHEAD;
    switch (*((long *) *ptr)) {
    case SIG_GOOD:
	return (*((unsigned *) &((*ptr)[sizeof(long)])));
    case SIG_FREE:
	(void) fprintf(stderr, msg, action, "free");
	abort();
    default:
	(void) fprintf(stderr, msg, action, "invalid");
	abort();
    }
    return (0);
}				/* end _chainc */


/* Malloc():
 *	real alloc
 */
public  Ptr
Malloc(n)
unsigned n;
{
    static char *routine = "malloc";

    return (_chaina(n, malloc, routine, (Ptr) 0));
}				/* end Malloc */


/* Calloc():
 *	real alloc
 */
public  Ptr
Calloc(n, sz)
unsigned n,
        sz;
{
    Ptr     ptr;
    static char *routine = "calloc";

    n *= sz;
    ptr = _chaina(n, malloc, routine, (Ptr) 0);
    memset((char *) ptr, 0, n);
    return (ptr);
}				/* end Calloc */


/* Realloc():
 *	real alloc
 */
public  Ptr
Realloc(ptr, n)
Ptr     ptr;
unsigned n;
{
    static char *routine = "realloc";

    memused -= _chainc((char **) &ptr, routine);
    memalloc--;
    *((long *) ptr) = SIG_FREE;
    return (_chaina(n, realloc, routine, ptr));
}				/* end Realloc */


/* Free():
 *	free memory counting the number of bytes freed
 */
public void
Free(ptr)
Ptr     ptr;
{
    static char *routine = "free";

    memused -= _chainc((char **) &ptr, routine);
    memalloc--;
    *((long *) ptr) = SIG_FREE;
    free(ptr);
}				/* end Free */


/* MemChain():
 *	Dump the chain
 */
public void
MemChain()
{
    if (memused == 0 && memalloc == 0)
	(void) fprintf(stdout, "\tNo memory allocated.\n");
    else {
	(void) fprintf(stdout, "\t%u Bytes allocated in %u chunks.\n", memused,
		       memalloc);
	(void) fprintf(stdout, "\tAverage chunk length %u bytes.\n",
		       memused / memalloc);
    }
}				/* end MemChain */


/* MemStat():
 *	return the amount of memory in use
 */
public unsigned
MemStat()
{
    return (memused);
}				/* end MemStat */


/* MemPtr():
 *	return the amount of memory used by the pointer
 */
public unsigned
MemPtr(ptr)
Ptr     ptr;
{
    static char *routine = "get size";

    return (_chainc((char **) &ptr, routine));
}				/* end MemPtr */
