/* Autoconf patching by David Hedbor, neotron@lysator.liu.se */
/*********************************************************************/
/* file: llist.c - linked-list datastructure                         */
/*                             TINTIN III                            */
/*          (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t             */
/*                     coded by peter unold 1992                     */
/*********************************************************************/
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif

#include "tintin.h"

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

void insertnode_list();
int match();

/***************************************/
/* init list - return: ptr to listhead */
/***************************************/
struct listnode *init_list()
{
	struct listnode *listhead;

	if ((listhead = (struct listnode *) (malloc(sizeof(struct listnode)))) == NULL) {
		fprintf(stderr, "couldn't alloc listhead\n");
		exit(1);
	}
	listhead->next = NULL;
	return (listhead);
}

/************************************************/
/* kill list - run throught list and free nodes */
/************************************************/
void kill_list(nptr)
     struct listnode *nptr;
{
	struct listnode *nexttodel;

	nexttodel = nptr->next;
	free(nptr);

	for (nptr = nexttodel; nptr; nptr = nexttodel) {
		nexttodel = nptr->next;
		free(nptr->left);
		free(nptr->right);
		free(nptr->pr);
		free(nptr);
	}
}
/********************************************************************
**   This function will clear all lists associated with a session  **
********************************************************************/
void kill_all(ses, mode)
     struct session *ses;
     int mode;
{
	switch (mode) {
	case END:
		if (ses != NULL) {
			kill_list(ses->aliases);
			kill_list(ses->actions);
			kill_list(ses->myvars);
			kill_list(ses->highs);
			kill_list(ses->subs);
			kill_list(ses->antisubs);
			kill_list(ses->path);
			kill_list(ses->pathdirs);
		}
		break;
	case CLEAN:
		if (ses != NULL) {
			kill_list(ses->aliases);
			kill_list(ses->actions);
			kill_list(ses->myvars);
			kill_list(ses->highs);
			kill_list(ses->subs);
			kill_list(ses->antisubs);
			kill_list(ses->path);
			kill_list(ses->pathdirs);

			ses->aliases = init_list();
			ses->actions = init_list();
			ses->myvars = init_list();
			ses->highs = init_list();
			ses->subs = init_list();
			ses->antisubs = init_list();
			ses->path = init_list();
			ses->pathdirs = init_list();
			tintin_puts("Lists cleared.", ses);
			prompt(NULL);
		}
		else {
			tintin_puts("Can't clean the common lists (yet):", NULL);
			prompt(NULL);
		}
		break;
	}
}
/***********************************************/
/* make a copy of a list - return: ptr to copy */
/***********************************************/
struct listnode *copy_list(sourcelist, mode)
     struct listnode *sourcelist;
{
	struct listnode *resultlist;

	resultlist = init_list();
	while ((sourcelist = sourcelist->next)) {
		insertnode_list(resultlist, sourcelist->left, sourcelist->right,
				sourcelist->pr, mode);
	}

	return (resultlist);
}

/*****************************************************************/
/* create a node containing the ltext, rtext fields and stuff it */
/* into the list - in lexicographical order, or by numerical     */
/* priority (dependent on mode) - Mods by Joann Ellsworth 2/2/94 */
/*****************************************************************/
void insertnode_list(listhead, ltext, rtext, prtext, mode)
     struct listnode *listhead;
     char *ltext;
     char *rtext;
     char *prtext;
     int mode;
{
	struct listnode *nptr, *nptrlast, *newnode;

	if ((newnode = (struct listnode *) (malloc(sizeof(struct listnode)))) == NULL) {
		fprintf(stderr, "couldn't malloc listhead");
		exit(1);
	}
	newnode->left = (char *) malloc(strlen(ltext) + 1);
	newnode->right = (char *) malloc(strlen(rtext) + 1);
	newnode->pr = (char *) malloc(strlen(prtext) + 1);
	strcpy(newnode->left, ltext);
	strcpy(newnode->right, rtext);
	strcpy(newnode->pr, prtext);

	nptr = listhead;
	switch (mode) {
	case PRIORITY:
		while ((nptrlast = nptr) && (nptr = nptr->next)) {
			if (strcmp(prtext, nptr->pr) < 0) {
				newnode->next = nptr;
				nptrlast->next = newnode;
				return;
			}
			else if (strcmp(prtext, nptr->pr) == 0) {
				while ((nptrlast) && (nptr) &&
				       (strcmp(prtext, nptr->pr) == 0)) {
					if (strcmp(ltext, nptr->left) <= 0) {
						newnode->next = nptr;
						nptrlast->next = newnode;
						return;
					}
					nptrlast = nptr;
					nptr = nptr->next;
				}
				nptrlast->next = newnode;
				newnode->next = nptr;
				return;
			}

		}
		nptrlast->next = newnode;
		newnode->next = NULL;
		return;
		break;
	case ALPHA:
		while ((nptrlast = nptr) && (nptr = nptr->next)) {
			if (strcmp(ltext, nptr->left) <= 0) {
				newnode->next = nptr;
				nptrlast->next = newnode;
				return;
			}
		}
		nptrlast->next = newnode;
		newnode->next = NULL;
		return;
		break;
	}			/*  Switch  */
}

