/*-----------------------------------------*
   Komfortable Speicher allokierfunktionen
   von Tobias Ferber, geschrieben 1990.
 *-----------------------------------------*/

#include <exec/types.h>
#include <exec/memory.h>

static char rcs_id[]= "$Id: memblock.c,v 1.2 90/08/15 09:13:31 tf Exp $";

#define mb_NIL (struct memblock *)NULL

struct memblock { struct memblock *succ, *pred;
                  char *memory;
                  long bytesize;
                };

/*
 * Die folgenden Funktionen arbeiten alle mit *einer* statischen Liste.
 * mb_list mu\3 nicht *unbedingt* Kopf dieser Liste sein, muß aber in jedem
 * Fall entweder mb_NIL oder Teil von ihr (dieser Liste, nicht mb_NIL :) sein.
 */

static struct memblock *mb_list= mb_NIL;

struct memblock *tail_mb(struct memblock *list)
{ if(list==mb_NIL) list= mb_list;
  while(list && list->succ)
    list= list->succ;
  return list;
}

struct memblock *head_mb(struct memblock *list)
{ if(list==mb_NIL) list= mb_list;
  while(list && list->pred)
    list= list->pred;
  return list;
}

void insert_mb(struct memblock *node,
               struct memblock *pred )
{ if(node)
  { if(pred==mb_NIL) pred= mb_list;
    if(pred)
    { tail_mb(node)->succ= pred->succ;
      pred->succ= head_mb(node);
      head_mb(node)->pred= pred;
    }
    else mb_list= node;
  }
}

void delete_mb(struct memblock *node)
{ if(node)
  { if(node->pred)
    { if(node->succ)
      { node->pred->succ= node->succ;
        node->succ->pred= node->pred;
      }
      else node->pred->succ= mb_NIL;
    }
    else if(node->succ)
      node->succ->pred= mb_NIL;

    node->pred= node->succ= mb_NIL;
  }
}

struct memblock *new_mb(void)
{ struct memblock *new= (struct memblock *)
                        AllocMem(sizeof(struct memblock), MEMF_PUBLIC|MEMF_CLEAR);

  new->succ= new->pred= mb_NIL;
  new->memory= (char *)NULL;
  new->bytesize= (long)0;

  return new;
}

void dispose_mb(struct memblock *which)
{ delete_mb(which); /* sicher ist sicher... */
  FreeMem(which, sizeof(struct memblock));
}

char *alloc_mem(long numbytes)
{ struct memblock *new= new_mb();
  char *mem= (char *)NULL;
  if(new)
  { if(mem= (char *)AllocMem(numbytes, MEMF_PUBLIC))
    { new->memory= mem;
      new->bytesize= numbytes;
      insert_mb(new, mb_list);
    }
    else
    { dispose_mb(new);
      new= mb_NIL;
    }
  }
  return mem;
}

void flame_mb(struct memblock *which)
{ if(which)
  { if(which->memory && which->bytesize)
    { FreeMem(which->memory, which->bytesize);
      delete_mb(which);
    }
    dispose_mb(which);
  }
}

void free_mem(char *memory)
{ struct memblock *node= head_mb(mb_list);
  while(node && node->memory != memory)
    node= node->succ;
  if(node) flame_mb(node);
}

void free_all(void)
{ struct memblock *node= head_mb(mb_list);
  while(node)
  { struct memblock *temp= node->succ;
    flame_mb(node);
    node= temp;
  }
}
