
/* "WOL", an integrated circuit layout tool,
   Copyright (C) 1983, 1990 California Institute of Technology.
   Author: Massimo Sivilotti
   Thanks to: Glenn Gribble, Marty Sirkin, Sylvie Rychebusch
	      Maryann Mayer, Carver Mead, Rick Koshi, Torre Lande
   Maintainer: John Lazzaro
   Maintainers's address: lazzaro@hobiecat.cs.caltech.edu;
                          CB 425/ CU Boulder/Boulder CO 91125. 
			  Send questions, bug fixes, to this address.

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 (Version 1, 1989).

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. */

/* Output from p2c, the Pascal-to-C translator */
/* p2c: wolopt.text, line 9: Note: Range checking is OFF [216] */
/* p2c: wolopt.text, line 10: Note: Stack checking is OFF [217] */
/* p2c: wolopt.text, line 16: Note: Range checking is ON [216] */
/* From input file "wol_drc.text" */


/* Change these for testing */

/*$heap_dispose on$*/
/* Definitions for a drc program within the xtract environment*/

#include "global.h"


#define WOL_DRC_G
#include "wol_drc.h"


#define MEMORYHOG       true   /* try to use dynamic storage for big arrays */


/*    const drcrows = 300;
    const drccols = 100;      fine for BOBCATS */

#define drcrows         300
    /* changed from 250 to 200 on 4/6/88 by TPA so drc might work on Synaptics design*/


#define drccols         200   


#define LARGE           1000


#define printer_ok      false   /* print out LOTS of diagnostics if TRUE */


typedef short drcstruct[drcrows + 1][drccols][max_layer - min_layer + 1];
typedef short tabletype[max_layer - min_layer + 1][max_layer - min_layer + 1];
typedef long boxestype[max_layer - min_layer + 1][drcrows + 1];
typedef short tabletype2[max_layer - min_layer + 1][max_layer - min_layer + 1]
	      [max_layer - min_layer + 1];


Static short (*startb)[drccols][max_layer - min_layer + 1],
	     (*endb)[drccols][max_layer - min_layer + 1];
Static long (*boxeslen)[drcrows + 1];
Static short (*width)[max_layer - min_layer + 1],
	     (*separation)[max_layer - min_layer + 1],
	     (*overlap)[max_layer - min_layer + 1],
	     (*extension)[max_layer - min_layer + 1];
/*separation[i][j] is the minimum distance from layer i TO layer j */
Static short (*separation2)[max_layer - min_layer + 1][max_layer - min_layer + 1],
	     (*overlap2)[max_layer - min_layer + 1][max_layer - min_layer + 1];
Static long i;

Static boolean hdrcflag = true;
Static FILE *printer;
Static boolean vertical_drc;   /* true if magic xform in effect */
Static node *drc_list_head;   /* temp list of error boxes */

Static short window_llx, window_lly, window_urx, window_ury, window_buffer;
    /* number of lambda around perimeter */

Static void *drc_marker;   /* pointer for MARK/RELEASE if not MEMORYHOG */


Static void log_message(Char *s);


Static void swap_(short *a, short *b)
{
  short c;

  c = *a;
  *a = *b;
  *b = c;
}


Static void xform_vertical(short *llx, short *lly, short *urx, short *ury)
{
  if (vertical_drc) {  /*exchange x and y */
    swap_(llx, lly);
    swap_(urx, ury);
  }
}


/* Local variables for drc_clean_cell: */
struct LOC_drc_clean_cell {
  boolean found_one;
} ;

Local void delete_obj(node **obj, struct LOC_drc_clean_cell *LINK)
{
  /* nuke the object, and return pointer to child in 'obj' */
  node *old_child;

  LINK->found_one = true;
  old_child = NULL;
  if (*obj != NULL) {
    node_out_of_tree(*obj);   /* Clear node from tree.     */
    /*   old_child := obj^.child; */
    reshuffle((*obj)->child);   /* Put its children back into tree */
    (*obj)->child = NULL;   /* and clear node's children   */
    recl_nodes(obj);
  }
  *obj = NULL;   /*old_child*/
}

Local void clean_node(node *a, struct LOC_drc_clean_cell *LINK)
{
  while (a != NULL) {
    clean_node(a->child, LINK);
    if (a->layer == error_layer)
      delete_obj(&a, LINK);
    else
      a = a->next;
  }
}


void drc_clean_cell(void)
{
  struct LOC_drc_clean_cell V;

  /* repeatedly clean up the cell, until no more error boxes are found */
  do {
    V.found_one = false;
    clean_node(main_, &V);
  } while (V.found_one);
}


void drc_cleanup(void)
{
  if (drc_initialized) {
    /*  DO NOT TRY TO DISPOSE THINGS !!!
    dispose(startb);
    dispose(endb);
    dispose(boxeslen);
    dispose(width);
    dispose(separation);
    dispose(overlap);
    dispose(extension);
    dispose(separation2);
    dispose(overlap2);       */
    /*$if not MEMORYHOG$
               release (drc_marker);
$end$*/
    TRY(try1);
      if (printer != NULL)
	fclose(printer);
      printer = NULL;
    RECOVER(try1);
      ;
    ENDTRY(try1);
  }
  drc_initialized = false;
}


Static Char *layername(Char *Result, short i)
{
  /* make SURE layer names are 5 or fewer characters !!!! */
  switch (i) {

  case 1:
    strcpy(Result, "POLY");
    break;

  case 2:
    strcpy(Result, "DIFF");
    break;

  case 3:
    strcpy(Result, "METAL");
    break;

  case 4:
    strcpy(Result, "WELL");
    break;

  case 5:
    strcpy(Result, "POLYCUT");
    break;

  case 6:
    strcpy(Result, "DIFFCUT");
    break;

  case 8:
    strcpy(Result, "METAL2");
    break;

  case 9:
    strcpy(Result, "SELECT");
    break;

  case 10:
    strcpy(Result, "VIA");
    break;

  case 11:   /***/
    strcpy(Result, "POLY2");
    break;

  case 12:   /***/
    strcpy(Result, "POLY2CUT");
    break;

  default:
    sprintf(Result, "**unknown layer: %d", i);
    break;
  }
  return Result;
}


Local short lookup(Char *str)
{
  if (strcicmp(str, "POLY") == 0)
    return 1;
  else if (strcicmp(str, "DIFF") == 0)
    return 2;
  else if (strcicmp(str, "METAL") == 0)
    return 3;
  else if (strcicmp(str, "WELL") == 0)
    return 4;
  else if (strcicmp(str, "POLYCUT") == 0)
    return 5;
  else if (strcicmp(str, "DIFFCUT") == 0)
    return 6;
  else if (strcicmp(str, "METAL2") == 0)
    return 8;
  else if (strcicmp(str, "SELECT") == 0)
    return 9;
  else if (strcicmp(str, "VIA") == 0)
    return 10;
  else if (strcicmp(str, "POLY2") == 0)
    return 11;   /***/
  else if (strcicmp(str, "POLY2CUT") == 0)
    return 12;   /***/
  else {
    printf("WOW!  Unknown layer: %s\n", str);
    return 0;
  }
}


