/***********************************************
 (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   EPS General Public License (see file LICENSE)
 ***********************************************
 $Log: clrST.c,v $
 * Revision 2.7  1994/10/10  19:20:04  eps
 * portability
 *
 * Revision 2.6  1993/01/25  16:06:45  eps
 * fix ecase argument declaration
 *
 * Revision 2.5  1993/01/12  16:34:41  eps
 * portability issues
 *
 * Revision 2.4  1992/11/17  11:47:58  eps
 * fix definition of *alloc for PC portability
 *
 * Revision 2.3  1992/01/14  15:43:15  eps
 * distribution issues
 *
 * Revision 2.2  92/01/14  15:26:16  eps
 * speed up case independent hashing
 * 
 * Revision 2.1  90/10/30  08:32:43  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.6  90/06/21  15:26:23  eps
 * calloc (N, s) => malloc (N * s)
 * allocate in incements of 256
 * 
 * Revision 1.5  90/05/10  17:12:42  eps
 * change colour delimiters from !...! into {...}
 * 
 * Revision 1.4  90/03/16  15:59:55  eps
 * get, put, fIT, fITs, cIT, cITs completely recoded
 * 
 * Revision 1.3  90/02/16  17:56:05  eps
 * miscellaneous cleanup
 * external format is made compatible with STRlists
 * 
 * Revision 1.2  90/01/29  14:52:14  eps
 * fixing license details
 * 
 * Revision 1.1  90/01/25  18:00:50  eps
 * Initial revision
 * 
 **********************************************/

#ifndef lint
static char rcsid[]= "$Id: clrST.c,v 2.7 1994/10/10 19:20:04 eps Exp $";
#endif

/***********************************************************************
	Jose A. Manas
        dpt. Ingenieria Telematica
        E.T.S.I. Telecomunicacion
        Ciudad Universitaria
        E-28040  MADRID
        jmanas@dit.upm.es

        Tables of strings
 **********************************************************************/

/* LINTLIBRARY */

# define cast_IMP
# include "cast.hh"

# include <stdio.h>
# include <string.h>
# include <ctype.h>

PUBLIC int
cstrcmp (s1, s2)
  char *s1, *s2;
{
  register char ls1, ls2;

  while (*s1 && *s2) {
    ls1= isupper (*s1) ? tolower (*s1) : *s1;
    ls2= isupper (*s2) ? tolower (*s2) : *s2;
    if (ls1 < ls2)
      return -1;
    else if (ls1 > ls2)
      return 1;
    s1++; s2++;
  }
  if (*s1 == *s2)
    return 0;
  else if (*s1)
    return 1;
  else
    return -1;
}

PUBLIC ST*
STcreate (size, incr, class, ecase)
  int size, incr;
  short class, ecase;
{
  ST* tbl;
  int s;

  tbl= (ST*) malloc (sizeof (ST));
  if (tbl == NULL)
    fatal ("STcreate run out of memory");
  tbl->size= 0;
  if (incr < 0)
    s= size;
  else if (incr == 0)
    for (s= 4; s < size; s*= 2)
      ;
  else
    for (s= incr; s < size; s+= incr)
      ;
  tbl->max= s;
  tbl->incr= incr;
  tbl->class= class;
  tbl->ecase= ecase;
  tbl->data= (char**) malloc (s * sizeof (char*));
  if (tbl->data == NULL)
    fatal ("STcreate run out of memory for data");
  return tbl;
}

PUBLIC ST*
STdup (tbl, share)
  ST* tbl;
  int share;
{
  ST* new;
  int i;

  new= STcreate (tbl->size, tbl->incr, tbl->class, tbl->ecase);
  for (i= 0; i < tbl->size; i++)
    if (share)
      new->data[i]= tbl->data[i];
    else
      new->data[i]= str_alloc (tbl->data[i]);
  new->size= tbl->size;
  return new;
}

PRIVATE void
expand (tbl)
  ST* tbl;
{
  int s;
  
  if (tbl->incr < 0) {
    (void) fprintf (stderr, "ST colour: cannot expand fixed table\n");
    exit (1);
  }
  else if (tbl->incr == 0)
    for (s= 4; s < tbl->max+1; s*= 2)
      ;
  else
    for (s= tbl->incr; s < tbl->max+1; s+= tbl->incr)
      ;
  tbl->data= (char**) realloc (tbl->data, s * sizeof (char*));
  if (tbl->data == NULL)
    fatal ("colour ST cannot get memory for expansion");
  tbl->max= s;
}

PUBLIC int
STadd (n, tbl, shared)
  char* n;
  ST* tbl;
  int shared;
{
  int i, m, j;
  int cmp;
  
  switch (tbl->class) {
  case 1:			/* no dup */
    for (i= 0; i < tbl->size; i++)
      if (tbl->ecase) {
	if (strcmp (tbl->data[i], n) == 0)
	  return i;
      }
      else {
	if (cstrcmp (tbl->data[i], n) == 0)
	  return i;
      }
  case 0:			/* as is */
    if (tbl->size+1 > tbl->max)
      expand (tbl);
    if (shared)
      tbl->data[tbl->size++]= n;
    else
      tbl->data[tbl->size++]= str_alloc (n);
    return tbl->size-1;
  case 2:			/* sorted */
    i= 0;
    j= tbl->size-1;
    while (i <= j) {		       /* invariant:    */
      m= (i+j)/2;                      /* tbl[i-1] < n  */
      if (tbl->ecase)
	cmp= strcmp (tbl->data[m], n);	/* tbl[j+1] > n  */
      else
	cmp= cstrcmp (tbl->data[m], n);	/* tbl[j+1] > n  */
      if (cmp == 0)
	return m;
      if (cmp > 0)
	j= m-1;
      else
	i= m+1;
    }
    if (tbl->size+1 > tbl->max)
      expand (tbl);
    for (m= tbl->size; m > j; m--)
      tbl->data[m]= tbl->data[m-1];
    if (shared)
      tbl->data[i]= n;
    else
      tbl->data[i]= str_alloc (n);
    tbl->size++;
    return i;
  default:
    (void) fprintf (stderr, "ST colour: unkown class (%d)\n", tbl->class);
    exit (1);
  }
  return -2;			/* should never happen! */
}

