/* "boxify", is a simple filter for cleaning up quite general CIF
             and make it readable for "WOL"
   Copyright (C) 1990 Tor Sverre Lande
   Author's address: bassen@ifi.uio.no

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "p2c.h"

#include "trapes/poly.h"

#include "boxify.h"

Static long lastsymbol;

Static Char actualChar, d, d1;

Static long digit[5], upperChar[5];

Static boolean includeFile, fromFile, quit, trace, dummy, dupChar;

Static FILE *ComFile, *tmpFile, *Source;

Static DDIRNAME dirname, filename;
Static PATHNAME FName, fline;

Static SymbolDefs symbol[maxsymbols + 1];
Static boolean SymbolDef;
Static short nextSymbol;
Static pointdef *disposePoint;

Static long currentlayer, j, i;
Static uchar inPos;
Static Char inLine[132];
Static long figureNumber, lineNumber, templine;

Static Tarray currentT, auxT;
Static long currentsa, currentsb;
Static double a, b, dd;
Static long PathMinX, PathMinY, PathMaxX, PathMaxY;
Static long SymbolMinX, SymbolMinY, SymbolMaxX, SymbolMaxY;

Static CallEntry *CurrentCall;

Static long MaxSymbol = 0;

Static int Naming = false, Offset = true, SepHierarcy = true;

Static FilterDef *UserFilter = NULL;

Static char CellName[200];
Static int Nid = 0;

/* Check if at end of line (or end of entire file). */

int P_eoln(f)
FILE *f;
{
    register int ch;

    ch = getc(f);
    if (ch == EOF)
        return 1;
    ungetc(ch, f);
    return (ch == '\n');
}


Void putcode(cc)
CodeDef cc;
{
  long chno, ind;

  if (CurrentSymbol != NULL) {
      chno = CurrentSymbol->codep / (ChunkSize + 1);
      ind = CurrentSymbol->codep % (ChunkSize + 1);
      if (CurrentSymbol->code[chno] == NULL)
	  CurrentSymbol->code[chno] = (CodeChunk *)Malloc(sizeof(CodeChunk));
      CurrentSymbol->code[chno]->code[ind] = cc;
      CurrentSymbol->codep++;
  } else {
      /* Global code */
      chno = GlobalSymbol->codep / (ChunkSize + 1);
      ind = GlobalSymbol->codep % (ChunkSize + 1);
      if (GlobalSymbol->code[chno] == NULL)
	  GlobalSymbol->code[chno] = (CodeChunk *)Malloc(sizeof(CodeChunk));
      GlobalSymbol->code[chno]->code[ind] = cc;
      GlobalSymbol->codep++;
  }
}  /*** putcode ***/


Static CodeDef *getcodesym(Symbol)
SymbolDefs *Symbol;
{
  long chno, ind;

  chno = Symbol->codep / (ChunkSize + 1);
  ind = Symbol->codep % (ChunkSize + 1);
  if (Symbol->code[chno] == NULL)
    printf("Undefined codeChunk\n");
  else {
    Symbol->codep++;
    return &Symbol->code[chno]->code[ind];
  }
}  /*** getcodesym ***/


Static Char lcase(a)
Char a;
{
  if (a >= 'A' && a <= 'Z')
    a = _tolower(a);
  return a;
}  /*** lcase ***/

Static Void error(nr)
long nr;
{
  long i, FORLIM;

  fprintf(stderr,"\n%6ld.  ", lineNumber);
  inLine[inPos - 1] = '\0';
  fprintf(stderr,"%s\n",inLine);
  fprintf(stderr,"ERROR: ");
  switch (nr) {

  case 0:
    fprintf(stderr,"Unknown error");
    break;

  case 1:
    fprintf(stderr,"Path should at least be 1 point");
    break;

  case 2:
    fprintf(stderr,"Number missing i symbol definition");
    break;

  case 3:
    fprintf(stderr,"A scaling consists of two numbers");
    break;

  case 4:
    fprintf(stderr,"Number missing in defDeleteCommand");
    break;

  case 5:
    fprintf(stderr,"Number missing in callCommand");
    break;

  case 6:
    fprintf(stderr,"Width missing in wireCommand");
    break;

  case 7:
    fprintf(stderr,"Diametre missing in roundFlashCommand");
    break;

  case 8:
    fprintf(stderr,"Centre-definition missing in roundFlashCommand");
    break;

  case 9:
    fprintf(stderr,"Length missing in BoxRecordCommand");
    break;

  case 10:
    fprintf(stderr,"Width missing in BoxCommand");
    break;

  case 11:
    fprintf(stderr,"Centre-point missing in BoxRecordCommand");
    break;

  case 12:
    fprintf(stderr,"Missing ; (1)");
    break;

  case 13:
    fprintf(stderr,"Missing ; (2)");
    break;

  case 14:
    fprintf(stderr,"Unknown definition command");
    break;

  case 15:
    fprintf(stderr,"Unknown command");
    break;

  case 16:
    fprintf(stderr,"Missing ; (3)");
    break;

  case 17:
    fprintf(stderr,"Radius<0 in plotCircle");
    break;

  case 18:
    fprintf(stderr,"Symbol-definition inside symbol not legal");
    break;

  case 19:
    fprintf(stderr,"Symbol-table overflow");
    break;

  case 20:
    fprintf(stderr,"Unknown symbolnumber in call");
    break;

  case 21:
    fprintf(stderr,"Wrong symbol-code");
    break;

  case 22:
    fprintf(stderr,"First defCommand in symbol must be DF");
    break;

  case 23:
    fprintf(stderr,"Illegal statement in symbol");
    break;

  case 24:
    fprintf(stderr,"Missing ; in symbol-code");
    break;

  case 25:
    fprintf(stderr,"Impossible error");
    break;

  case 26:
    fprintf(stderr,"Missing point in transformaion");
    break;

  case 27:
    fprintf(stderr,"Missing X or Y in Mirror-command");
    break;

  case 28:
    fprintf(stderr,"Missing point in Rotate-command");
    break;

  case 29:
    fprintf(stderr,"Unknown Layername");
    break;

  case 30:
    fprintf(stderr,"Wire should be more then one point");
    break;

  case 31:
    fprintf(stderr,"Same point should not be repeated in path");
    break;

  case 32:
    fprintf(stderr,"First and last point should not be the same in a path");
    break;

  case 34:
    fprintf(stderr,"Too few points in polygon");
    break;

  case 35:
    fprintf(stderr,"Redundant point in polygon");
    break;

  case 36:
    fprintf(stderr,"Not Manhatten path!");
    break;

  case 37:
    fprintf(stderr,"Double defined symbol");
    break;

  }/*** case ***/

  fprintf(stderr,"!!\n");

}  /*** error ***/


Static Void nullaux()
{
  long i, j;

  /*nullaux*/
  for (i = 1; i <= 3; i++) {
    for (j = 1; j <= 3; j++) {
      if (i == j)
	auxT[i - 1][j - 1] = 1.0;
      else
	auxT[i - 1][j - 1] = 0.0;
    }
  }
}


Static Void nullcurrent()
{
  long i, j;

  /*nullcurrent*/
  for (i = 1; i <= 3; i++) {
    for (j = 1; j <= 3; j++) {
      if (i == j)
	currentT[i - 1][j - 1] = 1.0;
      else
	currentT[i - 1][j - 1] = 0.0;
    }
  }
}


Static Void mulaux()
{
  Tarray c;
  long i, j, k;

  for (i = 0; i <= 2; i++) {
    for (j = 0; j <= 2; j++) {
      c[i][j] = 0.0;
      for (k = 0; k <= 2; k++)
	c[i][j] += auxT[i][k] * currentT[k][j];
    }
  }
  for (i = 0; i <= 2; i++) {
    for (j = 0; j <= 2; j++)
      currentT[i][j] = c[i][j];
  }
}  /** mulaux **/