Static void drc_parse(Char *fname)
{
  FILE *f;
  Char line[81], arg1s[81], arg2s[81], arg3s[81], cmd[81];
  short arg1, arg2, arg3, value;
  long junk;
  Char *TEMP;
  Char *STR1;
  Char STR2[81], STR3[81], STR5[81];

  f = NULL;
  if (f != NULL)
    f = freopen(fname, "r", f);
  else
    f = fopen(fname, "r");
  if (f == NULL)
    _EscIO(FileNotFound);
  while (fgets(line, 81, f) != NULL) {
    TEMP = strchr(line, '\n');
    if (TEMP != NULL)
      *TEMP = 0;
    strword(line, cmd);
    if (strcicmp(cmd, "WIDTH") == 0) {
      strword(line, arg1s);
      arg1 = lookup(arg1s);
      value = strtol(line, &STR1, 10);
      junk = STR1 - line + 1;
      width[arg1 - min_layer][arg1 - min_layer] = value;
      fprintf(printer, "WIDTH %s = %d\n", layername(STR3, arg1), value);
      continue;
    }

    if (strcicmp(cmd, "SEPARATION") == 0) {
      strword(line, arg1s);
      strword(line, arg2s);
      arg1 = lookup(arg1s);
      arg2 = lookup(arg2s);
      value = strtol(line, &STR1, 10);
      junk = STR1 - line + 1;
      separation[arg1 - min_layer][arg2 - min_layer] = value;
      separation[arg2 - min_layer][arg1 - min_layer] = value;
      fprintf(printer, "SEPARATION %s %s = %d\n",
	      layername(STR3, arg1), layername(STR5, arg2), value);
      continue;
    }
    if (strcicmp(cmd, "OVERLAP") == 0) {
      strword(line, arg1s);
      strword(line, arg2s);
      arg1 = lookup(arg1s);
      arg2 = lookup(arg2s);
      value = strtol(line, &STR1, 10);
      junk = STR1 - line + 1;
      /* layer arg1 must overlap arg2 by value */
      overlap[arg2 - min_layer][arg1 - min_layer] = value;
      fprintf(printer, "OVERLAP %s %s = %d\n",
	      layername(STR3, arg1), layername(STR5, arg2), value);
      continue;
    }
    if (strcicmp(cmd, "EXTENSION") == 0) {
      strword(line, arg1s);
      strword(line, arg2s);
      arg1 = lookup(arg1s);
      arg2 = lookup(arg2s);
      value = strtol(line, &STR1, 10);
      junk = STR1 - line + 1;
      extension[arg1 - min_layer][arg2 - min_layer] = value;
      fprintf(printer, "EXTENSION %s %s = %d\n",
	      layername(STR3, arg1), layername(STR5, arg2), value);
      continue;
    }
    if (strcicmp(cmd, "OVERLAP2") == 0) {
      strword(line, arg1s);
      strword(line, arg2s);
      strword(line, arg3s);
      arg1 = lookup(arg1s);
      arg2 = lookup(arg2s);
      arg3 = lookup(arg3s);
      value = strtol(line, &STR1, 10);
      junk = STR1 - line + 1;
      overlap2[arg1 - min_layer][arg2 - min_layer][arg3 - min_layer] = value;
      fprintf(printer, "OVERLAP2 %s+%s %s = %d\n",
	      layername(STR3, arg1), layername(STR5, arg2),
	      layername(STR2, arg3), value);
      continue;
    }
    if (strcicmp(cmd, "SEPARATION2") != 0)
      continue;
    strword(line, arg1s);
    strword(line, arg2s);
    strword(line, arg3s);
    arg1 = lookup(arg1s);
    arg2 = lookup(arg2s);
    arg3 = lookup(arg3s);
    value = strtol(line, &STR1, 10);
    junk = STR1 - line + 1;
    separation2[arg1 - min_layer][arg2 - min_layer][arg3 - min_layer] = value;
    fprintf(printer, "SEPARATION2 %s+%s %s = %d\n",
	    layername(STR3, arg1), layername(STR5, arg2),
	    layername(STR2, arg3), value);
  }
  if (f != NULL)
    fclose(f);
  f = NULL;
  if (f != NULL)
    fclose(f);
}


Static short index_(short layer, short row, short x)
{
  /* return the INDEX into the boxes array:
       return 0 if x < startb^[1]
       return n if startb^[n] <= x <= endb^[n]
       return -n if endb^[n] < x < startb^[n+1]
       return -boxeslen if endb^[boxeslen] < x
   */
  short l, r, test, result;

  l = 1;
  if (row < 0) {
    result = 0;
    return result;
  }
  r = boxeslen[layer - min_layer][row];
  if (r == 0 || x < startb[row][0][layer - min_layer]) {
    result = 0;
    return result;
  }
  /*$if printer_ok$
               writeln (printer,'index: x = ',x:0,' y = ',row:0,
                                '; layer = ',layername(layer),'; result = ',result:0);
$end$*/
  do {
    test = (l + r) / 2;
    if (x < startb[row][test - 1][layer - min_layer])
      r = test - 1;
    else
      l = test + 1;
  } while ((x < startb[row][test - 1][layer - min_layer] ||
	    x >= startb[row][test][layer - min_layer]) && l <= r);
  if (test == boxeslen[layer - min_layer][row] &&
      x > endb[row][test - 1][layer - min_layer]) {
    result = -boxeslen[layer - min_layer][row];
    return result;
  }
  if (x <= endb[row][test - 1][layer - min_layer])
    result = test;
  else
    result = -test;
  return result;
}


Static short nextstart(short layer, short row, short x)
{
  /* always return the lambda coordinate of the NEXT positive transition
     of layer on row starting at position x */
  short tmp, result;

  if (row < 0) {
    result = LARGE;
    return result;
  }
  if (boxeslen[layer - min_layer][row] == 0) {
    result = LARGE;
    return result;
  }
  tmp = index_(layer, row, x);
  if (tmp == 0) {
    result = startb[row][0][layer - min_layer];
    return result;
  }
  if (tmp < 0)
    tmp = -tmp;
  if (x == startb[row][tmp - 1][layer - min_layer]) {
    result = x;
    return result;
  }
  if (tmp == boxeslen[layer - min_layer][row])
    result = LARGE;
  else
    result = startb[row][tmp][layer - min_layer];
  /*$if printer_ok$
      writeln (printer,'nextstart: x = ',x:0,'; layer = ',layername(layer),'; result = ',result:0);
$end$*/
  return result;
}


Static short prevend(short layer, short row, short x)
{
  /* always return the lambda coordinate of the PREVious negative transition
     of layer on row relative to position x */
  /* if there is no previous end, return -LARGE */
  short tmp, result;

  if (row < 0 || boxeslen[layer - min_layer][row] == 0) {
    result = -LARGE;
    return result;
  }
  tmp = index_(layer, row, x);
  if (tmp == 0) {
    result = -LARGE;
    return result;
  }
  /*$if false$
                     if tmp < 0 then tmp := -tmp;
                     if x <= endb^[row][tmp][layer] then
                        begin
                          if tmp = 1 then result := -LARGE  { no previous end }
                                     else result := endb^[row][tmp-1][layer];
                        end
                      else result := endb^[row][tmp][layer];
$end$*/
  if (tmp < 0) {
    result = endb[row][-tmp - 1][layer - min_layer];
    return result;
  }
  if (tmp == 1)
    result = -LARGE;
  else
    result = endb[row][tmp - 2][layer - min_layer];
  /*$if printer_ok$
      writeln (printer,'prevend: x = ',x:0,'; layer = ',layername(layer),'; result = ',result:0);
$end$*/
  return result;
}


Static short prevstart(short layer, short row, short x)
{
  /* always return the lambda coordinate of the PREVious positive transition
     of layer on row relative to position x */
  /* if we are not already in the middle of 'layer', return LARGE */
  short tmp, result;

  if (row < 0 || boxeslen[layer - min_layer][row] == 0) {
    result = LARGE;
    return result;
  }
  tmp = index_(layer, row, x);
  if (tmp > 0)
    result = startb[row][tmp - 1][layer - min_layer];
  else
    result = LARGE;
  /*$if printer_ok$
      writeln (printer,'prevstart: x = ',x:0,'; layer = ',layername(layer),'; result = ',result:0);
$end$*/
  return result;
}


Static short nextend(short layer, short row, short x)
{
  /* always return the lambda coordinate of the NEXT negative transition
     of layer on row relative to position x */
  /* if we are not already in the middle of 'layer', return -LARGE */
  short tmp, result;

  if (row < 0 || boxeslen[layer - min_layer][row] == 0) {
    result = -LARGE;
    return result;
  }
  tmp = index_(layer, row, x);
  if (tmp > 0)
    result = endb[row][tmp - 1][layer - min_layer];
  else
    result = -LARGE;
  /*$if printer_ok$
      writeln (printer,'nextend: x = ',x:0,'; layer = ',layername(layer),'; result = ',result:0);
$end$*/
  return result;
}


