/* realloc2.c (emx+gcc) -- Copyright (c) 1990-1993 by Eberhard Mattes */

#include <sys/emx.h>
#include <stdlib.h>
#include "malloc2.h"

void *_realloc2 (void *mem, size_t new_size, int tile)
{
  void *p;
  size_t *block;
  size_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 = (*block & ~3);
  *block = 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 a new location in the
     heap.  Moving the block backwards over free blocks immediately
     preceding the block is not yet implemented. */

  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);
}