/*****************************/
/* delete a node from a list */
/*****************************/
/* @@@changed -- perry */
struct listnode *deletenode_list(listhead, nptr)
     struct listnode *listhead;
     struct listnode *nptr;
{
	struct listnode *lastnode = listhead;

	while ((listhead = listhead->next)) {
		if (listhead == nptr) {
			lastnode->next = listhead->next;
			free(listhead->left);
			free(listhead->right);
			free(listhead->pr);
			free(listhead);
			return lastnode->next;
		}
		lastnode = listhead;
	}
	return lastnode;
}

/********************************************************/
/* search for a node containing the ltext in left-field */
/* return: ptr to node on succes / NULL on failure      */
/********************************************************/
struct listnode *searchnode_list(listhead, cptr)
     struct listnode *listhead;
     char *cptr;
{
	int i;
	while ((listhead = listhead->next)) {
		if ((i = strcmp(listhead->left, cptr)) == 0)
			return listhead;
		/* CHANGED to fix bug when list isn't alphabetically sorted
		   else if(i>0)
		   return NULL;
		 */
	}
	return NULL;
}
/********************************************************/
/* search for a node that has cptr as a beginning       */
/* return: ptr to node on succes / NULL on failure      */
/* Mods made by Joann Ellsworth - 2/2/94                */
/********************************************************/
struct listnode *searchnode_list_begin(listhead, cptr, mode)
     struct listnode *listhead;
     char *cptr;
     int mode;
{
	int i;
	switch (mode) {
	case PRIORITY:
		while ((listhead = listhead->next)) {
			if ((i = strncmp(listhead->left, cptr, strlen(cptr))) == 0 &&
			    (*(listhead->left + strlen(cptr)) == ' ' ||
			     *(listhead->left + strlen(cptr)) == '\0'))
				return listhead;
		}
		return NULL;
		break;

	case ALPHA:
		while ((listhead = listhead->next)) {
			if ((i = strncmp(listhead->left, cptr, strlen(cptr))) == 0 &&
			    (*(listhead->left + strlen(cptr)) == ' ' ||
			     *(listhead->left + strlen(cptr)) == '\0'))
				return listhead;
			else if (i > 0)
				return NULL;
		}
		return NULL;
		break;
	}

}

/************************************/
/* show contens of a node on screen */
/************************************/
void shownode_list(nptr)
     struct listnode *nptr;
{
	char temp[BUFFER_SIZE];
	sprintf(temp, "{%s}={%s}", nptr->left, nptr->right);
	tintin_puts2(temp, (struct session *) NULL);
}

void shownode_list_action(nptr)
     struct listnode *nptr;
{
	char temp[BUFFER_SIZE];
	sprintf(temp, "{%s}={%s} @ {%s}", nptr->left, nptr->right, nptr->pr);
	tintin_puts2(temp, (struct session *) NULL);
}

/************************************/
/* list contens of a list on screen */
/************************************/
void show_list(listhead)
     struct listnode *listhead;
{
	if (!listhead)
		return;
	while ((listhead = listhead->next))
		shownode_list(listhead);
}

void show_list_action(listhead)
     struct listnode *listhead;
{
	if (!listhead)
		return;
	while ((listhead = listhead->next))
		shownode_list_action(listhead);
}

struct listnode *search_node_with_wild(listhead, cptr)
     struct listnode *listhead;
     char *cptr;
{
	while (listhead) {
		if (match(cptr, listhead->left))
			return listhead;
		listhead = listhead->next;
	}
	return NULL;
}

/* @@@deleted -- perry (unused)
 * int check_one_node(text, action)
 */
/*********************************************************************/
/* create a node containint the ltext, rtext fields and place at the */
/* end of a list - as insertnode_list(), but not alphabetical        */
/*********************************************************************/
void addnode_list(listhead, ltext, rtext, prtext)
     struct listnode *listhead;
     char *ltext;
     char *rtext;
     char *prtext;
{
	struct listnode *newnode;

	if ((newnode = (struct listnode *) malloc(sizeof(struct listnode))) == NULL) {
		fprintf(stderr, "couldn't malloc listhead");
		exit(1);
	}
	newnode->left = (char *) malloc(strlen(ltext) + 1);
	newnode->right = (char *) malloc(strlen(rtext) + 1);
	newnode->pr = (char *) malloc(strlen(prtext) + 1);
	newnode->next = NULL;
	strcpy(newnode->left, ltext);
	strcpy(newnode->right, rtext);
	strcpy(newnode->pr, prtext);
	while (listhead->next != NULL)
		(listhead = listhead->next);
	listhead->next = newnode;
}

int count_list(listhead)
     struct listnode *listhead;
{
	int count = 0;
	struct listnode *nptr;

	nptr = listhead;
	while (nptr = nptr->next)
		++count;
	return (count);
}