Static boolean inside(short layer, short row, short x)
{
  /* returns TRUE if position x is inside 'layer' on 'row' */
  /* if we are not already in the middle of 'layer', return -LARGE */
  return (index_(layer, row, x) > 0);
}


Static void quicksort(long l, long r, long layer, long row)
{
  long v, t, t2, i, j;

  if (r <= l)
    return;
  v = startb[row][r - 1][layer - min_layer];
  i = l - 1;
  j = r;
  do {
    do {
      i++;
    } while (startb[row][i - 1][layer - min_layer] < v);
    do {
      j--;
    } while (j != 1 && startb[row][j - 1][layer - min_layer] > v);
    /* MAS  */
    t = startb[row][i - 1][layer - min_layer];
    startb[row][i - 1][layer - min_layer] = startb[row][j - 1]
      [layer - min_layer];
    startb[row][j - 1][layer - min_layer] = t;
    t2 = endb[row][i - 1][layer - min_layer];
    endb[row][i - 1][layer - min_layer] = endb[row][j - 1][layer - min_layer];
    endb[row][j - 1][layer - min_layer] = t2;
  } while (j > i);
  startb[row][j - 1][layer - min_layer] = startb[row][i - 1]
    [layer - min_layer];
  startb[row][i - 1][layer - min_layer] = startb[row][r - 1]
    [layer - min_layer];
  startb[row][r - 1][layer - min_layer] = t;
  endb[row][j - 1][layer - min_layer] = endb[row][i - 1][layer - min_layer];
  endb[row][i - 1][layer - min_layer] = endb[row][r - 1][layer - min_layer];
  endb[row][r - 1][layer - min_layer] = t2;
  quicksort(l, i - 1, layer, row);
  quicksort(i + 1, r, layer, row);
}


Static void merge(long layer, long row)
{
  /* little FSM that unifies boxes into largest horizontal extents */
  long currentseg, currentpos;

  currentseg = 1;
  currentpos = 1;
  while (currentpos <= boxeslen[layer - min_layer][row]) {
    if (startb[row][currentpos - 1][layer - min_layer] > endb[row]
	[currentseg - 1][layer - min_layer])
    {  /* start new segment */
      currentseg++;
      startb[row][currentseg - 1][layer - min_layer] = startb[row]
	[currentpos - 1][layer - min_layer];
      endb[row][currentseg - 1][layer - min_layer] = endb[row][currentpos - 1]
	[layer - min_layer];
    }
    if (startb[row][currentpos - 1][layer - min_layer] <= endb[row]
	[currentseg - 1][layer - min_layer] &&
	endb[row][currentpos - 1][layer - min_layer] > endb[row]
	[currentseg - 1][layer - min_layer])
      endb[row][currentseg - 1][layer - min_layer] = endb[row][currentpos - 1]
	[layer - min_layer];
    currentpos++;
  }
  boxeslen[layer - min_layer][row] = currentseg;
}


Static void sort_rows(void)
{
  short row, layer;

  for (layer = min_layer; layer <= max_layer; layer++) {
    for (row = 0; row <= drcrows; row++) {
      if (boxeslen[layer - min_layer][row] > 1) {
	quicksort(1, boxeslen[layer - min_layer][row], layer, row);
	merge(layer, row);
      }
    }
  }
}



Static void add_to_row(short row, short lx, short rx, short layer)
{
  short len;
  Char STR1[256];

  len = boxeslen[layer - min_layer][row] + 1;
  if (len > drccols) {
    sprintf(STR1, "  Too many horizontal segments (drccols = %ld)",
	    (long)drccols);
    log_message(STR1);
    sprintf(STR1, "Too many horizontal segments (drccols = %ld)",
	    (long)drccols);
    show_message(STR1, false);
    _Escape(10);
  }
  startb[row][len - 1][layer - min_layer] = lx;
  endb[row][len - 1][layer - min_layer] = rx;
  boxeslen[layer - min_layer][row] = len;
  /*$if false$
          if  len = drccols then    { try to do garbage collection }
            begin
               quicksort (1, boxeslen^[layer][row], layer,row);
               merge (layer, row);
            end;
$end$*/
}



Static void drc_addbox(node *box)
{
  long i, FORLIM;

  if (vertical_drc) {
    FORLIM = box->ur.x;
    for (i = box->ll.x; i <= FORLIM; i++)
      add_to_row(i, box->ll.y, box->ur.y, box->layer);
  } else {
    FORLIM = box->ur.y;
    for (i = box->ll.y; i <= FORLIM; i++)
      add_to_row(i, box->ll.x, box->ur.x, box->layer);
  }
}


Static void drc_buffer(node *box)
{
  while (box != NULL) {
    drc_addbox(box);
    drc_buffer(box->child);
    box = box->next;
  }
}


Static void print_table(short (*table)[max_layer - min_layer + 1],
			Char *tablename)
{
  short i, j;
  Char STR3[81];

  fprintf(printer, "%10s   ", tablename);
  for (i = min_layer; i <= 6; i++)   /*max_layer*/
    fprintf(printer, "%5s", layername(STR3, i));
  putc('\n', printer);
  for (i = min_layer; i <= 6; i++) {   /*max_layer*/
    fprintf(printer, "%10s:  ", layername(STR3, i));
    for (j = min_layer; j <= 6; j++)   /*max_layer*/
      fprintf(printer, "%5d", table[i - min_layer][j - min_layer]);
    putc('\n', printer);
  }
}


Static void print_tables(void)
{
  print_table(separation, "SEP");
  print_table(width, "WIDTH");
  print_table(overlap, "OVERLAP");
  print_table(extension, "EXT");
}


Static void print_row(long i, long layer)
{
  long j, FORLIM;

  FORLIM = boxeslen[layer - min_layer][i];
  for (j = 0; j < FORLIM; j++)   /*printer,*/
    printf("%5d%3d",
	   startb[i][j][layer - min_layer], endb[i][j][layer - min_layer]);
  /*(printer)*/
  putchar('\n');
}


Static void drc_print(void)
{
  short color, row;

  for (color = min_layer; color <= max_layer; color++) {
    fprintf(printer, "color = %d\n", color);
    for (row = 0; row <= drcrows; row++) {
      if (boxeslen[color - min_layer][row] > 0) {
	fprintf(printer, "row = %d:  ", row);
	print_row(row, color);
      }
    }
  }
}


Static void get_drc_rules(void)
{
  /* sequentially search './drc.rules', '~/drc.rules', '/lib/wollib/drc.rules' */
  FILE *inf_fil;
  Char filename[81];

  inf_fil = NULL;
  TRY(try2);
    strcpy(filename, "drc.rules");
    if (inf_fil != NULL)
      inf_fil = freopen(filename, "r", inf_fil);
    else
      inf_fil = fopen(filename, "r");
    if (inf_fil == NULL) {
      P_escapecode = -10;
      P_ioresult = FileNotFound;
      goto _Ltry2;
    }
  RECOVER2(try2,_Ltry2);
    TRY(try3);
      sprintf(filename, "/usr/%s/drc.rules", wol_username);
      if (P_escapecode != -10 && P_escapecode != 10)
	goto _Ltry3;
      if (inf_fil != NULL)
	inf_fil = freopen(filename, "r", inf_fil);
      else
	inf_fil = fopen(filename, "r");
      if (inf_fil == NULL) {
	P_escapecode = -10;
	P_ioresult = FileNotFound;
	goto _Ltry3;
      }
    RECOVER2(try3,_Ltry3);
      sprintf(filename, "%sdrc.rules", WolLib);
      if (P_escapecode != -10 && P_escapecode != 10)
	_Escape(P_escapecode);
      if (inf_fil != NULL)
	inf_fil = freopen(filename, "r", inf_fil);
      else
	inf_fil = fopen(filename, "r");
      if (inf_fil == NULL)
	_EscIO(FileNotFound);
    ENDTRY(try3);
  ENDTRY(try2);
  if (inf_fil != NULL)
    fclose(inf_fil);
  inf_fil = NULL;
  drc_parse(filename);
  if (inf_fil != NULL)
    fclose(inf_fil);
}


