/***********************************
  (C) Copyright 1992-1993; dit/upm
  Distributed under the conditions stated in the
  TOPO General Public License (see file LICENSE)
  ***********************************/

/***********************************

  Santiago Pavon Gomez

  11-1-1990

  This module defines a type of dymanic trees. These trees are
  formed by cells, which are linked between them, and attributes,
  which are associated to the cells.

  The memory used by both cells and attributes can be shared,
  so there are some counters that indicates how many fathers has
  any cell or attribute.
  These counter are called "copy" for the cells and "cont" for the
  attributes.

  COMPILATION OPTIONS: The behaviour of this module can be modified
  by the following compilation flags:

  SDEBUG : activate debugging mode
  DEBUGMEM : activate control of deallocated memory


  ************************************/

/* LINTLIBRARY */


#include "listdh.h"
#include "licell.h"
#include "limisc.h"


/******************************************************************
 *
 *  Cell and the attribute definition tables.
 *
 *  The cells and the attributes defined in the aplications are
 *  recorded in these tables.
 *
 *******************************************************************/


#define MAXCELLTFUNC 30
#define MAXATTRTFUNC 30


/* Entries of the cell definition table.
 * Contains:
 *    type: a number for each cell type.
 *    name: a string name for each cell type.
 *    d2n:  a function that returns a name for a given cell name.
 */
typedef struct { CellTypeTyp   type;
		 char *        name;
		 char *        (*d2n)();
	       } CellTFuncTyp;


/* Entries of the attribute definition table.
 * Contains:
 *   type: a number for each attribute type.
 *   name: a string name for each attribute type.
 *   print: function to print attributes of a given type.
 *   deall: function to deallocate the memory used by attributes of
 *         a given type.
 *   copy: function to copy attributes of a given type.
 *   unshare: function to unshare attributes of a given type.
 */
typedef struct { AttrTypeTyp   type;
		 char *        name;
		 void          (*print)();
		 void          (*deall)();
		 AttrValueTyp  (*copy)();
		 AttrValueTyp  (*unshare)();
	       } AttrTFuncTyp;

/*----------------------------------------------------------------*/

/*
 * The tables.
 */
static CellTFuncTyp  CellTFunc[MAXCELLTFUNC];
static AttrTFuncTyp  AttrTFunc[MAXATTRTFUNC];

/*----------------------------------------------------------------*/

/* DeclareCell
 * Declares a cell type.
 * Parameters:
 *    type: a number for each cell type.
 *    name: a string name for each cell type.
 *    d2n:  a function that returns a name for a given cell name.
 */
void DeclareCell( type, name, d2n )
     CellTypeTyp   type;
     char *        name;
     char *        (*d2n)();
{
  LASSERT(CellTFunc[type].type == -1);
  LASSERT(type>=0);
  LASSERT(type<MAXCELLTFUNC);
  CellTFunc[type].type = type;
  CellTFunc[type].name = name;
  CellTFunc[type].d2n  = d2n;
}

/*----------------------------------------------------------------*/

/* DeclareAttr
 * Declares an attribute type.
 * Parameters:
 *   type: a number for each attribute type.
 *   name: a string name for each attribute type.
 *   print: function to print attributes of a given type.
 *   deall: function to deallocate the memory used by attributes of
 *         a given type.
 *   copy: function to copy attributes of a given type.
 *   unshare: function to unshare attributes of a given type.
 */
void DeclareAttr( type,name,print,deall,copy,unshare )
     AttrTypeTyp   type;
     char *        name;
     void          (*print)();
     void          (*deall)();
     AttrValueTyp  (*copy)();
     AttrValueTyp  (*unshare)();
{
  LASSERT(AttrTFunc[type].type == -1);
  LASSERT(type>=0);
  LASSERT(type<MAXATTRTFUNC);
  AttrTFunc[type].type = type;
  AttrTFunc[type].name = name;
  AttrTFunc[type].print = print;
  AttrTFunc[type].deall = deall;
  AttrTFunc[type].copy = copy;
  AttrTFunc[type].unshare = unshare;
}