Static char ReadChar()
{
  if (includeFile) {
    actualChar = getc(tmpFile);
    if (dupChar)
	return actualChar;
    if (actualChar == '\n')
      actualChar = ' ';
    if (P_eoln(tmpFile)) {
      inPos = 1;
      lineNumber++;
      return actualChar;
    }
    if (actualChar >= 32) {
      inLine[inPos - 1] = actualChar;
      inPos++;
    }
    return actualChar;
  }

  actualChar = getc(stdin);
  if (dupChar) 
      return actualChar;
  if (actualChar == '\n')
    actualChar = ' ';
  if (actualChar == EOF)
    return actualChar;
  if (P_eoln(stdin)) {
    inPos = 1;
    lineNumber++;
    return actualChar;
  }
  if (actualChar >= 32) {
    inLine[inPos - 1] = actualChar;
    inPos++;
  }
}  /*** ReadChar ***/


Static Void displayPoints(p)
pointdef *p;
{
  fprintf(stderr,"Point list:\n");
  while (p != NULL) {
    fprintf(stderr," x= %12ld y= %12ld\n", p->x, p->y);
    p = p->next;
  }
}  /*** displayPoints ***/

#ifdef DEBUG
Static Void displayEdges(e)
edgedef *e;
{
  edgedef *f;
  boolean all;

  if (e == NULL)
    return;
  f = e;
  all = false;
  while (!all) {
    fprintf(stderr,"%12ld,%12ld", e->x, e->y);
    fprintf(stderr,"#%12ld\n", e->angle);
    e = e->suc;
    all = (e == f);
  }
}  /*** displayEdges ***/
#endif

Local double CFloat(a, b, c, d)
double a, b, c, d;
{
  return (a * b + c * d);
}

Static long WireToPolygon(points, w)
pointdef **points;
long w;
{
  /* Converts wire to polygon */
  pointdef *f, *q, *p;
  double A1, B1, C1, A2, B2, C2, K1, K2, dx, dy;
  long n, x, y;

  p = *points;
  if (trace) {
    fprintf(stderr,"WireToPolygon\n");
#ifdef DEBUG
    displayPoints(p);
#endif
  }
 if (p->next == NULL) {
/*    error(30L);
    return;*/
     x = p->x; y = p->y;
     p->x = x - w/2;
     p->y = y - w/2;
     p->next = (pointdef *)Malloc(sizeof(pointdef));
     p = p->next;
     p->x = x + w/2;
     p->y = y - w/2;
     p->next = (pointdef *)Malloc(sizeof(pointdef));
     p = p->next;
     p->x = x + w/2;
     p->y = y + w/2;
     p->next = (pointdef *)Malloc(sizeof(pointdef));
     p = p->next;
     p->x = x - w/2;
     p->y = y + w/2;
     p->next = NULL;
     return 4;
  }
  A1 = p->next->y - p->y;
  B1 = p->x - p->next->x;
  C1 = CFloat((double)(-p->x), (double)p->next->y, (double)p->y,
	      (double)p->next->x);
  K1 = w * sqrt((double)A1 * A1 + B1 * B1) / 2;
  f = (pointdef *)Malloc(sizeof(pointdef));
  f->next = NULL;
  dx = w * A1 / (2 * sqrt((double)A1 * A1 + B1 * B1));
  dy = w * B1 / (2 * sqrt((double)A1 * A1 + B1 * B1));
  f->x = (long)floor((double)p->x - dx + dy + 0.5);
  f->y = (long)floor((double)p->y - dx - dy + 0.5);
  p->x = (long)floor((double)p->x + dx + dy + 0.5);
  p->y = (long)floor((double)p->y - dx + dy + 0.5);
  p = p->next;
  A2 = A1;
  B2 = B1;
  C2 = C1;
  K2 = K1;
  n = 2;
  while (p->next != NULL) {
    /* At least 3 points */
    /* general case      */
    A2 = p->next->y - p->y;
    B2 = p->x - p->next->x;
    C2 = CFloat((double)(-p->x), (double)p->next->y, (double)p->y,
		(double)p->next->x);
    K2 = w * sqrt((double)A2 * A2 + B2 * B2) / 2;
    if (A1 * B2 == A2 * B1) {
      /* parallell lines */
      p->x = p->next->x;
      p->y = p->next->y;
      p->next = p->next->next;
      if (p->next == NULL) {
	A2 = A1;
	B2 = B1;
	C2 = C1;
	K2 = K1;
      }
      continue;
    }
    q = (pointdef *)Malloc(sizeof(pointdef));
    q->next = f;
    f = q;
    f->x = (long)floor((double)
	     (B1 * (C2 + K2) - B2 * (C1 + K1)) / (A1 * B2 - A2 * B1) + 0.5);
    f->y = (long)floor((double)
	     ((C1 + K1) * A2 - (C2 + K2) * A1) / (A1 * B2 - A2 * B1) + 0.5);
    p->x = (long)floor((double)
	     (B1 * (C2 - K2) - B2 * (C1 - K1)) / (A1 * B2 - A2 * B1) + 0.5);
    p->y = (long)floor((double)
	     ((C1 - K1) * A2 - (C2 - K2) * A1) / (A1 * B2 - A2 * B1) + 0.5);
    A1 = A2;
    B1 = B2;
    C1 = C2;
    K1 = K2;
    p = p->next;
    n += 2;
  }

  /* Last point */
  q = (pointdef *)Malloc(sizeof(pointdef));
  q->next = f;
  f = q;
  dx = w * A2 / (2 * sqrt((double)A2 * A2 + B2 * B2));
  dy = w * B2 / (2 * sqrt((double)A2 * A2 + B2 * B2));
  f->x = (long)floor((double)p->x - dx - dy + 0.5);
  f->y = (long)floor((double)p->y + dx - dy + 0.5);
  p->x = (long)floor((double)p->x + dx - dy + 0.5);
  p->y = (long)floor((double)p->y + dx + dy + 0.5);
  p->next = f;
  n += 2;
  p = *points;
  PathMaxX = PathMinX = p->x;
  PathMaxY = PathMinY = p->y;
  p = p->next;
  while (p != NULL) {
      PathMinX = ((p->x < (double)PathMinX)?(long)p->x:PathMinX);
      PathMinY = ((p->y < (double)PathMinY)?(long)p->y:PathMinY);
      PathMaxX = ((p->x > (double)PathMaxX)?(long)p->x:PathMaxX);
      PathMaxY = ((p->y > (double)PathMaxY)?(long)p->y:PathMaxY);
      p = p->next;
  }
  return n;


}  /*** WireToPolygon ***/