/*extern void asm_newbytes_(void **p, long z);*/


void drc_init(void)
{
  /*first time, allocate memory; each time,  clear out data structures*/
  if (printer != NULL)
    printer = freopen("drc.out", "a", printer);
  else
    printer = fopen("drc.out", "w");
  if (printer == NULL)
    _EscIO(FileNotFound);
  if (drc_initialized)
    {
      if (hdrcflag)
	fprintf(printer, "Log of Errors (horizontal) \n");
      else
	fprintf(printer, "Log of Errors (vertical) \n");
      hdrcflag = !hdrcflag;
    }
  if (!drc_initialized) {
    drc_list_head = NULL;   /* temporary list of error boxes */
    vertical_drc = false;   /* first time through only */
    fprintf(printer, "initializing drc data structures \n");
    if (startb == NULL)
      startb = Malloc(sizeof(drcstruct));
    if (endb == NULL)
      endb = Malloc(sizeof(drcstruct));
    if (boxeslen == NULL)
      boxeslen = Malloc(sizeof(boxestype));

    if (width == NULL)
      width = Malloc(sizeof(tabletype));
    if (separation == NULL)
      separation = Malloc(sizeof(tabletype));
    if (overlap == NULL)
      overlap = Malloc(sizeof(tabletype));
    if (extension == NULL)
      extension = Malloc(sizeof(tabletype));
    if (separation2 == NULL)
      separation2 = Malloc(sizeof(tabletype2));
    if (overlap2 == NULL)
      overlap2 = Malloc(sizeof(tabletype2));
    /*$if not MEMORYHOG$
         core_mark (drc_marker);
         asm_newbytes(startb,   sizeof(drcstruct));
         asm_newbytes(endb,     sizeof(drcstruct));
         asm_newbytes(boxeslen, sizeof(boxestype));

         asm_newbytes(width,      sizeof(tabletype));
         asm_newbytes(separation, sizeof(tabletype));
         asm_newbytes(overlap,    sizeof(tabletype));
         asm_newbytes(extension,  sizeof(tabletype));


         asm_newbytes(separation2, sizeof(tabletype2));
         asm_newbytes(overlap2,    sizeof(tabletype2));
$end$*/


    memset(separation, 255, sizeof(tabletype));
    memset(width, 255, sizeof(tabletype));
    memset(overlap, 255, sizeof(tabletype));
    memset(extension, 255, sizeof(tabletype));
    memset(separation2, 255, sizeof(tabletype2));
    memset(overlap2, 255, sizeof(tabletype2));
    get_drc_rules();
  }
  memset(startb, 0, sizeof(drcstruct));
  memset(endb, 0, sizeof(drcstruct));
  memset(boxeslen, 0, sizeof(boxestype));

  drc_initialized = true;
}


Static void add_wire_to_list(point p1, point p2, short layer, Char *shorterr)
{
  node *data_node;

  data_node = get_a_node();   /* Get a node */
  data_node->ll = p1;   /* Stuff points, and layer in it */
  data_node->ur = p2;
  data_node->layer = layer;
  strcpy(data_node->name, shorterr);
  data_node->child = NULL;
  data_node->next = drc_list_head;
  drc_list_head = data_node;
}


Static void dump_geom_list(void)
{
  node *ptr;

  ptr = drc_list_head;
  while (ptr != NULL) {
    add_wire(ptr->ll, ptr->ur, error_layer, ptr->name, NULL);
    ptr = ptr->next;
  }
  recl_nodes(&drc_list_head);
  drc_list_head = NULL;
}


Static void drc_error(short llx, short lly, short urx, short ury,
		      Char *errstr, Char *shorterr)
{
  point p1, p2;

  xform_vertical(&llx, &lly, &urx, &ury);
  llx += window_llx - window_buffer;
  lly += window_lly - window_buffer;
  urx += window_llx - window_buffer;
  ury += window_lly - window_buffer;
  fprintf(printer, "%s: (%d,%d) (%d,%d)\n", errstr, llx, lly, urx, ury);
  printf("%s: (%d,%d) (%d,%d)\n", errstr, llx, lly, urx, ury);
  if (llx == urx)   /*make box non-zero*/
    urx++;
  if (lly == ury)
    ury++;
  p1 = change_to_point(llx, lly);
  p2 = change_to_point(urx, ury);
  add_wire_to_list(p1, p2, error_layer, shorterr);
}


Static void drc_separation(node *box, short against_layer, short rule)
{
  short llx, urx, lly, ury, layer, row, tmp;
  Char STR1[81], STR2[81];
  Char STR3[184];
  Char STR4[256];
  Char STR5[256], STR6[256];
  Char STR7[256];
  short FORLIM;

  llx = box->ll.x;
  lly = box->ll.y;
  urx = box->ur.x;
  ury = box->ur.y;
  xform_vertical(&llx, &lly, &urx, &ury);
  layer = box->layer;

  if (nextend(layer, ury, urx) == urx) {
    /* do the following only if the box is on the convex hull */
    if (against_layer != layer && inside(against_layer, ury, urx)) {
      sprintf(STR3, "SEPARATION error (%s,%s)",
	      layername(STR1, layer), layername(STR2, against_layer));
      sprintf(STR7, "SEP %d,%d", layer, against_layer);
      sprintf(STR4, "%.10s", STR7);
      drc_error(urx, ury, urx + rule, ury + rule, STR3, STR4);
      goto _L96;
    }
    for (row = ury; row < ury + rule; row++)
    {  /* check above and to the right */
      tmp = nextstart(against_layer, row, urx);
      if (tmp - urx < rule) {
	sprintf(STR3, "SEPARATION error (%s,%s)",
		layername(STR1, layer), layername(STR2, against_layer));
	sprintf(STR5, "SEP %d,%d", layer, against_layer);
	sprintf(STR4, "%.10s", STR5);
	drc_error(urx, ury, tmp, row, STR3, STR4);
	/*
	writeln('corner_violation = ',corner_violation);
	writeln('inside at position ',urx:0,' gives ',inside(against_layer,row,urx));
	writeln('  boxeslen = ',boxeslen^[against_layer][row]);
	writeln('  Found error on row = ',row:0,'; row of corner = ',ury:0);
	for tmp := 1 to boxeslen^[against_layer][row] do
	    writeln(startb^[row][tmp][against_layer],
	            endb^[row][tmp][against_layer]);
	*/
	goto _L96;
      }
    }
  }

_L96:
  if (nextend(layer, lly, urx) == urx) {
    /* do the following only if the box is on the convex hull */
    if (against_layer != layer && inside(against_layer, lly, urx)) {
      sprintf(STR3, "SEPARATION error (%s,%s)",
	      layername(STR1, layer), layername(STR2, against_layer));
      sprintf(STR6, "SEP %d,%d", layer, against_layer);
      sprintf(STR4, "%.10s", STR6);
      drc_error(urx, lly, urx + rule, lly - rule, STR3, STR4);
      goto _L97;
    }
    FORLIM = lly - rule;
    for (row = lly; row > FORLIM; row--) {  /* check below and to the right */
      tmp = nextstart(against_layer, row, urx);
      if (tmp - urx < rule) {
	sprintf(STR3, "SEPARATION error (%s,%s)",
		layername(STR1, layer), layername(STR2, against_layer));
	sprintf(STR5, "SEP %d,%d", layer, against_layer);
	sprintf(STR4, "%.10s", STR5);
	drc_error(urx, lly, tmp, row, STR3, STR4);
	goto _L97;
      }
    }
  }

_L97:
  if (prevstart(layer, ury, llx) == llx) {
    /* do the following only if the box is on the convex hull */
    if (against_layer != layer && inside(against_layer, ury, llx)) {
      sprintf(STR3, "SEPARATION error (%s,%s)",
	      layername(STR1, layer), layername(STR2, against_layer));
      sprintf(STR6, "SEP %d,%d", layer, against_layer);
      sprintf(STR4, "%.10s", STR6);
      drc_error(llx, ury, urx - rule, lly + rule, STR3, STR4);
      goto _L98;
    }
    for (row = ury; row < ury + rule; row++)
    {  /* check above and to the left */
      tmp = prevend(against_layer, row, llx);
      if (llx - tmp < rule) {
	sprintf(STR3, "SEPARATION error (%s,%s)",
		layername(STR1, layer), layername(STR2, against_layer));
	sprintf(STR5, "SEP %d,%d", layer, against_layer);
	sprintf(STR4, "%.10s", STR5);
	drc_error(tmp, row, llx, ury, STR3, STR4);
	goto _L98;
      }
    }
  }

_L98:
  if (prevstart(layer, lly, llx) == llx) {
    /* do the following only if the box is on the convex hull */
    if (against_layer != layer && inside(against_layer, lly, llx)) {
      sprintf(STR3, "SEPARATION error (%s,%s)",
	      layername(STR1, layer), layername(STR2, against_layer));
      sprintf(STR6, "SEP %d,%d", layer, against_layer);
      sprintf(STR4, "%.10s", STR6);
      drc_error(llx, lly, urx - rule, lly - rule, STR3, STR4);
      goto _L99;
    }
    FORLIM = lly - rule;
    for (row = lly; row > FORLIM; row--) {  /* check below and to the left */
      tmp = prevend(against_layer, row, llx);
      if (llx - tmp < rule) {
	sprintf(STR3, "SEPARATION error (%s,%s)",
		layername(STR1, layer), layername(STR2, against_layer));
	sprintf(STR5, "SEP %d,%d", layer, against_layer);
	sprintf(STR4, "%.10s", STR5);
	drc_error(tmp, row, llx, lly, STR3, STR4);
	goto _L99;
      }
    }
  }
_L99: ;
}


