/*
 *  FILE: memchain.c
 *  Support routines for chaining memory, anchored to a head which
 *  points to the latest chunk of memory allocated.
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Aug-88	Jan Sven Trabandt   first release version
 *  31-Oct-88	Jan Sven Trabandt   chainAllocMem acts like normal AllocMem
 *				      if no memory-chain pointer given
 *				    parameters checked in all these functions
 */


#include "gimmelib/gimmefuncs.h"


struct memnode {
   struct memnode *next;
   ULONG size;
};


void *chainAllocMem( headptr, size, type )
    struct memnode  **headptr;
    ULONG   size;
    ULONG   type;
{
    register struct memnode *p;

    if( !headptr ) {
	p = AllocMem( size, type );
    } else {
	size += sizeof(struct memnode);
	if( p = AllocMem(size, type) ) {
	    p->size = size;
	    p->next = *headptr;
	    *headptr = p;
	    ++p;		    /* make p point to user's memory */
	}
    }
    return( p );
} /* chainAllocMem */


VOID chainFreeMem( head )
    register struct memnode *head;
{
    struct memnode  *p;

    while( head ) {
	p = head->next;
	FreeMem( head, head->size );
	head = p;
    }
} /* chainFreeMem */


short linkChainMem( headptr, head )
    struct memnode  **headptr;
    struct memnode  *head;
{
    register struct memnode *p;

    if( headptr && head ) {
	p = head;
	if( *headptr ) {
	    for( ; p->next; p = p->next ) {
	    } /* for */
	    p->next = *headptr;
	}
	*headptr = head;
    }
    return( 0 );
} /* linkChainMem */


short pluckChainMem( headptr, mem )
    struct memnode  **headptr;
    void	    *mem;
{
    register struct memnode *p;
    struct memnode	    *mine;

    if( !headptr ) {
	return( -1 );
    }
    if( mem && *headptr ) {
	mine = (struct memnode *)( ((UBYTE *) mem) -
				    (ULONG)sizeof(struct memnode) );
	if( mine == *headptr ) {
	    *headptr = mine->next;
	} else {
	    for( p = *headptr; p->next != mine; p = p->next ) {
		if( !p->next ) {
		    return( -1 );           /* not in this chain */
		}
	    } /* for */
	    p->next = mine->next;
	}
	FreeMem( mine, mine->size );
    }
    return( 0 );
} /* pluckChainMem */