Static Void PolyToBoxes(p,n,manhatten)
pointdef *p;
long n;
int manhatten;
{
    struct polygon *poly,*pol;
    pointdef *p1, *lp;
    int i;
#ifdef DEBUG
    if (trace) displayPoints(p);
#endif
    if (CurrentSymbol != NULL) {
    /* find offset */
	SymbolMinX = (SymbolMinX > PathMinX?PathMinX:SymbolMinX);
	SymbolMinY = (SymbolMinY > PathMinY?PathMinY:SymbolMinY);
	SymbolMaxX = (SymbolMaxX < PathMaxX?PathMaxX:SymbolMaxX);
	SymbolMaxY = (SymbolMaxY < PathMaxY?PathMaxY:SymbolMaxY);
    }
    /* Convert to trapes-format */
    poly = (struct polygon *)malloc((n+2)*sizeof(struct polygon));
    poly->a = -n; poly->b = n;
    p1 = p;
    pol = poly;
    for (i=1;i<=n;i++) {
	pol++;
	lp = p1;
	if (!GlobalBlowUp) {
	    pol->a = (p1->x - (PathMinX<0?PathMinX:0));
	    pol->b = (p1->y - (PathMinY<0?PathMinY:0));
	} else {
	pol->a = (p1->x - (PathMinX<0?PathMinX:0))
	    *(CurrentSymbol == NULL?GlobalSymbol:CurrentSymbol)->sa
		/(CurrentSymbol == NULL?GlobalSymbol:CurrentSymbol)->sb;
	pol->b = (p1->y - (PathMinY<0?PathMinY:0))
	    *(CurrentSymbol == NULL?GlobalSymbol:CurrentSymbol)->sa
		/(CurrentSymbol == NULL?GlobalSymbol:CurrentSymbol)->sb;
        }
	p1 = p1->next;
    }
    trapes(poly,currentsa,currentsb,(PathMinX<0)?PathMinX:0,(PathMinY<0)?PathMinY:0);
    free(poly);

}  /*** PolyToBoxes ***/


Static Void NewSymbol(n)
long n;
{
  long i;
  boolean p;

  if (trace)
    fprintf(stderr,"newsymb\n");
  if (nextSymbol > maxsymbols)   /*Symbol-table overfolw*/
    error(19L);
  /* Moves symbols with number>n */
  i = nextSymbol;
  MaxSymbol = (n>MaxSymbol)?n:MaxSymbol;
  if (i >= 1)
    p = (symbol[i].number >= n);
  while (i >= 1 && p) {
    symbol[i + 1] = symbol[i];
    i--;
    if (i >= 1)
      p = (symbol[i].number > n);
  }
  i++;
  /* i points at an empty entry in symbol-table */
  symbol[i].number = n;
  symbol[i].written = false;
  symbol[i].blowup = GlobalBlowUp;
  symbol[i].calls = false;
  symbol[i].sa = 1;
  symbol[i].sb = 1;
  symbol[i].depend = NULL;
  symbol[i].code[0] = NULL;
  symbol[i].codep = 0;
  symbol[i].Xmin = 0;
  symbol[i].Ymin = 0;
  symbol[i].Xmax = 0;
  symbol[i].Ymax = 0;
  CurrentSymbol = &symbol[i];
  SymbolMinX = LONG_MAX;
  SymbolMinY = LONG_MAX;
  SymbolMaxX = LONG_MIN;
  SymbolMaxY = LONG_MIN;
  nextSymbol++;
}  /*** NewSymbol ***/


Static SymbolDefs *FindSymbol(n)
long n;
{
  /* Returns index in symbol-table of symbol n */
  /* Returns 0 if symbol don't exist            */
  long i, t, b;

  if (trace)
    fprintf(stderr,"FindSymbol\n");
  /* Binary search */
  t = nextSymbol;
  b = 1;
  i = (t + b) / 2;
  while (symbol[i].number != n && t >= b) {
    if (symbol[i].number < n)
      b = i + 1;
    else
      t = i - 1;
    i = (t + b) / 2;
  }
  if (trace)
    fprintf(stderr,"symbol:%12ld\n", symbol[i].number);
  if (symbol[i].number == n)
    return &symbol[i];
  else
    return NULL;

}  /*** FindSymbol ***/


Static Void blanks()
{
    char c;
  while (!(isdigit(actualChar) || isalpha(actualChar) ||
	   (actualChar == '-') || (actualChar == '(') || (actualChar == ')') ||
	   (actualChar == '[') || (actualChar == ']') ||
	   (actualChar == ';')))
    c = ReadChar();
}  /*** blanks ***/


Static Void separator()
{
    char c;
  blanks();
  while (isupper(actualChar)) {
    c = ReadChar();
    blanks();
  }
}  /*** separator ***/


Static boolean readInteger(n)
long *n;
{
  /* When integer found the value is returned in n */
  /* else the parameter is not changed             */
  long i;
  char c;

  *n = 0;
  separator();
  if (isdigit(actualChar)) {
    i = 0;
    while (isdigit(actualChar)) {
      i = i * 10 + actualChar - '0';
      c = ReadChar();
    }
    *n = i;
    return true;
  } else
    return false;
}  /*** readInteger ***/


Static boolean point(x, y)
long *x, *y;
{
  /* Should return true if a point is read and the */
  /* coordinates are returned in x,y       */
  boolean Result, neg;
  char c;

  separator();
  Result = false;
  if (actualChar == '-') {
    neg = true;
    c = ReadChar();
  } else
    neg = false;

  if (!readInteger(x))
    return Result;
  if (neg)
    *x = -*x;
  separator();
  if (actualChar == '-') {
    neg = true;
    c = ReadChar();
  } else
    neg = false;

  if (!readInteger(y))
    return Result;
  if (neg)
    *y = -*y;
  /* Global Scaling */
  (*x) = (*x)*PreScaleA/PreScaleB;
  (*y) = (*y)*PreScaleA/PreScaleB;
  return true;
}  /*** point ***/


Static boolean translate()
{
  boolean Result;
  long a, b, ia, ib;
  TransDef *t, *u;
  char c;

  blanks();
  if (actualChar != 'T')
    return false;
  Result = true;
  t = (TransDef *) malloc(sizeof(TransDef));
  c = ReadChar();
  if (!point(&ia, &ib)) {   /*missing point in transformation*/
    error(26L);
    return Result;
  }
  t->type = Trans;
  t->t1 = ia; t->t2 = ib;
  t->next = NULL;
  if (CurrentCall->TList == NULL) 
      CurrentCall->TList = t;
  else {
      u = CurrentCall->TList;
      while (u->next != NULL)
	  u = u->next;
      u->next = t;
  }
  return Result;
}  /*** translate ***/


Static boolean mirror()
{
  boolean Result;
  TransDef *t, *u;
  char c;

  blanks();
  if (actualChar != 'M')
    return false;
  Result = true;
  t = (TransDef *) malloc(sizeof(TransDef));
  c = ReadChar();
  blanks();
  if (actualChar == 'X') {
    c = ReadChar();
    t->t1 = 1;
  } else {
      if (actualChar == 'Y') {
	  c = ReadChar();
	  t->t1 = -1;
      } else {
	  error(27L);
	  return Result;
      }
  }
  t->type = Mirror; t->next = NULL;
  if (CurrentCall->TList == NULL) 
      CurrentCall->TList = t;
  else {
      u = CurrentCall->TList;
      while (u->next != NULL)
	  u = u->next;
      u->next = t;
  }
  return Result;

}  /*** mirror ***/


Static boolean rotate()
{
  boolean Result;
  double ac, bc, c, x1, x2;
  long ia, ib;
  char ch;
  TransDef *t, *u;

  blanks();
  if (actualChar != 'R')
    return false;
  Result = true;
  t = (TransDef *) malloc(sizeof(TransDef));
  ch = ReadChar();
  if (!point(&ia, &ib)) {
    error(28L);
    return Result;
  }
  t->type = Rot;
  t->t1 = ia; t->t2 = ib; t->next = NULL;
  if (CurrentCall->TList == NULL) 
      CurrentCall->TList = t;
  else {
      u = CurrentCall->TList;
      while (u->next != NULL)
	  u = u->next;
      u->next = t;
  }
  return Result;

}  /*** rotate ***/