Static void drc_overlap(node *box, short against_layer, short rule)
{
  short llx, urx, lly, ury, layer, tmp, row, errbox;
  Char STR1[81], STR2[81];
  Char STR3[180];
  Char STR4[256];
  Char STR5[256], STR7[256];

  llx = box->ll.x;
  lly = box->ll.y;
  urx = box->ur.x;
  ury = box->ur.y;
  xform_vertical(&llx, &lly, &urx, &ury);
  layer = box->layer;
  for (row = lly - rule + 1; row < ury + rule; row++)
  {  /* check to the right */
    tmp = nextend(against_layer, row, urx);
    if (tmp - urx < rule) {
      if (row > ury)
	errbox = ury;
      else if (row < lly)
	errbox = lly;
      else
	errbox = row;
      if (tmp == -LARGE)
	tmp = urx + rule;
      sprintf(STR3, "OVERLAP error (%s,%s)",
	      layername(STR1, layer), layername(STR2, against_layer));
      sprintf(STR7, "OVER %d,%d", layer, against_layer);
      sprintf(STR4, "%.10s", STR7);
      drc_error(urx, errbox, tmp, row, STR3, STR4);
    }
  }
  for (row = lly - rule + 1; row < ury + rule; row++) {
	/* check to the left */
	  tmp = prevstart(against_layer, row, llx);
    if (llx - tmp < rule) {
      if (row > ury)
	errbox = ury;
      else if (row < lly)
	errbox = lly;
      else
	errbox = row;
      if (tmp == LARGE)
	tmp = llx - rule;
      sprintf(STR3, "OVERLAP error (%s,%s)",
	      layername(STR1, layer), layername(STR2, against_layer));
      sprintf(STR5, "OVER %d,%d", layer, against_layer);
      sprintf(STR4, "%.10s", STR5);
      drc_error(llx, errbox, tmp, row, STR3, STR4);
    }
  }
}


Static void drc_overlap2(node *box, short within_layer, short against_layer,
			 short rule)
{
  /* if box is contained in 'within_layer', then make sure
     it is surrounded by 'against_layer' */
  short llx, urx, lly, ury, layer, tmp, row, errbox;
  Char STR1[81], STR2[81];
  Char STR3[182];
  Char STR4[256];
  Char STR5[256], STR7[256];

  llx = box->ll.x;
  lly = box->ll.y;
  urx = box->ur.x;
  ury = box->ur.y;
  xform_vertical(&llx, &lly, &urx, &ury);
  layer = box->layer;
  for (row = lly - rule + 1; row < ury + rule; row++) {
    /* check to the right */
    if (index_(within_layer, row, urx) > 0)
    {  /* we are inside the 'within_layer' */
      tmp = nextend(against_layer, row, urx);
      if (tmp - urx < rule) {
	if (row > ury)
	  errbox = ury;
	else if (row < lly)
	  errbox = lly;
	else
	  errbox = row;
	if (tmp == -LARGE)
	  tmp = urx + rule;
	sprintf(STR3, "OVERLAP2 error (%s,%s)",
		layername(STR1, layer), layername(STR2, against_layer));
	sprintf(STR7, "OVER2 %d,%d", layer, against_layer);
	sprintf(STR4, "%.10s", STR7);
	drc_error(urx, errbox, tmp, row, STR3, STR4);
      }
    }
  }
  for (row = lly - rule + 1; row < ury + rule; row++) {
    /* check to the left */
    if (index_(within_layer, row, llx) > 0)
    {  /* we are inside 'within_layer' */
      tmp = prevstart(against_layer, row, llx);
      if (llx - tmp < rule) {
	if (row > ury)
	  errbox = ury;
	else if (row < lly)
	  errbox = lly;
	else
	  errbox = row;
	if (tmp == LARGE)
	  tmp = llx - rule;
	sprintf(STR3, "OVERLAP2 error (%s,%s)",
		layername(STR1, layer), layername(STR2, against_layer));
	sprintf(STR5, "OVER2 %d,%d", layer, against_layer);
	sprintf(STR4, "%.10s", STR5);
	drc_error(llx, errbox, tmp, row, STR3, STR4);
      }
    }
  }
}


Static void drc_separation2(node *box, short within_layer,
			    short against_layer, short rule)
{
  /* if box is within layer 'within_layer' then check
     separations to against_layer */
  short llx, urx, lly, ury, layer, row, tmp;
  Char STR1[81], STR2[81];
  Char STR3[184];
  Char STR4[256];
  Char STR5[256], STR7[256];

  llx = box->ll.x;
  lly = box->ll.y;
  urx = box->ur.x;
  ury = box->ur.y;
  xform_vertical(&llx, &lly, &urx, &ury);
  layer = box->layer;
  for (row = lly - rule + 1; row < ury + rule; row++)
  {  /* check to the right */
    tmp = nextstart(against_layer, row, urx);
    if (tmp - urx < rule) {
      sprintf(STR3, "SEPARATION2 error (%s,%s)",
	      layername(STR1, layer), layername(STR2, against_layer));
      sprintf(STR7, "SEP2 %d,%d", layer, against_layer);
      sprintf(STR4, "%.10s", STR7);
      drc_error(urx, ury, tmp, row, STR3, STR4);
    }
  }
  for (row = lly - rule + 1; row < ury + rule; row++)
  {  /* check above and to the left */
    tmp = prevend(against_layer, row, llx);
    if (llx - tmp < rule) {
      sprintf(STR3, "SEPARATION2 error (%s,%s)",
	      layername(STR1, layer), layername(STR2, against_layer));
      sprintf(STR5, "SEP2 %d,%d", layer, against_layer);
      sprintf(STR4, "%.10s", STR5);
      drc_error(tmp, row, llx, ury, STR3, STR4);
    }
  }
}


Static void drc_box(node *box)
{
  /* perform separation and extension checks for the box */
  /* separation checks are done corner-to-corner, in both directions */
  short against_layer, against_layer2, rule;

  /* do separation check */
  /* if external edge ????? */
  for (against_layer = min_layer; against_layer <= max_layer; against_layer++) {
    rule = separation[box->layer - min_layer][against_layer - min_layer];
    if (rule != -1)
      drc_separation(box, against_layer, rule);

    rule = overlap[box->layer - min_layer][against_layer - min_layer];
    if (rule != -1)
      drc_overlap(box, against_layer, rule);

    if (drc_extensive) {
      for (against_layer2 = min_layer;
	   against_layer2 <= max_layer;
	   against_layer2++) {
	rule = separation2[box->layer - min_layer][against_layer - min_layer]
	  [against_layer2 - min_layer];
	if (rule != -1)
	  drc_separation2(box, against_layer, against_layer2, rule);

	rule = overlap2[box->layer - min_layer][against_layer - min_layer]
	  [against_layer2 - min_layer];
	if (rule != -1)
	  drc_overlap2(box, against_layer, against_layer2, rule);
      }
    }

  }
}