/******************************************************************
 *
 * Account of the number of the cells and attributes used
 * and released.
 *
 *******************************************************************/

#ifdef SDEBUG
static int new_cell_count      = 0;
static int max_cell_count      = 0;
static int released_cell_count = 0;
static int new_attr_count      = 0;
static int max_attr_count      = 0;
static int released_attr_count = 0;
#endif

/*----------------------------------------------------------------*/

/* InitCell
 * Initialization of this module.
 * This function must be called only when the application starts.
 */
void InitCell()
{
  int i;

  for (i=0 ; i<MAXCELLTFUNC ; i++)
    CellTFunc[i].type = -1;
  for (i=0 ; i<MAXATTRTFUNC ; i++)
    AttrTFunc[i].type = -1;
#ifdef SDEBUG
  new_cell_count      = 0;
  new_attr_count      = 0;
  released_cell_count = 0;
  released_attr_count = 0;
  max_cell_count      = 0;
  max_attr_count      = 0;
#endif
}

/*----------------------------------------------------------------*/

/* GetNameCell
 * Returns the name of the cell which type is "t".
 */
char * GetNameCell( t )
     CellTypeTyp   t;
{
  return CellTFunc[t].name;
}

/*----------------------------------------------------------------*/

/* GetNameAttr
 * Returns the name of the attribute which type is "t".
 */
char * GetNameAttr( t )
     AttrTypeTyp   t;
{
  return AttrTFunc[t].name;
}

/******************************************************************
 *
 * Functions to manage cells.
 *
 *******************************************************************/


/* NewCell
 * Gets memory for a new cell
 */
PCellTyp NewCell( t )
     CellTypeTyp   t;
{
  PCellTyp p;

  p = (PCellTyp) NewCellM(sizeof(CellTyp));
#ifdef SDEBUG
  new_cell_count++;
  max_cell_count = MAX( max_cell_count, new_cell_count-released_cell_count );
#endif
  p->type = t;
  p->b1   = NULL;
  p->b2   = NULL;
  return p;
}

/*----------------------------------------------------------------*/

/* DispCell
 * Disposes the memory used by the cell "c".
 */
void DispCell( c )
     PCellTyp c;
{
  FreeCellM((void*)c,sizeof(CellTyp));
#ifdef SDEBUG
  released_cell_count++;
#endif
}

/*----------------------------------------------------------------*/

/* DrawCell
 * Prints the cell "c" with indentation "i".
 * "pstr" is the function used to print strings.
 */
void DrawCell( c, i, pstr )
     PCellTyp  c;
     int       i;
     void      (*pstr)();
{
  char str[15];

  LASSERT(c != NULL);
  for ( ; i>0 ; i-- )
    pstr(" ");
  pstr("T:");  (void)sprintf(str,"%-8d",c->type);    pstr(str);
  pstr(" N:"); (void)sprintf(str,"%-8d",c->name);    pstr(str);
  pstr(" A:"); (void)sprintf(str,"%-8d",c->attrlist);pstr(str);
  pstr(" B1:");(void)sprintf(str,"%-8d",c->b1);      pstr(str);
  pstr(" B2:");(void)sprintf(str,"%-8d",c->b2);      pstr(str);
  pstr("\n");
}

/*----------------------------------------------------------------*/

/* CopyCell
 * Copies the cell "t".
 * Attributes are shared (not copied).
 * Links b1 and b2 are set to NULL.
 * The "copy" fields is set to 0.
 */
PCellTyp CopyCell( t )
     PCellTyp t;
{
  PCellTyp  nc;
  PAttrsTyp as;

  nc = NewCell(LookType(t));
  nc->b1 = NULL;
  nc->b2 = NULL;
  nc->copy = 0;
  nc->attrlist = NULL;
  PutName(nc,LookName(t));
  for (as = (PAttrsTyp) t->attrlist; as != NULL; as = Next_list(as))
    PutA(nc,(PAttrTyp)LookInfo_list(as));
  return nc;
}

/*----------------------------------------------------------------*/