Static long path(points,manhatten,polygon)
pointdef **points;
int *manhatten, polygon;
{
  /* Should draw a path along the points read */
  long sa, sb, n;
  pointdef *f, *p;

  *manhatten = true;


  if (!point(&sa, &sb))   /*path should be at least one point*/
    error(1L);
  else {
    *points = (pointdef *)Malloc(sizeof(pointdef));
    (*points)->next = NULL;
    p = *points;
    PathMaxX = PathMinX = (*points)->x = sa;
    PathMaxY = PathMinY = (*points)->y = sb;
    n = 1;
    separator();
    while (point(&sa, &sb)) {
      p->next = (pointdef *)Malloc(sizeof(pointdef));
      f = p;
      p = p->next;
      p->x = sa;
      PathMinX = (long)(p->x<(double)PathMinX?p->x:PathMinX);
      PathMaxX = (long)(p->x>(double)PathMaxX?p->x:PathMaxX);
      p->y = sb;
      PathMinY = (long)(p->y<(double)PathMinY?p->y:PathMinY);
      PathMaxY = (long)(p->y>(double)PathMaxY?p->y:PathMaxY);
      if ((p->x != f->x) && (p->y != f->y))
	  *manhatten = false;
      if (p->x == f->x && p->y == f->y)
      {   /*Same point should not be repeated in path*/
	error(31L);
	displayPoints(*points);
	p = f;
	p->next = NULL;
      } else
	  n++;
      separator();
    }

    if (polygon && (p->x != (*points)->x) && (p->y != (*points)->y))
	*manhatten = false;

    p->next = NULL;
    if (! (*manhatten)) {
	fprintf(stderr,"Non-manhatten path\n");
	displayPoints(*points);
    }
    return n;
  }
  return 0;
}  /*** path ***/


Static Void shortname(Layer)
char *Layer;
{
  long n;
  char c;
  if (trace)
      fprintf(stderr,"ShortName\n");

  for (n = 0; n <= 3; n++) {
    if (isdigit(actualChar) || isalpha(actualChar)) {
      Layer[n] = (char)actualChar;
      c = ReadChar();

    } else
      Layer[n] = '\0';
  }
  Layer[4] = '\0';
}  /*** shortname ***/


Static boolean semicolon()
{
  boolean Result;
  char c;

  blanks();
  if (actualChar != ';')
    return false;
  c = ReadChar();
  Result = true;
  blanks();
  return Result;
}  /*** semicolon ***/


Static boolean defStartCommand()
{
  boolean Result;
  long number, a, b;
  char c;

  if (trace)
    fprintf(stderr,"*defStartCommand\n");
  if (actualChar != 'S')
    return false;
  a = 1;
  b = 1;
  Result = true;
  c = ReadChar();
  if (!readInteger(&number))   /*number missing in symbol definition*/
    error(2L);
  separator();
  lastsymbol = number;
  fprintf(stderr,"#%ld, ", number);
  if (FindSymbol(number) != NULL) {   /*Double defined symbol*/
    error(37L);
    return Result;
  }
  NewSymbol(number);
  if (!readInteger(&a)) {
    currentsa = 1;
    currentsb = 1;
    return Result;
  }
  separator();
  if (!readInteger(&b))   /*a scale consists of 2 numbers*/
    error(3L);
  currentsa = a;
  currentsb = b;
  CurrentSymbol->sa = a;
  CurrentSymbol->sb = b;
  return Result;
}  /* defStartCommand ***/


Static boolean defDeleteCommand()
{
  boolean Result;
  long number;
  char c;

  if (actualChar != 'D')
    return false;
  Result = true;
  c = ReadChar();
  fprintf(stderr,"DefDelete not implemented\n");
  if (!readInteger(&number))   /*number missing in defDeleteCommand*/
    error(4L);
  return Result;
}  /*** defDeleteCommand ***/


Static boolean defFinishCommand()
{
  boolean Result;
  CodeDef cd;
  char c;

  if (actualChar != 'F')
    return false;
  if (trace)
    fprintf(stderr,"defFinishCommand\n");
  Result = true;

  cd.CType = EndS;
  putcode(cd);
  /* Save min/max */
  if (SymbolMinX != LONG_MAX)
  (CurrentSymbol == NULL?GlobalSymbol:CurrentSymbol)->Xmin = SymbolMinX;
  if (SymbolMinY != LONG_MAX)
  (CurrentSymbol == NULL?GlobalSymbol:CurrentSymbol)->Ymin = SymbolMinY;
  if (SymbolMaxX != LONG_MIN)
  (CurrentSymbol == NULL?GlobalSymbol:CurrentSymbol)->Xmax = SymbolMaxX;
  if (SymbolMaxY != LONG_MIN)
  (CurrentSymbol == NULL?GlobalSymbol:CurrentSymbol)->Ymax = SymbolMaxY;
  c = ReadChar();
  while (actualChar != ';')
    c = ReadChar();
  currentsa = 1;
  currentsb = 1;
  CurrentSymbol = NULL;
  return Result;
}  /*** defFinishCommand ***/


Static boolean defCommand()
{
  boolean Result;
  char c;

  if (actualChar != 'D')
    return false;
  Result = true;
  c = ReadChar();
  blanks();
  return Result;
}  /*** defCommand ***/


Static boolean layerCommand()
{
  boolean Result;
  char *l,c;
  CodeDef cd;

  if (actualChar != 'L')
    return false;
  if (trace)
    fprintf(stderr,"LayerCommand\n");
  Result = true;
  c = ReadChar();
  blanks();
  l = malloc(5);
  shortname(l);
  cd.CType = Layer;
  cd.UU.Str = l;
  putcode(cd);
  
  return Result;
}  /*** layerCommand ***/


Static boolean userCommand()
{
  boolean Result;
  long i;
  DDIRNAME incFile;
  Char *STR2,cs[2];
  CodeDef cd;
  char c;

  if (!isdigit(actualChar))
    return false;
  STR2 = malloc(256);
  Result = true;
  sprintf(cs,"%c",actualChar);
  strcat(STR2,cs);
  dupChar = true;
  if (actualChar != '0') {
    while (ReadChar() != ';') {
      sprintf(cs,"%c",actualChar);
      strcat(STR2,cs);
    }
    dupChar = false;
    cd.CType = User;
    cd.UU.Str = STR2;
    putcode(cd);
    return Result;
  }
  if (includeFile) {
    includeFile = false;
    actualChar = ';';
    lineNumber = templine;
    dupChar = false;
    return Result;
  }
  i = 1;
  while (actualChar != ';') {
    c = ReadChar();
    incFile[i - 1] = lcase(actualChar);
    i++;
  }
  dupChar = false;
  return Result;
}  /***userCOmmand ***/


Static boolean commentCommand()
{
  boolean Result;
  char *st1,cs[2],c;
  CodeDef cd;
  int depth;

  if ((actualChar != '(') && (actualChar != '['))
    return false;
  dupChar = true;
  st1 = malloc(256);
  if (actualChar == '[')
      actualChar = '(';
  sprintf(cs,"%c",actualChar);
  strcat(st1,cs);
  Result = true;
  depth = 1;
  while (depth > 0) {
      c = ReadChar();
      if ((c == ')') ||  (c == ']'))
	  depth--;
      if ((c == '(') ||  (c == '['))
	  depth++;
      if (c == EOF)
	  depth = -1;
      sprintf(cs,"%c",actualChar);
      strcat(st1,cs);
  }
  dupChar = false;
  cd.CType = Comment;
  cd.UU.Str = st1;
  putcode(cd);
  if (actualChar == ']') 
      actualChar = ';';
  else
      c = ReadChar();
  return Result;
}  /*** commentCommand ***/


Static boolean primCommand PV();