Static void drc_run(node *box)
{
  while (box != NULL) {
    drc_box(box);
    drc_run(box->child);
    box = box->next;
  }
}


/* Local variables for drc_width: */
struct LOC_drc_width {
  short layer, rule;
} ;

Local short max(short a, short b)
{
  if (a > b)
    return a;
  else
    return b;
}

Local short min(short a, short b)
{
  if (a < b)
    return a;
  else
    return b;
}

Local void drc_width_corner(node *box, struct LOC_drc_width *LINK)
{
  /* check above each box to see if there is contact
     made to a different box; if so, check widths that
     are in common */
  short index1, index2, boxeslength, i, left, right, llx, lly, urx, ury;
  Char STR1[81];
  Char STR3[98];
  Char STR4[256];

  while (box != NULL) {
    llx = box->ll.x;
    lly = box->ll.y;
    urx = box->ur.x;
    ury = box->ur.y;
    xform_vertical(&llx, &lly, &urx, &ury);
    index1 = index_(LINK->layer, ury + 1, llx);
    index2 = index_(LINK->layer, ury + 1, urx);
    if (index1 != index2) {  /* need to look more carefully */
      boxeslength = boxeslen[LINK->layer - min_layer][ury + 1];
      if (index1 == -boxeslength)
	index1 = LARGE;
      else if (index1 < 0)
	index1 = 1 - index1;
      if (index2 == -boxeslength)
	index2 = LARGE;
      else if (index2 < 0)
	index2 = -index2;
      /* now check overlaps */
      for (i = index1; i <= index2; i++) {
	if (i != 0 && i <= boxeslength) {
	  left = max(llx, startb[ury + 1][i - 1][LINK->layer - min_layer]);
	  right = min(urx, endb[ury + 1][i - 1][LINK->layer - min_layer]);
	  if (right - left < LINK->rule) {
	    sprintf(STR3, "WIDTH* error (%s)", layername(STR1, LINK->layer));
	    sprintf(STR4, "WIDTH* %d", LINK->layer);
	    drc_error(left, ury, right, ury, STR3, STR4);
	  }
	}
      }
    }
    if (box->child != NULL)
      drc_width_corner(box->child, LINK);
    box = box->next;
  }
}




Static void drc_width(void)
{
  /* simple test -- run along each scan line to make sure
     that the layer is at least rule units wide.
    NOTE:  this does not catch all corner-corner interactions */
  struct LOC_drc_width V;
  short row, i;
  long max_extent;
  short FORLIM2;
  Char STR1[81];
  Char STR3[96];
  Char STR4[256];


  if (vertical_drc)
    max_extent = window_ury - window_lly + window_buffer;
  else
    max_extent = window_urx - window_llx + window_buffer;
  for (V.layer = min_layer; V.layer <= max_layer; V.layer++) {
    V.rule = width[V.layer - min_layer][V.layer - min_layer];
    if (V.rule != -1) {
      for (row = 0; row <= drcrows; row++) {
	FORLIM2 = boxeslen[V.layer - min_layer][row];
	for (i = 0; i < FORLIM2; i++) {
	  if (endb[row][i][V.layer - min_layer] - startb[row][i]
	      [V.layer - min_layer] < V.rule &&
	      endb[row][i][V.layer - min_layer] >= window_buffer &&
	      startb[row][i][V.layer - min_layer] <= max_extent) {
	    sprintf(STR3, "WIDTH error (%s)", layername(STR1, V.layer));
	    sprintf(STR4, "WIDTH %d", V.layer);
	    drc_error(startb[row][i][V.layer - min_layer], row, endb[row][i]
		      [V.layer - min_layer], row, STR3, STR4);
	  }
	}
      }
      /* now consider corner-corner interactions */
      /*  drc_width_corner (main);  */
    }
  }
}


Static void drc_geom_horizontal(void)
{
  vertical_drc = false;
  drc_init();
  drc_buffer(main_);
  sort_rows();
  drc_run(main_);
  drc_width();
}


Static void drc_geom_vertical(void)
{
  vertical_drc = true;
  drc_init();   /* reset data structures */
  drc_buffer(main_);
  sort_rows();
  drc_run(main_);
  drc_width();
}


Static void show_stats(long area, long time)
{
  FILE *t;
  Char s[81];
  Char STR1[88];

  t = NULL;
  /* Logging stats to /LIB/WOLLIB/DRC.LOG...  */
  get_date_string(s);
  if (t != NULL) {
    sprintf(STR1, "%sdrc.log", WolLib);
    t = freopen(STR1, "a", t);
  } else {
    sprintf(STR1, "%sdrc.log", WolLib);
    t = fopen(STR1, "a");
  }
  if (t == NULL)
    _EscIO(FileNotFound);
  fprintf(t, "DRC used by: %s on %s\n", wol_username, s);
  if (area != 0)
    fprintf(t,
	    "  performance: %ld lambda^2 in %ld cs = %0.2f lambda^2 / sec\n",
	    area, time, area * 100.0 / time);
  if (t != NULL)
    fclose(t);
  t = NULL;
  if (t != NULL)
    fclose(t);
}


Static void log_message(Char *s)
{
  FILE *t;
  Char STR1[88];

  t = NULL;
  show_stats(0, 0);
  if (t != NULL) {
    sprintf(STR1, "%sdrc.log", WolLib);
    t = freopen(STR1, "a", t);
  } else {
    sprintf(STR1, "%sdrc.log", WolLib);
    t = fopen(STR1, "a");
  }
  if (t == NULL)
    _EscIO(FileNotFound);
  fprintf(t, "%s\n", s);
  if (t != NULL)
    fclose(t);
  t = NULL;
  if (t != NULL)
    fclose(t);
}



void do_geom_drc(void)
{
  window_llx = 0;
  window_urx = LARGE;
  window_lly = 0;
  window_ury = LARGE;
  window_buffer = 0;
  drc_geom_horizontal();
  drc_geom_vertical();
  dump_geom_list();
  show_stats(0, 0);
  TRY(try4);
    if (printer != NULL)
      fclose(printer);
    printer = NULL;
  RECOVER(try4);
    ;
  ENDTRY(try4);
  printf("DRC COMPLETED\n");
}


Local void drc_geom_stuff(node *t_p)
{
  node *t_p2;
  long temp;
  node *WITH;

  if (asm_memavail() < min_mem_recurse) {
    show_message("\007Low on memory in DRC_GEOM_STUFF", false);
    goto _L1;
  }
  t_p2 = get_a_node();
  while (t_p != NULL) {
    WITH = t_p;
    *t_p2 = *t_p;
    t_p2->next = NULL;
    t_p2->child = NULL;
    t_p2->ll = transform_point(t_p->ll);
    t_p2->ur = transform_point(t_p->ur);

    /*  writeln ('processing box at ',t_p2^.ll.x, t_p2^.ll.y, t_p2^.ur.x, t_p2^.ur.y); */

    /* sort absolute lambda coordinates */
    if (t_p2->ll.x > t_p2->ur.x) {
      temp = t_p2->ll.x;
      t_p2->ll.x = t_p2->ur.x;
      t_p2->ur.x = temp;
    }
    if (t_p2->ll.y > t_p2->ur.y) {
      temp = t_p2->ll.y;
      t_p2->ll.y = t_p2->ur.y;
      t_p2->ur.y = temp;
    }
    /* do a trivial reject clip */
    if (t_p2->ll.x <= window_urx && t_p2->ur.x >= window_llx &&
	t_p2->ll.y <= window_ury && t_p2->ur.y >= window_lly)
    {   /*t_p^.*/
      /* clip to window size */
      if (t_p2->ll.x < window_llx)
	t_p2->ll.x = window_llx;
      if (t_p2->ur.x > window_urx)
	t_p2->ur.x = window_urx;
      if (t_p2->ll.y < window_lly)
	t_p2->ll.y = window_lly;
      if (t_p2->ur.y > window_ury)
	t_p2->ur.y = window_ury;
      /* now normalize to 0,0 */
      t_p2->ll.x -= window_llx;
      t_p2->ll.y -= window_lly;
      t_p2->ur.x -= window_llx;
      t_p2->ur.y -= window_lly;
      /*  writeln ('    adding box at ',t_p2^.ll.x, t_p2^.ll.y, t_p2^.ur.x, t_p2^.ur.y); */
      if (t_p2->ll.x != t_p2->ur.x && t_p2->ll.y != t_p2->ur.y)
	drc_addbox(t_p2);
    }
    if (WITH->child != NULL)   /*t_p^.*/
      drc_geom_stuff(WITH->child);
    t_p = WITH->next;   /*t_p^.*/
  }
_L1:
  recl_nodes(&t_p2);
}