/* GlueCellB1
 * The tree "t->b1" is copied in the memory used by "t".
 * This function is equal to moving all the pointer to "t" to "t->b1"
 */
void GlueCellB1( t )
     PCellTyp  t;
{
  LASSERT(LookB1(t)!=NULL);
  GlueCell(t,LookB1(t));
}

/*----------------------------------------------------------------*/

/* GlueCellB2
 * The tree "t->b2" is copied in the memory used by "t".
 * This function is equal to moving all the pointer to "t" to "t->b2"
 * and deleting "t".
 */
void GlueCellB2( t )
     PCellTyp  t;
{
  LASSERT(LookB2(t)!=NULL);
  GlueCell(t,LookB2(t));
}

/*----------------------------------------------------------------*/

/* ExchangeCell
 * Exchanges the fiels of the cells pointed by b1p and b2p, except the
 * copy field.
 */
void ExchangeCell(b1p,b2p)
     PCellTyp *b1p,*b2p;
{
  PCellTyp b1b,b2b,b1,b2;
  CellTypeTyp typeb;
  DescriptorTyp nameb;
  PAttrsTyp attrlistb;

  b1=*b1p;
  b2=*b2p;

  typeb = b1->type;
  nameb = b1->name;
  b1b = b1->b1;
  b2b = b1->b2;
  attrlistb = b1->attrlist;

  b1->type = b2->type;
  b1->name = b2->name;
  b1->b2 = b2->b2;
  b1->b1 = b2->b1;
  b1->attrlist = b2->attrlist;

  b2->type = typeb;
  b2->name = nameb;
  b2->b2 = b2b;
  b2->b1 = b1b;
  b2->attrlist = attrlistb;

  *b1p=b2;
  *b2p=b1;
}


/******************************************************************
 *
 * Functions to manage attributes.
 *
 *******************************************************************/


/* NewAttr
 * Gets memory for an AttrTyp
 */
PAttrTyp NewAttr()
{
  PAttrTyp p;

  p = (PAttrTyp) NewCellM(sizeof(AttrTyp));
#ifdef SDEBUG
  new_attr_count++;
  max_attr_count = MAX( max_attr_count, new_attr_count-released_attr_count );
#endif
  p->cont = 0;
  p->attr = NULL;
  return p;
}

/*----------------------------------------------------------------*/

/* DispAttr
 * Frees the memory used by the AttrTyp "p".
 */
void DispAttr( p )
     PAttrTyp  p;
{
  FreeCellM((void*)p,sizeof(AttrTyp));
#ifdef SDEBUG
  released_attr_count++;
#endif
}

/*----------------------------------------------------------------*/

/* PutA
 * Adds the attribute "a" to the cell "c".
 * If the attribute already exists, it produces a error.
 */
void PutA( c,a )
     PCellTyp  c;
     PAttrTyp a;
{ PAttrsTyp as;
  PAttrTyp  a1;

  LASSERT(c!=NULL);
  as = LookAttr(c);
  if (as == NULL) {
    as = Create_list();
    a->cont += 1;
    as = Insert_list((DataListTyp) a,as);
    PutAttr(c,as);
    return;
  }
  else {
    for (;as!=NULL;as = Next_list(as)) {
      a1 = (PAttrTyp) LookInfo_list(as);
      if (a1->type == a->type) {
	Error("PutA: Not empty attribute.");
      }
    }
    a->cont += 1;
    PutAttr(c,Insert_list((DataListTyp)a,LookAttr(c)));
    return;
  }
}

/*----------------------------------------------------------------*/

/* FindAttr
 * Finds the attribute of type "t" in the cell "c".
 * Returns the node of the list of attributes where is placed.
 * If it is not found then it returns NULL.
 */
static PAttrsTyp FindAttr ( t,c )
     AttrTypeTyp t;
     PCellTyp      c;
{
  PAttrsTyp as;
  PAttrTyp  a;

  LASSERT(c!=NULL);
  for (as= LookAttr(c); as != NULL; as= Next_list(as))
    { a = (PAttrTyp) LookInfo_list(as);
      if (a->type == t)
	return as;
    }
  return NULL;
}