Static boolean callCommand()
{
  boolean Result;
  long tnr, number;
  SymRef *sr;
  CodeDef cd;

  if (actualChar != 'C')
    return false;
  if (trace)
    fprintf(stderr,"Callcommand\n");
  Result = true;
  if (!readInteger(&number))   /*Number missing in callCommand*/
    error(5L);
  blanks();
  CurrentCall = (CallEntry *)malloc(sizeof(CallEntry));
  CurrentCall->num = number;
  CurrentCall->TList = NULL;
  while (translate() | mirror() | rotate()) ;
  cd.CType = Call;
  cd.UU.CPtr = CurrentCall;
  putcode(cd);
  /* Check for previous dependence */
  (CurrentSymbol == NULL?GlobalSymbol:CurrentSymbol)->calls = true;
  sr = ((CurrentSymbol == NULL)?GlobalSymbol:CurrentSymbol)->depend;
  while (sr != NULL) {
      if (sr->symbol == number) break;
      sr = sr->next;
  }
  if (sr == NULL) {
      /* Add dependence */
      sr = (SymRef *)malloc(sizeof(SymRef));
      sr->symbol = number;
      sr->next = ((CurrentSymbol == NULL)?GlobalSymbol:CurrentSymbol)->depend;
      ((CurrentSymbol == NULL)?GlobalSymbol:CurrentSymbol)->depend = sr;
  }
  return Result;
}  /*** callCOmmand ***/


Static boolean wireCommand()
{
  boolean Result;
  pointdef *p,*p1;
  long w,n;
  char c;
  int manht;

  if (actualChar != 'W')
    return false;
  if (trace)
    fprintf(stderr,"WireCommand\n");
  Result = true;
  c = ReadChar();
  if (!readInteger(&w))   /*width missing in wireCommand*/
    error(6L);
  /* Global Scaling */
  w = w*PreScaleA/PreScaleB;
  separator();
  n = path(&p,&manht,false);
  if (p != NULL) {
    n = WireToPolygon(&p, w);
    PolyToBoxes(p,n,manht);
  }
  return Result;
}  /*** wireCOmmand ***/


Static boolean roundFlashCommand()
{
  boolean Result;
  long diameter, cx, cy;
  char c;

  if (actualChar != 'R')
    return false;
  if (trace)
    fprintf(stderr,"RoundFlahCommand\n");
  fprintf(stderr,"RoundFlashCommand not allowed\n");
  Result = true;
  c = ReadChar();
  if (!readInteger(&diameter))   /*diameter missing in roundFlashCommand*/
    error(7L);
  separator();
  if (!point(&cx, &cy))   /*centre-definition missing in roundFlashCommand*/
    error(8L);
  return Result;
}  /*** roundFlashCommand ***/


Static boolean boxCommand()
{
  boolean Result;
  long l, w, cx, cy, dx, dy;
  CodeDef cd;
  char c;
  BoxRecord *br;

  if (actualChar != 'B')
    return false;
  if (trace)
    fprintf(stderr,"boxCommand\n");
  br = (BoxRecord *)malloc(sizeof(BoxRecord));
  br->scaled = false;
  Result = true;
  c = ReadChar();
  if (!readInteger(&br->l))   /*length missing in BoxRecordCommand*/
    error(9L);
  separator();
  if (!readInteger(&br->w))   /*width missing in BoxRecordCommand*/
    error(10L);
  separator();
  if (!point(&br->cx, &br->cy))   
      /*centre-points missing in BoxRecordCommand*/
    error(11L);
  separator();
  if (!point(&br->dx, &br->dy)) {
      /* direction vector not specified */
      br->dx = 0; br->dy = 0;
  }
  if (br->l == 0 || br->w == 0) {
    fprintf(stderr,"\nHmm, Box with length or width = 0 (dropped)");
    return Result;
  }
  /* Global Scaling */
  br->l = br->l*PreScaleA/PreScaleB;
  br->w = br->w*PreScaleA/PreScaleB;
  br->cx = br->cx*PreScaleA/PreScaleB;
  br->cy = br->cy*PreScaleA/PreScaleB;
  cd.CType = Box;
  cd.UU.B = br;
  putcode(cd);
  if (CurrentSymbol != NULL) {
  /* Find Offset */
  SymbolMinX = (br->cx - br->l/2)<SymbolMinX?br->cx - br->l/2:SymbolMinX;
  SymbolMinY = (br->cy - br->w/2)<SymbolMinY?br->cy - br->w/2:SymbolMinY;
  SymbolMaxX = (br->cx + br->l/2)>SymbolMaxX?br->cx + br->l/2:SymbolMaxX;
  SymbolMaxY = (br->cy + br->w/2)>SymbolMaxY?br->cy + br->w/2:SymbolMaxY;
  }
  return Result;
}  /*** boxCommand ***/


Static boolean polygonCommand()
{
  boolean Result;
  pointdef *p, *q;
  long n, d;
  char c;
  int manht;

  if (actualChar != 'P')
    return false;
  if (trace)
    fprintf(stderr,"polygonCommand\n");
  Result = true;
  c = ReadChar();
  n = path(&p,&manht,true);
  /* check for at least three different points */
  q = p;
  d = 0;
  if (q != NULL) {
      while (q->next != NULL) {
	  /* compare following points */
	  if ((q->x != q->next->x) || (q->y != q->next->y))
	      d++;
	  q = q->next;
      }
      /* last point */
      if ((q->x != p->x) || (q->y != p->y))
	  d++;
  }
  if ((n < 3) || (d < 3)) {
      fprintf(stderr,"No-area polygon dropped\n");
      displayPoints(&p);
      return Result;
  }
  if (p != NULL)
    PolyToBoxes(p,n,manht);
  return Result;
}  /*** polygonCommand ***/


Static boolean primCommand()
{
  boolean b;

  b = true;
  if (polygonCommand())
    return b;

  if (boxCommand())
    return b;

  if (roundFlashCommand())
    return b;

  if (wireCommand())
    return b;

  if (layerCommand())
    return b;

  if (callCommand())
    return b;

  if (!userCommand()) {
    if (!commentCommand())
      b = false;

  }

  return b;
}  /*** primCommand ***/


Static Void command()
{
  char c;
  
  if (primCommand())
    return;
  /** Primary command */
  if (defCommand()) {
    if (defDeleteCommand())
      return;
    /*Delete*/
    if (!defStartCommand()) {
      error(14L);
      return;
    }
    if (SymbolDef)   /*Symbol definition inside symbol not legal*/
      error(18L);
    if (!semicolon())   /*'Missing ;'*/
      error(12L);
    else {
      SymbolDef = true;
      blanks();
      while (primCommand()) {
	if (trace)
	  fprintf(stderr,"symbol-loop\n");
	if (!semicolon())   /*'Missing ;'*/
	  error(13L);
	blanks();
      }
      if (defCommand()) {
	if (!defFinishCommand())   /*First defCommand in symbol must be DF*/
	  error(22L);
      } else   /*illegale statement in symbol*/
	error(23L);
      if (trace)
	fprintf(stderr,"endSymbol:%c\n", actualChar);
    }
    SymbolDef = false;
    return;
  }
  error(15L);
  while (actualChar != ';')
    c = ReadChar();
  c = ReadChar();

}  /*** Command ***/


Static boolean endCommand()
{
  boolean Result;
  char c;
  CodeDef cd;

  if (actualChar != 'E')
    return false;
  c = ReadChar();
  Result = true;
  cd.CType = EndS;
  putcode(cd);
  return Result;
}


Static Void CifFile()
{
  /* skip blanks */
  blanks();
  while (!endCommand()) {
    blanks();
    command();
    if (!semicolon())   /*'Missing ;'*/
      error(16L);
  }
}  /*** cifFile ***/