PUBLIC void
STrm (i, tbl, shared)
  int i;
  ST* tbl;
  int shared;
{
  int m;

  if (i < 0 || i >= tbl->size)
    return;
  tbl->size--;
  if (!shared)
    free (tbl->data[i]);
  for (m= i; m < tbl->size; m++)
    tbl->data[m]= tbl->data[m+1];
}

PUBLIC int
STfind (n, tbl)
  char* n;
  ST* tbl;
{
  int i, m, j;
  int cmp;

  switch (tbl->class) {
  case 0:			/* as is */
  case 1:			/* no dup */
    for (i= 0; i < tbl->size; i++)
      if (tbl->ecase) {
	if (strcmp (tbl->data[i], n) == 0)
	  return i;
      }
      else {
	if (cstrcmp (tbl->data[i], n) == 0)
	  return i;
      }
    return -1;
  case 2:			/* sorted */
    i= 0;
    j= tbl->size-1;
    while (i <= j) {		       /* invariant:    */
      m= (i+j)/2;                      /* tbl[i-1] < n  */
      if (tbl->ecase)
	cmp= strcmp (tbl->data[m], n);	/* tbl[j+1] > n  */
      else
	cmp= cstrcmp (tbl->data[m], n);	/* tbl[j+1] > n  */
      if (cmp == 0)
	return m;
      if (cmp > 0)
	j= m-1;
      else
	i= m+1;
    }
    return -1;
  default:
    (void) fprintf (stderr, "ST colour: unkown class (%d)\n", tbl->class);
    exit (1);
  }
  return -2;			/* should never happen! */
}

PUBLIC void
STnodup (tbl)
  ST* tbl;
{
  int i, j;

  for (i= 0; i < tbl->size; i++)
    for (j= i+1; j < tbl->size; j++) {
      if (tbl->ecase) {
	if (strcmp (tbl->data[i], tbl->data[j]) == 0)
	  STrm (j, tbl, FALSE);
      }
      else {
	if (cstrcmp (tbl->data[i], tbl->data[j]) == 0)
	  STrm (j, tbl, FALSE);
      }
    }
  tbl->class= 1;
}

PUBLIC void
STsort (tbl)
  ST* tbl;
{
  int i, j, m;
  char* t;

  for (i= 0; i < tbl->size; i++) {
    m= i;
    for (j= i+1; j < tbl->size; j++) {
      if (tbl->ecase) {
	if (strcmp (tbl->data[j], tbl->data[m]) < 0)
	  m= j;
      }
      else {
	if (cstrcmp (tbl->data[j], tbl->data[m]) < 0)
	  m= j;
      }
    }
    if (m != i) {
      t= tbl->data[i];
      tbl->data[i]= tbl->data[m];
      tbl->data[m]= t;
    }
  }
  tbl->class= 2;
}

PUBLIC CLR_TYPE
getST (fp)
     FILE* fp;
{
  int size, incr;
  short class, ecase;
  ST* tbl;
  int i;
  char *s, *p;

  s= (char*) getstring (fp);
  size= 4;			/* anyone would fit! */
  incr= 4;
  class= 0;			/* as is */
  ecase= 0;			/* case insensitive */
  tbl= STcreate (size, incr, class, ecase);
  while (*s != 0) {
    for (p= s; *p != '\n'; p++)
      if (*p == '@')
	p++;
    *p= 0;
    (void) STadd (s, tbl, TRUE);
    s= p+1;
  }
  for (i= 0; i < tbl->size; i++)
    for (s= tbl->data[i];
	 (p= strchr (s, '@')) != NULL;
	 s= p) {
      (void) strcpy (p, p+1);
      p++;
    }
  tbl->incr= -1;		/* freeze it! */
  return (CLR_TYPE) tbl;
}

PUBLIC void
putST (fp, val)
     FILE* fp;
     CLR_TYPE val;
{
  ST* tbl;
  int i;
  char* p;
  char c;

  tbl= (ST*) val;
  if (tbl->size == 0)
    return;
  for (i= 0; i < tbl->size; i++) {
    for (p= tbl->data[i]; *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
fST (attrp)
     TATTR* attrp;
{
  ST* tbl;
  int i;

  tbl= (ST*)attrp->value;
  for (i= 0; i < tbl->size; i++)
    free (tbl->data[i]);
  (void) free ((char*)tbl->data);
  (void) free ((char*)tbl);
  attrp->value= NULL;
}

PUBLIC void
fSTs (attrp)
     TATTR* attrp;
{
  ST* tbl;

  tbl= (ST*)attrp->value;
  (void) free ((char*)tbl->data);
  (void) free ((char*)tbl);
  attrp->value= NULL;
}

PUBLIC CLR_TYPE
cST (val)
    CLR_TYPE val;
{
  return (CLR_TYPE) STdup ((ST*) val, FALSE);
}

PUBLIC CLR_TYPE
cSTs (val)
    CLR_TYPE val;
{
  return (CLR_TYPE) STdup ((ST*) val, TRUE);
}