/*----------------------------------------------------------------*/

/* LookA
 * Returns the attribute of type t of the cell c
 * If it is not found then it returns NULL.
 */
PAttrTyp LookA( c,t )
     PCellTyp  c;
     AttrTypeTyp t;
{
  PAttrsTyp as;

  LASSERT(c!=NULL);
  as = FindAttr(t,c);
  if (as!=NULL)
    return (PAttrTyp) LookInfo_list(as);
  return NULL;
}

/*----------------------------------------------------------------*/

/* GetA
 * Returns the attribute of type "t" of the cell "c"
 * and removes it from the cell.
 * If it is not found then it returns NULL.
 */
PAttrTyp GetA( c,t )
     PCellTyp  c;
     AttrTypeTyp t;
{
  PAttrsTyp as;
  PAttrTyp  a;

  LASSERT(c!=NULL);
  if ((as = FindAttr(t,c)) != NULL) {
    a = (PAttrTyp) LookInfo_list(as);
    PutAttr(c,DeleteNode_list(as,LookAttr(c)));
    a->cont -= 1;
    return a;
  }
  else
    return NULL;
}

/*----------------------------------------------------------------*/

/* FreeA
 * Frees the memory used by the attibute "a" if "a->cont" is 0.
 */
void FreeA( a )
     PAttrTyp a;
{
  if (a->cont == 0) {
    (AttrTFunc[a->type].deall)(a->attr);
    DispAttr(a);
  }
}

/*----------------------------------------------------------------*/

/* CopyA
 * Returns a copy of the the attribute "a".
 * Note: the value stored in the attribute is copied.
 */
PAttrTyp CopyA( a )
     PAttrTyp a;
{
  PAttrTyp na;

  na = NewAttr();
  na->type = a->type;
  na->attr = (AttrTFunc[a->type].copy)(a->attr);
  return na;
}

/*----------------------------------------------------------------*/

/* UnshareA
 * Unshares the attribute of type "t" of the cell "c".
 * Then the cont field of the attribute will be 1.
 */
void UnshareA( c,t )
     PCellTyp  c;
     AttrTypeTyp t;
{
  PAttrTyp a /* ,na */ ;

  a = GetA(c,t);
  if (a!=NULL) {
    if (a->cont!=0) {
      /*
	 na = NewAttr();
	 na->type = a->type;
	 na->attr = (AttrTFunc[a->type].unshare)(a->attr);
	 PutA(c,na);
	 */

      a = CopyA(a);

    }
    else /* {
	  */
      a->attr = (AttrTFunc[a->type].unshare)(a->attr);
    PutA(c,a);
    /*
       }
       */
  }
}

/*----------------------------------------------------------------*/

/* MakeA
 * Makes a new attribute of type "t" with the value "v" stored in it.
 */
PAttrTyp MakeA( v,t )
     AttrValueTyp  v;
     AttrTypeTyp   t;
{
  PAttrTyp na;

  na = NewAttr();
  na->type = t;
  na->attr = v;
  return na;
}

/*----------------------------------------------------------------*/

/* PutAInfo
 * Puts the value "v" into the attribute "a", which must not have a value.
 */
void PutAInfo( a,v )
     PAttrTyp   a;
     AttrValueTyp  v;
{
  LASSERT(a!=NULL && a->attr == NULL);
  a->attr = v;
}

/*----------------------------------------------------------------*/

/* GetAInfo
 * Extracts the value stored in the attribute "a".
 * Then "a" will not have value  after applying this function.
 * Use PutAInfo to put another value in "a".
 */
AttrValueTyp GetAInfo( a )
     PAttrTyp a;
{
  AttrValueTyp aux;

  if (a != NULL) {
    aux = a->attr;
    a->attr = NULL;
    return aux;
  }
  else
    return NULL;
}

/*----------------------------------------------------------------*/

/* LookAInfo
 * Returns the value stored in the attribute "a", but it is not
 * extracted from the attribute. So, it must not be modified, i.e.
 * it must only be examined.
 */