Static Void writeCodeDef(cd,s)
CodeDef *cd;
SymbolDefs *s;
{
    long i1,i2,i3,i4;
    TransDef *tr;
    SymbolDefs *cs;
    FilterDef *fd;
    double tm[3][3];
    double c,ac,bc,x1,x2;

    switch (cd->CType) {
      case Call:
	printf("C %ld",cd->UU.CPtr->num);
	
	cs = FindSymbol(cd->UU.CPtr->num);
    
	/* init matrix */
	tm[0][0] = tm[1][1] = tm[2][2] = 1;
	tm[0][1] = tm[0][2] = 0;
	tm[1][0] = tm[1][2] = 0;
	tm[2][0] = tm[2][1] = 0;
	if (Offset) {
	    /* do T offset */
	    tm[0][0] += cs->Xmin * tm[0][2];
	    tm[0][1] += cs->Ymin * tm[0][2];
	    tm[1][0] += cs->Xmin * tm[1][2];
	    tm[1][1] += cs->Ymin * tm[1][2];
	    tm[2][0] += cs->Xmin * tm[2][2];
	    tm[2][1] += cs->Ymin * tm[2][2];
	}
	/* Make up the transformation-matrix */
	tr = cd->UU.CPtr->TList;
	while (tr != NULL) {
	    switch (tr->type) {
	      case Trans:
		if (s->blowup) {
		    x1 = tr->t1 * s->sa / s->sb;
		    x2 = tr->t2 * s->sa / s->sb;
		} else {
		    x1 = tr->t1;
		    x2 = tr->t2;
		}
		tm[0][0] += x1 * tm[0][2];
		tm[0][1] += x2 * tm[0][2];
		tm[1][0] += x1 * tm[1][2];
		tm[1][1] += x2 * tm[1][2];
		tm[2][0] += x1 * tm[2][2];
		tm[2][1] += x2 * tm[2][2];
		break;
	      case Rot:
		ac = tr->t1;
		bc = tr->t2;
		c = (long)sqrt(ac * ac + bc * bc);
		ac /= c;
		bc /= c;
		x1 = tm[0][0];
		x2 = tm[0][1];
		tm[0][0] = ac * x1 - bc * x2;
		tm[0][1] = bc * x1 + ac * x2;
		x1 = tm[1][0];
		x2 = tm[1][1];
		tm[1][0] = ac * x1 - bc * x2;
		tm[1][1] = bc * x1 + ac * x2;
		x1 = tm[2][0];
		x2 = tm[2][1];
		tm[2][0] = ac * x1 - bc * x2;
		tm[2][1] = bc * x1 + ac * x2;
		break;
	      case Mirror:
		if (tr->t1>0) {
		    /* MX */
		    tm[0][0] = -tm[0][0];
		    tm[1][0] = -tm[1][0];
		    tm[2][0] = -tm[2][0];
		} else {
		    /* MY */
		    tm[0][1] = -tm[0][1];
		    tm[1][1] = -tm[1][1];
		    tm[2][1] = -tm[2][1];
		}
		break;
	    };
	    tr = tr->next;
	}
	if (Offset) {
	    /* do T offset */
	    tm[0][0] -= s->Xmin * tm[0][2];
	    tm[0][1] -= s->Ymin * tm[0][2];
	    tm[1][0] -= s->Xmin * tm[1][2];
	    tm[1][1] -= s->Ymin * tm[1][2];
	    tm[2][0] -= s->Xmin * tm[2][2];
	    tm[2][1] -= s->Ymin * tm[2][2];
	}
#if 0
fprintf(stderr,"%f %f %f\n",tm[0][0],tm[0][1],tm[0][2]);
fprintf(stderr,"%f %f %f\n",tm[1][0],tm[1][1],tm[1][2]);
fprintf(stderr,"%f %f %f\n",tm[2][0],tm[2][1],tm[2][2]);
#endif

	/* write the transformation */
	if (tm[0][0] * tm[1][1] < 0)  {
	    /* mirror */
	    printf(" MX");
	    tm[0][0] = - tm[0][0];
	}
	if (tm[0][1] * tm[1][0] > 0) {
	    /* mirror */
	    printf(" MX");
	    tm[0][1] = - tm[0][1];
	}
	if ((((long)tm[0][1]) != 0) || (tm[1][1] < 0)) {
	    /* Rotate */
	    ac = tm[1][1]; bc = tm[0][1];
	    printf(" R %d %d",(long)ac,(long)bc);
	}
	printf(" T %ld %ld;\n",(long)(tm[2][0]*GlobalScaleA/GlobalScaleB),(long)(tm[2][1]*GlobalScaleA/GlobalScaleB));
	break;
      case Box:
	i1 = cd->UU.B->l;
	i2 = cd->UU.B->w;
	if (Offset) {
	    i3 = cd->UU.B->cx - s->Xmin;
	    i4 = cd->UU.B->cy - s->Ymin;
	} else {
	    i3 = cd->UU.B->cx;
	    i4 = cd->UU.B->cy;
	}
	if (s->blowup && !cd->UU.B->scaled) {
	    i1 = i1*s->sa/s->sb;
	    i2 = i2*s->sa/s->sb;
	    i3 = i3*s->sa/s->sb;
	    i4 = i4*s->sa/s->sb;
	};
	printf("B %ld %ld %ld %ld",
	       (long)(i1*GlobalScaleA/GlobalScaleB),
	       (long)(i2*GlobalScaleA/GlobalScaleB),
	       (long)(i3*GlobalScaleA/GlobalScaleB),
	       (long)(i4*GlobalScaleA/GlobalScaleB));
	if ((cd->UU.B->dx != 0) || (cd->UU.B->dy != 0))
	    /* write rotation */
	    printf(" %ld %ld",cd->UU.B->dx,cd->UU.B->dy);
	printf(";\n");
	break;
      case Layer:
	printf("L%s;\n",cd->UU.Str);
	break;
      case Comment:
	if (strncmp("(MBB",cd->UU.Str,4) != 0)
	    printf("%s ;\n",cd->UU.Str);
	break;
      case User:
	fd = UserFilter;
	i1 = true;
	while (fd != NULL) {
	    if (!strncmp(fd->com,cd->UU.Str,strlen(fd->com))) {
		i1 = false;
		break;
	    }
	    fd = fd->next;
	}
	if (i1) printf("%s;\n",cd->UU.Str);
	break;
      case Nop:
	break;
    }
}

