/* Copyright (C) 1993,1994 by the author(s).
 
 This software is published in the hope that it will be useful, but
 WITHOUT ANY WARRANTY for any part of this software to work correctly
 or as described in the manuals. See the ShapeTools Public License
 for details.

 Permission is granted to use, copy, modify, or distribute any part of
 this software but only under the conditions described in the ShapeTools 
 Public License. A copy of this license is supposed to have been given
 to you along with ShapeTools in a file named LICENSE. Among other
 things, this copyright notice and the Public License must be
 preserved on all copies.
 */
/*
 * AtFS -- Attribute Filesystem
 *
 * afmemory.c -- memory allocation module for AtFS archive handling
 *
 * Author: Andreas Lampen (Andreas.Lampen@cs.tu-berlin.de)
 *
 * $Header: afmemory.c[7.0] Fri Feb  4 13:55:32 1994 andy@cs.tu-berlin.de frozen $
 */

#include "atfs.h"
#include "afarchive.h"

extern int af_listmem;

/*=========================================================================
 *     af_malloc -- allocate memory and registrate it
 *
 * all memory allocated for data in an archive is preceeded by a pointer
 * pointing to the prevoiusly allocated memory segment.
 * So we get a chain of allocated memory segments.
 * ( probably not portable )
 *
 *=========================================================================*/

#define ALIGN sizeof(long)

EXPORT char *af_malloc (list, size)
     Af_revlist *list;
     unsigned   size;
{
  register char **mem;
  register int i;

  if ((i = size%ALIGN))
    size += ALIGN-i;
  size += sizeof(mem);

  if (afListSpace ((int) size) == ERROR)
    af_wng ("malloc", "Application exceeds memory limit");

  if ((mem = (char **)malloc ((unsigned) (size))) == NULL)
    FAIL ("malloc", "malloc", AF_ESYSERR, NULL);
  list->af_totalmem += size;
  af_listmem += size;
  *mem = list->af_mem;
  list->af_mem = (char *)mem;

  mem++; /* increment by sizeof ptr */

  return ((char *)mem);
}


EXPORT char *af_realloc (list, ptr, size)
     Af_revlist *list;
     char       *ptr;
     unsigned   size;
{
  char **mem, **segptr, **nextptr;
  register int i;

  if ((i = size%ALIGN))
    size += ALIGN-i;

  ptr -= sizeof ((char *)0);

  /* unregistrate memory segment to be realloc'ed */
  segptr = &(list->af_mem);
  while (*segptr != ptr)
    segptr = (char **)*segptr;
  nextptr = (char **)*segptr;
  *segptr = *nextptr;

  if ((mem = (char **)realloc (ptr, (unsigned) (size + sizeof (mem)))) == NULL)
    return NULL;
  list->af_totalmem += size; /* not correct (size of old segment should */
  af_listmem += size;        /*              be subtracted */

  *mem = list->af_mem; /* registrate new segment */
  list->af_mem = (char *)mem;

  mem++; /* increment by sizeof ptr */

  return ((char *)mem);
}

EXPORT void af_free (list, ptr)
     Af_revlist *list;
     char       *ptr;
{
  char **segptr, **nextptr;

  ptr -= sizeof ((char *)0);

  segptr = &(list->af_mem); /* remove memory segment from registration list */
  while (*segptr != ptr)
    segptr = (char **)*segptr;
  nextptr = (char **)*segptr;
  *segptr = *nextptr;

  free (ptr);
}


EXPORT void af_frmemlist (list)
     Af_revlist *list;
{
  register char **ptr, **ptr1;

  ptr = (char **)list->af_mem;
  while ((char *)ptr) {
    ptr1 = (char **)*ptr;
    free (ptr);
    ptr = ptr1;
  }
  af_listmem -= list->af_totalmem;
  
  list->af_mem = NULL;
  list->af_totalmem = 0;
}
