/***********************************************
 (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   EPS General Public License (see file LICENSE)
 ***********************************************
 $Log: INTlists.c,v $
 * Revision 2.8  1993/09/20  14:16:40  eps
 * new function: ILshare
 *
 * Revision 2.7  1993/08/02  16:51:19  eps
 * fix minor bugs
 *
 * Revision 2.6  1993/07/21  12:42:42  eps
 * new functions: INTIsIn INTpos INTnth ITcmp IAT_IL_add
 *
 * Revision 2.5  1993/06/15  10:58:17  eps
 * bug fix: check call arguments for NULL
 *
 * Revision 2.4  1993/01/12  16:34:31  eps
 * portability issues
 *
 * Revision 2.3  1992/11/17  11:47:41  eps
 * fix definition of *alloc for PC portability
 *
 * Revision 2.2  1992/01/14  15:43:10  eps
 * distribution issues
 *
 * Revision 2.1  90/10/30  08:32:38  eps
 * hardwired colours added
 * new colours I2, IAT, AT
 * ! is no longer used as colour delimiter
 * still some bugs are known w.r.t. colour deallocation
 * 
 * Revision 1.7  90/06/21  15:26:17  eps
 * calloc (N, s) => malloc (N * s)
 * allocate in incements of 256
 * 
 * Revision 1.6  90/05/10  17:12:33  eps
 * change colour delimiters from !...! into {...}
 * 
 * Revision 1.5  90/03/16  15:55:26  eps
 * INTappend is now iterative
 * new functions INTrev, INTcmp
 * get, put, fIL and cIL completely recoded
 * 
 * Revision 1.4  90/02/19  19:13:14  eps
 * buck allocation of memory
 * 
 * Revision 1.3  90/02/16  17:53:57  eps
 * remake
 * miscellaneous cleanup
 * some functions become #define for efficiency
 * memory is managed
 * 
 * Revision 1.2  90/01/29  14:52:04  eps
 * fixing license details
 * 
 * Revision 1.1  90/01/25  18:00:22  eps
 * Initial revision
 * 
 **********************************************/

#ifndef lint
static char rcsid[]= "$Id: INTlists.c,v 2.8 1993/09/20 14:16:40 eps Exp $";
#endif

/*************************************************************
	Tomas P. de Miguel Moro
	dpt. Ingenieria Telematica
	E.T.S.I. Telecomunicaci'on
	Ciudad Universitaria
	E-28040  MADRID
 *************************************************************/

/* LINTLIBRARY */

# include "cast.hh"
# include <stdio.h>
# include <string.h>
# include <assert.h>

PRIVATE	INTlist freelist= NULL;
# define BUCKSIZE 256

PRIVATE INTlist
new ()
{
  INTlist slot;
  INTlist buck;
  int i;

  if (freelist == NULL) {
    buck= (INTlist) malloc (BUCKSIZE * sizeof (struct IL));
    if (buck == NULL)
      fatal ("IL: run out of memory");
    for (i= 0; i < BUCKSIZE; i++)
      buck[i].next= &buck[i+1];
    freelist= buck;
    buck[BUCKSIZE-1].next= NULL;
  }
  slot= freelist;
  freelist= freelist->next;
  slot->next= NULL;
  slot->cnt= 0;
  return slot;
}

PUBLIC INTlist
INTcons (E, L)
     int E;
     INTlist L;
{
  INTlist slot= new ();

  slot->elt= E;
  slot->next= L;
  if (L != NULL)
    slot->next->cnt++;
  return slot;
}

PUBLIC INTlist
INTappend (L1, L2)
     INTlist L1, L2;
{
  INTlist start, this, prev, slot;

  if (L1 == NULL)
    return L2;
  if (L2 == NULL)
    return L1;
  /* KJT 13/02/12: Added */
  start = NULL;
  prev= NULL;
  for (this= L1; this != NULL; this= this->next) {
    slot= new ();
    slot->elt= this->elt;
    if (prev != NULL) {
      prev->next= slot;
      slot->cnt++;
    }
    else
      start= slot;
    prev= slot;
  }
  if (prev != NULL) {
    prev->next= L2;
    L2->cnt++;
    }
  return start;
}