Void findminmax(s)
SymbolDefs *s;
{
    SymbolDefs *cs;
    double tm[3][3];
    double c,ac,bc,x1,x2,y1,y2;
    CodeDef *cd;
    TransDef *tr;
    /* Preak through all calls */
    
    s->codep = 0;
    s->Xmin = LONG_MAX;
    s->Ymin = LONG_MAX;
    s->Xmax = LONG_MIN;
    s->Ymax = LONG_MIN;
    cd = getcodesym(s);
    while (cd->CType != EndS) {
	if (cd->CType == Call) {
	    /* init matrix */
	    tm[0][0] = tm[1][1] = tm[2][2] = 1;
	    tm[0][1] = tm[0][2] = 0;
	    tm[1][0] = tm[1][2] = 0;
	    tm[2][0] = tm[2][1] = 0;
	    cs = FindSymbol(cd->UU.CPtr->num);
	    tr = cd->UU.CPtr->TList;
	    while (tr != NULL) {
		switch (tr->type) {
		  case Trans:
		    if (s->blowup) {
			x1 = tr->t1 * s->sa / s->sb;
			x2 = tr->t2 * s->sa / s->sb;
		    } else {
			x1 = tr->t1;
			x2 = tr->t2;
		    }
		    tm[0][0] += x1 * tm[0][2];
		    tm[0][1] += x2 * tm[0][2];
		    tm[1][0] += x1 * tm[1][2];
		    tm[1][1] += x2 * tm[1][2];
		    tm[2][0] += x1 * tm[2][2];
		    tm[2][1] += x2 * tm[2][2];
		    break;
		  case Rot:
		    ac = tr->t1;
		    bc = tr->t2;
		    c = sqrt(ac * ac + bc * bc);
		    ac /= c;
		    bc /= c;
		    x1 = tm[0][0];
		    x2 = tm[0][1];
		    tm[0][0] = ac * x1 - bc * x2;
		    tm[0][1] = bc * x1 + ac * x2;
		    x1 = tm[1][0];
		    x2 = tm[1][1];
		    tm[1][0] = ac * x1 - bc * x2;
		    tm[1][1] = bc * x1 + ac * x2;
		    x1 = tm[2][0];
		    x2 = tm[2][1];
		    tm[2][0] = ac * x1 - bc * x2;
		    tm[2][1] = bc * x1 + ac * x2;
		    break;
		  case Mirror:
		    if (tr->t1>0) {
			/* MX */
			tm[0][0] = -tm[0][0];
			tm[1][0] = -tm[1][0];
			tm[2][0] = -tm[2][0];
		    } else {
			/* MY */
			tm[0][1] = -tm[0][1];
			tm[1][1] = -tm[1][1];
			tm[2][1] = -tm[2][1];
		    }
		    break;
		};
		tr = tr->next;
	    }
	    x1 = tm[0][0] * cs->Xmin + tm[1][0] * cs->Ymin + tm[2][0];
	    y1 = tm[0][1] * cs->Xmin + tm[1][1] * cs->Ymin + tm[2][1];
	    x2 = tm[0][0] * cs->Xmax + tm[1][0] * cs->Ymax + tm[2][0];
	    y2 = tm[0][1] * cs->Xmax + tm[1][1] * cs->Ymax + tm[2][1];
	    if (x1>x2) {
		/*exchange */
		ac = x1; x1 = x2; x2 = ac;
	    }
	    if (y1>y2) {
		/*exchnge*/
		ac = y1; y1 = y2; y2 = ac;
	    }
	    s->Xmin = ((x1 < (double)s->Xmin)?(long)x1:s->Xmin);
	    s->Ymin = ((y1 < (double)s->Ymin)?(long)y1:s->Ymin);
	    s->Xmax = ((x2 > (double)s->Xmax)?(long)x2:s->Xmax);
	    s->Ymax = ((y2 > (double)s->Ymax)?(long)y2:s->Ymax);
        }
	cd = getcodesym(s);
    }
}

Static Void WriteSymbols()
{
    /* go through all symbols and write out those without resolved */
    /* dependices. Then resolve all dependencies for the written symbol */
    CodeDef *cd;
    SymbolDefs *s,*t;
    SymRef *sr;
    int i, no_dep, wr = true;

    while (wr) {
      wr = false;
      for (i=1;i<nextSymbol+1;i++) {
	/* check dependencies */
       if (!symbol[i].written) {
	s = &symbol[i];
	no_dep = true;
	sr = s->depend;
	while (sr != NULL) {
	    t = FindSymbol(sr->symbol);
	    if (!(no_dep &= (t->written))) break;
	    sr = sr->next;
	}
	if (no_dep) {
	    /* write symbol */
	    wr = true;
	    if (s->blowup)
		printf("DS %ld %d %d ;\n",s->number,CifScaleA,CifScaleB);
	    else
		printf("DS %ld %ld %ld ;\n",s->number,s->sa*CifScaleA,s->sb*CifScaleB);
	    if (Naming) {
		/* write some name */
		if (CellName[0] != '\0') {
		    printf("9 %s",CellName);
		    if (Nid != 0) 
			printf("%d;\n",Nid++);
		    else {
			printf(";\n");
			Nid++;
		    }
		} else
		    printf("9 Cell%ld;\n",s->number);
	    } else {
		/* look for name */
		s->codep = 0;
		cd = getcodesym(s);
		while (cd->CType == User) {
		    writeCodeDef(cd,s);
		    cd = getcodesym(s);
		}
	    }
	    if (s->calls) {
		/* Peak through all calls and find MBB */
		/* Since thre is no dependencies we can safly assume */
		/* Every called symbol have correct MBB */
		findminmax(s);
	    }
	    /* write MBB */
	    if (Offset) {
		printf("(MBB;\nB %ld %ld %ld %ld;);\n",
		       (s->Xmax - s->Xmin)*GlobalScaleA/GlobalScaleB, 
		       (s->Ymax - s->Ymin)*GlobalScaleA/GlobalScaleB,
		       (long)(((s->Xmax - s->Xmin)/2)*GlobalScaleA/GlobalScaleB), 
		       (long)(((s->Ymax - s->Ymin)/2)*GlobalScaleA/GlobalScaleB));
	    } else {
		printf("(MBB;\nB %ld %ld %ld %ld;);\n",
		       (s->Xmax - s->Xmin)*GlobalScaleA/GlobalScaleB, 
		       (s->Ymax - s->Ymin)*GlobalScaleA/GlobalScaleB,
		   (long)((s->Xmin + (long)fabs((double)((s->Xmax - s->Xmin)/2)))*GlobalScaleA/GlobalScaleB), 
		   (long)((s->Ymin + (long)fabs((double)((s->Ymax - s->Ymin)/2)))*GlobalScaleA/GlobalScaleB));
	    }
	    s->codep = 0;
	    cd = getcodesym(s);
	    while (cd->CType != EndS) {
		writeCodeDef(cd,s);
		cd = getcodesym(s);
	    }
	    /* print end-of-symbol */
	    printf("DF;\n");
	    s->written = true;
	}
       }
      }
    }
    for (i=1;i<nextSymbol+1;i++) 
	if (!symbol[i].written) {
	    fprintf(stderr,"Symbol %ld could not resolv dependencies\n",symbol[i].number);
	    sr = symbol[i].depend;
	    while (sr != NULL) {
		fprintf(stderr,"Calling %ld with written=%d\n",sr->symbol,FindSymbol(sr->symbol)->written);
		sr = sr->next;
	    }
	}
		
    /* writing global code */
    s = GlobalSymbol;
    no_dep = true;
    sr = s->depend;
    while (sr != NULL) {
	    if (!(no_dep &= FindSymbol(sr->symbol)->written)) break;
	    sr = sr->next;
	}
    if (no_dep) {
	/* write symbol */
	    wr = true;
	    s->codep = 0;
	    while ((cd = getcodesym(s))->CType != EndS) 
		writeCodeDef(cd,s);
	    /* print end-of-file */
	    printf("E\n");
	    s->written = true;
	} else
	    fprintf(stderr,"Some calls in global code to undefined symboles\n");

}

