/***********************************************
 (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   EPS General Public License (see file LICENSE)
 ***********************************************
 $Log: STRlists.c,v $
 * Revision 2.6  1994/10/10  19:19:53  eps
 * portability
 *
 * Revision 2.5  1993/09/20  14:16:40  eps
 * new function: SLshare
 *
 * Revision 2.4  1993/01/12  16:34:34  eps
 * portability issues
 *
 * Revision 2.3  1992/11/17  11:47:45  eps
 * fix definition of *alloc for PC portability
 *
 * Revision 2.2  1992/01/14  15:43:12  eps
 * distribution issues
 *
 * Revision 2.1  90/10/30  08:32:39  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:19  eps
 * calloc (N, s) => malloc (N * s)
 * allocate in incements of 256
 * 
 * Revision 1.6  90/05/10  17:12:36  eps
 * change colour delimiters from !...! into {...}
 * 
 * Revision 1.5  90/03/16  15:57:23  eps
 * STRappend is now iterative
 * new functions STRrev, STRcmp
 * get, put, fSL, fSLs, cSL, cSLs completely recoded
 * 
 * Revision 1.4  90/02/19  19:04:47  eps
 * buck allocation of memory
 * 
 * Revision 1.3  90/02/16  17:54:50  eps
 * remake
 * miscellaneous cleanup
 * some functions become #define for efficiency
 * memory is managed
 * allocating space for strings is under caller control
 * external format is made compatible with ST
 * 
 * Revision 1.2  90/01/29  14:52:06  eps
 * fixing license details
 * 
 * Revision 1.1  90/01/25  18:00:31  eps
 * Initial revision
 * 
 **********************************************/

#ifndef lint
static char rcsid[]= "$Id: STRlists.c,v 2.6 1994/10/10 19:19:53 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>

PRIVATE	STRlist freelist= NULL;
# define BUCKSIZE 256

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

  if (freelist == NULL) {
    buck= (STRlist) malloc (BUCKSIZE * sizeof (struct SL));
    if (buck == NULL)
      fatal ("SL: 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->elt= NULL;
  slot->next= NULL;
  slot->cnt= 0;
  return slot;
}

PUBLIC STRlist
STRcons (E, L, shared)
     char* E;
     STRlist L;
     int shared;
{
  STRlist slot= new ();

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

PUBLIC STRlist
STRappend (L1, L2, shared)
     STRlist L1, L2;
     int shared;
{
  STRlist 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 ();
    if (shared)
      slot->elt= this->elt;
    else
      slot->elt= str_alloc (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 STRlist
STRrev (L, shared)
     STRlist L;
     int shared;
{
  STRlist this, prev, slot;

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

PUBLIC int
STRcmp (L1, L2)
     STRlist L1, L2;
{
  STRlist this1, this2;

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

PUBLIC int
STRlength (L)
     STRlist L;
{
  int i;

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

PUBLIC char*
STRlast	(L)
     STRlist L;
{
  while (L->next != NULL)
    L= L->next;
  return L->elt;
}

PUBLIC CLR_TYPE
getSTRlist (fp)
     FILE* fp;
{
  STRlist start, prev, slot;
  char *s, *p;
  
  s= (char*) getstring (fp);
  start= prev= NULL;
  while (*s != 0) {
    for (p= s;  *p && *p != '\n'; p++)
      if (*p == '@')
	p++;
    *p= 0;
    slot= new ();
    slot->elt= s;
    slot->next= NULL;
    if (prev != NULL) {
      prev->next= slot;
      slot->cnt++;
    }
    else
      start= slot;
    prev= slot;
    s= p+1;
  }
  for (slot= start; slot != NULL; slot= slot->next)
    for (s= slot->elt;
	 (p= strchr (s, '@')) != NULL;
	 s= p) {
      (void) strcpy (p, p+1);
      p++;
    }
  return (CLR_TYPE) start;
}

PUBLIC void
putSTRlist (fp, val)
     FILE* fp;
     CLR_TYPE val;
{
  STRlist L;
  char* p;
  char c;

  for (L= (STRlist) val; L != NULL; L= L->next) {
    for (p= L->elt; *p != '\0'; p++) {
      c= *p;
      if (c == '@' || c == '\n')
	(void) fputc ('@', fp);
      if (c == '\\' || c == '{' || c == '}')
	(void) fputc ('\\', fp);
      (void) fputc (c, fp);
    }
    (void) fputc ('\n', fp);
  }
}

PUBLIC void
fSL (val)
     CLR_TYPE val;
{
  STRlist L, p;

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

PUBLIC void
fSLs (val)
     CLR_TYPE val;
{
  STRlist L, p;

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

PUBLIC CLR_TYPE
cSL (val)
     CLR_TYPE val;
{
  STRlist start, this, prev, slot;

  /* KJT 13/02/12: Added */
  start = NULL;
  prev= NULL;
  for (this= (STRlist) val; this != NULL; this= this->next) {
    slot= new ();
    slot->elt= str_alloc (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
cSLs (val)
     CLR_TYPE val;
{
  STRlist start, this, prev, slot;

  prev= NULL;
  for (this= (STRlist) 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
SLshare (val)
     CLR_TYPE val;
{
  if (val != NULL)
    ((STRlist) val)->cnt++;
  return val;
}

