/* heapchk.c (emx+gcc) -- Copyright (c) 1990-1996 by Eberhard Mattes */

#include <stdlib.h>
#include <string.h>
#include <emx/startup.h>
#include "malloc1.h"

static int dummy;

#define HEAP_NO_FILL 0xf7dc6a4e /* illegal fill value */

static int _heapset2 (unsigned fill);


int _heapchk (void)
{
  return _heapset (HEAP_NO_FILL);
}


int _heapset (unsigned fill)
{
  int r;

  HEAP_LOCK;
  r = _heapset2 (fill);
  HEAP_UNLOCK;
  return r;
}


static int _heapset2 (unsigned fill)
{
  mheader_t *p, *last;
  msize_t len;
  maddr_t next;
  int met_rover;

  met_rover = 0;
  if (_malloc_rover == NULL && _malloc_bottom == NULL && _malloc_top == NULL)
    return _HEAPEMPTY;
  if (_malloc_rover == NULL || _malloc_bottom == NULL || _malloc_top == NULL)
    return _HEAPBADBEGIN;
  if (ADDR (_malloc_bottom) >= ADDR (_malloc_top))
    return _HEAPBADBEGIN;
  if (FLAGS (ADDR (_malloc_bottom)) != 0)
    return _HEAPBADBEGIN;
  if (!_cdll_flag && ADDR (_malloc_bottom) <= ADDR (&dummy))
    return _HEAPBADBEGIN;

  if (FLAGS (ADDR (_malloc_top)) != 0)
    return _HEAPBADEND;
  last = _sbrk (0);
  if (ADDR (_malloc_top) >= ADDR (last))
    return _HEAPBADEND;
  if (_malloc_top->size != END_OF_HEAP)
    return _HEAPBADEND;

  p = _malloc_bottom;
  while (p != _malloc_top)
    {
      /* Hitting a `size' member equal to END_OF_HEAP before hitting
         _malloc_top is an error. */

      if (p->size == END_OF_HEAP)
        return _HEAPBADNODE;

      /* Check the `size' member. */

      len = p->size;
      if (len > 0x7fffffff)
        return _HEAPBADNODE;

      /* Compute and check the address of the next block. */

      next = ADDR (p) + MHEADER_SIZE + SIZE (len);
      if (next <= ADDR (p) || next > ADDR (_malloc_top) || (len & MF_RESERVED))
        return _HEAPBADNODE;

      /* If filling is requested and the block is free, fill it. */

      if (fill != HEAP_NO_FILL && (len & MF_FREE))
        memset ((char *)p + MHEADER_SIZE, (int)fill, SIZE (len));

      /* Increment MET_ROVER if we have met the roving pointer. */

      if (p == _malloc_rover)
        ++met_rover;

      /* Move on to the next block. */

      p = MHEADER (next);
    }
  if (met_rover != 1)
    return _HEAPBADROVER;
  return _HEAPOK;
}
