/***********************************************
 (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   EPS General Public License (see file LICENSE)
 ***********************************************
 $Log: clrio.c,v $
 * Revision 2.4  1993/01/12  16:34:13  eps
 * portability issues
 *
 * Revision 2.3  1992/11/17  11:47:22  eps
 * fix definition of *alloc for PC portability
 *
 * Revision 2.2  1992/01/14  15:42:50  eps
 * distribution issues
 *
 * Revision 2.1  90/10/30  08:32:23  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.5  90/06/21  15:26:08  eps
 * calloc (N, s) => malloc (N * s)
 * allocate in increments of 256
 *
 * Revision 1.4  90/05/10  17:11:46  eps
 * change colour delimiters from !...! into {...}
 *
 * Revision 1.3  90/03/16  15:45:18  eps
 * other colours have a singular colour {name, value}
 * colour delimiter in files is always '!'
 * FILE* is passed to get/put functions rather than a buffer
 * field cpy is new in TIOcolours, taking care of attribute copying
 * bulk allocation of attribute nodes (in chunks of 128)
 *
 * Revision 1.2  90/01/29  14:51:40  eps
 * fixing license details
 *
 * Revision 1.1  90/01/25  17:59:37  eps
 * Initial revision
 *
 **********************************************/

#ifndef lint
static char rcsid[]= "$Id: clrio.c,v 2.4 1993/01/12 16:34:13 eps Exp $";
#endif

/***********************************************************************
	Jose A. Manas
	dpt. Ingenieria Telematica
	E.T.S.I. Telecomunicacion
	Ciudad Universitaria
	E-28040  MADRID

	jmanas@dit.upm.es

	input/output of attributes
 **********************************************************************/

/* LINTLIBRARY */

# define cast_IMP
# include "cast.hh"

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

PUBLIC TIOCOLOURS HWclr [] = {
  "clr0",      0, IO_int,
  "clr1",      1, IO_int
  };

PRIVATE TATTR* freelist= NULL;
# define BUCKSIZE 256

typedef struct {
    char* name;
    CLR_TYPE value;
    } cothers;

PRIVATE char name[BUFSIZ];

PUBLIC void
getattrs (fp, nodep)
     FILE*   fp;
     TNODE*  nodep;
{
  int c;
  int iname;
  TIOCOLOURS* iiotb;
  TATTR* new;
  cothers* o;

  /* hardwired colours */
  if ((c= getc (fp)) == '{') {
    if ((c= getc (fp)) == '}')
      nodep->value0= NULL;
    else {
      (void) ungetc (c, fp);
      if (HWclr[0].get == NULL) {
	nodep->value0= NULL;
	while ((c= getc (fp)) != '}')
	  if (c == '\\')
	    c= getc (fp);
      }
      else {
	nodep->value0= HWclr[0].get (fp);
	c= getc (fp);		/* skip '}' */
      }
    }
    if ((c= getc (fp)) == '{') {
      if ((c= getc (fp)) == '}')
	nodep->value1= NULL;
      else {
	(void) ungetc (c, fp);
	if (HWclr[1].get == NULL) {
	  nodep->value1= NULL;
	  while ((c= getc (fp)) != '}')
	    if (c == '\\')
	      c= getc (fp);
	}
	else {
	  nodep->value1= HWclr[1].get (fp);
	  c= getc (fp);		/* skip '}' */
	}
      }
    }
    else
      (void) ungetc (c, fp);
  }
  else
    (void) ungetc (c, fp);

  /* linked list of colours */
  for (;;) {
    c= getc (fp);
    while (c == ' ' || c == '\t')
      c= getc (fp);
    if (c == EOF) {
      (void) fprintf (stderr, "getattrs: unexpected EOF\n");
      exit (1);
    }
    if (c == '\n')
      return;
    iname= 0;			/* get colour name */
    do {
      name[iname++]= c;
    } while ((c= getc (fp)) != '{');
    name[iname++]= 0;
    iiotb= name2clr (name);
    if (iiotb->get == NULL) {
      while ((c= getc (fp)) != '}')
	if (c == '\\')
	  c= getc (fp);
      c= '}';
    }
    else {				/* must be loaded */
      new= add_attr (iiotb->atype, nodep);
      assert (new != NULL);
      if (iiotb->keyword == NULL) {		/* others */
	o= (cothers*) malloc (sizeof (cothers));
	if (o == NULL)
	  fatal ("run out of memory while loading colour");
	new->value= (CLR_TYPE) o;
	o->name= newid (name);
	if ((c= getc (fp)) == '}')
	  o->value= NULL;
	else {
	  (void) ungetc (c, fp);
	  o->value= iiotb->get (fp);
	  c= getc (fp);
	  assert (c == '}');
	}
      }
      else {
	if ((c= getc (fp)) == '}')
	  new->value= NULL;
	else {
	  (void) ungetc (c, fp);
	  new->value= iiotb->get (fp);
	  c= getc (fp);
	  assert (c == '}');
	}
      }
    }
  }
}

