#include <stdlib.h>

/*#include <exec/memory.h>*/
#include <proto/exec.h>
#include <proto/dos.h>

/*  stark modifizierte Version aus K&R  */

static union _mheader _base;
static union _mheader *_freep=0;

size_t _nalloc=1023;
union _mheader *_first_mlist=0,*_last_mlist=0;

union _mheader *_morecore(size_t anu)
{
    union _mheader *up;size_t nu;
    if(anu<_nalloc) nu=_nalloc; else nu=anu;
    up=(union _mheader *)AllocMem((nu+1)*sizeof(union _mheader),0L);
    if(!up) return(0);
    up->s.size=nu+1; up->s.ptr=0; /*  Merken fuer Freigabe am Schluss */
    if(_last_mlist){
        _last_mlist->s.ptr=up;_last_mlist=up;
    }else{
        _last_mlist=_first_mlist=up;
    }
    up++;
    up->s.size=nu;
    if(anu>_nalloc) return((void *)up);
    free((void *)(up+1));
    return(_freep);
}
void _freemem(void)
/*  Gibt allen Speicher frei    */
{
    union _mheader *p=_first_mlist,*m;
    while(p){
        m=p->s.ptr;
        FreeMem(p,p->s.size*sizeof(union _mheader));
        p=m;
    }
}
void *malloc(size_t nbytes)
{
    union _mheader *p,*prevp;
    size_t nunits;
    /*  aufrunden   */
    nunits=(nbytes+sizeof(union _mheader)-1)/sizeof(union _mheader)+1;
    if(nunits>_nalloc){
        if(!(p=_morecore(nunits))) return(0);
        p->s.size=nunits;p->s.ptr=0;
        return(p+1);
    }
    if((prevp=_freep)==0){   /*  noch keine base */
        _base.s.ptr=_freep=prevp=&_base;
        _base.s.size=0;
    }
    for(p=prevp->s.ptr;;prevp=p,p=p->s.ptr){
        if(p->s.size>=nunits){  /*  Block passt */
            if(p->s.size==nunits){  /*  genau   */
                prevp->s.ptr=p->s.ptr;
            }else{  /*  ist kleiner */
                p->s.size-=nunits;p+=p->s.size;p->s.size=nunits;
            }
            _freep=prevp;
            return((void *)(p+1));
        }
        /*  mehr Speicher anfordern     */
        if(p==_freep) if(!(p=_morecore(nunits))) return(0);
    }
}
void free(void *ap)
{
    union _mheader *bp,*p,*last;
    bp=(union _mheader *)ap;
    if(!bp) return;
    bp--;
    if(bp->s.size>_nalloc){
    /*  grosse Bloecke gleich freigeben     */
        bp--;   /*  Startadresse der mlist  */
        p=_first_mlist;
/*        printf("bp=%p\n",bp);*/
        while(p){
/*            printf("p=%p\n",p);*/
            if(p==bp){  /*  Block gefunden  */
                if(p==_first_mlist) _first_mlist=p->s.ptr;
                    else last->s.ptr=p->s.ptr;
                if(p==_last_mlist) _last_mlist=last;
                FreeMem(p,p->s.size*sizeof(union _mheader));
                return;
            }
            last=p;p=p->s.ptr;
        }
        /*  wenn man hierherkommt, koennte man einen Fehler melden  */
        Write(Output(),"memory list corrupt!\n",21);
        return;
    }
    for(p=_freep;!(bp>p&&bp<p->s.ptr);p=p->s.ptr)
        if(p>=p->s.ptr&&(bp>p||bp<p->s.ptr))
            break;

    if(bp+bp->s.size==p->s.ptr){
        bp->s.size+=p->s.ptr->s.size;
        bp->s.ptr=p->s.ptr->s.ptr;
    }else{
        bp->s.ptr=p->s.ptr;
    }
    if(p+p->s.size==bp){
        p->s.size+=bp->s.size;
        p->s.ptr=bp->s.ptr;
    }else{
        p->s.ptr=bp;
    }
    _freep=p;
}

