/**
 **		list.c -- implementation of LISP-type list structure
 **		Russell S. Finn, 3-FEB-90
 **             Raymie Stata, 15-SEP-90
 **/

#include <stdio.h>
#include <assert.h>
#include "bucket.h"
#include "list.h"

#define LOCAL static
#define IMPORT extern
#define EXPORT /* */

/* begin rep */
struct cons_struct {
  char *car;
  struct cons_struct *cdr;
};
/* end rep */


/* Imported variables. */
IMPORT char *malloc();


/* Local variables */
LOCAL Bucket ccells = NULL;
typedef struct cons_struct cons_cell;


/* Exported routines */
EXPORT void lst_init()
{ ccells = bk_create(sizeof(struct cons_struct)); }


EXPORT List lst_cons(el, lst)
  char *el;
  List lst;
{
  List cc = (List) bk_alloc(ccells);
  assert(cc);
  cc->car = el;
  cc->cdr = lst;
  return(cc);
}


EXPORT List lst_append(lst, el)
  List lst;
  char *el;
{
  List p;

  for (p = lst; p->cdr; p = p->cdr);
  p->cdr = lst_cons(el, NULL);
  return(lst);
}


EXPORT char *lst_car(lst)
  List lst;
{ return( lst->car ); }


EXPORT List lst_cdr(lst)
  List lst;
{ return( lst->cdr ); }


EXPORT List lst_member(lst, el, eq)
  List lst;
  char *el;
  int (*eq)();
{
  List p;
	
  for (p = lst; p; p = p->cdr) if ((*eq)(p->car, el)) return(p);
  return(NULL);
}


EXPORT int lst_size(lst)
  List lst;
{
  int l;
  for(l = 0; lst; l++) lst = lst->cdr;
  return(l);
}


EXPORT void lst_free_node(lst)
  List lst;
{
  bk_free(ccells, (char *)lst);
}


EXPORT void lst_free_list(lst)
  List lst;
{
  while (lst) {
    cons_cell *cc = lst;
    lst = cc->cdr;
    bk_free(ccells, (char *)cc);
  }
}


EXPORT char *lst_unparse(lst, unparse)
  List lst;
  char *(*unparse)();
{
  int i, print_size = 0, lst_len;
  char *ret, **component_names;

  if (! (lst_len = lst_size(lst))) {
    assert( ret = malloc(1) );
    *ret = '\0';
    return(ret);
  }
   
  /* Unparse each component */
  assert( component_names = (char **)malloc(lst_len * sizeof(char *)) );
  for(i = 0; i < lst_len; i++) {
    component_names[i] = unparse(lst_car(lst));
    print_size += strlen(component_names[i]) + 2;
    lst = lst_cdr(lst);
  }

  /* Copy components into return string, then free them. */
  assert( ret = malloc(print_size + 1) );
  *ret = '\0';
  for(i = 0; i < lst_len-1; i++) {
    strcat(ret, component_names[i]);
    strcat(ret, ", ");
    free(component_names[i]);
  }

  strcat(ret, component_names[i]);
  free(component_names[i]);
  free(component_names);
  return(ret);
}