PUBLIC void
putattrs (fp, nodep)
     FILE* fp;
     TNODE* nodep;
{
  TIOCOLOURS* iiotb;
  TATTR* p;
  char* k;
  CLR_TYPE v;

  /* hardwired colours */
  if (nodep->value1 != NULL) {
    if (nodep->value0 == NULL)
      fprintf (fp, "{}");
    else {
      putc ('{', fp);
      HWclr[0].put (fp, nodep->value0);
      putc ('}', fp);
    }
    putc ('{', fp);
    HWclr[1].put (fp, nodep->value1);
    putc ('}', fp);
  }
  else if (nodep->value0 != NULL) {
    putc ('{', fp);
    HWclr[0].put (fp, nodep->value0);
    putc ('}', fp);
  }

  /* linked list of colours */
  for (p= nodep->attrs; p != NULL; p= p->next) {
    if (p->atype < 0) {
      iiotb= type2clr (-p->atype);
      (void) fprintf (fp, " %s{--}", iiotb->keyword);
    }
    else {
      iiotb= type2clr (p->atype);
      if (iiotb->put != NULL) {
	if (iiotb->atype == others) {
	  k= ((cothers*)p->value)->name;
	  v= ((cothers*)p->value)->value;
	}
	else {
	  k= iiotb->keyword;
	  v= p->value;
	}
	if (v == NULL)
	  (void) fprintf (fp, " %s{}", k);
	else {
	  (void) fprintf (fp, " %s{", k);
	  iiotb->put (fp, v);
	  putc ('}', fp);
	}
      }
    }
  }
  putc ('\n', fp);
}

PUBLIC void
free_attr (attrp)
     TATTR* attrp;
{
  TIOCOLOURS* iiotb;
  cothers* o;

  iiotb= type2clr (attrp->atype);
  if (iiotb->free != NULL) {
    if (iiotb->atype == others) {
      o= (cothers*) attrp->value;
      if (o->value != NULL)
	iiotb->free (o->value);
      free ((char*) o);
    }
    else
      if (attrp->value != NULL)
	iiotb->free (attrp->value);
  }
  attrp->next= freelist;
  freelist= attrp;
}

PUBLIC void
copyattrs (newn, oldn)
     TNODE*  newn;
     TNODE*  oldn;
{
  TATTR *nattr, *oattr;
  TIOCOLOURS* ioc;
  cothers *no, *oo;

  if (newn == NULL || oldn == NULL)
    return;

  if (oldn->value0 != NULL) {
    if (HWclr[0].cpy == NULL)
      newn->value0= oldn->value0;
    else
      newn->value0= HWclr[0].cpy (oldn->value0);
  }
  if (oldn->value1 != NULL) {
    if (HWclr[1].cpy == NULL)
      newn->value1= oldn->value1;
    else
      newn->value1= HWclr[1].cpy (oldn->value1);
  }

  for (oattr= oldn->attrs; oattr != NULL; oattr= oattr->next) {
    nattr= add_attr (oattr->atype, newn);
    assert (nattr != NULL);
    ioc= type2clr (oattr->atype);
    if (ioc->cpy == NULL)
      nattr->value= oattr->value;
    else {
      if (ioc->atype == others) {
	oo= (cothers*) oattr->value;
	no= (cothers*) malloc (sizeof (cothers));
	if (no == NULL)
	  fatal ("run out of memory while loading colour");
	no->name= oo->name;
	if (oo->value == NULL)
	  no->value= NULL;
	else
	  no->value=  ioc->cpy (oo->value);
	nattr->value= (CLR_TYPE) no;
      }
      else
	if (oattr->value == NULL)
	  nattr->value= NULL;
	else
	  nattr->value= ioc->cpy (oattr->value);
    }
  }
}

PUBLIC TATTR*
new_attr ()
{
  TATTR* slot;
  TATTR* buck;
  int i;

  if (freelist == NULL) {
    buck= (TATTR*) malloc (BUCKSIZE * sizeof (TATTR));
    if (buck == NULL)
      fatal ("new_attr: 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->atype= 0;
  slot->value= NULL;
  slot->next= NULL;
  return slot;
}

PUBLIC void
freeattrs (nodep)
     TNODE* nodep;
{
  TATTR *p, *q;

  if (nodep == NULL)
    return;

  if (nodep->value0 != NULL) {
    if (HWclr[0].free != NULL)
      HWclr[0].free (nodep->value0);
  }
  if (nodep->value1 != NULL) {
    if (HWclr[1].free != NULL)
      HWclr[1].free (nodep->value1);
  }

  for (p= nodep->attrs; p != NULL; p= q) {
    q= p->next;
    free_attr (p);
  }
  nodep->attrs= NULL;
}

