/* Copyright (c) 1993 Stephen F. White */

#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif

#include "config.h"
#include "cool.h"
#include "proto.h"
#include "sys_proto.h"

List *
list_new(int size)
{
    List	*new;

    new = MALLOC(List, 1);
    new->len = size;
    new->ref = 1;
    if (size) {
	new->el = MALLOC(Var, size);
    } else {
	new->el = 0;
    }
    new->mem = size;
    return new;
}

List *
list_setadd(List *list, Var value)
{
    List		*ret;

    ret = list;
    if (list_ismember(value, list)) {
	var_free(value);
	return ret;
    }
    return list_append(list, value, 0);
}
	
List *
list_setremove(List *list, Var value)
{
    List	*ret;
    int		 t;

    ret = list;
    if ((t = list_ismember(value, list))) {
	ret = list_delete(list, t);
    }
    return ret;
}

int
list_ismember(Var element, List *list)
{
    int		i;

    for (i = 0; i < list->len; i++) {
	if (var_eq(element, list->el[i])) {
	    return i + 1;
	}
    }
    return 0;
}

List *
list_assign(List *list, Var value, int pos)
{
    List	*new = list_new(list->len);
    int		 i;

    for (i = 0; i < list->len; i++) {
	if (i == pos - 1) {
	    new->el[i] = value;
	} else { 
	    new->el[i] = var_dup(list->el[i]);
	}
    }
    list_free(list);
    return new;
}

List *
doinsert(List *list, Var value, int pos)
{
    List	*new;
    int		 i;

    new = list_new(list->len + 1);
    for (i = 0; i < pos - 1; i++) {
	new->el[i] = var_dup(list->el[i]);
    }
    new->el[pos - 1] = value;
    for (i = pos; i < new->len; i++) {
	new->el[i] = var_dup(list->el[i - 1]);
    }
    list_free(list);
    return new;
}

List *
list_insert(List *list, Var value, int pos)
{
    if (pos < 1 || pos > list->len) {
	pos = 1;
    }
    return(doinsert(list, value, pos));
}
    
List *
list_append(List *list, Var value, int pos)
{
    if (pos < 1 || pos > list->len) {
	pos = list->len;
    }
    return(doinsert(list, value, pos + 1));
}

List *
list_delete(List *list, int pos)
{
    List	*new;
    int		 i;

    new = list_new(list->len - 1);
    for (i = 0; i < pos - 1; i++) {
	new->el[i] = var_dup(list->el[i]);
    }
    for (i = pos - 1; i < new->len; i++) {
	new->el[i] = var_dup(list->el[i + 1]);
    }
    list_free(list);				/* free old list */
    return new;
}

List
*list_subset(List *list, int lower, int upper)
{
    List	*r;
    int		i;

    r = list_new(upper - lower + 1);
    for (i = lower - 1; i < upper; i++) {
	r->el[i - lower + 1] = var_dup(list->el[i]);
    }
    return r;
}

#ifdef INLINE
void
list__free(List *list)
{
    int		i;

    for (i = 0; i < list->len; i++) {
	var_free(list->el[i]);
    }
    if (list->len) {
	FREE(list->el);
    }
    FREE(list);
}

#else /* !INLINE */

void
list_free(List *list)
{
    int		i;

    if (!--list->ref) {
	for (i = 0; i < list->len; i++) {
	    var_free(list->el[i]);
	}
	if (list->len) {
	    FREE(list->el);
	}
	FREE(list);
    }
}

List *
list_dup(List *list)
{
    list->ref++;
    return list;
}
#endif /* !INLINE */

List *
explode(const char *str, char sep, int nwords)
{
    const char	*word_start;
    List	*list = list_new(nwords);
    int		 i;

    for (i = 0; i < nwords; i++) {
	while (*str == sep)
	    str++;
	word_start = str;
	while (*str && *str != sep)
	    str++;
	list->el[i].type = STR;
	list->el[i].v.str = string_ncpy(word_start, str - word_start);
    }
    return list;
}