Static Void SeparateHierarcy()
{
    int i,rs,writelayer;
    SymbolDefs *s, *sn;
    CodeDef *cd, dd;
    char l[5];
    SymRef *sr;

    rs = nextSymbol + 1;
    for (i=1;i<rs;i++) {
	/* Peak through all symbols and look for basic geometry */
	/* If nesessary, make a new symbol */
	s = &symbol[i];
	sn = NULL;
	writelayer = true;
	if (s->calls) {
	    s->codep = 0;
	    cd = getcodesym(s);
	    while (cd->CType != EndS) {
		switch (cd->CType) {
		  case Call:
		    /* Forget it! */
		    break;
		  case Box:
		    /* make a new symbol with basic geometry */
		    if (sn == NULL) {
			fprintf(stderr,"#%ld ",MaxSymbol+1);
			NewSymbol(MaxSymbol+1);
			sn = CurrentSymbol;
			sn->sa = s->sa;
			sn->sb = s->sb;
		    };
		    if (writelayer) {
			dd.CType = Layer;
			dd.UU.Str = malloc(5);
			strcpy(dd.UU.Str,l);
			putcode(dd);
			writelayer = false;
		    }
		    if (Offset) {
		    cd->UU.B->cx -= s->Xmin;
		    cd->UU.B->cy -= s->Ymin;
		}
		    /* Find Offset */
		    SymbolMinX = (cd->UU.B->cx - fabs((double)cd->UU.B->l/2))<SymbolMinX
			?cd->UU.B->cx - (long)fabs((double)cd->UU.B->l/2):SymbolMinX;
		    SymbolMinY = (cd->UU.B->cy - fabs((double)cd->UU.B->w/2))<SymbolMinY
			?cd->UU.B->cy - (long)fabs((double)cd->UU.B->w/2):SymbolMinY;
		    SymbolMaxX = (cd->UU.B->cx + cd->UU.B->l/2)>SymbolMaxX
			?cd->UU.B->cx + (long)fabs((double)cd->UU.B->l/2):SymbolMaxX;
		    SymbolMaxY = (cd->UU.B->cy + fabs((double)cd->UU.B->w/2))>SymbolMaxY
			?cd->UU.B->cy + (long)fabs((double)cd->UU.B->w/2):SymbolMaxY;
		    putcode(*cd); /* This should go to CurrentSymbol */
		    cd->CType = Nop;
		    break;
		  case Layer:
		    if (strcmp(cd->UU.Str,l)) {
			/* Change layer */
			strcpy(l,cd->UU.Str);
			writelayer = true;
		    }
		    break;
		  default:
		    break;
		}
		cd = getcodesym(s);
	    }
	    if (sn != NULL) {
		/* A new symbol has been generated */
		dd.CType=EndS;
		putcode(dd);
		/* Save offset */
		sn->Xmin = SymbolMinX;
		sn->Ymin = SymbolMinY;
		sn->Xmax = SymbolMaxX;
		sn->Ymax = SymbolMaxY;
		/* Add a new call to the old symbol */
		CurrentCall = (CallEntry *)malloc(sizeof(CallEntry));
		CurrentCall->num = sn->number;
		CurrentCall->TList = (TransDef *) malloc(sizeof(TransDef));
		CurrentCall->TList->type = Trans;
		if (Offset) {
		    CurrentCall->TList->t1 = s->Xmin; 
		    CurrentCall->TList->t2 = s->Ymin;
		} else {
		    CurrentCall->TList->t1 = 0; 
		    CurrentCall->TList->t2 = 0;
		}
		CurrentCall->TList->next = NULL;
		cd->CType = Call;
		cd->UU.CPtr = CurrentCall;
		CurrentSymbol = s;
		dd.CType=EndS;
		putcode(dd);
		/* Add dependence */
		sr = (SymRef *)malloc(sizeof(SymRef));
		sr->symbol = sn->number;
		sr->next = s->depend;
		s->depend = sr;
	    }
	}
    }
}

main(argc, argv)
int argc;
Char *argv[];
{
  Char STR2[256], *c1;
  int ap = 1;
  FilterDef *fd;

  CellName[0] = '\0';
  GlobalScaleA = GlobalScaleB = 1;
  CifScaleA = CifScaleB = 1;
  PreScaleA = PreScaleB = 1;
  while (ap < argc) {
      if (!strcmp(argv[ap],"-s")) {
	  if ((argc - ap) < 2) {
	      fprintf(stderr,"Global Scaling (-s) needs two integers\n");
	      exit(-1);
	  };
	  ap++;	
	  sscanf(argv[ap++],"%d",&GlobalScaleA);
	  sscanf(argv[ap++],"%d",&GlobalScaleB);
      } else
      if (!strcmp(argv[ap],"-c")) {
	  if ((argc - ap) < 2) {
	      fprintf(stderr,"CIFScaling (-s) needs two integers\n");
	      exit(-1);
	  };
	  ap++;	
	  sscanf(argv[ap++],"%d",&CifScaleA);
	  sscanf(argv[ap++],"%d",&CifScaleB);
      } else
      if (!strcmp(argv[ap],"-p")) {
	  if ((argc - ap) < 2) {
	      fprintf(stderr,"PreScaling (-s) needs two integers\n");
	      exit(-1);
	  };
	  ap++;	
	  sscanf(argv[ap++],"%d",&PreScaleA);
	  sscanf(argv[ap++],"%d",&PreScaleB);
      } else
      if (!strcmp(argv[ap],"-n")) {
	  Naming = true;
	  ap++;
      } else
      if (!strcmp(argv[ap],"-N")) {
	  Naming = true;
	  ap++;
	  sscanf(argv[ap++],"%s",CellName);
      } else
      if (!strcmp(argv[ap],"-b")) {
	  GlobalBlowUp = true;
	  ap++;
      } else
      if (!strcmp(argv[ap],"-o")) {
	  Offset = false;
	  ap++;
      } else
      if (!strcmp(argv[ap],"-z")) {
	  DropZeroArea = true;
	  ap++;
      } else
      if (!strcmp(argv[ap],"-h")) {
	  SepHierarcy = !SepHierarcy;
	  ap++;
      } else
      if (!strcmp(argv[ap],"-d")) {
	  if ((argc - ap) < 1) {
	      fprintf(stderr,"-d needs a number\n");
	      exit(-1);
	  }
	  ap++;
	  sscanf(argv[ap++],"%s",STR2);
	  c1 = STR2;
	  while (*c1 != '\0') {
	      if (!isdigit(*c1)) {
		  fprintf(stderr,"Only digits in UserCommand\n");
		  exit(-1);
	      }
	      c1++;
	  }
	  fd = (FilterDef *)malloc(sizeof(FilterDef));
	  fd->next = UserFilter;
	  UserFilter = fd;
	  fd->com = malloc(20);
	  strcpy(fd->com,STR2);
      } else 
	  {
	  fprintf(stderr,"Usage: boxify [-s a b] [-c a b] [-n] [-b] [-d n] [-o] [-h] [-z] < inputfile > outputfile\n");
	  exit(-1);
      }
  };
  includeFile = false;
  figureNumber = 0;
  fromFile = true;
  a = 1.0;
  b = 1.0;
  dd = 0.0;
  currentsa = 1;
  currentsb = 1;
  currentlayer = -1;
  GlobalSymbol = (SymbolDefs *)malloc(sizeof(SymbolDefs));
  GlobalSymbol->number = 0;
  GlobalSymbol->written = false;
  GlobalSymbol->blowup = false;
  GlobalSymbol->sa = 1;
  GlobalSymbol->sb = 1;
  GlobalSymbol->depend = NULL;
  GlobalSymbol->code[0] = NULL;
  GlobalSymbol->codep = 0;
  CurrentSymbol = NULL;
  nullcurrent();
  trace = false;
  dupChar = false;
  lineNumber = 1;
  inPos = 1;
  nextSymbol = 0;
  actualChar = getc(stdin);
  
  if (actualChar == '\n')
      actualChar = ' ';
  CifFile();
  if (SepHierarcy) {
      fprintf(stderr,"\nSeparating hierarcy\n");
      SeparateHierarcy();
  }
  fprintf(stderr,"\nWriting CIF-file...\n");
  WriteSymbols();


}