AttrValueTyp LookAInfo( a )
     PAttrTyp a;
{
  if (a!=NULL)
    return a->attr;
  else
    return NULL;
}

/*----------------------------------------------------------------*/

/* WriteA
 * Prints the attribute "a".
 * "pstr" is the function used to print strings.
 */
void WriteA( a, pstr )
     PAttrTyp  a;
     void      (*pstr)();
{
  pstr(AttrTFunc[a->type].name);
  pstr("<");
  PrintInt(pstr,a->cont);
  (AttrTFunc[a->type].print)(a->attr,pstr);
  pstr("> ");
}

/*----------------------------------------------------------------*/

/* UnshareAS
 * Unshares all the attributes of the attribute list of the cell "c".
 */
void UnshareAS(c)
     PCellTyp c;
{
  PAttrsTyp al,fl;
  PAttrTyp a,na;

  al = fl = LookAttr(c);
  while (al!=NULL) {
    a = (PAttrTyp) LookInfo_list(al);
    if (a->cont>1) {
      a        = (PAttrTyp) GetInfo_list(al);
      na       = CopyA(a);
      na->cont = 1;
      a->cont -= 1;
      PutInfo_list(al,(DataListTyp) na);
    }
    al = Next_list(al);
  }
  PutAttr(c,fl);
}

/*----------------------------------------------------------------*/

static void AuxFreeAS(a)
     PAttrTyp a;
{
  a->cont -= 1;
  FreeA(a);
}


/* FreeAS
 * Frees the list of attributes of the cell "c".
 */
void FreeAS(c)
     PCellTyp c;
{
  PAttrsTyp al;

  al = LookAttr(c);
  if (al!=NULL) {
    Free_list(al,AuxFreeAS);
    PutAttr(c,(ListTyp)NULL);
  }
}

/*----------------------------------------------------------------*/

/* CopyAS
 * Copies the list of attributes of the cell "c1" into the cell "c2".
 * The attribute values are not copied, they are shared by "c1" and "c2".
 */
void CopyAS( c1 , c2 )
     PCellTyp c1,c2;
{
  PAttrsTyp al;

  LASSERT(LookAttr(c2)==NULL);
  for ( al=LookAttr(c1) ; al!=NULL ; al=Next_list(al) )
    PutA(c2,(PAttrTyp)LookInfo_list(al));
}


/******************************************************************
 *
 *   Functions to manage trees.
 *
 *******************************************************************/


/* FreeB1
 * Deallocates the memory used by the tree "t->b1" and sets "t->b1"
 * to NULL.
 * If the tree "t->b1" has got any other father then the memory is
 * not dealoocated.
 */
void FreeB1( t )
     PCellTyp t;
{
  LASSERT(t!=NULL);
  if (t->b1 != NULL) {
    if (t->b1->copy>=0)
      t->b1->copy -= 1;
    else
      t->b1->copy += 1;
    FreeTree(t->b1);
    t->b1 = NULL;
  }
}

/*----------------------------------------------------------------*/

/* FreeB2
 * Deallocates the memory used by the tree "t->b2" and sets "t->b2"
 * to NULL.
 * If the tree "t->b2" has got any other father then the memory is
 * not dealoocated.
 */
void FreeB2( t )
     PCellTyp t;
{
  LASSERT(t!=NULL);
  if (t->b2 != NULL) {
    if (t->b2->copy>=0)
      t->b2->copy -= 1;
    else
      t->b2->copy += 1;
    FreeTree(t->b2);
    t->b2 = NULL;
  }
}

/*----------------------------------------------------------------*/

/* FreeTree
 * Deallocates the memory used by the cells and the attributes of
 * the tree "t" if the "copy" field of the cell in the root of the
 * tree is equal to 0, i.e. if this cell has not got any other father.
 */
void FreeTree( t )
     PCellTyp t;
{
  /*  LASSERT(LookCopy(t)>=0); */
  if (LookCopy(t)==0) {
    if (t->b1 != NULL) {
      if (t->b1->copy>=0)
	t->b1->copy -= 1;
      else
	t->b1->copy += 1;
      FreeTree(t->b1);
    }
    if (t->b2 != NULL) {
      if (t->b2->copy>=0)
	t->b2->copy -= 1;
      else
	t->b2->copy += 1;
      FreeTree(t->b2);
    }
    FreeAS(t);
    DispCell(t);
  }
}