PUBLIC INTlist
INTrev (L)
     INTlist L;
{
  INTlist this, prev, slot;

  if (L == NULL)
    return NULL;

  prev= NULL;
  for (this= L; this != NULL; this= this->next) {
    slot= new ();
    slot->elt= this->elt;
    slot->next= prev;
    if (prev != NULL)
      slot->next->cnt++;
    prev= slot;
  }
  return prev;
}

PUBLIC int
INTcmp (L1, L2)
     INTlist L1, L2;
{
  INTlist this1, this2;

  for (this1= L1, this2= L2;
       this1 != NULL && this2 != NULL;
       this1= this1->next, this2= this2->next)
    if (this1->elt != this2->elt)
      return FALSE;
  return (this1 == NULL && this2 == NULL);
}

PUBLIC int
INTlength (L)
     INTlist L;
{
  int i;

  for (i= 0; L != NULL; L= L->next)
    i++;
  return i;
}

PUBLIC int
INTlast (L)
     INTlist L;
{
  while (L->next != NULL)
    L= L->next;
  return L->elt;
}

PUBLIC int
INTIsIn (e, L)
  int e;
  INTlist L;
{
  for ( ; L != NULL; L = INTtail (L))
    if (L->elt == e)
      return TRUE;
  return FALSE;
}

PUBLIC int
INTpos (e, L)
  int e;
  INTlist L;
{
  register int i = 1;

  for ( ; L != NULL; L = INTtail (L), i++)
    if (e == INThead (L))
      return i;
  return 0;  /* Not found */
}

PUBLIC int
INTnth (n, L)
  int n;
  INTlist L;
{
  assert (n >= 1);

  for ( ; (n > 1) && (L != NULL); n--, L = INTtail (L))
    ;
  assert (L != NULL);

  return INThead (L);
}

PUBLIC CLR_TYPE
getINTlist (fp)
     FILE* fp;
{
  INTlist start, prev, slot;
  int i;
  char c;
  
  /* KJT 13/02/12: Added */
  start = NULL;
  prev= NULL;
  for (c= getc (fp); c != '}'; c= getc (fp)) {
    while (c == ',' || c == '\n' || c == ' ')
      c= getc (fp);
    (void) ungetc (c, fp);
    if (c != '}') {
      (void) fscanf (fp, "%d", &i);
      slot= new ();
      slot->elt= i;
      slot->next= NULL;
      if (prev != NULL) {
	prev->next= slot;
	slot->cnt++;
      }
      else
	start= slot;
      prev= slot;
    }
  }
  (void) ungetc (c, fp);
  return (CLR_TYPE) start;
}
 
PUBLIC void
putINTlist (fp, val)
     FILE* fp;
     CLR_TYPE val;
{
  INTlist L;
  int nn;

  if (val == NULL)
    return;

  nn= 0;
  for (L= (INTlist) val; L->next != NULL; L= L->next) {
    if ((++nn)%16 == 0)
      (void) fprintf (fp, "%d,\n", L->elt);
    else
      (void) fprintf (fp, "%d,", L->elt);
  }
  (void) fprintf (fp, "%d", L->elt);
}

PUBLIC void
fIL (val)
     CLR_TYPE val;
{
  INTlist L, p;

  for (L= (INTlist) val; L != NULL; L= p) {
    if (L->cnt > 0) {
      L->cnt--;
      return;
    }
    p= L->next;
    L->next= freelist;
    freelist= L;
  }
}

PUBLIC CLR_TYPE
cIL (val)
     CLR_TYPE val;
{
  INTlist start, this, prev, slot;

  if (val == NULL)
    return NULL;

  /* KJT 13/02/12: Added */
  start = NULL;
  prev= NULL;
  for (this= (INTlist) val; this != NULL; this= this->next) {
    slot= new ();
    slot->elt= this->elt;
    slot->next= NULL;
    if (prev != NULL) {
      prev->next= slot;
      slot->cnt++;
    }
    else
      start= slot;
    prev= slot;
  }
  return (CLR_TYPE) start;
}

PUBLIC CLR_TYPE
ILshare (val)
     CLR_TYPE val;
{
  if (val != NULL)
    ((INTlist) val)->cnt++;
  return val;
}

