/*
 * 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;
}