/*----------------------------------------------------------------*/

/* GetTree
 * Returns a copy of the tree "t" where all the shared sub-tree has
 * been unshered. Note that if the whole tree has not got any sub-tree
 * shared, then nothing is done.
 * Only the cells are copied. The attributes are always shared.
 */
PCellTyp  GetTree( t )
     PCellTyp t;
{
  PCellTyp nt;

  LASSERT(t!=NULL);
  nt = CopyTree(t);
  FreeTree(t);
  return nt;
}

/*----------------------------------------------------------------*/

/* CopyTree
 * Returns a unshared copy of the tree "t".
 * Only the cells are copied. The attributes are always shared.
 */
PCellTyp  CopyTree( t )
     PCellTyp t;
{
  PCellTyp nc;

  LASSERT(t!=NULL);
  nc = CopyCell(t);
  if ( t->b1 != NULL) {
    PutB1(nc,CopyTree(t->b1));
    PutCopy(LookB1(nc),1);
  }
  if ( t->b2 != NULL) {
    PutB2(nc,CopyTree(t->b2));
    PutCopy(LookB2(nc),1);
  }
  return nc;
}

/*----------------------------------------------------------------*/

/* UnshareAttrsOfTree
 * Unshares the attributes of the tree "t" until the end of the tree
 * or a cell with copy field larger than 1 is found.
 */
void UnshareAttrsOfTree( t )
     PCellTyp  t;
{
  if (LookCopy(t)>=1) {
    if (t->b1 != NULL)
      UnshareAttrsOfTree(t->b1);
    if (t->b2 != NULL)
      UnshareAttrsOfTree(t->b2);
    UnshareAS(t);
  }
}

/*----------------------------------------------------------------*/

/* WriteNode
 * Prints the cell "n".
 * "pstr" is the function used to print strings.
 */
static void WriteNode( n,pstr )
     PCellTyp  n;
     void      (*pstr)();
{
  PAttrsTyp p;
  DescriptorTyp d;
  CellTypeTyp t;

  t = LookType(n);
  d = LookName(n);
  if (CellTFunc[t].type==-1) {
    Warning("Unknown cell type\n");
    pstr("T=<");PrintInt(pstr,t);pstr("> ");
    pstr("D=<");PrintInt(pstr,d);pstr("> ");
  }
  else {
    pstr("T=<");pstr(CellTFunc[t].name);pstr("> ");
    pstr("D=<");PrintInt(pstr,d);
    if (CellTFunc[t].d2n != NULL) {
      pstr("=");pstr((*CellTFunc[t].d2n)(d));
    }
    pstr("> ");
  }
  pstr("C=<");PrintInt(pstr,LookCopy(n));pstr("-");
  PrintInt(pstr,(int)n);pstr("> ");
  for (p = (PAttrsTyp) n->attrlist;p != NULL;p=Next_list(p))
    WriteA((PAttrTyp)LookInfo_list(p),pstr);
}


/* WriteTree
 * Print the no Null Tree "t" with indentation "pos".
 * "pstr" is the function used to print strings.
 * depth refers to cells disregarding their types.
 */
static void WriteTree( t, depth, pos, pstr )
     PCellTyp  t;
     int       depth, pos;
     void      (*pstr)();
{
  int i;

  while (t != NULL) {
    for (i=0 ; i<pos ; i++ )
      pstr("| ");
    if (depth==0){
      pstr("<.....more.....>\n");
      return;
    }
    WriteNode(t,pstr);
    pstr("\n");
    WriteTree( LookB1(t), depth-1, pos+1, pstr );
    t = LookB2(t);
  }
}


/* DrawTree
 * Prints the tree "t" until a depth of cells.
 * "pstr" is the function used to print strings.
 */
void DrawTree( t, depth, pstr )
     PCellTyp  t;
     int       depth;
     void      (*pstr)();
{
  LASSERT(t!=NULL);
  WriteTree( t, depth, 0, pstr );
}

