/*
 * expandable lists
 * March 1989, Miles Bader
 */

#include "common.h"
#include "list.h"

#define BUMPSIZE 5                     /* grow list this much at a time */

char insertMark;                       /* dummy used for its address */

struct list *list_Create(init)
void **init;
{
    void **p,**q;
    struct list *l=NEW(struct list);
    
    DBUG_ENTER("list_Create");

    if(l==NULL)
       fatal("couldn't allocate a list");

    l->num=0;

    l->insertionPoint=(-1);

    for(p=init; p!=NULL && *p!=NULL; p++)
       if(*p==&insertMark)
           l->insertionPoint=l->num;
       else
           l->num++;

    l->els=(void **)malloc(l->num*sizeof(void *));

    if(l->els==NULL && l->num>0 /* ANSI compat */)
       fatal("couldn't allocate initial list elements");

    for(p=init,q=l->els; p!=NULL && *p!=NULL; p++)
       if(*p!=&insertMark)
           *q++=(*p);

    l->max=l->num;
    if(l->insertionPoint<0)
       l->insertionPoint=l->num;       /* default is at end */

    l->freeProc=NULL;

    DBUG_RETURN(struct list *,l);
}

void list_Free(l)
struct list *l;
{
    DBUG_ENTER("list_Free");

    if(l->freeProc!=NULL){
       void **els;
       int n;
       
       DBUG_4("free","using freeProc on %d els: 0x%x",l->num,l->freeProc);

       for(n=l->num,els=l->els; n>0; n--,els++){
           DBUG_3("free","freeProc(0x%x)",*els);
           (*l->freeProc)(*els);
       }
    }

    if(l->els!=NULL){
        DBUG_3("free","freeing els: 0x%x",l->els);
       FREE(l->els);
    }

    DBUG_3("free","freeing list: 0x%x",l);

    FREE(l);

    DBUG_VOID_RETURN;
}

void list_Add(l,e)
struct list *l;
void *e;
{
    int i;
    
    DBUG_ENTER("list_Add");

    if(l->num>=l->max){
        l->max+=BUMPSIZE;
       l->els=(void **)realloc((void *)l->els,l->max*sizeof(void *));

       if(l->els==NULL)
           fatal("couldn't extend a list to %d elements",l->max);
    }

    for(i=l->num; i>l->insertionPoint; i--)
       l->els[i]=l->els[i-1];

    l->els[l->insertionPoint++]=e;

    l->num++;

    DBUG_VOID_RETURN;
}