Local void drc_comp_2(c_cell *root)
{
  /* stacks up a transformation matrix */
  point tp2;
  tr_matrix old_matrix;
  bb_states bb_save;
  point ll, ur;


  old_matrix = tr_ctm;
  bb_save = bb_state;
  if (asm_memavail() < min_mem_recurse) {
    show_message("\007Low on memory in DRC_COMP", false);
    return;
  }
  TRY(try5);
    while (root != NULL) {
      bb_state = bb_save;

      pl_tran(root->ll.x, root->ll.y);
      pl_xform(root->xform);

      /* TP2 is used in bounding box calculation and also if the cell is */
      /* closed. */
      tp2.x = root->ur.x - root->ll.x;
      tp2.y = root->ur.y - root->ll.y;

      ll = transform_point(change_to_point(0, 0));
      ur = transform_point(tp2);

      /*  writeln('  next MBB at (',ll.x:0,',',ll.y:0,') (',ur.x:0,',',ur.y:0,')');  */
      if ((ll.x < window_urx || ur.x < window_urx) &&
	  (ll.x > window_llx || ur.x > window_llx) &&
	  (ll.y < window_ury || ur.y < window_ury) &&
	  (ll.y > window_lly || ur.y > window_lly)) {
	if (root->tag == COMP) {
	  /*  drc_routing(root^.c_d^.routing);   */
	  drc_comp_2(root->UU.U1.c_d->data);
	} else
	  drc_geom_stuff(root->UU.g_d->data);
      }
      /* trivial clip and ignore */

      root = root->next;   /* deal with its siblings */
      tr_ctm = old_matrix;   /* restore transformation matrix */
    }
  RECOVER(try5);
    if (P_escapecode == 10)
      _Escape(P_escapecode);
    else {
      show_error("Error in procedure DRC_COMP_2", false);
      _Escape(10);
    }
  ENDTRY(try5);
}


Static void drc_comp(void)
{
  tr_matrix old_mat;

  old_mat = tr_ctm;   /* Save it for later */
  pl_ident();
  /*drc_routing (comp_cells^.routing); */
  drc_comp_2(comp_cells->data);
  tr_ctm = old_mat;
}


Local void drc_geom_stuff_(node *t_p)
{
  node *t_p2;
  long temp;
  node *WITH;

  if (asm_memavail() < min_mem_recurse) {
    show_message("\007Low on memory in DRC_GEOM_STUFF", false);
    goto _L1;
  }
  t_p2 = get_a_node();
  while (t_p != NULL) {
    WITH = t_p;
    *t_p2 = *t_p;
    t_p2->next = NULL;
    t_p2->child = NULL;
    t_p2->ll = transform_point(t_p->ll);
    t_p2->ur = transform_point(t_p->ur);
    if (t_p2->ll.x > t_p2->ur.x) {
      temp = t_p2->ll.x;
      t_p2->ll.x = t_p2->ur.x;
      t_p2->ur.x = temp;
    }
    if (t_p2->ll.y > t_p2->ur.y) {
      temp = t_p2->ll.y;
      t_p2->ll.y = t_p2->ur.y;
      t_p2->ur.y = temp;
    }

    /* do a trivial reject clip */
    if (t_p2->ll.x <= window_urx && t_p2->ur.x >= window_llx &&
	t_p2->ll.y <= window_ury && t_p2->ur.y >= window_lly)
    {   /*t_p^.*/
      /* clip to window size */
      if (t_p2->ll.x < window_llx)
	t_p2->ll.x = window_llx;
      if (t_p2->ur.x > window_urx)
	t_p2->ur.x = window_urx;
      if (t_p2->ll.y < window_lly)
	t_p2->ll.y = window_lly;
      if (t_p2->ur.y > window_ury)
	t_p2->ur.y = window_ury;
      /* now normalize to 0,0 */
      t_p2->ll.x += window_buffer - window_llx;
      t_p2->ll.y += window_buffer - window_lly;
      t_p2->ur.x += window_buffer - window_llx;
      t_p2->ur.y += window_buffer - window_lly;
      if (t_p2->ll.x != t_p2->ur.x && t_p2->ll.y != t_p2->ur.y)
	drc_box(t_p2);
    }
    if (WITH->child != NULL)   /*t_p^.*/
      drc_geom_stuff_(WITH->child);
    t_p = WITH->next;   /*t_p^.*/
  }
_L1:
  recl_nodes(&t_p2);
}


Local void drc_comp_2b(c_cell *root)
{
  /* stacks up a transformation matrix */
  point tp2;
  tr_matrix old_matrix;
  bb_states bb_save;
  point ll, ur;


  old_matrix = tr_ctm;
  bb_save = bb_state;
  if (asm_memavail() < min_mem_recurse) {
    show_message("\007Low on memory in DRC_COMP_RUN", false);
    return;
  }
  TRY(try6);
    while (root != NULL) {
      bb_state = bb_save;

      pl_tran(root->ll.x, root->ll.y);
      pl_xform(root->xform);

      /* TP2 is used in bounding box calculation and also if the cell is */
      /* closed. */
      tp2.x = root->ur.x - root->ll.x;
      tp2.y = root->ur.y - root->ll.y;

      ll = transform_point(change_to_point(0, 0));
      ur = transform_point(tp2);

      if ((ll.x < window_urx || ur.x < window_urx) &&
	  (ll.x > window_llx || ur.x > window_llx) &&
	  (ll.y < window_ury || ur.y < window_ury) &&
	  (ll.y > window_lly || ur.y > window_lly)) {
	if (root->tag == COMP) {
	  /*  drc_routing(root^.c_d^.routing);  */
	  drc_comp_2b(root->UU.U1.c_d->data);
	} else
	  drc_geom_stuff_(root->UU.g_d->data);
      }
      /* trivial clip and ignore */

      root = root->next;   /* deal with its siblings */
      tr_ctm = old_matrix;   /* restore transformation matrix */
    }
  RECOVER(try6);
    if (P_escapecode == 10)
      _Escape(P_escapecode);
    else {
      show_error("Error in procedure DRC_COMP_2B", false);
      _Escape(10);
    }
  ENDTRY(try6);
}


Static void drc_comp_run(void)
{
  tr_matrix old_mat;

  /* set clipping window to be same as DRAWN box */
  window_llx += window_buffer;
  window_lly += window_buffer;
  window_urx -= window_buffer;
  window_ury -= window_buffer;
  old_mat = tr_ctm;   /* Save it for later */
  pl_ident();
  /*drc_routing (comp_cells^.routing); */
  drc_comp_2b(comp_cells->data);
  tr_ctm = old_mat;
}



Static void drc_comp_horizontal(void)
{
  vertical_drc = false;
  drc_init();
  drc_comp();
  sort_rows();
  drc_comp_run();
  drc_width();
}


Static void drc_comp_vertical(void)
{
  vertical_drc = true;
  drc_init();
  drc_comp();
  sort_rows();
  drc_comp_run();
  drc_width();
}



