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

#include <stdlib.h>
#include <string.h>
#include "malloc1.h"


void *_realloc2 (void *mem, size_t new_size, int tile)
{
  void *p;
  mheader_t *block;
  msize_t old_size;

  /* Get a pointer to the block header, read the old size and mark the
     block in-use. */

  block = mem;
  --block;
  old_size = SIZE (block->size);
  block->size = old_size;       /* Block is in use */

  /* Try to expand the block in-place, without expanding the heap. */

  if (_expand2 (mem, new_size, FALSE, tile) != NULL)
    return mem;

  /* To save space, try to move the block to an entirely new location
     in the heap. */

  p = _malloc2 (new_size, FALSE, tile);
  if (p != NULL)
    {
      memcpy (p, mem, old_size);
      FREE (mem);
      return p;
    }

  /* Now try to expand the heap to expand the block.  This works only
     if the block is the last used one of the heap. */

  if (_expand2 (mem, new_size, TRUE, tile) != NULL)
    return mem;

  /* No chance is left but expanding the heap and allocating a new
     block at the end of the heap.  A speed optimization could be done
     here: searching the heap after MEM would be sufficient. */

  p = _malloc2 (new_size, TRUE, tile);
  if (p != NULL)
    {
      memcpy (p, mem, old_size);
      FREE (mem);
      return p;
    }

  /* Everything failed.  Shrink the block to the original size. */

  _expand2 (mem, old_size, FALSE, tile);
  return NULL;
}
