/*+++++++++++++++++
  linklist.c - implements some functions for linked lists
  markus@mhoenicka.de 7-11-00

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, see <http://www.gnu.org/licenses/>

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include <stdio.h> /* for a definition of NULL */
#include <stdlib.h> /* for malloc */
#include <string.h>

#include "linklist.h"

/*********************************************************************
 linked list for file descriptors
 This is an ordered linked list. The highest fd will always be the
 first member of the list.
********************************************************************/
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  insert_olili(): inserts a new item into an ordered linked list. The
                  list will be in descending order, so the first item
                  after the sentinel is the item with the highest
                  value

  int insert_olili returns 0 if ok, 1 if error

  struct olili *ptr_first pointer to sentinel

  int value the value to be inserted into the list (value >= 0)

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int insert_olili(Olili *ptr_first, int value) {
  Olili *ptr_before; /* item before insertion point */
  Olili *ptr_after; /* item after insertion point */
  Olili *ptr_new_olili; /* new item */

  ptr_before = ptr_first; /* start search at the beginning */
  ptr_after = ptr_before->ptr_next;

  while (ptr_after != NULL) {
    if (ptr_after->fd <= value) { /* sort in descending order */
      break;
    }
    ptr_after = ptr_after->ptr_next;
    ptr_before = ptr_before->ptr_next;
  }

  ptr_new_olili = malloc(sizeof(Olili));
  if (ptr_new_olili == NULL) {
    return 1;
  }
  ptr_new_olili->fd = value;
  ptr_before->ptr_next = ptr_new_olili;
  ptr_new_olili->ptr_next = ptr_after;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  delete_olili(): deletes an item from an ordered linked list.

  int delete_olili returns 0 if ok, 1 if error

  Olili *ptr_first pointer to sentinel

  int value the value to be inserted into the list

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int delete_olili(Olili *ptr_first, int value) {
  Olili *ptr_before; /* item before deletion point */
  Olili *ptr_curr; /* item at deletion point */

  ptr_before = ptr_first; /* start search at the beginning */
  ptr_curr = ptr_before->ptr_next;

  while (ptr_curr != NULL) {
    if (ptr_curr->fd == value) { /* got it */
      break;
    }
    ptr_curr = ptr_curr->ptr_next;
    ptr_before = ptr_before->ptr_next;
  }

  if (ptr_curr == NULL) {
    return 1;
  }

  ptr_before->ptr_next = ptr_curr->ptr_next;
  free(ptr_curr);
  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  max_olili(): returns the item with the highest value from an ordered
               linked list.

  int max_olili returns the maximum value, or -1 if an error occurred

  Olili *ptr_first pointer to sentinel

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int max_olili(Olili *ptr_first) {
  if (ptr_first != NULL && ptr_first->ptr_next != NULL) {
    return ptr_first->ptr_next->fd;
  }
  else if (ptr_first != NULL) {
    return ptr_first->fd;
  }
  else {
    return -1;
  }
}


/*********************************************************************
 linked list for allocated memory
 This is an unsorted linked list. The first list member is a sentinel
 which is not automatically deallocated by the lilimem functions.
 The calling fn has to explicitly declare, initialize, and destruct
 a lilimem struct for this purpose.
********************************************************************/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  insert_lilimem(): inserts a new member into the list

  int insert_lilimem returns 0 if ok, or 1 if an error occurred
                 if an error occurs, the memory pointed to by ptr_mem
		 will be freed

  Lilimem *ptr_first pointer to sentinel
  
  void** ptr_mem ptr to ptr to allocated memory

  char* varname ptr to string with the name of the variable used for
                that memory location. This name is used to find the
		correct list member if you want to delete a specific
		entry with the delete_lilimem() function. This can in
		fact be any unique string other than the variable name.
		You may pass NULL here if you don't use
		delete_lilimem(), but only delete_all_lilimem()

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int insert_lilimem(Lilimem *ptr_first, void** ptr_mem, char* varname) {
  Lilimem* ptr_new_item;

  if (varname && strlen(varname) > 32) { /* string too long to fit into struct */
    return 1;
  }

  ptr_new_item = malloc(sizeof(Lilimem));

  if (ptr_new_item == NULL) { /* malloc failed */
    free(*ptr_mem);
    return 1;
  }

  if (varname) {
    strcpy(ptr_new_item->varname, varname);
  }
  else {
    (ptr_new_item->varname)[0] = '\0';
  }
  ptr_new_item->ptr_mem = ptr_mem;
  ptr_new_item->ptr_next = ptr_first->ptr_next;
  ptr_first->ptr_next = ptr_new_item;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  delete_lilimem(): deletes a member from the list by the varname

  int delete_lilimem returns 0 if ok, or 1 if an error occurred

  Lilimem *ptr_first pointer to sentinel
  
  char* varname ptr to string with the name of the variable used for
                that memory location

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int delete_lilimem(Lilimem *ptr_first, char* varname) {
  Lilimem* ptr_curr_item;
  Lilimem* ptr_prev_item;
  int gotit = 0;

  ptr_prev_item = ptr_first;
  ptr_curr_item = ptr_first->ptr_next;

  while (ptr_curr_item) {
    if (ptr_curr_item->varname && strcmp(ptr_curr_item->varname, varname) == 0) {
      gotit = 1;
      break;
    }
    /* else: silently ignore if item has no varname */
    ptr_prev_item = ptr_curr_item;
    ptr_curr_item = ptr_curr_item->ptr_next;
  }

  if (gotit) {
    free(*(ptr_curr_item->ptr_mem)); /* free the memory referenced by the list
					member */
/*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
    *(ptr_curr_item->ptr_mem) = NULL; /* set the memory ptr to NULL to avoid
				      problems with erroneous subsequent
				      free() calls */
    ptr_prev_item->ptr_next = ptr_curr_item->ptr_next;
    free(ptr_curr_item); /* free the memory allocated for the list member */
    return 0;
  }
  else {
    return 1;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  delete_all_lilimem(): deletes all members from the list

  int delete_all_lilimem returns 0 if ok, or 1 if an error occurred

  Lilimem *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int delete_all_lilimem(Lilimem *ptr_first) {
  Lilimem* ptr_curr_item;
  Lilimem* ptr_next_item;

  ptr_curr_item = ptr_first->ptr_next;
  ptr_first->ptr_next = NULL;

  while (ptr_curr_item) {
    ptr_next_item = ptr_curr_item->ptr_next;
/*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
    free(*(ptr_curr_item->ptr_mem)); /* free the memory referenced by the list
					member */
    *(ptr_curr_item->ptr_mem) = NULL; /* set the memory ptr to NULL to avoid
				      problems with erroneous subsequent
				      free() calls */
    free(ptr_curr_item); /* free the memory allocated for the list member */

    ptr_curr_item = ptr_next_item;
  }
  return 0;
}

/*********************************************************************
 linked list for decoding cgi data
 This is an unsorted linked list. The first list member is a sentinel
 which is not automatically deallocated by the lilimem functions.
 The calling fn has to explicitly declare, initialize, and destruct
 a lilimem struct for this purpose.
********************************************************************/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  insert_liliform(): inserts a new member into the list

  int insert_liliform returns 0 if ok, or 1 if an error occurred
                 if an error occurs, the memory pointed to by ptr_mem
		 will be freed

  Liliform *ptr_first pointer to sentinel
  
  char* name ptr to string with the name of the variable used for
                that memory location.

  char* value ptr to allocated memory

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int insert_liliform(Liliform *ptr_first, char* name, char* value) {
  Liliform* ptr_new_item;
  char* my_value;

  if (name == NULL) {
    return 0; /* do nothing, no error */
  }

  if (strlen(name) > 32) { /* string too long to fit into struct */
    return 1;
  }

  ptr_new_item = malloc(sizeof(Liliform));

  if (!ptr_new_item) { /* malloc failed */
    return 1;
  }

  strcpy(ptr_new_item->name, name);

  if (value && strlen(value)) {
    my_value = malloc(strlen(value)+1);
    if (!my_value) {
      free(ptr_new_item);
      return 1;
    }
    strcpy(my_value, value);
    ptr_new_item->value = my_value;
  }
  else {
    ptr_new_item->value = NULL;
  }

  ptr_new_item->ptr_next = ptr_first->ptr_next;
  ptr_first->ptr_next = ptr_new_item;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  append_liliform(): appends a new member into the list. The
                       implementation is not very efficient but is ok
		       for a low number of entries

  int append_liliform returns 0 if ok, or 1 if an error occurred
                 if an error occurs

  Liliform *ptr_first pointer to sentinel
  
  char* name ptr to string with the name of the variable used for
                that memory location.

  char* value ptr to allocated memory

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int append_liliform(Liliform *ptr_first, char* name, char* value) {
  char* my_value;
  Liliform* ptr_new_item;
  Liliform* ptr_last_item;

  ptr_new_item = malloc(sizeof(Liliform));

  if (!ptr_new_item) { /* malloc failed */
    return 1;
  }

  strcpy(ptr_new_item->name, name);

  if (value && *value) {
    my_value = malloc(strlen(value)+1);
    if (!my_value) {
      free(ptr_new_item);
      return 1;
    }
    strcpy(my_value, value);
    ptr_new_item->value = my_value;
  }
  else {
    ptr_new_item->value = NULL;
  }

  ptr_new_item->ptr_next = NULL;
  
  ptr_last_item = ptr_first;

  /* this is going to be inefficient for a large number of entries */
  while (ptr_last_item->ptr_next) {
    ptr_last_item = ptr_last_item->ptr_next;
  }
  ptr_last_item->ptr_next = ptr_new_item;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_liliform(): retrieves a member of the list by name

  Liliform* get_liliform returns a ptr to the first member
                   whose name matches as specified and whose value is
		   not NULL, otherwise it returns NULL

  Liliform *ptr_first pointer to sentinel
  
  char* name ptr to string with the name of the variable

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
Liliform* get_liliform(Liliform* ptr_first, char* name) {
  Liliform* ptr_curr_item;
  Liliform* ptr_result = NULL;
  
  ptr_curr_item = ptr_first->ptr_next;

  while (ptr_curr_item) {
    if (!strcmp(ptr_curr_item->name, name)) {
      if (ptr_curr_item->value) {
	ptr_result = ptr_curr_item;
      }
      break;
    }
    ptr_curr_item = ptr_curr_item->ptr_next;
  }
  return ptr_result;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_nliliform(): retrieves a member of the list by partial name match

  Liliform* get_nliliform returns a ptr to the first member
                   whose name matches as specified and whose value is
		   not NULL, otherwise it returns NULL

  Liliform *ptr_first pointer to sentinel
  
  char* name ptr to string with the name of the variable

  size_t n the number of characters to compare, starting at name[0]

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
Liliform* get_nliliform(Liliform* ptr_first, char* name, size_t n) {
  Liliform* ptr_curr_item;
  Liliform* ptr_result = NULL;
  
  ptr_curr_item = ptr_first->ptr_next;

  while (ptr_curr_item) {
    if (!strncmp(ptr_curr_item->name, name, n)) {
      if (ptr_curr_item->value) {
	ptr_result = ptr_curr_item;
      }
      break;
    }
    ptr_curr_item = ptr_curr_item->ptr_next;
  }
  return ptr_result;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_next_liliform(): retrieves next member of the list

  Liliform* get_next_liliform returns a ptr to the next member or NULL
                      if we're at the end of the list. Use this fn
		      to loop over all list entries. In the first
		      iteration, pass a ptr to the sentinel. In
		      subsequent iterations, pass the ptr that the
		      previous iteration returns.
                   

  Liliform *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
Liliform* get_next_liliform(Liliform* ptr_first) {
  return ptr_first->ptr_next;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  delete_all_liliform(): deletes all members from the list

  int delete_all_liliform returns 0 if ok, or 1 if an error occurred

  Liliform *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int delete_all_liliform(Liliform *ptr_first) {
  Liliform* ptr_curr_item;
  Liliform* ptr_next_item;

  ptr_curr_item = ptr_first->ptr_next;
  ptr_first->ptr_next = NULL;

  while (ptr_curr_item) {
    ptr_next_item = ptr_curr_item->ptr_next;
/*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
    free(ptr_curr_item->value); /* free the memory allocated for the value */
    free(ptr_curr_item); /* free the memory allocated for the list member */

    ptr_curr_item = ptr_next_item;
  }
  return 0;
}

/*********************************************************************
 linked list for reading non-standard field mapping for BibTeX data
 This is an unsorted linked list. The first list member is a sentinel
 which is not automatically deallocated by the lilimem functions.
 The calling fn has to explicitly declare, initialize, and destruct
 a lilimem struct for this purpose.
********************************************************************/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  insert_lilibib(): inserts a new member into the list

  int insert_lilibib returns 0 if ok, or 1 if an error occurred
                 if an error occurs, the memory pointed to by ptr_mem
		 will be freed

  Lilibib *ptr_first pointer to sentinel
  
  char* name ptr to string with the name of the variable used for
                that memory location. May be NULL if retrieval by name
		is not necessary

  char* value ptr to allocated memory

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int insert_lilibib(Lilibib *ptr_first, char* name, char* value) {
  Lilibib* ptr_new_item;
  char* my_value;
  char* my_name;

  ptr_new_item = malloc(sizeof(Lilibib));

  if (!ptr_new_item) { /* malloc failed */
    return 1;
  }

  if (name && *name) {
    my_name = malloc(strlen(name)+1);
    if (!my_name) {
      free(ptr_new_item);
      return 1;
    }
    strcpy(my_name, name);
    ptr_new_item->name = my_name;
  }
  else {
    ptr_new_item->name = NULL;
  }

  if (value && *value) {
    my_value = malloc(strlen(value)+1);
    if (!my_value) {
      free(ptr_new_item);
      return 1;
    }
    strcpy(my_value, value);
    ptr_new_item->value = my_value;
  }
  else {
    ptr_new_item->value = NULL;
  }

  ptr_new_item->ptr_next = ptr_first->ptr_next;
  ptr_first->ptr_next = ptr_new_item;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_next_lilibib(): retrieves next member of the list

  Lilibib* get_next_lilibib returns a ptr to the next member or NULL
                      if we're at the end of the list. Use this fn
		      to loop over all list entries. In the first
		      iteration, pass a ptr to the sentinel. In
		      subsequent iterations, pass the ptr that the
		      previous iteration returns.
                   

  Lilibib *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
Lilibib* get_next_lilibib(Lilibib* ptr_first) {
  return ptr_first->ptr_next;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_lilibib(): retrieves a member of the list by name

  Lilibib* get_next_lilibib returns a ptr to the list member with
                 the given name or NULL if none such exists.
                   

  Lilibib *ptr_first pointer to sentinel

  char* name name of the list member to return
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
Lilibib* get_lilibib(Lilibib* ptr_first, char* name) {
  Lilibib* ptr_curr_item;
  Lilibib* ptr_result = NULL;
  
  ptr_curr_item = ptr_first->ptr_next;

  while (ptr_curr_item) {
    if (!strcmp(ptr_curr_item->name, name)) {
      if (ptr_curr_item->value) {
	ptr_result = ptr_curr_item;
      }
      break;
    }
    ptr_curr_item = ptr_curr_item->ptr_next;
  }
  return ptr_result;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  delete_all_lilibib(): deletes all members from the list

  int delete_all_lilibib returns 0 if ok, or 1 if an error occurred

  Lilibib *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int delete_all_lilibib(Lilibib *ptr_first) {
  Lilibib* ptr_curr_item;
  Lilibib* ptr_next_item;

  ptr_curr_item = ptr_first->ptr_next;
  ptr_first->ptr_next = NULL;

  while (ptr_curr_item) {
    ptr_next_item = ptr_curr_item->ptr_next;
/*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
    if (ptr_curr_item->name) {
      free(ptr_curr_item->name); /* free the memory allocated for the name */
    }
    if (ptr_curr_item->value) {
      free(ptr_curr_item->value); /* free the memory allocated for the value */
    }
    free(ptr_curr_item); /* free the memory allocated for the list member */

    ptr_curr_item = ptr_next_item;
  }
  return 0;
}

/*********************************************************************
 linked list for reading id lists
 This is a sorted linked list. The first list member is a sentinel
 which is not automatically deallocated by the lilimem functions.
 The calling fn has to explicitly declare, initialize, and destruct
 a lilid struct for this purpose.
 The payload of a member is an id value and two ints used as booleans
********************************************************************/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  insert_lilid(): inserts a new member into the list

  int insert_lilid returns 0 if ok, or 1 if an error occurred

  Lilid *ptr_first pointer to sentinel
  
  unsigned long long value the value to store

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int insert_lilid(Lilid *ptr_first, unsigned long long value) {
  Lilid* ptr_new_item; /* ptr to new list member */
  Lilid* ptr_before; /* ptr to member before insertion point */
  Lilid* ptr_after; /* ptr to member after insertion point */

  ptr_new_item = malloc(sizeof(Lilid));

  if (!ptr_new_item) { /* malloc failed */
    return 1;
  }

  /* set requested value */
  ptr_new_item->value = value;

  /* set default values */
  ptr_new_item->is_duplicate = 0;
  ptr_new_item->is_existent = 0;

  /* find insertion point */
  ptr_before = ptr_first; /* start search at the beginning */
  ptr_after = ptr_before->ptr_next;

  while (ptr_after != NULL) {
    if (ptr_after->value >= value) { /* sort in ascending order */
      break;
    }
    ptr_after = ptr_after->ptr_next;
    ptr_before = ptr_before->ptr_next;
  }

  /* insert new item into list */
  ptr_before->ptr_next = ptr_new_item;
  ptr_new_item->ptr_next = ptr_after;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_next_lilid(): retrieves next member of the list in ascending order

  Lilid* get_next_lilid returns a ptr to the next member or NULL
                      if we're at the end of the list. Use this fn
		      to loop over all list entries. In the first
		      iteration, pass a ptr to the sentinel. In
		      subsequent iterations, pass the ptr that the
		      previous iteration returns.
                   

  struct lilid *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
Lilid* get_next_lilid(Lilid* ptr_first) {
  return ptr_first->ptr_next;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  count_lilid(): counts all members in the list

  unsigned long long count_lilid returns the number of list members

  Lilid *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
unsigned long long count_lilid(Lilid* ptr_first) {
  unsigned long long ull_counter = 0;
  Lilid *ptr_curr;

  /* start at the beginning */
  ptr_curr = ptr_first;

  /* loop over all list elements */
  while ((ptr_curr = get_next_lilid(ptr_curr)) != NULL) {
    ull_counter++;
  }

  return ull_counter;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  delete_all_lilid(): deletes all members from the list

  int delete_all_lilid returns 0 if ok, or 1 if an error occurred

  Lilid *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int delete_all_lilid(Lilid *ptr_first) {
  Lilid* ptr_curr_item;
  Lilid* ptr_next_item;

  /* skip the sentinel when freeing memory */
  ptr_curr_item = ptr_first->ptr_next;
  ptr_first->ptr_next = NULL;

  /* loop over all list members after the sentinel */
  while (ptr_curr_item) {
    /* save a pointer to the next member, if any */
    ptr_next_item = ptr_curr_item->ptr_next;

    /* free the memory allocated for the list member */
    free(ptr_curr_item); 

    ptr_curr_item = ptr_next_item;
  }
  return 0;
}

/*********************************************************************
 linked list for tokenizing strings. The list stores pointers to
 the individual tokens. The calling function should terminate the tokens
 by inserting \0 between the tokens.
 This is an unsorted linked list. The first list member is a sentinel
 which is not automatically deallocated by the lilimem functions.
 The calling fn has to explicitly declare, initialize, and destruct
 a lilimem struct for this purpose.
********************************************************************/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  insert_lilistring(): inserts a new member into the list

  int insert_lilistring returns 0 if ok, or 1 if an error occurred
                 if an error occurs

  Lilistring *ptr_first pointer to sentinel
  
  char* token ptr to token 

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int insert_lilistring(Lilistring *ptr_first, char* token) {
  Lilistring* ptr_new_item;

  ptr_new_item = malloc(sizeof(Lilistring));

  if (!ptr_new_item) { /* malloc failed */
    return 1;
  }

  if (token) {
    ptr_new_item->token = token;
  }
  else {
    ptr_new_item->token = NULL;
  }

  ptr_new_item->ptr_next = ptr_first->ptr_next;
  ptr_first->ptr_next = ptr_new_item;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  append_lilistring(): appends a new member into the list. The
                       implementation is not very efficient but is ok
		       for a low number of entries

  int append_lilistring returns 0 if ok, or 1 if an error occurred
                 if an error occurs

  Lilistring *ptr_first pointer to sentinel
  
  char* token ptr to token 

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int append_lilistring(Lilistring *ptr_first, char* token) {
  Lilistring* ptr_new_item;
  Lilistring* ptr_last_item;

  ptr_new_item = malloc(sizeof(Lilistring));

  if (!ptr_new_item) { /* malloc failed */
    return 1;
  }

  if (token) {
    ptr_new_item->token = token;
  }
  else {
    ptr_new_item->token = NULL;
  }

  ptr_new_item->ptr_next = NULL;
  
  ptr_last_item = ptr_first;

  /* this is going to be inefficient for a large number of entries */
  while (ptr_last_item->ptr_next) {
    ptr_last_item = ptr_last_item->ptr_next;
  }
  ptr_last_item->ptr_next = ptr_new_item;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_next_lilistring(): retrieves next member of the list

  Lilistring* get_next_lilistring returns a ptr to the next member or NULL
                      if we're at the end of the list. Use this fn
		      to loop over all list entries. In the first
		      iteration, pass a ptr to the sentinel. In
		      subsequent iterations, pass the ptr that the
		      previous iteration returns.
                   

  Lilistring *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
Lilistring* get_next_lilistring(Lilistring* ptr_first) {
  return ptr_first->ptr_next;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  delete_all_lilistring(): deletes all members from the list

  int delete_all_lilistring returns 0 if ok, or 1 if an error occurred

  Lilistring *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int delete_all_lilistring(Lilistring *ptr_first) {
  Lilistring* ptr_curr_item;
  Lilistring* ptr_next_item;

  ptr_curr_item = ptr_first->ptr_next;
  ptr_first->ptr_next = NULL;

  while (ptr_curr_item) {
    ptr_next_item = ptr_curr_item->ptr_next;
/*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
    free(ptr_curr_item); /* free the memory allocated for the list member */

    ptr_curr_item = ptr_next_item;
  }
  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  count_lilistring(): counts all members in the list

  int count_lilistring returns the number of list members

  Lilistring *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int count_lilistring(Lilistring* ptr_first) {
  int counter = 0;
  Lilistring *ptr_curr;

  /* start at the beginning */
  ptr_curr = ptr_first;

  /* loop over all list elements */
  while ((ptr_curr = get_next_lilistring(ptr_curr)) != NULL) {
    counter++;
  }

  return counter;
}

/*********************************************************************
 linked list for fixed-size strings. The list keeps the original order
 of items
********************************************************************/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  append_lilifstring(): appends a new member into the list. The
                       implementation is not very efficient but is ok
		       for a low number of entries

  int append_lilifstring returns 0 if ok, or 1 if an error occurred
                 if an error occurs

  Lilifstring *ptr_first pointer to sentinel
  
  char* token ptr to token 

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int append_lilifstring(Lilifstring *ptr_first, char* token) {
  Lilifstring* ptr_new_item;
  Lilifstring* ptr_last_item;

  ptr_new_item = malloc(sizeof(Lilifstring));

  if (!ptr_new_item) { /* malloc failed */
    return 1;
  }

  if (token) {
    strncpy(ptr_new_item->token, token, LILIFSTRING_SIZE);
    (ptr_new_item->token)[LILIFSTRING_SIZE-1] = '\0';
  }
  else {
    (ptr_new_item->token)[0] = '\0';
  }

  ptr_new_item->ptr_next = NULL;
  
  ptr_last_item = ptr_first;

  /* this is going to be inefficient for a large number of entries */
  while (ptr_last_item->ptr_next) {
    ptr_last_item = ptr_last_item->ptr_next;
  }
  ptr_last_item->ptr_next = ptr_new_item;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_next_lilifstring(): retrieves next member of the list

  Lilifstring* get_next_lilifstring returns a ptr to the next member or NULL
                      if we're at the end of the list. Use this fn
		      to loop over all list entries. In the first
		      iteration, pass a ptr to the sentinel. In
		      subsequent iterations, pass the ptr that the
		      previous iteration returns.
                   

  Lilifstring *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
Lilifstring* get_next_lilifstring(Lilifstring* ptr_first) {
  return ptr_first->ptr_next;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  delete_all_lilifstring(): deletes all members from the list

  int delete_all_lilifstring returns 0 if ok, or 1 if an error occurred

  Lilifstring *ptr_first pointer to sentinel
  
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int delete_all_lilifstring(Lilifstring *ptr_first) {
  Lilifstring* ptr_curr_item;
  Lilifstring* ptr_next_item;

  ptr_curr_item = ptr_first->ptr_next;
  ptr_first->ptr_next = NULL;

  while (ptr_curr_item) {
    ptr_next_item = ptr_curr_item->ptr_next;
/*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
    free(ptr_curr_item); /* free the memory allocated for the list member */

    ptr_curr_item = ptr_next_item;
  }
  return 0;
}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  find_lilifstring(): checks whether token is already stored in the list

  int find_lilifstring returns 1 if token is part of the list. or
                 0 if not

  Lilifstring *ptr_first pointer to sentinel
  
  char* token ptr to token 

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* find_lilifstring(Lilifstring* ptr_first, char* token) {
  Lilifstring* ptr_curr_item;

  ptr_curr_item = ptr_first;

  while ((ptr_curr_item = get_next_lilifstring(ptr_curr_item)) != NULL) {
    if (!strcmp(ptr_curr_item->token, token)) {
      return token;
    }
  }

  return NULL;
}