void show_comp_drc(void)
{
  node *ptr;
  point ll, ur;

  gsave();
  make_matrix();
  ptr = drc_list_head;
  while (ptr != NULL) {
    if (strcmp(m_machine, "320"))
      printf("%s at (%ld,%ld)\n", ptr->name, ptr->ll.x, ptr->ur.y);
    ll = transform_point(ptr->ll);
    ur = transform_point(ptr->ur);
    m_color(BR_WHITE);   /*m_color (7);*/
    smartbox(ll.x, ll.y, ur.x, ur.y);
    ptr = ptr->next;
  }
  grestore();
}


void flash_comp_drc(void)
{
  node *ptr;
  point ll, ur;
  tablet_info t;
  boolean was_near, down;

  gsave();
  make_matrix();
  alpha_screen(CLR);
  printf("\nPress or lift pen to stop flashing.");

  was_near = false;
  down = false;
  m_colormode(m_xor);
  do {
    ptr = drc_list_head;
    m_color(BR_WHITE);   /*m_color (7);  */
    while (ptr != NULL) {
      if (strcmp(m_machine, "320"))
	printf("%s at (%ld,%ld)\n", ptr->name, ptr->ll.x, ptr->ur.y);
      ll = transform_point(ptr->ll);
      ur = transform_point(ptr->ur);
      smartbox(ll.x, ll.y, ur.x, ur.y);
      ptr = ptr->next;
    }
    /* Only call get_pen in this part to prevent screen screwups */
    t = get_pen();
    m_cursor(t.x, t.y);
    if (t.near_)
      was_near = true;
    if (t.depressed)
      down = true;

    ptr = drc_list_head;
    /* m_color (8);    redraw in black */
    while (ptr != NULL) {
      if (strcmp(m_machine, "320"))
	printf("%s at (%ld,%ld)\n", ptr->name, ptr->ll.x, ptr->ur.y);
      ll = transform_point(ptr->ll);
      ur = transform_point(ptr->ur);
      smartbox(ll.x, ll.y, ur.x, ur.y);
      ptr = ptr->next;
    }
    /* Call check_pen in this part to allow zoom/pan */
    t = check_pen();
    m_cursor(t.x, t.y);
    if (t.near_)
      was_near = true;
    if (t.depressed)
      down = true;
  } while (!(down || !t.near_ && was_near));
  grestore();
}


void clean_comp_drc(void)
{
  recl_nodes(&drc_list_head);
}


void do_comp_drc_window(void)
{
  tablet_info pen;
  point start, finish;
  short old_color;
  Char STR1[256];

  show_message("Draw window for DRC", true);
  TRY(try7);
    pen = tr_pen();
    start = change_to_point(pen.x, pen.y);
    old_color = curr_color;
    set_layer(sel_box);
    if (get_rbb(&start, &finish)) {
      if (finish.x - start.x > drcrows || finish.y - start.y > drcrows) {
	sprintf(STR1, "DRC BOX is too large (max size = %ld lambda)",
		(long)drcrows);
	show_message(STR1, false);
      } else {
	time_start();
	window_buffer = 5;
	window_llx = start.x - window_buffer;
	window_lly = start.y - window_buffer;
	window_urx = finish.x + window_buffer;
	window_ury = finish.y + window_buffer;
	drc_comp_horizontal();
	window_llx = start.x - window_buffer;
	window_lly = start.y - window_buffer;
	window_urx = finish.x + window_buffer;
	window_ury = finish.y + window_buffer;
	drc_comp_vertical();
	show_stats((window_urx - window_llx) * (window_ury - window_lly),
		   elapsed_time());
	printf("DRC completed\n");
	TRY(try8);
	  if (printer != NULL)
	    fclose(printer);
	printer = NULL;
	RECOVER(try8);
	  ;
	ENDTRY(try8);
	show_comp_drc();
      }
    }
  RECOVER(try7);
    if (P_escapecode != -1)
    {   /* ignore internal errors; user already notified */
      if (P_escapecode == 10)
	_Escape(10);
      else {
	show_error("ERROR in do_comp_drc:", false);
	_Escape(P_escapecode);
      }
    }
  ENDTRY(try7);
  set_layer(old_color);

  /*  writeln ('start  = ', start.x:0, ' ', start.y:0);
      writeln ('finish = ', finish.x:0, ' ', finish.y:0);  */

}


void do_comp_drc(void)
{
  point start;
  long window_size;
  comp_list *compmbb;

  /* similar to do_comp_drc_window, but calls DRC's entire COMP buffer */
  compmbb = get_c_cell();
  compmbb->data = comp_cells->data;
  set_c_bb(compmbb);

  time_start();
  window_buffer = 5;
  window_size = drcrows - window_buffer * 2 - 10;   /* kluge by MAS */
  start.y = compmbb->ll.y;
  while (start.y < compmbb->ur.y) {
    start.x = compmbb->ll.x;
    while (start.x < compmbb->ur.x) {
      TRY(try9);
	window_llx = start.x - window_buffer;
	window_lly = start.y - window_buffer;
	window_urx = start.x + window_size + window_buffer;
	window_ury = start.y + window_size + window_buffer;
	drc_comp_horizontal();
	window_llx = start.x - window_buffer;
	window_lly = start.y - window_buffer;
	window_urx = start.x + window_size + window_buffer;
	window_ury = start.y + window_size + window_buffer;
	drc_comp_vertical();
	start.x += window_size;
      RECOVER(try9);
	if (P_escapecode != -1)
	{   /* ignore internal errors; user already notified */
	  if (P_escapecode == 10)
	    _Escape(10);
	  else {
	    show_error("ERROR in do_comp_drc:", false);
	    _Escape(P_escapecode);
	  }
	}
      ENDTRY(try9);
    }
    start.y += window_size;
  }
  show_stats((window_urx - window_llx) * (window_ury - window_lly),
	     elapsed_time());
  printf("DRC completed\n");
  TRY(try10);
    if (printer != NULL)
       fclose(printer);
    printer = NULL;
  RECOVER(try10);
    ;
  ENDTRY(try10);
  compmbb->data = NULL;
  recl_c_cell(&compmbb);
  show_comp_drc();
}


void drc_test(void)
{
  short layer, row, x, tmp;
  Char STR3[81];

  vertical_drc = false;
  drc_init();
  drc_buffer(main_);
  sort_rows();
  printf("Enter layer to search:     ");
  scanf("%hd%*[^\n]", &layer);
/*  getchar();*/
  nk_getkey();
  printf("Enter start of search: (x) ");
  scanf("%hd%*[^\n]", &x);
/*  getchar();*/
  nk_getkey();
  printf("Enter row to consider: (y) ");
  scanf("%hd%*[^\n]", &row);
/*  getchar();*/
  nk_getkey();
  tmp = index_(layer, row, x);
  if (tmp == 0)
    printf("index = 0\n");
  else if (tmp == -boxeslen[layer - min_layer][row])
    printf("index = -boxeslen\n");
  else {
    if (tmp < 0) {
      printf("index negative\n");
      tmp = -tmp;
    }
    printf("index = %d start = %d end = %d\n",
	   tmp, startb[row][tmp - 1][layer - min_layer], endb[row][tmp - 1]
	   [layer - min_layer]);
  }
  tmp = nextstart(layer, row, x);
  printf("nextstart: x = %d; layer = %s; result = %d\n",
	 x, layername(STR3, layer), tmp);
  tmp = prevend(layer, row, x);
  printf("prevend:   x = %d; layer = %s; result = %d\n",
	 x, layername(STR3, layer), tmp);
  tmp = prevstart(layer, row, x);
  printf("prevstart: x = %d; layer = %s; result = %d\n",
	 x, layername(STR3, layer), tmp);
  tmp = nextend(layer, row, x);
  printf("nextend:   x = %d; layer = %s; result = %d\n",
	 x, layername(STR3, layer), tmp);
  printf("finished drc_test\n");
  TRY(try11);
    if (printer != NULL)
      fclose(printer);
    printer = NULL;
  RECOVER(try11);
    ;
  ENDTRY(try11);
}




/* End. */
