/*	Copyright (C) 1992 Free Software Foundation, Inc.

This file is GNU software.

GNU software is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this software; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */



#include <stdio.h>
#include "util.h"

extern void *malloc(int);
extern void *calloc(int, int);
extern void *realloc(void *, int);
extern void free(void *);
extern bcopy(char *, char *, int);

static int util_time = 0;

void (*check_error)(char *) = check_abort;

void
check_abort(char *msg)
{
  write(2, msg, strlen(msg));
  exit(-1);
}


void *
check_malloc(int x, char *f, int l)
{
  void *r = malloc(x);
#ifdef DBUG
  printf("%d %d malloc %s(%d): %d\n", r, util_time++, f, l, x);
#endif

  if (r)
    return r;

  check_error("out of memory");
}

void *
check_calloc(int x, char *f, int l)
{
  void *r = calloc(x, 1);
#ifdef DBUG
  printf("%d %d malloc %s(%d): calloc %d\n", r, util_time++, f, l, x);
#endif

  if (r)
    return r;

  check_error("out of memory");
}


void *
check_realloc(void *m, int x, char *f, int l)
{
  void *r = realloc(m, x);
#ifdef DBUG
  printf ("%d %d free %s(%d): realloc\n", m, util_time++, f, l);
  printf("%d %d malloc %s(%d): realloc %d (old=%d)\n",
	 r, util_time++, f, l, x, m);
#endif
  if (r)
    return r;

  check_error("out of memory");
}


void
check_free(void *m, char *f, int l)
{
#ifdef DBUG
  printf("%d %d free %s(%d):\n", m, util_time++, f, l);
#endif

  free(m);
}



#define POOL 1

struct pool_header
{
  int alloced;
  int pooled;
  void * first;
};

static struct pool_header * pools = 0;
static int biggest_pool = 0;

static struct pool_header * 
pool_header_hard (n)
     int n;
{
  if (!biggest_pool)
    {
      biggest_pool = n;
      pools = (struct pool_header *)ck_calloc (sizeof (*pools) * n);
    }

  if (n > biggest_pool)
    {
      pools = (struct pool_header *)ck_realloc (pools, sizeof (*pools) * n);
      bzero (pools + biggest_pool, (n - biggest_pool) * (sizeof (*pools)));
      biggest_pool = n;
    }

  return pools + n - 1;
}
#define pool_header_get(N) ((N) > biggest_pool \
			?pool_header_hard(N) : pools + N - 1)
static void * 
palloc (x)
     int x;
{
  struct pool_header * h = pool_header_get(x);
  void * r = h->first;
  ++h->alloced;
  if (r)
    {
      --h->pooled;
      h->first = *(void **)h->first;
    }
  else
    r = malloc (x);

  return r;
}


static void
pfree (m, x)
     void * m;
     int x;
{
  struct pool_header * h = pool_header_get(x);

  h->alloced--;
  if (h->pooled >= 2 * h->alloced)
    {
      while (h->pooled > h->alloced)
	{
	  void * t = h->first;
	  h->first = *(void **)h->first;
	  free (t);
	  --h->pooled;
	}
    }
  ++h->pooled;
  *(void **)m = h->first;
  h->first = m;
}


void *
check_palloc (x, f, l)
     int x;
     char *f;
     int l;
{
#if POOL
  void *r = palloc(x);

#ifdef DBUG
  printf("%d %d malloc %s(%d): palloc %d\n", r, util_time++, f, l, x);
#endif

  if (r)
    return r;

  check_error("out of memory");
#else
  return check_malloc (x, f, l);
#endif
}

void *
check_pcalloc (x, f, l)
     int x;
     char *f;
     int l;
{
#if POOL
  void *r = palloc(x);

  bzero (r, x);
#ifdef DBUG
  printf("%d %d malloc %s(%d): pcalloc %d\n", r, util_time++, f, l, x);
#endif

  if (r)
    return r;

  check_error("out of memory");
#else
  return check_calloc (x, f, l);
#endif
}

void
check_pfree (m, x, f, l)
     void *m;
     int x;
     char * f;
     int l;
{
#if POOL
#ifdef DBUG
  printf("%d %d free %s(%d):\n", m, util_time++, f, l);
#endif
  pfree (m, x);
#else
  check_free (m, f, l);
#endif
}
