/*********************************************************************/
/* 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                     */
/*********************************************************************/
#include <string.h>
#include "tintin.h"

#if IRIX
  #include <stdlib.h>
  #include <unistd.h>
#endif
void insertnode_list();
int match(char *, char*);

/***************************************/
/* 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 CLEAN:
   if (ses != NULL) {
    kill_list(ses->aliases);
    ses->aliases=init_list();
    kill_list(ses->actions);
    ses->actions=init_list();
    kill_list(ses->myvars);
    ses->myvars=init_list();
    kill_list(ses->highs);
    ses->highs=init_list();
    kill_list(ses->subs);
    ses->subs=init_list();
    kill_list(ses->antisubs);
    ses->antisubs=init_list();
    /* CHANGED to kill path stuff as well */
    kill_list(ses->path);
    ses->path=init_list();
    kill_list(ses->pathdirs);
    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;

  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);
   } /* If */
   break;
  } /* Switch */
 
}
/***********************************************/
/* 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;
{
  while((listhead=listhead->next))
    shownode_list(listhead);
}

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

struct listnode *search_node_with_wild(listhead, cptr)
     struct listnode *listhead;
     char *cptr;
{
  /* int i; */
  while((listhead=listhead->next)) {
    /* CHANGED to fix silly globbing behavior
    if(check_one_node(listhead->left, cptr))
    */
    if(match(cptr, listhead->left))
      return listhead;
  }
  return NULL;
}

int check_one_node(text, action)
     char *text;
     char *action;
{
  char *temp, temp2[BUFFER_SIZE], *tptr;
  while (*text && *action) {
    if (*action=='*') {
      action++;
      temp=action;
      tptr=temp2;
      while(*temp && *temp !='*')
        *tptr++= *temp++;
      *tptr='\0';
      if (strlen(temp2)==0) 
        return TRUE;
      while(strncmp(temp2,text,strlen(temp2))!=0 && *text)
        text++;
    }
    else {
      temp=action;
      tptr=temp2;
      while (*temp && *temp !='*')
        *tptr++= *temp++;
      *tptr='\0';
      if(strncmp(temp2,text,strlen(temp2))!=0)
        return FALSE;
      else {
        text+=strlen(temp2);
        action+=strlen(temp2);
      }
    }
  }
  if (*text)
    return FALSE;
  else if ((*action=='*' && !*(action+1)) || !*action)
    return TRUE;
  return FALSE;
}

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