/*----------------------------------------------------------------*/

/* DrawLTree
 * Prints the tree "t" without the attributes in a list format.
 * "pstr" is the function used to print strings.
 */
void DrawLTree( t, pstr )
     PCellTyp  t;
     void      (*pstr)();
{
  DescriptorTyp dt;
  CellTypeTyp tt;

  if (t==NULL)
    pstr("NULL");
  else {
    pstr("(");
    tt = LookType(t);
    dt = LookName(t);
    if (CellTFunc[tt].type==-1) {
      Warning("Unknown cell type\n");
      pstr("T=<");PrintInt(pstr,tt);pstr(">,");
      pstr("D=<");PrintInt(pstr,dt);pstr(">,");
    }
    else {
      pstr("T=<");pstr(CellTFunc[tt].name);pstr(">,");
      pstr("D=<");PrintInt(pstr,dt);
      if (CellTFunc[tt].d2n != NULL) {
	pstr("=");pstr((*CellTFunc[tt].d2n)(dt));
      }
      pstr(">,");
    }
    pstr("C=<");PrintInt(pstr,LookCopy(t));pstr(">,");
    pstr("A=<");PrintInt(pstr,(int)LookAttr(t));pstr(">,");
    DrawLTree(t->b1,pstr);
    pstr(",");
    DrawLTree(t->b2,pstr);
    pstr(")");
  }
}

/*----------------------------------------------------------------*/

/* GlueCell
 * Copies the tree "t2" into the memory used by "t1".
 * This function is equal to moving all the pointer to "t1" to "t2"
 * and deleting "t1".
 */
void GlueCell( t1,t2 )
     PCellTyp  t1,t2;
{
  PCellTyp c1,c2;

  if (t1!=t2) {
    c1 = LookB1(t2);
    c2 = LookB2(t2);

    if (LookCopy(t2)>=0){
      PutCopy(t2,LookCopy(t2)+1);
    }
    else
      PutCopy(t2,LookCopy(t2)-1);

    if (c1!=NULL)
      if (LookCopy(c1)>=0) {
	PutCopy(c1,LookCopy(c1)+1);
      }
      else
	PutCopy(c1,LookCopy(c1)-1);

    if (c2!=NULL)
      if (LookCopy(c2)>=0) {
	PutCopy(c2,LookCopy(c2)+1);
      }
      else
	PutCopy(c2,LookCopy(c2)-1);

    FreeAS(t1);
    CopyAS(t2,t1);
    PutName(t1,LookName(t2));
    PutType(t1,LookType(t2));
    if (LookB1(t1)!=NULL) {
      if (t1->b1->copy>=0)
	t1->b1->copy -= 1;
      else
	t1->b1->copy += 1;
      FreeTree(LookB1(t1));
    }
    if (LookB2(t1)!=NULL) {
      if (t1->b2->copy>=0)
	t1->b2->copy -= 1;
      else
	t1->b2->copy += 1;
      FreeTree(LookB2(t1));
    }
    PutB1(t1,c1);
    PutB2(t1,c2);
    if (t2->copy>=0) /* sobra = ? */
      t2->copy--;
    else
      t2->copy++;

    FreeTree(t2);
  }
}

/*----------------------------------------------------------------*/

/* StatCell
 * Gives some statistics about the cell and attr used, etc...
 * uc: number of cell queries the system has granted this module with.
 * rc: number of cell releases.
 * mc: max number of cells hold on by this module till now.
 * ua: attrs queries.
 * ra: attrs releases.
 * ma: max number of attrs hold on by this module till now.
 */
void StatCell( uc, rc, mc, ua, ra, ma )
     int *uc, *rc, *mc, *ua, *ra, *ma;
{
#ifdef SDEBUG
  *uc = new_cell_count;
  *rc = released_cell_count;
  *mc = max_cell_count;
  *ua = new_attr_count;
  *ra = released_attr_count;
  *ma = max_attr_count;
#endif
}

/*----------------------------------------------------------------*/

